Upgrade rust/crates/grpcio-sys to 0.9.0+1.38.0

Test: make
Change-Id: I216e32d09b497864276eaa4743f6c88722cebe14
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 3ae5b96..2587a95 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "4b29b582c723ced543508bc0395d1e303f7eed97"
+    "sha1": "7a48e0bb843e702832c1c3ac024c468dedf0023c"
   }
 }
diff --git a/Android.bp b/Android.bp
index 009e0e4..b523e8b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -108,8 +108,8 @@
 // dependent_library ["feature_list"]
 //   bindgen-0.57.0 "runtime"
 //   bitflags-1.2.1 "default"
-//   boringssl-src-0.2.0
-//   cc-1.0.67
+//   boringssl-src-0.3.0+688fc5c
+//   cc-1.0.68
 //   cexpr-0.4.0
 //   cfg-if-1.0.0
 //   clang-sys-1.2.0 "clang_3_5,clang_3_6,clang_3_7,clang_3_8,clang_3_9,clang_4_0,clang_5_0,clang_6_0,libloading,runtime"
@@ -117,20 +117,20 @@
 //   glob-0.3.0
 //   lazy_static-1.4.0
 //   lazycell-1.3.0
-//   libc-0.2.93 "default,std"
+//   libc-0.2.97 "default,std"
 //   libloading-0.7.0
-//   libz-sys-1.1.2 "default,libc,static,stock-zlib"
-//   memchr-2.3.4 "std,use_std"
+//   libz-sys-1.1.3 "libc,static"
+//   memchr-2.4.0 "std,use_std"
 //   nom-5.1.2 "alloc,std"
 //   peeking_take_while-0.1.2
 //   pkg-config-0.3.19
-//   proc-macro2-1.0.26
+//   proc-macro2-1.0.27
 //   quote-1.0.9
-//   regex-1.4.5 "std,unicode,unicode-age,unicode-bool,unicode-case,unicode-gencat,unicode-perl,unicode-script,unicode-segment"
-//   regex-syntax-0.6.23 "unicode,unicode-age,unicode-bool,unicode-case,unicode-gencat,unicode-perl,unicode-script,unicode-segment"
+//   regex-1.5.4 "std,unicode,unicode-age,unicode-bool,unicode-case,unicode-gencat,unicode-perl,unicode-script,unicode-segment"
+//   regex-syntax-0.6.25 "unicode,unicode-age,unicode-bool,unicode-case,unicode-gencat,unicode-perl,unicode-script,unicode-segment"
 //   rustc-hash-1.1.0 "default,std"
 //   same-file-1.0.6
 //   shlex-0.1.1
-//   unicode-xid-0.2.1 "default"
+//   unicode-xid-0.2.2 "default"
 //   version_check-0.9.3
 //   walkdir-2.3.2
diff --git a/Cargo.toml b/Cargo.toml
index 231c13c..7dc8a0c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 [package]
 edition = "2018"
 name = "grpcio-sys"
-version = "0.8.1"
+version = "0.9.0+1.38.0"
 authors = ["The TiKV Project Developers"]
 build = "build.rs"
 exclude = ["grpc/doc/*", "grpc/etc/*", "grpc/examples/*", "grpc/Makefile", "grpc/templates/*", "grpc/src/android/*", "grpc/src/csharp/*", "grpc/src/node/*", "grpc/src/objective-c/*", "grpc/src/php/*", "grpc/src/python/*", "grpc/src/ruby/*", "grpc/test/core/end2end/*", "grpc/third_party/zlib/*", "grpc/third_party/abseil-cpp/absl/time/internal/cctz/testdata", "grpc/third_party/benchmark/*", "grpc/third_party/bloaty/*", "grpc/third_party/boringssl-with-bazel/*", "grpc/third_party/libuv/*", "grpc/third_party/gflags/*", "grpc/third_party/googletest/*", "grpc/third_party/objective_c/*", "grpc/third_party/protobuf/*", "grpc/third_party/toolchans/*", "grpc/third_party/envoy-api/*", "grpc/third_party/googleapis/*", "grpc/third_party/protoc-gen-validate/*", "grpc/third_party/udpa/*", "grpc/tools/run_tests/generated/*", "grpc/test/core/", "!grpc/test/core/security/*.cc", "!grpc/test/core/util/cmdline.cc", "grpc/test/cpp"]
@@ -28,8 +28,9 @@
 version = "0.2"
 
 [dependencies.libz-sys]
-version = "1.0.25"
-features = ["static"]
+version = "1.1.3"
+features = ["libc", "static"]
+default-features = false
 
 [dependencies.openssl-sys]
 version = "0.9"
@@ -42,7 +43,7 @@
 default-features = false
 
 [build-dependencies.boringssl-src]
-version = "0.2.0"
+version = "0.3.0"
 
 [build-dependencies.cc]
 version = "1.0"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 27c58a8..4b4e16a 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "grpcio-sys"
-version = "0.8.1"
+version = "0.9.0+1.38.0"
 authors = ["The TiKV Project Developers"]
 license = "Apache-2.0"
 keywords = ["grpc", "bindings"]
@@ -50,7 +50,7 @@
 [dependencies]
 libc = "0.2"
 openssl-sys = { version = "0.9", optional = true, features = ["vendored"] }
-libz-sys = { version = "1.0.25", features = ["static"] }
+libz-sys = { version = "1.1.3", default-features = false, features = ["libc", "static"] }
 
 [features]
 default = ["use-bindgen"]
@@ -70,4 +70,4 @@
 walkdir = "2.2.9"
 # Because of rust-lang/cargo#5237, bindgen should not be upgraded util a minor or major release.
 bindgen = { version = "0.57.0", default-features = false, optional = true, features = ["runtime"] }
-boringssl-src = "0.2.0"
+boringssl-src = "0.3.0"
diff --git a/METADATA b/METADATA
index d28576c..213b447 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/grpcio-sys/grpcio-sys-0.8.1.crate"
+    value: "https://static.crates.io/crates/grpcio-sys/grpcio-sys-0.9.0+1.38.0.crate"
   }
-  version: "0.8.1"
+  version: "0.9.0+1.38.0"
   license_type: NOTICE
   last_upgrade_date {
     year: 2021
-    month: 4
-    day: 2
+    month: 6
+    day: 21
   }
 }
diff --git a/bindings/aarch64-unknown-linux-gnu-bindings.rs b/bindings/aarch64-unknown-linux-gnu-bindings.rs
index e4743cf..b24c0ee 100644
--- a/bindings/aarch64-unknown-linux-gnu-bindings.rs
+++ b/bindings/aarch64-unknown-linux-gnu-bindings.rs
@@ -109,6 +109,8 @@
     b"grpc.experimental.tcp_tx_zerocopy_max_simultaneous_sends\0";
 pub const GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS: &'static [u8; 28usize] =
     b"grpc.grpclb_call_timeout_ms\0";
+pub const GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG: &'static [u8; 55usize] =
+    b"grpc.TEST_ONLY_DO_NOT_USE_IN_PROD.xds_bootstrap_config\0";
 pub const GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS: &'static [u8; 32usize] =
     b"grpc.grpclb_fallback_timeout_ms\0";
 pub const GRPC_ARG_PRIORITY_FAILOVER_TIMEOUT_MS: &'static [u8; 34usize] =
@@ -159,7 +161,10 @@
 pub const GRPC_X509_PEM_CERT_CHAIN_PROPERTY_NAME: &'static [u8; 20usize] = b"x509_pem_cert_chain\0";
 pub const GRPC_SSL_SESSION_REUSED_PROPERTY: &'static [u8; 19usize] = b"ssl_session_reused\0";
 pub const GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME: &'static [u8; 15usize] = b"security_level\0";
+pub const GRPC_PEER_DNS_PROPERTY_NAME: &'static [u8; 9usize] = b"peer_dns\0";
 pub const GRPC_PEER_SPIFFE_ID_PROPERTY_NAME: &'static [u8; 15usize] = b"peer_spiffe_id\0";
+pub const GRPC_PEER_EMAIL_PROPERTY_NAME: &'static [u8; 11usize] = b"peer_email\0";
+pub const GRPC_PEER_IP_PROPERTY_NAME: &'static [u8; 8usize] = b"peer_ip\0";
 pub const GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR: &'static [u8; 33usize] =
     b"GRPC_DEFAULT_SSL_ROOTS_FILE_PATH\0";
 pub const GRPC_GOOGLE_CREDENTIALS_ENV_VAR: &'static [u8; 31usize] =
@@ -2096,12 +2101,28 @@
 }
 #[repr(C)]
 #[derive(Debug, Copy, Clone)]
+pub struct grpc_server_xds_status_notifier {
+    pub on_serving_status_update: ::std::option::Option<
+        unsafe extern "C" fn(
+            user_data: *mut ::std::os::raw::c_void,
+            uri: *const ::std::os::raw::c_char,
+            code: grpc_status_code::Type,
+            error_message: *const ::std::os::raw::c_char,
+        ),
+    >,
+    pub user_data: *mut ::std::os::raw::c_void,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
 pub struct grpc_server_config_fetcher {
     _unused: [u8; 0],
 }
 extern "C" {
     #[doc = " EXPERIMENTAL.  Creates an xDS config fetcher."]
-    pub fn grpc_server_config_fetcher_xds_create() -> *mut grpc_server_config_fetcher;
+    pub fn grpc_server_config_fetcher_xds_create(
+        notifier: grpc_server_xds_status_notifier,
+        args: *const grpc_channel_args,
+    ) -> *mut grpc_server_config_fetcher;
 }
 extern "C" {
     #[doc = " EXPERIMENTAL.  Destroys a config fetcher."]
@@ -2211,6 +2232,11 @@
     );
 }
 extern "C" {
+    #[doc = " EXPERIMENTAL.  Dumps xDS configs as a serialized ClientConfig proto."]
+    #[doc = "The full name of the proto is envoy.service.status.v3.ClientConfig."]
+    pub fn grpc_dump_xds_configs() -> grpc_slice;
+}
+extern "C" {
     #[doc = " Fetch a vtable for a grpc_channel_arg that points to a grpc_resource_quota"]
     pub fn grpc_resource_quota_arg_vtable() -> *const grpc_arg_pointer_vtable;
 }
@@ -3286,8 +3312,8 @@
 }
 extern "C" {
     #[doc = " Sets the options of whether to request and verify client certs. This should"]
-    #[doc = " be called only on the server side. It returns 1 on success and 0 on failure."]
-    #[doc = " It is used for experimental purpose for now and subject to change."]
+    #[doc = " be called only on the server side. It is used for experimental purpose for"]
+    #[doc = " now and subject to change."]
     pub fn grpc_tls_credentials_options_set_cert_request_type(
         options: *mut grpc_tls_credentials_options,
         type_: grpc_ssl_client_certificate_request_type,
@@ -3298,8 +3324,7 @@
     #[doc = " hostname check, etc. This should be called only on the client side. If"]
     #[doc = " |server_verification_option| is not GRPC_TLS_SERVER_VERIFICATION, use of a"]
     #[doc = " custom authorization check (grpc_tls_server_authorization_check_config) is"]
-    #[doc = " mandatory. It returns 1 on success and 0 on failure. It is used for"]
-    #[doc = " experimental purpose for now and subject to change."]
+    #[doc = " mandatory. It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_set_server_verification_option(
         options: *mut grpc_tls_credentials_options,
         server_verification_option: grpc_tls_server_verification_option,
@@ -3308,7 +3333,6 @@
 extern "C" {
     #[doc = " Sets the credential provider in the options."]
     #[doc = " The |options| will implicitly take a new ref to the |provider|."]
-    #[doc = " It returns 1 on success and 0 on failure."]
     #[doc = " It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_set_certificate_provider(
         options: *mut grpc_tls_credentials_options,
@@ -3317,8 +3341,14 @@
 }
 extern "C" {
     #[doc = " If set, gRPC stack will keep watching the root certificates with"]
-    #[doc = " name |root_cert_name|. It returns 1 on success and 0 on failure. It is used"]
-    #[doc = " for experimental purpose for now and subject to change."]
+    #[doc = " name |root_cert_name|."]
+    #[doc = " If this is not set on the client side, we will use the root certificates"]
+    #[doc = " stored in the default system location, since client side must provide root"]
+    #[doc = " certificates in TLS."]
+    #[doc = " If this is not set on the server side, we will not watch any root certificate"]
+    #[doc = " updates, and assume no root certificates needed for the server(single-side"]
+    #[doc = " TLS). Default root certs on the server side is not supported."]
+    #[doc = " It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_watch_root_certs(
         options: *mut grpc_tls_credentials_options,
     );
@@ -3334,8 +3364,9 @@
 }
 extern "C" {
     #[doc = " If set, gRPC stack will keep watching the identity key-cert pairs"]
-    #[doc = " with name |identity_cert_name|. It returns 1 on success and 0 on failure. It"]
-    #[doc = " is used for experimental purpose for now and subject to change."]
+    #[doc = " with name |identity_cert_name|."]
+    #[doc = " This is required on the server side, and optional on the client side."]
+    #[doc = " It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_watch_identity_key_cert_pairs(
         options: *mut grpc_tls_credentials_options,
     );
@@ -3352,8 +3383,8 @@
 extern "C" {
     #[doc = " Sets the configuration for a custom authorization check performed at the end"]
     #[doc = " of the handshake. The |options| will implicitly take a new ref to the"]
-    #[doc = " |config|. It returns 1 on success and 0 on failure. It is used for"]
-    #[doc = " experimental purpose for now and subject to change."]
+    #[doc = " |config|."]
+    #[doc = " It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_set_server_authorization_check_config(
         options: *mut grpc_tls_credentials_options,
         config: *mut grpc_tls_server_authorization_check_config,
diff --git a/bindings/x86_64-unknown-linux-gnu-bindings.rs b/bindings/x86_64-unknown-linux-gnu-bindings.rs
index e4743cf..b24c0ee 100644
--- a/bindings/x86_64-unknown-linux-gnu-bindings.rs
+++ b/bindings/x86_64-unknown-linux-gnu-bindings.rs
@@ -109,6 +109,8 @@
     b"grpc.experimental.tcp_tx_zerocopy_max_simultaneous_sends\0";
 pub const GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS: &'static [u8; 28usize] =
     b"grpc.grpclb_call_timeout_ms\0";
+pub const GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG: &'static [u8; 55usize] =
+    b"grpc.TEST_ONLY_DO_NOT_USE_IN_PROD.xds_bootstrap_config\0";
 pub const GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS: &'static [u8; 32usize] =
     b"grpc.grpclb_fallback_timeout_ms\0";
 pub const GRPC_ARG_PRIORITY_FAILOVER_TIMEOUT_MS: &'static [u8; 34usize] =
@@ -159,7 +161,10 @@
 pub const GRPC_X509_PEM_CERT_CHAIN_PROPERTY_NAME: &'static [u8; 20usize] = b"x509_pem_cert_chain\0";
 pub const GRPC_SSL_SESSION_REUSED_PROPERTY: &'static [u8; 19usize] = b"ssl_session_reused\0";
 pub const GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME: &'static [u8; 15usize] = b"security_level\0";
+pub const GRPC_PEER_DNS_PROPERTY_NAME: &'static [u8; 9usize] = b"peer_dns\0";
 pub const GRPC_PEER_SPIFFE_ID_PROPERTY_NAME: &'static [u8; 15usize] = b"peer_spiffe_id\0";
+pub const GRPC_PEER_EMAIL_PROPERTY_NAME: &'static [u8; 11usize] = b"peer_email\0";
+pub const GRPC_PEER_IP_PROPERTY_NAME: &'static [u8; 8usize] = b"peer_ip\0";
 pub const GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR: &'static [u8; 33usize] =
     b"GRPC_DEFAULT_SSL_ROOTS_FILE_PATH\0";
 pub const GRPC_GOOGLE_CREDENTIALS_ENV_VAR: &'static [u8; 31usize] =
@@ -2096,12 +2101,28 @@
 }
 #[repr(C)]
 #[derive(Debug, Copy, Clone)]
+pub struct grpc_server_xds_status_notifier {
+    pub on_serving_status_update: ::std::option::Option<
+        unsafe extern "C" fn(
+            user_data: *mut ::std::os::raw::c_void,
+            uri: *const ::std::os::raw::c_char,
+            code: grpc_status_code::Type,
+            error_message: *const ::std::os::raw::c_char,
+        ),
+    >,
+    pub user_data: *mut ::std::os::raw::c_void,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
 pub struct grpc_server_config_fetcher {
     _unused: [u8; 0],
 }
 extern "C" {
     #[doc = " EXPERIMENTAL.  Creates an xDS config fetcher."]
-    pub fn grpc_server_config_fetcher_xds_create() -> *mut grpc_server_config_fetcher;
+    pub fn grpc_server_config_fetcher_xds_create(
+        notifier: grpc_server_xds_status_notifier,
+        args: *const grpc_channel_args,
+    ) -> *mut grpc_server_config_fetcher;
 }
 extern "C" {
     #[doc = " EXPERIMENTAL.  Destroys a config fetcher."]
@@ -2211,6 +2232,11 @@
     );
 }
 extern "C" {
+    #[doc = " EXPERIMENTAL.  Dumps xDS configs as a serialized ClientConfig proto."]
+    #[doc = "The full name of the proto is envoy.service.status.v3.ClientConfig."]
+    pub fn grpc_dump_xds_configs() -> grpc_slice;
+}
+extern "C" {
     #[doc = " Fetch a vtable for a grpc_channel_arg that points to a grpc_resource_quota"]
     pub fn grpc_resource_quota_arg_vtable() -> *const grpc_arg_pointer_vtable;
 }
@@ -3286,8 +3312,8 @@
 }
 extern "C" {
     #[doc = " Sets the options of whether to request and verify client certs. This should"]
-    #[doc = " be called only on the server side. It returns 1 on success and 0 on failure."]
-    #[doc = " It is used for experimental purpose for now and subject to change."]
+    #[doc = " be called only on the server side. It is used for experimental purpose for"]
+    #[doc = " now and subject to change."]
     pub fn grpc_tls_credentials_options_set_cert_request_type(
         options: *mut grpc_tls_credentials_options,
         type_: grpc_ssl_client_certificate_request_type,
@@ -3298,8 +3324,7 @@
     #[doc = " hostname check, etc. This should be called only on the client side. If"]
     #[doc = " |server_verification_option| is not GRPC_TLS_SERVER_VERIFICATION, use of a"]
     #[doc = " custom authorization check (grpc_tls_server_authorization_check_config) is"]
-    #[doc = " mandatory. It returns 1 on success and 0 on failure. It is used for"]
-    #[doc = " experimental purpose for now and subject to change."]
+    #[doc = " mandatory. It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_set_server_verification_option(
         options: *mut grpc_tls_credentials_options,
         server_verification_option: grpc_tls_server_verification_option,
@@ -3308,7 +3333,6 @@
 extern "C" {
     #[doc = " Sets the credential provider in the options."]
     #[doc = " The |options| will implicitly take a new ref to the |provider|."]
-    #[doc = " It returns 1 on success and 0 on failure."]
     #[doc = " It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_set_certificate_provider(
         options: *mut grpc_tls_credentials_options,
@@ -3317,8 +3341,14 @@
 }
 extern "C" {
     #[doc = " If set, gRPC stack will keep watching the root certificates with"]
-    #[doc = " name |root_cert_name|. It returns 1 on success and 0 on failure. It is used"]
-    #[doc = " for experimental purpose for now and subject to change."]
+    #[doc = " name |root_cert_name|."]
+    #[doc = " If this is not set on the client side, we will use the root certificates"]
+    #[doc = " stored in the default system location, since client side must provide root"]
+    #[doc = " certificates in TLS."]
+    #[doc = " If this is not set on the server side, we will not watch any root certificate"]
+    #[doc = " updates, and assume no root certificates needed for the server(single-side"]
+    #[doc = " TLS). Default root certs on the server side is not supported."]
+    #[doc = " It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_watch_root_certs(
         options: *mut grpc_tls_credentials_options,
     );
@@ -3334,8 +3364,9 @@
 }
 extern "C" {
     #[doc = " If set, gRPC stack will keep watching the identity key-cert pairs"]
-    #[doc = " with name |identity_cert_name|. It returns 1 on success and 0 on failure. It"]
-    #[doc = " is used for experimental purpose for now and subject to change."]
+    #[doc = " with name |identity_cert_name|."]
+    #[doc = " This is required on the server side, and optional on the client side."]
+    #[doc = " It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_watch_identity_key_cert_pairs(
         options: *mut grpc_tls_credentials_options,
     );
@@ -3352,8 +3383,8 @@
 extern "C" {
     #[doc = " Sets the configuration for a custom authorization check performed at the end"]
     #[doc = " of the handshake. The |options| will implicitly take a new ref to the"]
-    #[doc = " |config|. It returns 1 on success and 0 on failure. It is used for"]
-    #[doc = " experimental purpose for now and subject to change."]
+    #[doc = " |config|."]
+    #[doc = " It is used for experimental purpose for now and subject to change."]
     pub fn grpc_tls_credentials_options_set_server_authorization_check_config(
         options: *mut grpc_tls_credentials_options,
         config: *mut grpc_tls_server_authorization_check_config,
diff --git a/build.rs b/build.rs
index 32bdeea..c717988 100644
--- a/build.rs
+++ b/build.rs
@@ -1,6 +1,5 @@
 // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
 
-use std::collections::HashSet;
 use std::env::VarError;
 use std::io::prelude::*;
 use std::io::BufReader;
@@ -11,7 +10,24 @@
 use pkg_config::{Config as PkgConfig, Library};
 use walkdir::WalkDir;
 
-const GRPC_VERSION: &str = "1.35.0";
+const GRPC_VERSION: &str = "1.38.0";
+
+/// Following two arrays are generated by running pkg-config manually. We can
+/// also choose to run pkg-config at build time, but it will requires pkg-config
+/// in path, which is unfriendly for platforms like Windows.
+// grpc_unsecure.pc is not accurate, see also grpc/grpc#24512. Should also include "address_sorting", "upb", "cares", "z".
+#[rustfmt::skip]
+const COMMON_DEPS: &[&str] = &[
+    "absl_bad_optional_access", "absl_bad_variant_access", "absl_base", "absl_city", "absl_civil_time",
+    "absl_cord", "absl_debugging_internal", "absl_demangle_internal", "absl_exponential_biased",
+    "absl_graphcycles_internal", "absl_hash", "absl_hashtablez_sampler", "absl_int128", "absl_log_severity",
+    "absl_malloc_internal", "absl_raw_hash_set", "absl_raw_logging_internal", "absl_spinlock_wait",
+    "absl_stacktrace", "absl_status", "absl_statusor", "absl_str_format_internal", "absl_strings",
+    "absl_strings_internal", "absl_symbolize", "absl_synchronization", "absl_throw_delegate", "absl_time",
+    "absl_time_zone", "absl_wyhash", "address_sorting", "cares", "gpr", "upb", "z",
+];
+const GRPC_DEPS: &[&str] = &["grpc", "re2"];
+const GRPC_UNSECURE_DEPS: &[&str] = &["grpc_unsecure"];
 
 fn probe_library(library: &str, cargo_metadata: bool) -> Library {
     match PkgConfig::new()
@@ -190,23 +206,12 @@
         }
     }
 
-    let collect = |path, to: &mut HashSet<_>| {
-        let f = fs::File::open(format!("{}/libs/opt/pkgconfig/{}.pc", build_dir, path)).unwrap();
-        for l in io::BufReader::new(f).lines() {
-            let l = l.unwrap();
-            if l.starts_with("Libs: ") {
-                for lib in l.split_whitespace() {
-                    if let Some(s) = lib.strip_prefix("-l") {
-                        to.insert(s.to_string());
-                    }
-                }
-            }
-        }
+    let libs = if library.contains("unsecure") {
+        GRPC_UNSECURE_DEPS
+    } else {
+        GRPC_DEPS
     };
-    let mut libs = HashSet::new();
-    collect("gpr", &mut libs);
-    collect(library, &mut libs);
-    for l in libs {
+    for l in COMMON_DEPS.iter().chain(libs) {
         println!("cargo:rustc-link-lib=static={}", l);
     }
 
@@ -217,12 +222,6 @@
             println!("cargo:rustc-link-lib=static=ssl");
             println!("cargo:rustc-link-lib=static=crypto");
         }
-    } else {
-        // grpc_unsecure.pc is not accurate, see also grpc/grpc#24512.
-        println!("cargo:rustc-link-lib=static=upb");
-        println!("cargo:rustc-link-lib=static=cares");
-        println!("cargo:rustc-link-lib=static=z");
-        println!("cargo:rustc-link-lib=static=address_sorting");
     }
 
     cc.include("grpc/include");
@@ -299,7 +298,7 @@
 // Generate the bindings to grpc C-core.
 // Try to disable the generation of platform-related bindings.
 #[cfg(feature = "use-bindgen")]
-fn bindgen_grpc(file_path: &PathBuf) {
+fn bindgen_grpc(file_path: &Path) {
     // create a config to generate binding file
     let mut config = bindgen::Builder::default();
     if cfg!(feature = "secure") {
diff --git a/grpc/.bazelignore b/grpc/.bazelignore
index b85dcc0..0334334 100644
--- a/grpc/.bazelignore
+++ b/grpc/.bazelignore
@@ -10,6 +10,7 @@
 third_party/boringssl-with-bazel
 third_party/googleapis
 third_party/googletest
+third_party/opencensus-proto
 third_party/protobuf
 third_party/protoc-gen-validate
 third_party/udpa
diff --git a/grpc/.clang-format b/grpc/.clang-format
index b641a64..7460950 100644
--- a/grpc/.clang-format
+++ b/grpc/.clang-format
@@ -3,6 +3,7 @@
 BasedOnStyle: Google
 DerivePointerAlignment: false
 PointerAlignment: Left
+IncludeBlocks: Preserve
 ---
 Language: ObjC
 BasedOnStyle: Google
diff --git a/grpc/.clang-tidy b/grpc/.clang-tidy
index 752b25e..8714bad 100644
--- a/grpc/.clang-tidy
+++ b/grpc/.clang-tidy
@@ -1,37 +1,122 @@
 ---
-# Disable abseil-no-namespace: https://bugs.llvm.org/show_bug.cgi?id=47947
+# Note on checks are disabled on purpose
+#
+# - abseil-no-namespace
+#   https://bugs.llvm.org/show_bug.cgi?id=47947
+#
+# - bugprone-reserved-identifier
+#   Some macros need to be defined for portability purpose; e.g. _BSD_SOURCE.
+#
+# - google-upgrade-googletest-case
+#   This requires googletest 1.10 which is higher than ones installed on many linux distributions.
+#
+# - modernize-redundant-void-arg
+#   Some source should be strictly C99 and func(void) should be used.
+#
+# Note on checks which will be enabled in future. These are good to have but
+# it's not activated yet due to the existing issues with the checks.
+# Once those issues are clear, these checks can be enabled later.
+#
+# - bugprone-branch-clone
+# - bugprone-infinite-loop
+# - bugprone-narrowing-conversions
+# - bugprone-not-null-terminated-result
+# - bugprone-signed-char-misuse
+# - bugprone-sizeof-expression
+# - bugprone-too-small-loop-variable
+# - clang-diagnostic-deprecated-declarations
+# - clang-diagnostic-unused-function
+# - google-readability-avoid-underscore-in-googletest-name
+# - google-runtime-int
+# - google-runtime-references
+# - modernize-avoid-bind
+# - modernize-deprecated-headers
+# - modernize-loop-convert
+# - modernize-pass-by-value
+# - modernize-raw-string-literal
+# - modernize-return-braced-init-list
+# - modernize-use-auto
+# - modernize-use-default-member-init
+# - modernize-use-emplace
+# - modernize-use-equals-default
+# - modernize-use-equals-delete
+# - modernize-use-using
+# - performance-no-automatic-move
+# - performance-unnecessary-copy-initialization
+# - performance-unnecessary-value-param
+# - readability-else-after-return
+# - readability-implicit-bool-conversion
+# - readability-redundant-declaration
+# - readability-static-definition-in-anonymous-namespace
+#
 Checks: '-*,
   abseil-*,
   -abseil-no-namespace,
   bugprone-*,
+  -bugprone-branch-clone,
+  -bugprone-infinite-loop,
   -bugprone-narrowing-conversions,
+  -bugprone-not-null-terminated-result,
+  -bugprone-reserved-identifier,
+  -bugprone-signed-char-misuse,
+  -bugprone-sizeof-expression,
   -bugprone-too-small-loop-variable,
-  performance-*,
-  -performance-unnecessary-copy-initialization,
-  -performance-unnecessary-value-param,
   google-*,
+  -google-readability-avoid-underscore-in-googletest-name,
   -google-runtime-int,
   -google-runtime-references,
+  -google-upgrade-googletest-case,
+  performance-*,
+  -performance-no-automatic-move,
+  -performance-unnecessary-copy-initialization,
+  -performance-unnecessary-value-param,
+  clang-diagnostic-deprecated-register,
+  clang-diagnostic-expansion-to-defined,
+  clang-diagnostic-ignored-attributes,
+  clang-diagnostic-non-pod-varargs,
+  clang-diagnostic-shadow-field,
+  clang-diagnostic-shift-sign-overflow,
+  clang-diagnostic-tautological-undefined-compare,
+  clang-diagnostic-thread-safety*,
+  clang-diagnostic-undefined-bool-conversion,
+  clang-diagnostic-unreachable-code,
+  clang-diagnostic-unreachable-code-loop-increment,
+  clang-diagnostic-unused-const-variable,
+  clang-diagnostic-unused-lambda-capture,
+  clang-diagnostic-unused-local-typedef,
+  clang-diagnostic-unused-private-field,
+  clang-diagnostic-user-defined-warnings,
   misc-definitions-in-headers,
   misc-static-assert,
   misc-unconventional-assign-operator,
   misc-uniqueptr-reset-release,
   misc-unused-alias-decls,
   misc-unused-using-decls,
+  modernize-make-shared,
   modernize-make-unique,
-  -modernize-redundant-void-arg,
   modernize-replace-auto-ptr,
+  modernize-replace-random-shuffle,
   modernize-shrink-to-fit,
+  modernize-unary-static-assert,
   modernize-use-bool-literals,
+  modernize-use-noexcept,
   modernize-use-nullptr,
   modernize-use-override,
+  modernize-use-transparent-functors,
+  readability-const-return-type,
   readability-container-size-empty,
+  readability-delete-null-pointer,
   readability-deleted-default,
   readability-function-size,
   readability-inconsistent-declaration-parameter-name,
+  readability-misleading-indentation,
+  readability-misplaced-array-index,
   readability-redundant-control-flow,
+  readability-redundant-function-ptr-dereference,
   readability-redundant-smartptr-get,
-  readability-string-compare'
+  readability-simplify-boolean-expr,
+  readability-string-compare,
+  readability-uniqueptr-delete-release'
 WarningsAsErrors: '*'
 CheckOptions:
   - key:    readability-function-size.StatementThreshold
diff --git a/grpc/.github/ISSUE_TEMPLATE/bug_report.md b/grpc/.github/ISSUE_TEMPLATE/bug_report.md
index 1a096d5..e69dc0b 100644
--- a/grpc/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/grpc/.github/ISSUE_TEMPLATE/bug_report.md
@@ -2,7 +2,7 @@
 name: Report a bug
 about: Create a report to help us improve
 labels: kind/bug, priority/P2
-assignees: donnadionne
+assignees: nicolasnoble
 
 ---
 
diff --git a/grpc/.github/ISSUE_TEMPLATE/cleanup_request.md b/grpc/.github/ISSUE_TEMPLATE/cleanup_request.md
index ef88ef4..c9a6d3f 100644
--- a/grpc/.github/ISSUE_TEMPLATE/cleanup_request.md
+++ b/grpc/.github/ISSUE_TEMPLATE/cleanup_request.md
@@ -2,7 +2,7 @@
 name: Request a cleanup
 about: Suggest a cleanup in our repository
 labels: kind/internal cleanup, priority/P2
-assignees: donnadionne
+assignees: nicolasnoble
 
 ---
 
diff --git a/grpc/.github/ISSUE_TEMPLATE/feature_request.md b/grpc/.github/ISSUE_TEMPLATE/feature_request.md
index f230fe2..e313799 100644
--- a/grpc/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/grpc/.github/ISSUE_TEMPLATE/feature_request.md
@@ -2,7 +2,7 @@
 name: Request a feature
 about: Suggest an idea for this project
 labels: kind/enhancement, priority/P2
-assignees: donnadionne
+assignees: nicolasnoble
 
 ---
 
diff --git a/grpc/.github/ISSUE_TEMPLATE/question.md b/grpc/.github/ISSUE_TEMPLATE/question.md
index 77ecf5e..cfde18b 100644
--- a/grpc/.github/ISSUE_TEMPLATE/question.md
+++ b/grpc/.github/ISSUE_TEMPLATE/question.md
@@ -2,7 +2,7 @@
 name: Ask a question
 about: Ask a question
 labels: kind/question, priority/P3
-assignees: donnadionne
+assignees: nicolasnoble
 
 ---
 
diff --git a/grpc/.github/change_repo_manager.sh b/grpc/.github/change_repo_manager.sh
index 739f42c..5f73a6c 100755
--- a/grpc/.github/change_repo_manager.sh
+++ b/grpc/.github/change_repo_manager.sh
@@ -27,9 +27,11 @@
 
 for file in bug_report.md cleanup_request.md feature_request.md question.md
 do
-	sed -i -E "s/assignees: ([a-zA-Z0-9-]+)/assignees: $1/" $BASE_PATH/ISSUE_TEMPLATE/$file
+	sed -i".bak" -E "s/assignees: ([a-zA-Z0-9-]+)/assignees: $1/" "$BASE_PATH/ISSUE_TEMPLATE/$file"
+  rm "$BASE_PATH/ISSUE_TEMPLATE/$file.bak"
 done
 
-sed -i -E "s/^@([a-zA-Z0-9-]+)/@$1/" $BASE_PATH/pull_request_template.md
+sed -i".bak" -E "s/^@([a-zA-Z0-9-]+)/@$1/" "$BASE_PATH/pull_request_template.md"
+rm "$BASE_PATH/pull_request_template.md.bak"
 
 echo "Done"
diff --git a/grpc/.github/pull_request_template.md b/grpc/.github/pull_request_template.md
index eddba66..57af6c2 100644
--- a/grpc/.github/pull_request_template.md
+++ b/grpc/.github/pull_request_template.md
@@ -8,4 +8,4 @@
 
 -->
 
-@donnadionne
+@nicolasnoble
diff --git a/grpc/.gitmodules b/grpc/.gitmodules
index ef97568..0c5e543 100644
--- a/grpc/.gitmodules
+++ b/grpc/.gitmodules
@@ -46,3 +46,6 @@
 [submodule "third_party/libuv"]
 	path = third_party/libuv
 	url = https://github.com/libuv/libuv.git
+[submodule "third_party/opencensus-proto"]
+	path = third_party/opencensus-proto
+	url = https://github.com/census-instrumentation/opencensus-proto.git
diff --git a/grpc/.pylintrc b/grpc/.pylintrc
index be8be6b..08ec7e8 100644
--- a/grpc/.pylintrc
+++ b/grpc/.pylintrc
@@ -95,3 +95,5 @@
 	no-else-return,
 	# NOTE(lidiz): Python 3 make object inheritance default, but not PY2
 	useless-object-inheritance,
+  # NOTE(sergiitk): yapf compatibility, ref #25071
+  bad-continuation,
diff --git a/grpc/.pylintrc-examples b/grpc/.pylintrc-examples
index 9480d6e..0100d84 100644
--- a/grpc/.pylintrc-examples
+++ b/grpc/.pylintrc-examples
@@ -98,3 +98,5 @@
 	no-else-return,
 	# NOTE(lidiz): Python 3 make object inheritance default, but not PY2
 	useless-object-inheritance,
+  # NOTE(sergiitk): yapf compatibility, ref #25071
+  bad-continuation,
diff --git a/grpc/.pylintrc-tests b/grpc/.pylintrc-tests
index d9cc4d1..808fe7f 100644
--- a/grpc/.pylintrc-tests
+++ b/grpc/.pylintrc-tests
@@ -124,3 +124,5 @@
 	no-else-return,
 	# NOTE(lidiz): Python 3 make object inheritance default, but not PY2
 	useless-object-inheritance,
+  # NOTE(sergiitk): yapf compatibility, ref #25071
+  bad-continuation,
diff --git a/grpc/BUILD b/grpc/BUILD
index 909b811..823abc2 100644
--- a/grpc/BUILD
+++ b/grpc/BUILD
@@ -77,14 +77,19 @@
     values = {"cpu": "darwin"},
 )
 
+config_setting(
+    name = "use_strict_warning",
+    values = {"define": "use_strict_warning=true"},
+)
+
 python_config_settings()
 
 # This should be updated along with build_handwritten.yaml
-g_stands_for = "gecko"
+g_stands_for = "guadalupe_river_park_conservancy"  # @unused
 
-core_version = "14.0.0"
+core_version = "16.0.0"  # @unused
 
-version = "1.35.0"
+version = "1.38.0"  # @unused
 
 GPR_PUBLIC_HDRS = [
     "include/grpc/support/alloc.h",
@@ -122,6 +127,13 @@
     "include/grpc/support/workaround_list.h",
 ]
 
+GRPC_PUBLIC_EVENT_ENGINE_HDRS = [
+    "include/grpc/event_engine/channel_args.h",
+    "include/grpc/event_engine/event_engine.h",
+    "include/grpc/event_engine/port.h",
+    "include/grpc/event_engine/slice_allocator.h",
+]
+
 GRPC_SECURE_PUBLIC_HDRS = [
     "include/grpc/grpc_security.h",
 ]
@@ -327,12 +339,12 @@
             "grpc_lb_policy_xds_cluster_manager",
             "grpc_lb_policy_xds_cluster_resolver",
             "grpc_resolver_xds",
+            "grpc_resolver_c2p",
             "grpc_xds_server_config_fetcher",
         ],
     },
     standalone = True,
     deps = [
-        "grpc_authorization_engine",
         "grpc_common",
         "grpc_lb_policy_grpclb_secure",
         "grpc_secure",
@@ -345,12 +357,36 @@
     name = "grpc++_public_hdrs",
     hdrs = GRPCXX_PUBLIC_HDRS,
     external_deps = [
+        "absl/synchronization",
         "protobuf_headers",
     ],
 )
 
 grpc_cc_library(
     name = "grpc++",
+    hdrs = [
+        "src/cpp/client/secure_credentials.h",
+        "src/cpp/common/secure_auth_context.h",
+        "src/cpp/common/tls_credentials_options_util.h",
+        "src/cpp/server/secure_server_credentials.h",
+    ],
+    language = "c++",
+    public_hdrs = GRPCXX_PUBLIC_HDRS,
+    select_deps = {
+        "grpc_no_xds": [],
+        "//conditions:default": [
+            "grpc++_xds_client",
+            "grpc++_xds_server",
+        ],
+    },
+    standalone = True,
+    deps = [
+        "grpc++_internals",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc++_internals",
     srcs = [
         "src/cpp/client/insecure_credentials.cc",
         "src/cpp/client/secure_credentials.cc",
@@ -371,18 +407,11 @@
         "src/cpp/server/secure_server_credentials.h",
     ],
     external_deps = [
+        "absl/synchronization",
         "protobuf_headers",
     ],
     language = "c++",
     public_hdrs = GRPCXX_PUBLIC_HDRS,
-    select_deps = {
-        "grpc_no_xds": [],
-        "//conditions:default": [
-            "grpc++_xds_client",
-            "grpc++_xds_server",
-        ],
-    },
-    standalone = True,
     deps = [
         "gpr",
         "grpc",
@@ -404,7 +433,7 @@
     ],
     language = "c++",
     deps = [
-        "grpc++_base",
+        "grpc++_internals",
     ],
 )
 
@@ -421,7 +450,7 @@
         "include/grpcpp/xds_server_builder.h",
     ],
     deps = [
-        "grpc++_base",
+        "grpc++_internals",
     ],
 )
 
@@ -457,7 +486,6 @@
     standalone = True,
     deps = [
         "grpc++",
-        "//src/proto/grpc/status:status_proto",
     ],
 )
 
@@ -511,6 +539,9 @@
     hdrs = [
         "include/grpcpp/impl/codegen/sync.h",
     ],
+    external_deps = [
+        "absl/synchronization",
+    ],
     language = "c++",
     deps = [
         "gpr_codegen",
@@ -560,8 +591,10 @@
         "src/core/lib/gprpp/mpscq.cc",
         "src/core/lib/gprpp/stat_posix.cc",
         "src/core/lib/gprpp/stat_windows.cc",
+        "src/core/lib/gprpp/status_helper.cc",
         "src/core/lib/gprpp/thd_posix.cc",
         "src/core/lib/gprpp/thd_windows.cc",
+        "src/core/lib/gprpp/time_util.cc",
         "src/core/lib/profiling/basic_timers.cc",
         "src/core/lib/profiling/stap_timers.cc",
     ],
@@ -594,8 +627,10 @@
         "src/core/lib/gprpp/memory.h",
         "src/core/lib/gprpp/mpscq.h",
         "src/core/lib/gprpp/stat.h",
+        "src/core/lib/gprpp/status_helper.h",
         "src/core/lib/gprpp/sync.h",
         "src/core/lib/gprpp/thd.h",
+        "src/core/lib/gprpp/time_util.h",
         "src/core/lib/profiling/timers.h",
     ],
     external_deps = [
@@ -611,6 +646,8 @@
     language = "c++",
     public_hdrs = GPR_PUBLIC_HDRS,
     deps = [
+        "debug_location",
+        "google_api_upb",
         "gpr_codegen",
         "grpc_codegen",
     ],
@@ -719,6 +756,8 @@
 grpc_cc_library(
     name = "grpc_base_c",
     srcs = [
+        "src/core/lib/address_utils/parse_address.cc",
+        "src/core/lib/address_utils/sockaddr_utils.cc",
         "src/core/lib/avl/avl.cc",
         "src/core/lib/backoff/backoff.cc",
         "src/core/lib/channel/channel_args.cc",
@@ -740,6 +779,8 @@
         "src/core/lib/compression/stream_compression_identity.cc",
         "src/core/lib/debug/stats.cc",
         "src/core/lib/debug/stats_data.cc",
+        "src/core/lib/event_engine/slice_allocator.cc",
+        "src/core/lib/event_engine/sockaddr.cc",
         "src/core/lib/http/format_request.cc",
         "src/core/lib/http/httpcli.cc",
         "src/core/lib/http/parser.cc",
@@ -784,7 +825,6 @@
         "src/core/lib/iomgr/is_epollexclusive_available.cc",
         "src/core/lib/iomgr/load_file.cc",
         "src/core/lib/iomgr/lockfree_event.cc",
-        "src/core/lib/iomgr/parse_address.cc",
         "src/core/lib/iomgr/polling_entity.cc",
         "src/core/lib/iomgr/pollset.cc",
         "src/core/lib/iomgr/pollset_custom.cc",
@@ -798,7 +838,6 @@
         "src/core/lib/iomgr/resolve_address_posix.cc",
         "src/core/lib/iomgr/resolve_address_windows.cc",
         "src/core/lib/iomgr/resource_quota.cc",
-        "src/core/lib/iomgr/sockaddr_utils.cc",
         "src/core/lib/iomgr/socket_factory_posix.cc",
         "src/core/lib/iomgr/socket_mutator.cc",
         "src/core/lib/iomgr/socket_utils_common_posix.cc",
@@ -881,6 +920,8 @@
         "src/core/lib/uri/uri_parser.cc",
     ],
     hdrs = [
+        "src/core/lib/address_utils/parse_address.h",
+        "src/core/lib/address_utils/sockaddr_utils.h",
         "src/core/lib/avl/avl.h",
         "src/core/lib/backoff/backoff.h",
         "src/core/lib/channel/channel_args.h",
@@ -936,12 +977,10 @@
         "src/core/lib/iomgr/iomgr.h",
         "src/core/lib/iomgr/iomgr_custom.h",
         "src/core/lib/iomgr/iomgr_internal.h",
-        "src/core/lib/iomgr/iomgr_posix.h",
         "src/core/lib/iomgr/is_epollexclusive_available.h",
         "src/core/lib/iomgr/load_file.h",
         "src/core/lib/iomgr/lockfree_event.h",
         "src/core/lib/iomgr/nameser.h",
-        "src/core/lib/iomgr/parse_address.h",
         "src/core/lib/iomgr/polling_entity.h",
         "src/core/lib/iomgr/pollset.h",
         "src/core/lib/iomgr/pollset_custom.h",
@@ -958,7 +997,6 @@
         "src/core/lib/iomgr/sockaddr.h",
         "src/core/lib/iomgr/sockaddr_custom.h",
         "src/core/lib/iomgr/sockaddr_posix.h",
-        "src/core/lib/iomgr/sockaddr_utils.h",
         "src/core/lib/iomgr/sockaddr_windows.h",
         "src/core/lib/iomgr/socket_factory_posix.h",
         "src/core/lib/iomgr/socket_mutator.h",
@@ -1031,10 +1069,9 @@
         "absl/container:flat_hash_map",
     ],
     language = "c++",
-    public_hdrs = GRPC_PUBLIC_HDRS,
+    public_hdrs = GRPC_PUBLIC_HDRS + GRPC_PUBLIC_EVENT_ENGINE_HDRS,
     deps = [
         "dual_ref_counted",
-        "eventmanager_libuv",
         "gpr_base",
         "grpc_codegen",
         "grpc_trace",
@@ -1079,6 +1116,7 @@
         "grpc_transport_chttp2_client_insecure",
         "grpc_transport_chttp2_server_insecure",
         "grpc_transport_inproc",
+        "grpc_fault_injection_filter",
         "grpc_workaround_cronet_compression_filter",
         "grpc_server_backward_compatibility",
     ],
@@ -1108,6 +1146,8 @@
         "src/core/ext/filters/client_channel/resolver.cc",
         "src/core/ext/filters/client_channel/resolver_registry.cc",
         "src/core/ext/filters/client_channel/resolver_result_parsing.cc",
+        "src/core/ext/filters/client_channel/retry_filter.cc",
+        "src/core/ext/filters/client_channel/retry_service_config.cc",
         "src/core/ext/filters/client_channel/retry_throttle.cc",
         "src/core/ext/filters/client_channel/server_address.cc",
         "src/core/ext/filters/client_channel/service_config.cc",
@@ -1140,6 +1180,8 @@
         "src/core/ext/filters/client_channel/resolver_factory.h",
         "src/core/ext/filters/client_channel/resolver_registry.h",
         "src/core/ext/filters/client_channel/resolver_result_parsing.h",
+        "src/core/ext/filters/client_channel/retry_filter.h",
+        "src/core/ext/filters/client_channel/retry_service_config.h",
         "src/core/ext/filters/client_channel/retry_throttle.h",
         "src/core/ext/filters/client_channel/server_address.h",
         "src/core/ext/filters/client_channel/service_config.h",
@@ -1235,6 +1277,23 @@
 )
 
 grpc_cc_library(
+    name = "grpc_fault_injection_filter",
+    srcs = [
+        "src/core/ext/filters/fault_injection/fault_injection_filter.cc",
+        "src/core/ext/filters/fault_injection/service_config_parser.cc",
+    ],
+    hdrs = [
+        "src/core/ext/filters/fault_injection/fault_injection_filter.h",
+        "src/core/ext/filters/fault_injection/service_config_parser.h",
+    ],
+    language = "c++",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+    ],
+)
+
+grpc_cc_library(
     name = "grpc_http_filters",
     srcs = [
         "src/core/ext/filters/http/client/http_client_filter.cc",
@@ -1370,6 +1429,8 @@
         "src/core/ext/xds/xds_certificate_provider.cc",
         "src/core/ext/xds/xds_client.cc",
         "src/core/ext/xds/xds_client_stats.cc",
+        "src/core/ext/xds/xds_http_fault_filter.cc",
+        "src/core/ext/xds/xds_http_filters.cc",
         "src/core/lib/security/credentials/xds/xds_credentials.cc",
     ],
     hdrs = [
@@ -1383,12 +1444,15 @@
         "src/core/ext/xds/xds_channel_args.h",
         "src/core/ext/xds/xds_client.h",
         "src/core/ext/xds/xds_client_stats.h",
+        "src/core/ext/xds/xds_http_fault_filter.h",
+        "src/core/ext/xds/xds_http_filters.h",
         "src/core/lib/security/credentials/xds/xds_credentials.h",
     ],
     external_deps = [
         "absl/functional:bind_front",
         "upb_lib",
         "upb_textformat_lib",
+        "upb_json_lib",
         "re2",
     ],
     language = "c++",
@@ -1397,8 +1461,12 @@
         "envoy_ads_upbdefs",
         "grpc_base",
         "grpc_client_channel",
+        "grpc_fault_injection_filter",
+        "grpc_matchers",
         "grpc_secure",
         "grpc_transport_chttp2_client_secure",
+        "udpa_type_upb",
+        "udpa_type_upbdefs",
     ],
 )
 
@@ -1475,7 +1543,9 @@
         "grpc_base",
         "grpc_client_channel",
         "grpc_lb_address_filtering",
+        "grpc_lb_xds_channel_args",
         "grpc_lb_xds_common",
+        "grpc_resolver_fake",
         "grpc_xds_client",
     ],
 )
@@ -1558,6 +1628,22 @@
 )
 
 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 = [
         "src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc",
@@ -1809,6 +1895,23 @@
     srcs = [
         "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc",
     ],
+    external_deps = [
+        "xxhash",
+    ],
+    language = "c++",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+        "grpc_lb_policy_ring_hash",
+        "grpc_xds_client",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_resolver_c2p",
+    srcs = [
+        "src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc",
+    ],
     language = "c++",
     deps = [
         "grpc_base",
@@ -1939,15 +2042,72 @@
     ],
 )
 
+# This target depends on RE2 and should not be linked into grpc by default for binary-size reasons.
 grpc_cc_library(
-    name = "grpc_authorization_engine",
+    name = "grpc_matchers",
     srcs = [
-        "src/core/lib/security/authorization/authorization_engine.cc",
+        "src/core/lib/matchers/matchers.cc",
+    ],
+    hdrs = [
+        "src/core/lib/matchers/matchers.h",
+    ],
+    external_deps = [
+        "re2",
+    ],
+    language = "c++",
+    deps = [
+        "grpc_base",
+    ],
+)
+
+# This target pulls in a dependency on RE2 and should not be linked into grpc by default for binary-size reasons.
+grpc_cc_library(
+    name = "grpc_rbac_engine",
+    srcs = [
         "src/core/lib/security/authorization/evaluate_args.cc",
+        "src/core/lib/security/authorization/grpc_authorization_engine.cc",
+        "src/core/lib/security/authorization/matchers.cc",
+        "src/core/lib/security/authorization/rbac_policy.cc",
     ],
     hdrs = [
         "src/core/lib/security/authorization/authorization_engine.h",
         "src/core/lib/security/authorization/evaluate_args.h",
+        "src/core/lib/security/authorization/grpc_authorization_engine.h",
+        "src/core/lib/security/authorization/matchers.h",
+        "src/core/lib/security/authorization/rbac_policy.h",
+    ],
+    language = "c++",
+    deps = [
+        "grpc_base",
+        "grpc_matchers",
+        "grpc_secure",
+    ],
+)
+
+# This target pulls in a dependency on RE2 and should not be linked into grpc by default for binary-size reasons.
+grpc_cc_library(
+    name = "grpc_authorization_provider",
+    srcs = [
+        "src/core/lib/security/authorization/rbac_translator.cc",
+    ],
+    hdrs = [
+        "src/core/lib/security/authorization/rbac_translator.h",
+    ],
+    language = "c++",
+    deps = [
+        "grpc_matchers",
+        "grpc_rbac_engine",
+    ],
+)
+
+# This target pulls in a dependency on RE2 and should not be linked into grpc by default for binary-size reasons.
+grpc_cc_library(
+    name = "grpc_cel_engine",
+    srcs = [
+        "src/core/lib/security/authorization/cel_authorization_engine.cc",
+    ],
+    hdrs = [
+        "src/core/lib/security/authorization/cel_authorization_engine.h",
     ],
     external_deps = [
         "absl/container:flat_hash_set",
@@ -1958,7 +2118,7 @@
         "google_api_upb",
         "grpc_base",
         "grpc_mock_cel",
-        "grpc_secure",
+        "grpc_rbac_engine",
     ],
 )
 
@@ -2275,6 +2435,7 @@
     srcs = GRPCXX_SRCS,
     hdrs = GRPCXX_HDRS,
     external_deps = [
+        "absl/synchronization",
         "protobuf_headers",
     ],
     language = "c++",
@@ -2292,6 +2453,7 @@
     srcs = GRPCXX_SRCS,
     hdrs = GRPCXX_HDRS,
     external_deps = [
+        "absl/synchronization",
         "protobuf_headers",
     ],
     language = "c++",
@@ -2311,13 +2473,13 @@
         "include/grpc++/impl/codegen/async_stream.h",
         "include/grpc++/impl/codegen/async_unary_call.h",
         "include/grpc++/impl/codegen/byte_buffer.h",
-        "include/grpc++/impl/codegen/call.h",
         "include/grpc++/impl/codegen/call_hook.h",
+        "include/grpc++/impl/codegen/call.h",
         "include/grpc++/impl/codegen/channel_interface.h",
         "include/grpc++/impl/codegen/client_context.h",
         "include/grpc++/impl/codegen/client_unary_call.h",
-        "include/grpc++/impl/codegen/completion_queue.h",
         "include/grpc++/impl/codegen/completion_queue_tag.h",
+        "include/grpc++/impl/codegen/completion_queue.h",
         "include/grpc++/impl/codegen/config.h",
         "include/grpc++/impl/codegen/core_codegen_interface.h",
         "include/grpc++/impl/codegen/create_auth_context.h",
@@ -2332,8 +2494,8 @@
         "include/grpc++/impl/codegen/server_interface.h",
         "include/grpc++/impl/codegen/service_type.h",
         "include/grpc++/impl/codegen/slice.h",
-        "include/grpc++/impl/codegen/status.h",
         "include/grpc++/impl/codegen/status_code_enum.h",
+        "include/grpc++/impl/codegen/status.h",
         "include/grpc++/impl/codegen/string_ref.h",
         "include/grpc++/impl/codegen/stub_options.h",
         "include/grpc++/impl/codegen/sync_stream.h",
@@ -2342,42 +2504,43 @@
         "include/grpcpp/impl/codegen/async_stream.h",
         "include/grpcpp/impl/codegen/async_unary_call.h",
         "include/grpcpp/impl/codegen/byte_buffer.h",
-        "include/grpcpp/impl/codegen/call.h",
         "include/grpcpp/impl/codegen/call_hook.h",
-        "include/grpcpp/impl/codegen/call_op_set.h",
         "include/grpcpp/impl/codegen/call_op_set_interface.h",
+        "include/grpcpp/impl/codegen/call_op_set.h",
+        "include/grpcpp/impl/codegen/call.h",
         "include/grpcpp/impl/codegen/callback_common.h",
         "include/grpcpp/impl/codegen/channel_interface.h",
         "include/grpcpp/impl/codegen/client_callback.h",
         "include/grpcpp/impl/codegen/client_context.h",
         "include/grpcpp/impl/codegen/client_interceptor.h",
         "include/grpcpp/impl/codegen/client_unary_call.h",
-        "include/grpcpp/impl/codegen/completion_queue.h",
         "include/grpcpp/impl/codegen/completion_queue_tag.h",
+        "include/grpcpp/impl/codegen/completion_queue.h",
         "include/grpcpp/impl/codegen/config.h",
         "include/grpcpp/impl/codegen/core_codegen_interface.h",
         "include/grpcpp/impl/codegen/create_auth_context.h",
         "include/grpcpp/impl/codegen/delegating_channel.h",
         "include/grpcpp/impl/codegen/grpc_library.h",
         "include/grpcpp/impl/codegen/intercepted_channel.h",
-        "include/grpcpp/impl/codegen/interceptor.h",
         "include/grpcpp/impl/codegen/interceptor_common.h",
+        "include/grpcpp/impl/codegen/interceptor.h",
         "include/grpcpp/impl/codegen/message_allocator.h",
         "include/grpcpp/impl/codegen/metadata_map.h",
+        "include/grpcpp/impl/codegen/method_handler_impl.h",
         "include/grpcpp/impl/codegen/method_handler.h",
         "include/grpcpp/impl/codegen/rpc_method.h",
         "include/grpcpp/impl/codegen/rpc_service_method.h",
         "include/grpcpp/impl/codegen/security/auth_context.h",
         "include/grpcpp/impl/codegen/serialization_traits.h",
-        "include/grpcpp/impl/codegen/server_callback.h",
         "include/grpcpp/impl/codegen/server_callback_handlers.h",
+        "include/grpcpp/impl/codegen/server_callback.h",
         "include/grpcpp/impl/codegen/server_context.h",
         "include/grpcpp/impl/codegen/server_interceptor.h",
         "include/grpcpp/impl/codegen/server_interface.h",
         "include/grpcpp/impl/codegen/service_type.h",
         "include/grpcpp/impl/codegen/slice.h",
-        "include/grpcpp/impl/codegen/status.h",
         "include/grpcpp/impl/codegen/status_code_enum.h",
+        "include/grpcpp/impl/codegen/status.h",
         "include/grpcpp/impl/codegen/string_ref.h",
         "include/grpcpp/impl/codegen/stub_options.h",
         "include/grpcpp/impl/codegen/sync_stream.h",
@@ -2472,6 +2635,50 @@
 )
 
 grpc_cc_library(
+    name = "grpcpp_csds",
+    srcs = [
+        "src/cpp/server/csds/csds.cc",
+    ],
+    hdrs = [
+        "src/cpp/server/csds/csds.h",
+    ],
+    language = "c++",
+    deps = [
+        ":grpc++_internals",
+        "//src/proto/grpc/testing/xds/v3:csds_proto",
+    ],
+    alwayslink = 1,
+)
+
+grpc_cc_library(
+    name = "grpcpp_admin",
+    srcs = [
+        "src/cpp/server/admin/admin_services.cc",
+    ],
+    hdrs = [],
+    defines = select({
+        "grpc_no_xds": ["GRPC_NO_XDS"],
+        "//conditions:default": [],
+    }),
+    external_deps = [
+        "absl/memory",
+    ],
+    language = "c++",
+    public_hdrs = [
+        "include/grpcpp/ext/admin_services.h",
+    ],
+    select_deps = {
+        "grpc_no_xds": [],
+        "//conditions:default": ["//:grpcpp_csds"],
+    },
+    deps = [
+        ":grpc++",
+        ":grpcpp_channelz",
+    ],
+    alwayslink = 1,
+)
+
+grpc_cc_library(
     name = "grpc++_test",
     srcs = [
         "src/cpp/client/channel_test_peer.cc",
@@ -2548,6 +2755,7 @@
         "absl-time",
         "opencensus-trace",
         "opencensus-trace-context_util",
+        "opencensus-trace-propagation",
         "opencensus-stats",
         "opencensus-context",
     ],
@@ -2604,7 +2812,9 @@
 grpc_cc_library(
     name = "envoy_ads_upb",
     srcs = [
+        "src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c",
         "src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c",
+        "src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.c",
@@ -2616,11 +2826,17 @@
         "src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c",
         "src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c",
         "src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c",
+        "src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c",
+        "src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c",
         "src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c",
         "src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c",
         "src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c",
         "src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.c",
         "src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c",
+        "src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c",
+        "src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c",
+        "src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c",
+        "src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c",
         "src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c",
         "src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c",
         "src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c",
@@ -2634,9 +2850,12 @@
         "src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c",
         "src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c",
         "src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c",
+        "src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c",
     ],
     hdrs = [
+        "src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h",
         "src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h",
+        "src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.h",
@@ -2648,11 +2867,17 @@
         "src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h",
         "src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h",
         "src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h",
+        "src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h",
+        "src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h",
         "src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h",
         "src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h",
         "src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h",
         "src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h",
         "src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h",
+        "src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h",
+        "src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h",
+        "src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h",
+        "src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h",
         "src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h",
         "src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.h",
         "src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h",
@@ -2666,6 +2891,7 @@
         "src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.h",
         "src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h",
         "src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h",
+        "src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h",
     ],
     external_deps = [
         "upb_lib",
@@ -2679,14 +2905,16 @@
         ":google_api_upb",
         ":proto_gen_validate_upb",
         ":udpa_annotations_upb",
-        ":udpa_core_upb",
+        ":xds_core_upb",
     ],
 )
 
 grpc_cc_library(
     name = "envoy_ads_upbdefs",
     srcs = [
+        "src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.c",
@@ -2698,10 +2926,16 @@
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c",
@@ -2715,9 +2949,12 @@
         "src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c",
     ],
     hdrs = [
+        "src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.h",
@@ -2729,10 +2966,16 @@
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.h",
@@ -2746,10 +2989,11 @@
         "src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h",
     ],
     external_deps = [
         "upb_lib",
-        "upb_lib_descriptor",
+        "upb_lib_descriptor_reflection",
         "upb_textformat_lib",
     ],
     language = "c++",
@@ -2761,7 +3005,7 @@
         ":google_api_upbdefs",
         ":proto_gen_validate_upbdefs",
         ":udpa_annotations_upbdefs",
-        ":udpa_core_upbdefs",
+        ":xds_core_upbdefs",
     ],
 )
 
@@ -2797,7 +3041,7 @@
     ],
     external_deps = [
         "upb_lib",
-        "upb_lib_descriptor",
+        "upb_lib_descriptor_reflection",
         "upb_textformat_lib",
     ],
     language = "c++",
@@ -2850,7 +3094,7 @@
         ":google_api_upb",
         ":proto_gen_validate_upb",
         ":udpa_annotations_upb",
-        ":udpa_core_upb",
+        ":xds_core_upb",
     ],
 )
 
@@ -2888,7 +3132,7 @@
     ],
     external_deps = [
         "upb_lib",
-        "upb_lib_descriptor",
+        "upb_lib_descriptor_reflection",
         "upb_textformat_lib",
     ],
     language = "c++",
@@ -2904,10 +3148,12 @@
     name = "envoy_type_upb",
     srcs = [
         "src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c",
+        "src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c",
+        "src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c",
         "src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c",
         "src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.c",
@@ -2918,10 +3164,12 @@
     ],
     hdrs = [
         "src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h",
+        "src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h",
+        "src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h",
         "src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.h",
         "src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.h",
@@ -2947,10 +3195,12 @@
     name = "envoy_type_upbdefs",
     srcs = [
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.c",
@@ -2961,10 +3211,12 @@
     ],
     hdrs = [
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.h",
@@ -2975,7 +3227,7 @@
     ],
     external_deps = [
         "upb_lib",
-        "upb_lib_descriptor",
+        "upb_lib_descriptor_reflection",
         "upb_textformat_lib",
     ],
     language = "c++",
@@ -3014,7 +3266,7 @@
     ],
     external_deps = [
         "upb_lib",
-        "upb_lib_descriptor",
+        "upb_lib_descriptor_reflection",
         "upb_textformat_lib",
     ],
     language = "c++",
@@ -3093,7 +3345,7 @@
     ],
     external_deps = [
         "upb_lib",
-        "upb_lib_descriptor",
+        "upb_lib_descriptor_reflection",
         "upb_textformat_lib",
     ],
     language = "c++",
@@ -3104,22 +3356,22 @@
 )
 
 grpc_cc_library(
-    name = "udpa_core_upb",
+    name = "xds_core_upb",
     srcs = [
-        "src/core/ext/upb-generated/udpa/core/v1/authority.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/resource.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/authority.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/context_params.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/resource.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c",
     ],
     hdrs = [
-        "src/core/ext/upb-generated/udpa/core/v1/authority.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/resource.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/authority.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/context_params.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/resource.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h",
     ],
     external_deps = [
         "upb_lib",
@@ -3134,26 +3386,26 @@
 )
 
 grpc_cc_library(
-    name = "udpa_core_upbdefs",
+    name = "xds_core_upbdefs",
     srcs = [
-        "src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c",
     ],
     hdrs = [
-        "src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h",
     ],
     external_deps = [
         "upb_lib",
-        "upb_lib_descriptor",
+        "upb_lib_descriptor_reflection",
         "upb_textformat_lib",
     ],
     language = "c++",
@@ -3161,7 +3413,46 @@
         ":google_api_upbdefs",
         ":proto_gen_validate_upbdefs",
         ":udpa_annotations_upbdefs",
-        ":udpa_core_upb",
+        ":xds_core_upb",
+    ],
+)
+
+grpc_cc_library(
+    name = "udpa_type_upb",
+    srcs = [
+        "src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c",
+    ],
+    hdrs = [
+        "src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h",
+    ],
+    external_deps = [
+        "upb_lib",
+        "upb_lib_descriptor",
+    ],
+    language = "c++",
+    deps = [
+        ":google_api_upb",
+        ":proto_gen_validate_upb",
+    ],
+)
+
+grpc_cc_library(
+    name = "udpa_type_upbdefs",
+    srcs = [
+        "src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c",
+    ],
+    hdrs = [
+        "src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h",
+    ],
+    external_deps = [
+        "upb_lib",
+        "upb_lib_descriptor_reflection",
+        "upb_textformat_lib",
+    ],
+    language = "c++",
+    deps = [
+        ":google_api_upbdefs",
+        ":proto_gen_validate_upbdefs",
     ],
 )
 
@@ -3228,7 +3519,6 @@
         "src/core/ext/upbdefs-generated/google/api/annotations.upbdefs.c",
         "src/core/ext/upbdefs-generated/google/api/http.upbdefs.c",
         "src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c",
-        "src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c",
         "src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c",
         "src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c",
         "src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.c",
@@ -3240,7 +3530,6 @@
         "src/core/ext/upbdefs-generated/google/api/annotations.upbdefs.h",
         "src/core/ext/upbdefs-generated/google/api/http.upbdefs.h",
         "src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.h",
-        "src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.h",
         "src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.h",
         "src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.h",
         "src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.h",
@@ -3250,7 +3539,7 @@
     ],
     external_deps = [
         "upb_lib",
-        "upb_lib_descriptor",
+        "upb_lib_descriptor_reflection",
         "upb_textformat_lib",
     ],
     language = "c++",
@@ -3337,25 +3626,3 @@
     ],
     visibility = ["//visibility:public"],
 )
-
-# Base classes of EventManagerInterface
-grpc_cc_library(
-    name = "eventmanager_interface",
-    hdrs = [
-        "src/core/lib/iomgr/poller/eventmanager_interface.h",
-    ],
-)
-
-# Libuv-based EventManager implementation
-grpc_cc_library(
-    name = "eventmanager_libuv",
-    srcs = [
-        "src/core/lib/iomgr/poller/eventmanager_libuv.cc",
-    ],
-    hdrs = [
-        "src/core/lib/iomgr/poller/eventmanager_libuv.h",
-    ],
-    deps = [
-        "gpr_base",
-    ],
-)
diff --git a/grpc/BUILD.gn b/grpc/BUILD.gn
index e3f6df5..2a2889d 100644
--- a/grpc/BUILD.gn
+++ b/grpc/BUILD.gn
@@ -97,6 +97,28 @@
         "include/grpc/support/sync_windows.h",
         "include/grpc/support/thd_id.h",
         "include/grpc/support/time.h",
+        "src/core/ext/upb-generated/google/api/annotations.upb.c",
+        "src/core/ext/upb-generated/google/api/annotations.upb.h",
+        "src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c",
+        "src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h",
+        "src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c",
+        "src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h",
+        "src/core/ext/upb-generated/google/api/http.upb.c",
+        "src/core/ext/upb-generated/google/api/http.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/any.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/any.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/duration.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/duration.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/empty.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/empty.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/struct.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/struct.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/timestamp.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/timestamp.upb.h",
+        "src/core/ext/upb-generated/google/protobuf/wrappers.upb.c",
+        "src/core/ext/upb-generated/google/protobuf/wrappers.upb.h",
+        "src/core/ext/upb-generated/google/rpc/status.upb.c",
+        "src/core/ext/upb-generated/google/rpc/status.upb.h",
         "src/core/lib/gpr/alloc.cc",
         "src/core/lib/gpr/alloc.h",
         "src/core/lib/gpr/arena.h",
@@ -147,6 +169,7 @@
         "src/core/lib/gprpp/arena.cc",
         "src/core/lib/gprpp/arena.h",
         "src/core/lib/gprpp/atomic.h",
+        "src/core/lib/gprpp/debug_location.h",
         "src/core/lib/gprpp/examine_stack.cc",
         "src/core/lib/gprpp/examine_stack.h",
         "src/core/lib/gprpp/fork.cc",
@@ -165,23 +188,28 @@
         "src/core/lib/gprpp/stat.h",
         "src/core/lib/gprpp/stat_posix.cc",
         "src/core/lib/gprpp/stat_windows.cc",
+        "src/core/lib/gprpp/status_helper.cc",
+        "src/core/lib/gprpp/status_helper.h",
         "src/core/lib/gprpp/sync.h",
         "src/core/lib/gprpp/thd.h",
         "src/core/lib/gprpp/thd_posix.cc",
         "src/core/lib/gprpp/thd_windows.cc",
+        "src/core/lib/gprpp/time_util.cc",
+        "src/core/lib/gprpp/time_util.h",
         "src/core/lib/profiling/basic_timers.cc",
         "src/core/lib/profiling/stap_timers.cc",
         "src/core/lib/profiling/timers.h",
     ]
     deps = [
-        ":absl/types:optional",
-        ":absl/time:time",
-        ":absl/synchronization:synchronization",
-        ":absl/strings:strings",
-        ":absl/strings:str_format",
-        ":absl/status:status",
-        ":absl/memory:memory",
         ":absl/base:base",
+        ":absl/memory:memory",
+        ":absl/status:status",
+        ":absl/strings:str_format",
+        ":absl/strings:strings",
+        ":absl/synchronization:synchronization",
+        ":absl/time:time",
+        ":absl/types:optional",
+        ":upb",
     ]
     
     public_configs = [
@@ -197,6 +225,10 @@
         "include/grpc/byte_buffer_reader.h",
         "include/grpc/census.h",
         "include/grpc/compression.h",
+        "include/grpc/event_engine/channel_args.h",
+        "include/grpc/event_engine/event_engine.h",
+        "include/grpc/event_engine/port.h",
+        "include/grpc/event_engine/slice_allocator.h",
         "include/grpc/fork.h",
         "include/grpc/grpc.h",
         "include/grpc/grpc_posix.h",
@@ -253,6 +285,8 @@
         "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",
@@ -287,6 +321,7 @@
         "src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc",
         "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc",
         "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h",
+        "src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc",
         "src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc",
         "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc",
         "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h",
@@ -295,6 +330,10 @@
         "src/core/ext/filters/client_channel/resolver_registry.h",
         "src/core/ext/filters/client_channel/resolver_result_parsing.cc",
         "src/core/ext/filters/client_channel/resolver_result_parsing.h",
+        "src/core/ext/filters/client_channel/retry_filter.cc",
+        "src/core/ext/filters/client_channel/retry_filter.h",
+        "src/core/ext/filters/client_channel/retry_service_config.cc",
+        "src/core/ext/filters/client_channel/retry_service_config.h",
         "src/core/ext/filters/client_channel/retry_throttle.cc",
         "src/core/ext/filters/client_channel/retry_throttle.h",
         "src/core/ext/filters/client_channel/server_address.cc",
@@ -313,6 +352,10 @@
         "src/core/ext/filters/client_idle/client_idle_filter.cc",
         "src/core/ext/filters/deadline/deadline_filter.cc",
         "src/core/ext/filters/deadline/deadline_filter.h",
+        "src/core/ext/filters/fault_injection/fault_injection_filter.cc",
+        "src/core/ext/filters/fault_injection/fault_injection_filter.h",
+        "src/core/ext/filters/fault_injection/service_config_parser.cc",
+        "src/core/ext/filters/fault_injection/service_config_parser.h",
         "src/core/ext/filters/http/client/http_client_filter.cc",
         "src/core/ext/filters/http/client/http_client_filter.h",
         "src/core/ext/filters/http/client_authority_filter.cc",
@@ -393,12 +436,16 @@
         "src/core/ext/transport/inproc/inproc_plugin.cc",
         "src/core/ext/transport/inproc/inproc_transport.cc",
         "src/core/ext/transport/inproc/inproc_transport.h",
+        "src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c",
+        "src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h",
         "src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c",
         "src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h",
         "src/core/ext/upb-generated/envoy/annotations/resource.upb.c",
         "src/core/ext/upb-generated/envoy/annotations/resource.upb.h",
         "src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c",
         "src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h",
+        "src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c",
+        "src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h",
         "src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c",
@@ -447,6 +494,10 @@
         "src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h",
         "src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c",
         "src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h",
+        "src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c",
+        "src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h",
+        "src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c",
+        "src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h",
         "src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c",
         "src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h",
         "src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c",
@@ -457,6 +508,14 @@
         "src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h",
         "src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c",
         "src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h",
+        "src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c",
+        "src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h",
+        "src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c",
+        "src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h",
+        "src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c",
+        "src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h",
+        "src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c",
+        "src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h",
         "src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c",
         "src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h",
         "src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c",
@@ -483,8 +542,12 @@
         "src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h",
         "src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c",
         "src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h",
+        "src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c",
+        "src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h",
+        "src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c",
+        "src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c",
@@ -493,6 +556,8 @@
         "src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h",
+        "src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c",
+        "src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c",
         "src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h",
         "src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c",
@@ -507,28 +572,6 @@
         "src/core/ext/upb-generated/envoy/type/v3/range.upb.h",
         "src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c",
         "src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.h",
-        "src/core/ext/upb-generated/google/api/annotations.upb.c",
-        "src/core/ext/upb-generated/google/api/annotations.upb.h",
-        "src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c",
-        "src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h",
-        "src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c",
-        "src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h",
-        "src/core/ext/upb-generated/google/api/http.upb.c",
-        "src/core/ext/upb-generated/google/api/http.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/any.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/any.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/duration.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/duration.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/empty.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/empty.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/struct.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/struct.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/timestamp.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/timestamp.upb.h",
-        "src/core/ext/upb-generated/google/protobuf/wrappers.upb.c",
-        "src/core/ext/upb-generated/google/protobuf/wrappers.upb.h",
-        "src/core/ext/upb-generated/google/rpc/status.upb.c",
-        "src/core/ext/upb-generated/google/rpc/status.upb.h",
         "src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c",
         "src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.h",
         "src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c",
@@ -549,28 +592,34 @@
         "src/core/ext/upb-generated/udpa/annotations/status.upb.h",
         "src/core/ext/upb-generated/udpa/annotations/versioning.upb.c",
         "src/core/ext/upb-generated/udpa/annotations/versioning.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/authority.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/authority.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/resource.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/resource.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h",
-        "src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c",
-        "src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h",
         "src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c",
         "src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h",
+        "src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c",
+        "src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h",
         "src/core/ext/upb-generated/validate/validate.upb.c",
         "src/core/ext/upb-generated/validate/validate.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/authority.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/authority.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/context_params.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/context_params.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/resource.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/resource.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h",
+        "src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c",
+        "src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h",
+        "src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c",
@@ -619,6 +668,10 @@
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c",
@@ -627,6 +680,14 @@
         "src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c",
@@ -653,8 +714,12 @@
         "src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c",
@@ -663,6 +728,8 @@
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h",
+        "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c",
+        "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c",
         "src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h",
         "src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c",
@@ -683,8 +750,6 @@
         "src/core/ext/upbdefs-generated/google/api/http.upbdefs.h",
         "src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c",
         "src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.h",
-        "src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c",
-        "src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.h",
         "src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c",
         "src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.h",
         "src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c",
@@ -707,20 +772,22 @@
         "src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h",
         "src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c",
         "src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c",
-        "src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h",
+        "src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c",
+        "src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h",
         "src/core/ext/upbdefs-generated/validate/validate.upbdefs.c",
         "src/core/ext/upbdefs-generated/validate/validate.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c",
+        "src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h",
         "src/core/ext/xds/certificate_provider_factory.h",
         "src/core/ext/xds/certificate_provider_registry.cc",
         "src/core/ext/xds/certificate_provider_registry.h",
@@ -739,7 +806,15 @@
         "src/core/ext/xds/xds_client.h",
         "src/core/ext/xds/xds_client_stats.cc",
         "src/core/ext/xds/xds_client_stats.h",
+        "src/core/ext/xds/xds_http_fault_filter.cc",
+        "src/core/ext/xds/xds_http_fault_filter.h",
+        "src/core/ext/xds/xds_http_filters.cc",
+        "src/core/ext/xds/xds_http_filters.h",
         "src/core/ext/xds/xds_server_config_fetcher.cc",
+        "src/core/lib/address_utils/parse_address.cc",
+        "src/core/lib/address_utils/parse_address.h",
+        "src/core/lib/address_utils/sockaddr_utils.cc",
+        "src/core/lib/address_utils/sockaddr_utils.h",
         "src/core/lib/avl/avl.cc",
         "src/core/lib/avl/avl.h",
         "src/core/lib/backoff/backoff.cc",
@@ -786,8 +861,9 @@
         "src/core/lib/debug/stats_data.h",
         "src/core/lib/debug/trace.cc",
         "src/core/lib/debug/trace.h",
+        "src/core/lib/event_engine/slice_allocator.cc",
+        "src/core/lib/event_engine/sockaddr.cc",
         "src/core/lib/gprpp/atomic.h",
-        "src/core/lib/gprpp/debug_location.h",
         "src/core/lib/gprpp/dual_ref_counted.h",
         "src/core/lib/gprpp/orphanable.h",
         "src/core/lib/gprpp/ref_counted.h",
@@ -863,7 +939,6 @@
         "src/core/lib/iomgr/iomgr_internal.cc",
         "src/core/lib/iomgr/iomgr_internal.h",
         "src/core/lib/iomgr/iomgr_posix.cc",
-        "src/core/lib/iomgr/iomgr_posix.h",
         "src/core/lib/iomgr/iomgr_posix_cfstream.cc",
         "src/core/lib/iomgr/iomgr_uv.cc",
         "src/core/lib/iomgr/iomgr_windows.cc",
@@ -874,10 +949,6 @@
         "src/core/lib/iomgr/lockfree_event.cc",
         "src/core/lib/iomgr/lockfree_event.h",
         "src/core/lib/iomgr/nameser.h",
-        "src/core/lib/iomgr/parse_address.cc",
-        "src/core/lib/iomgr/parse_address.h",
-        "src/core/lib/iomgr/poller/eventmanager_libuv.cc",
-        "src/core/lib/iomgr/poller/eventmanager_libuv.h",
         "src/core/lib/iomgr/polling_entity.cc",
         "src/core/lib/iomgr/polling_entity.h",
         "src/core/lib/iomgr/pollset.cc",
@@ -907,8 +978,6 @@
         "src/core/lib/iomgr/sockaddr.h",
         "src/core/lib/iomgr/sockaddr_custom.h",
         "src/core/lib/iomgr/sockaddr_posix.h",
-        "src/core/lib/iomgr/sockaddr_utils.cc",
-        "src/core/lib/iomgr/sockaddr_utils.h",
         "src/core/lib/iomgr/sockaddr_windows.h",
         "src/core/lib/iomgr/socket_factory_posix.cc",
         "src/core/lib/iomgr/socket_factory_posix.h",
@@ -978,16 +1047,8 @@
         "src/core/lib/json/json_util.cc",
         "src/core/lib/json/json_util.h",
         "src/core/lib/json/json_writer.cc",
-        "src/core/lib/security/authorization/authorization_engine.cc",
-        "src/core/lib/security/authorization/authorization_engine.h",
-        "src/core/lib/security/authorization/evaluate_args.cc",
-        "src/core/lib/security/authorization/evaluate_args.h",
-        "src/core/lib/security/authorization/mock_cel/activation.h",
-        "src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h",
-        "src/core/lib/security/authorization/mock_cel/cel_expression.h",
-        "src/core/lib/security/authorization/mock_cel/cel_value.h",
-        "src/core/lib/security/authorization/mock_cel/evaluator_core.h",
-        "src/core/lib/security/authorization/mock_cel/flat_expr_builder.h",
+        "src/core/lib/matchers/matchers.cc",
+        "src/core/lib/matchers/matchers.h",
         "src/core/lib/security/context/security_context.cc",
         "src/core/lib/security/context/security_context.h",
         "src/core/lib/security/credentials/alts/alts_credentials.cc",
@@ -1213,21 +1274,17 @@
         "src/core/tsi/transport_security_grpc.cc",
         "src/core/tsi/transport_security_grpc.h",
         "src/core/tsi/transport_security_interface.h",
+        "third_party/xxhash/xxhash.h",
     ]
     deps = [
-        "//third_party/boringssl",
         "//third_party/zlib",
-        ":gpr",
-        ":address_sorting",
-        ":upb",
-        ":absl/types:optional",
-        ":absl/strings:strings",
-        ":absl/status:statusor",
-        ":absl/status:status",
-        ":absl/functional:bind_front",
-        ":absl/container:inlined_vector",
-        ":absl/container:flat_hash_set",
         ":absl/container:flat_hash_map",
+        ":absl/container:inlined_vector",
+        ":absl/functional:bind_front",
+        ":absl/status:statusor",
+        ":gpr",
+        "//third_party/boringssl",
+        ":address_sorting",
         "//third_party/cares",
         ":address_sorting",
     ]
@@ -1365,6 +1422,7 @@
         "include/grpcpp/impl/codegen/message_allocator.h",
         "include/grpcpp/impl/codegen/metadata_map.h",
         "include/grpcpp/impl/codegen/method_handler.h",
+        "include/grpcpp/impl/codegen/method_handler_impl.h",
         "include/grpcpp/impl/codegen/proto_buffer_reader.h",
         "include/grpcpp/impl/codegen/proto_buffer_writer.h",
         "include/grpcpp/impl/codegen/proto_utils.h",
@@ -1494,9 +1552,6 @@
     deps = [
         "//third_party/protobuf:protobuf_lite",
         ":grpc",
-        ":gpr",
-        ":address_sorting",
-        ":upb",
     ]
     
     public_configs = [
diff --git a/grpc/BUILDING.md b/grpc/BUILDING.md
index 531e3dc..4a69c3b 100644
--- a/grpc/BUILDING.md
+++ b/grpc/BUILDING.md
@@ -144,7 +144,7 @@
 > cmake --build . --config Release
 ```
 
-If you want to build DLLs, run `cmake` with `-DBUILD_SHARED_LIBS=ON`.
+Using gRPC C++ as a DLL is not recommended, but you can still enable it by running `cmake` with `-DBUILD_SHARED_LIBS=ON`. 
 
 ### Windows, Using Ninja (faster build).
 
@@ -160,7 +160,16 @@
 > cmake --build .
 ```
 
-If you want to build DLLs, run `cmake` with `-DBUILD_SHARED_LIBS=ON`.
+Using gRPC C++ as a DLL is not recommended, but you can still enable it by running `cmake` with `-DBUILD_SHARED_LIBS=ON`.
+
+### Windows: A note on building shared libs (DLLs)
+
+Windows DLL build is supported at a "best effort" basis and we don't recommend using gRPC C++ as a DLL as there are some known drawbacks around how C++ DLLs work on Windows. For example, there is no stable C++ ABI and you can't safely allocate memory in one DLL, and free it in another etc.
+
+That said, we don't actively prohibit building DLLs on windows (it can be enabled in cmake with `-DBUILD_SHARED_LIBS=ON`), and are free to use the DLL builds
+at your own risk.
+- you've been warned that there are some important drawbacks and some things might not work at all or will be broken in interesting ways.
+- we don't have extensive testing for DLL builds in place (to avoid maintenance costs, increased test duration etc.) so regressions / build breakages might occur
 
 ### Dependency management
 
@@ -234,7 +243,13 @@
 $ make
 ```
 
-[Cross-compile example](test/distrib/cpp/run_distrib_test_raspberry_pi.sh)
+[Cross-compile example](test/distrib/cpp/run_distrib_test_cmake_aarch64_cross.sh)
+
+### A note on SONAME and its ABI compatibility implications in the cmake build
+
+Best efforts are made to bump the SONAME revision during ABI breaches. While a
+change in the SONAME clearly indicates an ABI incompatibility, no hard guarantees
+can be made about any sort of ABI stability across the same SONAME version.
 
 ## Building with make on UNIX systems (deprecated)
 
diff --git a/grpc/CMakeLists.txt b/grpc/CMakeLists.txt
index 1a5cab4..103df28 100644
--- a/grpc/CMakeLists.txt
+++ b/grpc/CMakeLists.txt
@@ -25,13 +25,13 @@
 cmake_minimum_required(VERSION 3.5.1)
 
 set(PACKAGE_NAME          "grpc")
-set(PACKAGE_VERSION       "1.35.0")
-set(gRPC_CORE_VERSION     "14.0.0")
-set(gRPC_CORE_SOVERSION   "14")
-set(gRPC_CPP_VERSION      "1.35.0")
-set(gRPC_CPP_SOVERSION    "1")
-set(gRPC_CSHARP_VERSION   "2.35.0")
-set(gRPC_CSHARP_SOVERSION "2")
+set(PACKAGE_VERSION       "1.38.0")
+set(gRPC_CORE_VERSION     "16.0.0")
+set(gRPC_CORE_SOVERSION   "16")
+set(gRPC_CPP_VERSION      "1.38.0")
+set(gRPC_CPP_SOVERSION    "1.38")
+set(gRPC_CSHARP_VERSION   "2.38.0")
+set(gRPC_CSHARP_SOVERSION "2.38")
 set(PACKAGE_STRING        "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME       "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT     "https://github.com/grpc/grpc/issues/")
@@ -123,7 +123,6 @@
   absl_exponential_biased
   absl_fixed_array
   absl_flat_hash_map
-  absl_flat_hash_set
   absl_function_ref
   absl_graphcycles_internal
   absl_hash
@@ -140,6 +139,7 @@
   absl_log_severity
   absl_malloc_internal
   absl_memory
+  absl_numeric_representation
   absl_optional
   absl_raw_hash_map
   absl_raw_hash_set
@@ -161,6 +161,7 @@
   absl_type_traits
   absl_utility
   absl_variant
+  absl_wyhash
   absl_meta
 )
 
@@ -255,6 +256,7 @@
 include(cmake/re2.cmake)
 include(cmake/ssl.cmake)
 include(cmake/upb.cmake)
+include(cmake/xxhash.cmake)
 include(cmake/zlib.cmake)
 
 if(_gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS)
@@ -458,21 +460,36 @@
   src/proto/grpc/testing/xds/v3/ads.proto
 )
 protobuf_generate_grpc_cpp(
+  src/proto/grpc/testing/xds/v3/aggregate_cluster.proto
+)
+protobuf_generate_grpc_cpp(
   src/proto/grpc/testing/xds/v3/base.proto
 )
 protobuf_generate_grpc_cpp(
   src/proto/grpc/testing/xds/v3/cluster.proto
 )
 protobuf_generate_grpc_cpp(
+  src/proto/grpc/testing/xds/v3/config_dump.proto
+)
+protobuf_generate_grpc_cpp(
   src/proto/grpc/testing/xds/v3/config_source.proto
 )
 protobuf_generate_grpc_cpp(
+  src/proto/grpc/testing/xds/v3/csds.proto
+)
+protobuf_generate_grpc_cpp(
   src/proto/grpc/testing/xds/v3/discovery.proto
 )
 protobuf_generate_grpc_cpp(
   src/proto/grpc/testing/xds/v3/endpoint.proto
 )
 protobuf_generate_grpc_cpp(
+  src/proto/grpc/testing/xds/v3/fault.proto
+)
+protobuf_generate_grpc_cpp(
+  src/proto/grpc/testing/xds/v3/fault_common.proto
+)
+protobuf_generate_grpc_cpp(
   src/proto/grpc/testing/xds/v3/http_connection_manager.proto
 )
 protobuf_generate_grpc_cpp(
@@ -500,6 +517,9 @@
   src/proto/grpc/testing/xds/v3/route.proto
 )
 protobuf_generate_grpc_cpp(
+  src/proto/grpc/testing/xds/v3/router.proto
+)
+protobuf_generate_grpc_cpp(
   src/proto/grpc/testing/xds/v3/string.proto
 )
 protobuf_generate_grpc_cpp(
@@ -659,7 +679,6 @@
   add_dependencies(buildtests_c slice_buffer_test)
   add_dependencies(buildtests_c slice_string_helpers_test)
   add_dependencies(buildtests_c sockaddr_resolver_test)
-  add_dependencies(buildtests_c sockaddr_utils_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     add_dependencies(buildtests_c socket_utils_test)
   endif()
@@ -708,6 +727,7 @@
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     add_dependencies(buildtests_cxx address_sorting_test_unsecure)
   endif()
+  add_dependencies(buildtests_cxx admin_services_end2end_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     add_dependencies(buildtests_cxx alarm_test)
   endif()
@@ -717,7 +737,7 @@
   add_dependencies(buildtests_cxx alts_util_test)
   add_dependencies(buildtests_cxx async_end2end_test)
   add_dependencies(buildtests_cxx auth_property_iterator_test)
-  add_dependencies(buildtests_cxx authorization_engine_test)
+  add_dependencies(buildtests_cxx authorization_matchers_test)
   add_dependencies(buildtests_cxx aws_request_signer_test)
   add_dependencies(buildtests_cxx backoff_test)
   add_dependencies(buildtests_cxx bad_streaming_id_bad_client_test)
@@ -791,6 +811,7 @@
   add_dependencies(buildtests_cxx byte_buffer_test)
   add_dependencies(buildtests_cxx byte_stream_test)
   add_dependencies(buildtests_cxx cancel_ares_query_test)
+  add_dependencies(buildtests_cxx cel_authorization_engine_test)
   add_dependencies(buildtests_cxx certificate_provider_registry_test)
   add_dependencies(buildtests_cxx certificate_provider_store_test)
   add_dependencies(buildtests_cxx cfstream_test)
@@ -813,6 +834,7 @@
   add_dependencies(buildtests_cxx codegen_test_minimal)
   add_dependencies(buildtests_cxx connection_prefix_bad_client_test)
   add_dependencies(buildtests_cxx connectivity_state_test)
+  add_dependencies(buildtests_cxx context_allocator_end2end_test)
   add_dependencies(buildtests_cxx context_list_test)
   add_dependencies(buildtests_cxx delegating_channel_test)
   add_dependencies(buildtests_cxx destroy_grpclb_channel_with_active_connect_stress_test)
@@ -820,8 +842,8 @@
   add_dependencies(buildtests_cxx duplicate_header_bad_client_test)
   add_dependencies(buildtests_cxx end2end_test)
   add_dependencies(buildtests_cxx error_details_test)
+  add_dependencies(buildtests_cxx error_utils_test)
   add_dependencies(buildtests_cxx evaluate_args_test)
-  add_dependencies(buildtests_cxx eventmanager_libuv_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     add_dependencies(buildtests_cxx examine_stack_test)
   endif()
@@ -835,6 +857,7 @@
   endif()
   add_dependencies(buildtests_cxx global_config_test)
   add_dependencies(buildtests_cxx google_mesh_ca_certificate_provider_factory_test)
+  add_dependencies(buildtests_cxx grpc_authorization_engine_test)
   add_dependencies(buildtests_cxx grpc_cli)
   add_dependencies(buildtests_cxx grpc_tls_certificate_distributor_test)
   add_dependencies(buildtests_cxx grpc_tls_certificate_provider_test)
@@ -866,7 +889,9 @@
   add_dependencies(buildtests_cxx lb_load_data_store_test)
   add_dependencies(buildtests_cxx linux_system_roots_test)
   add_dependencies(buildtests_cxx log_test)
+  add_dependencies(buildtests_cxx matchers_test)
   add_dependencies(buildtests_cxx message_allocator_end2end_test)
+  add_dependencies(buildtests_cxx mock_stream_test)
   add_dependencies(buildtests_cxx mock_test)
   add_dependencies(buildtests_cxx nonblocking_test)
   add_dependencies(buildtests_cxx noop-benchmark)
@@ -879,6 +904,7 @@
   add_dependencies(buildtests_cxx qps_json_driver)
   add_dependencies(buildtests_cxx qps_worker)
   add_dependencies(buildtests_cxx raw_end2end_test)
+  add_dependencies(buildtests_cxx rbac_translator_test)
   add_dependencies(buildtests_cxx ref_counted_ptr_test)
   add_dependencies(buildtests_cxx ref_counted_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -906,12 +932,14 @@
   add_dependencies(buildtests_cxx settings_timeout_test)
   add_dependencies(buildtests_cxx shutdown_test)
   add_dependencies(buildtests_cxx simple_request_bad_client_test)
+  add_dependencies(buildtests_cxx sockaddr_utils_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     add_dependencies(buildtests_cxx stack_tracer_test)
   endif()
   add_dependencies(buildtests_cxx stat_test)
   add_dependencies(buildtests_cxx static_metadata_test)
   add_dependencies(buildtests_cxx stats_test)
+  add_dependencies(buildtests_cxx status_helper_test)
   add_dependencies(buildtests_cxx status_metadata_test)
   add_dependencies(buildtests_cxx status_util_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -932,6 +960,7 @@
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     add_dependencies(buildtests_cxx time_jump_test)
   endif()
+  add_dependencies(buildtests_cxx time_util_test)
   add_dependencies(buildtests_cxx timer_test)
   add_dependencies(buildtests_cxx tls_security_connector_test)
   add_dependencies(buildtests_cxx too_many_pings_test)
@@ -1004,6 +1033,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(address_sorting
@@ -1082,10 +1112,12 @@
   test/core/end2end/tests/request_with_payload.cc
   test/core/end2end/tests/resource_quota_server.cc
   test/core/end2end/tests/retry.cc
+  test/core/end2end/tests/retry_cancel_during_delay.cc
   test/core/end2end/tests/retry_cancellation.cc
   test/core/end2end/tests/retry_disabled.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  test/core/end2end/tests/retry_lb_drop.cc
   test/core/end2end/tests/retry_non_retriable_status.cc
   test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -1113,6 +1145,7 @@
   test/core/end2end/tests/workaround_cronet_compression.cc
   test/core/end2end/tests/write_buffering.cc
   test/core/end2end/tests/write_buffering_at_end.cc
+  test/core/util/test_lb_policies.cc
 )
 
 set_target_properties(end2end_nosec_tests PROPERTIES
@@ -1141,15 +1174,12 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(end2end_nosec_tests
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -1216,10 +1246,12 @@
   test/core/end2end/tests/request_with_payload.cc
   test/core/end2end/tests/resource_quota_server.cc
   test/core/end2end/tests/retry.cc
+  test/core/end2end/tests/retry_cancel_during_delay.cc
   test/core/end2end/tests/retry_cancellation.cc
   test/core/end2end/tests/retry_disabled.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  test/core/end2end/tests/retry_lb_drop.cc
   test/core/end2end/tests/retry_non_retriable_status.cc
   test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -1247,6 +1279,7 @@
   test/core/end2end/tests/workaround_cronet_compression.cc
   test/core/end2end/tests/write_buffering.cc
   test/core/end2end/tests/write_buffering_at_end.cc
+  test/core/util/test_lb_policies.cc
 )
 
 set_target_properties(end2end_tests PROPERTIES
@@ -1275,22 +1308,29 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(end2end_tests
-  ${_gRPC_SSL_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
 endif()
 
 add_library(gpr
+  src/core/ext/upb-generated/google/api/annotations.upb.c
+  src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
+  src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
+  src/core/ext/upb-generated/google/api/http.upb.c
+  src/core/ext/upb-generated/google/protobuf/any.upb.c
+  src/core/ext/upb-generated/google/protobuf/duration.upb.c
+  src/core/ext/upb-generated/google/protobuf/empty.upb.c
+  src/core/ext/upb-generated/google/protobuf/struct.upb.c
+  src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
+  src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
+  src/core/ext/upb-generated/google/rpc/status.upb.c
   src/core/lib/gpr/alloc.cc
   src/core/lib/gpr/atm.cc
   src/core/lib/gpr/cpu_iphone.cc
@@ -1331,8 +1371,10 @@
   src/core/lib/gprpp/mpscq.cc
   src/core/lib/gprpp/stat_posix.cc
   src/core/lib/gprpp/stat_windows.cc
+  src/core/lib/gprpp/status_helper.cc
   src/core/lib/gprpp/thd_posix.cc
   src/core/lib/gprpp/thd_windows.cc
+  src/core/lib/gprpp/time_util.cc
   src/core/lib/profiling/basic_timers.cc
   src/core/lib/profiling/stap_timers.cc
 )
@@ -1363,18 +1405,20 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(gpr
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  absl::optional
-  absl::time
-  absl::synchronization
-  absl::strings
-  absl::str_format
-  absl::status
-  absl::memory
   absl::base
+  absl::memory
+  absl::status
+  absl::str_format
+  absl::strings
+  absl::synchronization
+  absl::time
+  absl::optional
+  upb
 )
 if(_gRPC_PLATFORM_ANDROID)
   target_link_libraries(gpr
@@ -1469,6 +1513,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
@@ -1490,10 +1535,13 @@
   src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc
   src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
   src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+  src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
   src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
   src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/resolver_result_parsing.cc
+  src/core/ext/filters/client_channel/retry_filter.cc
+  src/core/ext/filters/client_channel/retry_service_config.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/server_address.cc
   src/core/ext/filters/client_channel/service_config.cc
@@ -1503,6 +1551,8 @@
   src/core/ext/filters/client_channel/subchannel_pool_interface.cc
   src/core/ext/filters/client_idle/client_idle_filter.cc
   src/core/ext/filters/deadline/deadline_filter.cc
+  src/core/ext/filters/fault_injection/fault_injection_filter.cc
+  src/core/ext/filters/fault_injection/service_config_parser.cc
   src/core/ext/filters/http/client/http_client_filter.cc
   src/core/ext/filters/http/client_authority_filter.cc
   src/core/ext/filters/http/http_filters_plugin.cc
@@ -1548,9 +1598,11 @@
   src/core/ext/transport/chttp2/transport/writing.cc
   src/core/ext/transport/inproc/inproc_plugin.cc
   src/core/ext/transport/inproc/inproc_transport.cc
+  src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c
   src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c
   src/core/ext/upb-generated/envoy/annotations/resource.upb.c
   src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c
+  src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c
   src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c
   src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c
   src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.c
@@ -1575,11 +1627,17 @@
   src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c
   src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c
   src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c
+  src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c
+  src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c
   src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c
   src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c
   src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c
   src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.c
   src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c
+  src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c
+  src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c
+  src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c
+  src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c
   src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c
   src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c
   src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c
@@ -1593,11 +1651,14 @@
   src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c
   src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c
   src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c
+  src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c
   src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c
+  src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c
   src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c
   src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c
   src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.c
   src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c
+  src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c
   src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c
   src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c
   src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.c
@@ -1605,17 +1666,6 @@
   src/core/ext/upb-generated/envoy/type/v3/percent.upb.c
   src/core/ext/upb-generated/envoy/type/v3/range.upb.c
   src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c
-  src/core/ext/upb-generated/google/api/annotations.upb.c
-  src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
-  src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
-  src/core/ext/upb-generated/google/api/http.upb.c
-  src/core/ext/upb-generated/google/protobuf/any.upb.c
-  src/core/ext/upb-generated/google/protobuf/duration.upb.c
-  src/core/ext/upb-generated/google/protobuf/empty.upb.c
-  src/core/ext/upb-generated/google/protobuf/struct.upb.c
-  src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
-  src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
-  src/core/ext/upb-generated/google/rpc/status.upb.c
   src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c
   src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c
   src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c
@@ -1626,17 +1676,20 @@
   src/core/ext/upb-generated/udpa/annotations/sensitive.upb.c
   src/core/ext/upb-generated/udpa/annotations/status.upb.c
   src/core/ext/upb-generated/udpa/annotations/versioning.upb.c
-  src/core/ext/upb-generated/udpa/core/v1/authority.upb.c
-  src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c
-  src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c
-  src/core/ext/upb-generated/udpa/core/v1/resource.upb.c
-  src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c
-  src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c
   src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
+  src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c
   src/core/ext/upb-generated/validate/validate.upb.c
+  src/core/ext/upb-generated/xds/core/v3/authority.upb.c
+  src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c
+  src/core/ext/upb-generated/xds/core/v3/context_params.upb.c
+  src/core/ext/upb-generated/xds/core/v3/resource.upb.c
+  src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c
+  src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c
+  src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.c
@@ -1661,10 +1714,16 @@
   src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c
@@ -1678,11 +1737,14 @@
   src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c
+  src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c
   src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.c
@@ -1693,7 +1755,6 @@
   src/core/ext/upbdefs-generated/google/api/annotations.upbdefs.c
   src/core/ext/upbdefs-generated/google/api/http.upbdefs.c
   src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c
-  src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c
   src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c
   src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c
   src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.c
@@ -1705,13 +1766,14 @@
   src/core/ext/upbdefs-generated/udpa/annotations/sensitive.upbdefs.c
   src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.c
   src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c
-  src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c
-  src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c
-  src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c
-  src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c
-  src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c
-  src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c
+  src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c
   src/core/ext/upbdefs-generated/validate/validate.upbdefs.c
+  src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c
+  src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c
+  src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c
+  src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c
+  src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c
+  src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c
   src/core/ext/xds/certificate_provider_registry.cc
   src/core/ext/xds/certificate_provider_store.cc
   src/core/ext/xds/file_watcher_certificate_provider_factory.cc
@@ -1720,7 +1782,11 @@
   src/core/ext/xds/xds_certificate_provider.cc
   src/core/ext/xds/xds_client.cc
   src/core/ext/xds/xds_client_stats.cc
+  src/core/ext/xds/xds_http_fault_filter.cc
+  src/core/ext/xds/xds_http_filters.cc
   src/core/ext/xds/xds_server_config_fetcher.cc
+  src/core/lib/address_utils/parse_address.cc
+  src/core/lib/address_utils/sockaddr_utils.cc
   src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
@@ -1743,6 +1809,8 @@
   src/core/lib/debug/stats.cc
   src/core/lib/debug/stats_data.cc
   src/core/lib/debug/trace.cc
+  src/core/lib/event_engine/slice_allocator.cc
+  src/core/lib/event_engine/sockaddr.cc
   src/core/lib/http/format_request.cc
   src/core/lib/http/httpcli.cc
   src/core/lib/http/httpcli_security_connector.cc
@@ -1788,8 +1856,6 @@
   src/core/lib/iomgr/is_epollexclusive_available.cc
   src/core/lib/iomgr/load_file.cc
   src/core/lib/iomgr/lockfree_event.cc
-  src/core/lib/iomgr/parse_address.cc
-  src/core/lib/iomgr/poller/eventmanager_libuv.cc
   src/core/lib/iomgr/polling_entity.cc
   src/core/lib/iomgr/pollset.cc
   src/core/lib/iomgr/pollset_custom.cc
@@ -1803,7 +1869,6 @@
   src/core/lib/iomgr/resolve_address_posix.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
-  src/core/lib/iomgr/sockaddr_utils.cc
   src/core/lib/iomgr/socket_factory_posix.cc
   src/core/lib/iomgr/socket_mutator.cc
   src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -1846,8 +1911,7 @@
   src/core/lib/json/json_reader.cc
   src/core/lib/json/json_util.cc
   src/core/lib/json/json_writer.cc
-  src/core/lib/security/authorization/authorization_engine.cc
-  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/matchers/matchers.cc
   src/core/lib/security/context/security_context.cc
   src/core/lib/security/credentials/alts/alts_credentials.cc
   src/core/lib/security/credentials/alts/check_gcp_environment.cc
@@ -1997,28 +2061,24 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(grpc
   ${_gRPC_BASELIB_LIBRARIES}
-  ${_gRPC_SSL_LIBRARIES}
   ${_gRPC_ZLIB_LIBRARIES}
   ${_gRPC_CARES_LIBRARIES}
   ${_gRPC_ADDRESS_SORTING_LIBRARIES}
   ${_gRPC_RE2_LIBRARIES}
   ${_gRPC_UPB_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  gpr
-  address_sorting
-  upb
-  absl::optional
-  absl::strings
-  absl::statusor
-  absl::status
-  absl::bind_front
-  absl::inlined_vector
-  absl::flat_hash_set
   absl::flat_hash_map
+  absl::inlined_vector
+  absl::bind_front
+  absl::statusor
+  gpr
+  ${_gRPC_SSL_LIBRARIES}
+  address_sorting
 )
 if(_gRPC_PLATFORM_IOS OR _gRPC_PLATFORM_MAC)
   target_link_libraries(grpc "-framework CoreFoundation")
@@ -2029,6 +2089,10 @@
   include/grpc/byte_buffer_reader.h
   include/grpc/census.h
   include/grpc/compression.h
+  include/grpc/event_engine/channel_args.h
+  include/grpc/event_engine/event_engine.h
+  include/grpc/event_engine/port.h
+  include/grpc/event_engine/slice_allocator.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -2088,14 +2152,12 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(grpc_csharp_ext
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -2104,7 +2166,6 @@
 
 add_library(grpc_test_util
   test/core/util/cmdline.cc
-  test/core/util/eval_args_mock_endpoint.cc
   test/core/util/fuzzer_util.cc
   test/core/util/grpc_profiler.cc
   test/core/util/histogram.cc
@@ -2154,17 +2215,15 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(grpc_test_util
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::symbolize
-  absl::stacktrace
   absl::failure_signal_handler
+  absl::stacktrace
+  absl::symbolize
+  grpc
 )
 if(_gRPC_PLATFORM_IOS OR _gRPC_PLATFORM_MAC)
   target_link_libraries(grpc_test_util "-framework CoreFoundation")
@@ -2176,7 +2235,6 @@
 
 add_library(grpc_test_util_unsecure
   test/core/util/cmdline.cc
-  test/core/util/eval_args_mock_endpoint.cc
   test/core/util/fuzzer_util.cc
   test/core/util/grpc_profiler.cc
   test/core/util/histogram.cc
@@ -2225,17 +2283,15 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(grpc_test_util_unsecure
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_unsecure
-  gpr
-  address_sorting
-  upb
-  absl::symbolize
-  absl::stacktrace
   absl::failure_signal_handler
+  absl::stacktrace
+  absl::symbolize
+  grpc_unsecure
 )
 if(_gRPC_PLATFORM_IOS OR _gRPC_PLATFORM_MAC)
   target_link_libraries(grpc_test_util_unsecure "-framework CoreFoundation")
@@ -2290,6 +2346,8 @@
   src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/resolver_result_parsing.cc
+  src/core/ext/filters/client_channel/retry_filter.cc
+  src/core/ext/filters/client_channel/retry_service_config.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/server_address.cc
   src/core/ext/filters/client_channel/service_config.cc
@@ -2299,6 +2357,8 @@
   src/core/ext/filters/client_channel/subchannel_pool_interface.cc
   src/core/ext/filters/client_idle/client_idle_filter.cc
   src/core/ext/filters/deadline/deadline_filter.cc
+  src/core/ext/filters/fault_injection/fault_injection_filter.cc
+  src/core/ext/filters/fault_injection/service_config_parser.cc
   src/core/ext/filters/http/client/http_client_filter.cc
   src/core/ext/filters/http/client_authority_filter.cc
   src/core/ext/filters/http/http_filters_plugin.cc
@@ -2342,21 +2402,12 @@
   src/core/ext/transport/chttp2/transport/writing.cc
   src/core/ext/transport/inproc/inproc_plugin.cc
   src/core/ext/transport/inproc/inproc_transport.cc
-  src/core/ext/upb-generated/google/api/annotations.upb.c
-  src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
-  src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
-  src/core/ext/upb-generated/google/api/http.upb.c
-  src/core/ext/upb-generated/google/protobuf/any.upb.c
-  src/core/ext/upb-generated/google/protobuf/duration.upb.c
-  src/core/ext/upb-generated/google/protobuf/empty.upb.c
-  src/core/ext/upb-generated/google/protobuf/struct.upb.c
-  src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
-  src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
-  src/core/ext/upb-generated/google/rpc/status.upb.c
   src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c
   src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c
   src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
   src/core/ext/upb-generated/validate/validate.upb.c
+  src/core/lib/address_utils/parse_address.cc
+  src/core/lib/address_utils/sockaddr_utils.cc
   src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
@@ -2379,6 +2430,8 @@
   src/core/lib/debug/stats.cc
   src/core/lib/debug/stats_data.cc
   src/core/lib/debug/trace.cc
+  src/core/lib/event_engine/slice_allocator.cc
+  src/core/lib/event_engine/sockaddr.cc
   src/core/lib/http/format_request.cc
   src/core/lib/http/httpcli.cc
   src/core/lib/http/parser.cc
@@ -2423,8 +2476,6 @@
   src/core/lib/iomgr/is_epollexclusive_available.cc
   src/core/lib/iomgr/load_file.cc
   src/core/lib/iomgr/lockfree_event.cc
-  src/core/lib/iomgr/parse_address.cc
-  src/core/lib/iomgr/poller/eventmanager_libuv.cc
   src/core/lib/iomgr/polling_entity.cc
   src/core/lib/iomgr/pollset.cc
   src/core/lib/iomgr/pollset_custom.cc
@@ -2438,7 +2489,6 @@
   src/core/lib/iomgr/resolve_address_posix.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
-  src/core/lib/iomgr/sockaddr_utils.cc
   src/core/lib/iomgr/socket_factory_posix.cc
   src/core/lib/iomgr/socket_mutator.cc
   src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -2551,6 +2601,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(grpc_unsecure
@@ -2561,15 +2612,11 @@
   ${_gRPC_RE2_LIBRARIES}
   ${_gRPC_UPB_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flat_hash_map
+  absl::inlined_vector
+  absl::statusor
   gpr
   address_sorting
-  upb
-  absl::optional
-  absl::strings
-  absl::statusor
-  absl::status
-  absl::inlined_vector
-  absl::flat_hash_map
 )
 if(_gRPC_PLATFORM_IOS OR _gRPC_PLATFORM_MAC)
   target_link_libraries(grpc_unsecure "-framework CoreFoundation")
@@ -2580,6 +2627,10 @@
   include/grpc/byte_buffer_reader.h
   include/grpc/census.h
   include/grpc/compression.h
+  include/grpc/event_engine/channel_args.h
+  include/grpc/event_engine/event_engine.h
+  include/grpc/event_engine/port.h
+  include/grpc/event_engine/slice_allocator.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -2652,6 +2703,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -2662,14 +2714,10 @@
 target_link_libraries(benchmark_helpers
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util_unsecure
-  grpc++_unsecure
-  grpc_unsecure
-  grpc++_test_config
-  gpr
-  address_sorting
-  upb
   ${_gRPC_BENCHMARK_LIBRARIES}
+  grpc++_unsecure
+  grpc_test_util_unsecure
+  grpc++_test_config
 )
 
 endif()
@@ -2755,6 +2803,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -2763,9 +2812,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc
-  gpr
-  address_sorting
-  upb
 )
 
 foreach(_hdr
@@ -2889,6 +2935,7 @@
   include/grpcpp/impl/codegen/message_allocator.h
   include/grpcpp/impl/codegen/metadata_map.h
   include/grpcpp/impl/codegen/method_handler.h
+  include/grpcpp/impl/codegen/method_handler_impl.h
   include/grpcpp/impl/codegen/proto_buffer_reader.h
   include/grpcpp/impl/codegen/proto_buffer_writer.h
   include/grpcpp/impl/codegen/proto_utils.h
@@ -3002,6 +3049,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3010,10 +3058,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 foreach(_hdr
@@ -3037,12 +3081,7 @@
 endif()
 
 
-if(gRPC_BUILD_CODEGEN)
 add_library(grpc++_error_details
-  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.pb.cc
-  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.grpc.pb.cc
-  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.pb.h
-  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.grpc.pb.h
   src/cpp/util/error_details.cc
 )
 
@@ -3072,6 +3111,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3079,10 +3119,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 foreach(_hdr
@@ -3095,9 +3131,7 @@
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
-endif()
 
-if(gRPC_BUILD_CODEGEN)
 
 if(gRPC_INSTALL)
   install(TARGETS grpc++_error_details EXPORT gRPCTargets
@@ -3107,7 +3141,6 @@
   )
 endif()
 
-endif()
 
 if(gRPC_BUILD_CODEGEN)
 add_library(grpc++_reflection
@@ -3145,6 +3178,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3152,10 +3186,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 foreach(_hdr
@@ -3213,6 +3243,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -3224,10 +3255,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 foreach(_hdr
@@ -3278,6 +3305,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -3288,8 +3316,8 @@
 target_link_libraries(grpc++_test_config
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  gpr
   absl::flags_parse
+  gpr
 )
 
 
@@ -3334,6 +3362,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -3344,13 +3373,9 @@
 target_link_libraries(grpc++_test_util
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
   absl::flags
+  grpc++
+  grpc_test_util
 )
 
 
@@ -3425,6 +3450,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3433,9 +3459,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_unsecure
-  gpr
-  address_sorting
-  upb
 )
 
 foreach(_hdr
@@ -3559,6 +3582,7 @@
   include/grpcpp/impl/codegen/message_allocator.h
   include/grpcpp/impl/codegen/metadata_map.h
   include/grpcpp/impl/codegen/method_handler.h
+  include/grpcpp/impl/codegen/method_handler_impl.h
   include/grpcpp/impl/codegen/proto_buffer_reader.h
   include/grpcpp/impl/codegen/proto_buffer_writer.h
   include/grpcpp/impl/codegen/proto_utils.h
@@ -3676,6 +3700,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3744,6 +3769,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3751,10 +3777,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 foreach(_hdr
@@ -3770,7 +3792,9 @@
 
 if(gRPC_BUILD_CODEGEN)
 
-if(gRPC_INSTALL)
+# grpcpp_channelz doesn't build with protobuf-lite, so no install required
+# See https://github.com/grpc/grpc/issues/22826
+if(gRPC_INSTALL AND NOT gRPC_USE_PROTO_LITE)
   install(TARGETS grpcpp_channelz EXPORT gRPCTargets
     RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
     LIBRARY DESTINATION ${gRPC_INSTALL_LIBDIR}
@@ -3785,14 +3809,13 @@
   third_party/upb/upb/decode.c
   third_party/upb/upb/def.c
   third_party/upb/upb/encode.c
-  third_party/upb/upb/json_decode.c
-  third_party/upb/upb/json_encode.c
   third_party/upb/upb/msg.c
   third_party/upb/upb/reflection.c
   third_party/upb/upb/table.c
   third_party/upb/upb/text_encode.c
   third_party/upb/upb/upb.c
   src/core/ext/upb-generated/google/protobuf/descriptor.upb.c
+  src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c
 )
 
 set_target_properties(upb PROPERTIES
@@ -3821,6 +3844,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 target_link_libraries(upb
@@ -3853,6 +3877,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
@@ -3878,6 +3903,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3905,6 +3931,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3930,6 +3957,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -3956,16 +3984,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(algorithm_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -3986,16 +4011,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alloc_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4016,16 +4038,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alpn_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4047,16 +4066,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_counter_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4078,16 +4094,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_crypt_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4109,16 +4122,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_crypter_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4141,16 +4151,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_frame_protector_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4172,16 +4179,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_grpc_record_protocol_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4203,16 +4207,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_handshaker_client_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4234,16 +4235,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_iovec_record_protocol_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4264,16 +4262,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_security_connector_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4295,16 +4290,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_tsi_handshaker_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4326,16 +4318,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_tsi_utils_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4357,16 +4346,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(alts_zero_copy_grpc_protector_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4387,16 +4373,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(arena_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4417,16 +4400,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(auth_context_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4447,16 +4427,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(avl_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4477,16 +4454,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(b64_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4508,16 +4482,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(bad_server_response_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4540,16 +4511,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(bad_ssl_alpn_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -4573,16 +4541,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(bad_ssl_cert_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -4604,16 +4569,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(bin_decoder_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4634,16 +4596,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(bin_encoder_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4664,16 +4623,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(buffer_list_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4694,16 +4650,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(channel_args_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4724,16 +4677,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(channel_create_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4754,16 +4704,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(channel_stack_builder_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4784,16 +4731,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(channel_stack_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4814,16 +4758,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(check_gcp_environment_linux_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4844,16 +4785,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(check_gcp_environment_windows_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4875,16 +4813,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(client_ssl_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -4906,16 +4841,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(cmdline_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4937,16 +4869,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(combiner_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -4968,16 +4897,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(completion_queue_threading_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -4998,16 +4924,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(compression_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5028,16 +4951,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(concurrent_connectivity_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5059,16 +4979,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(connection_refused_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5089,16 +5006,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(cpu_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5119,16 +5033,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(dns_resolver_connectivity_using_ares_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5149,16 +5060,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(dns_resolver_connectivity_using_native_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5179,16 +5087,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(dns_resolver_cooldown_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5209,16 +5114,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(dns_resolver_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5241,16 +5143,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(dualstack_socket_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5273,16 +5172,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(endpoint_pair_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5303,16 +5199,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(env_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5334,16 +5227,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(error_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5365,16 +5255,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(ev_epollex_linux_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5396,16 +5283,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(fake_resolver_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5427,16 +5311,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(fake_transport_security_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5458,16 +5339,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(fd_conservation_posix_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5490,16 +5368,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(fd_posix_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5526,16 +5401,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(fling_stream_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5562,16 +5434,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(fling_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5594,16 +5463,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(fork_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5629,16 +5495,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(format_request_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5660,16 +5523,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(frame_handler_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5691,16 +5551,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(goaway_server_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5721,16 +5578,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_alts_credentials_options_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5751,16 +5605,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_byte_buffer_reader_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5781,16 +5632,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_completion_queue_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5811,16 +5659,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_ipv6_loopback_available_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5843,16 +5688,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(handshake_server_with_readahead_handshaker_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5875,16 +5717,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(handshake_verify_peer_options_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -5906,16 +5745,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(histogram_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5936,16 +5772,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(host_port_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5966,16 +5799,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(hpack_encoder_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -5996,16 +5826,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(hpack_parser_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6026,16 +5853,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(hpack_table_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6061,16 +5885,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(httpcli_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -6097,16 +5918,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(httpscli_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -6128,17 +5946,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(inproc_callback_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   end2end_tests
-  grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6160,16 +5974,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(invalid_call_argument_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6190,16 +6001,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(json_token_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6220,16 +6028,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(jwt_verifier_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6251,16 +6056,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(lame_client_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6281,16 +6083,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(load_file_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6311,16 +6110,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(manual_constructor_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6341,16 +6137,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(message_compress_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6371,16 +6164,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(metadata_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6401,16 +6191,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(minimal_stack_is_minimal_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6431,16 +6218,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(mpmcqueue_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6462,16 +6246,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(mpscq_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -6494,16 +6275,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(multiple_server_queues_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6524,16 +6302,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(murmur_hash_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6555,16 +6330,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(no_server_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6585,16 +6357,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(num_external_connectivity_watchers_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6602,7 +6371,7 @@
 if(gRPC_BUILD_TESTS)
 
 add_executable(parse_address_test
-  test/core/iomgr/parse_address_test.cc
+  test/core/address_utils/parse_address_test.cc
 )
 
 target_include_directories(parse_address_test
@@ -6615,16 +6384,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(parse_address_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6633,7 +6399,7 @@
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
   add_executable(parse_address_with_named_scope_id_test
-    test/core/iomgr/parse_address_with_named_scope_id_test.cc
+    test/core/address_utils/parse_address_with_named_scope_id_test.cc
   )
 
   target_include_directories(parse_address_with_named_scope_id_test
@@ -6646,16 +6412,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(parse_address_with_named_scope_id_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -6681,16 +6444,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(parser_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6711,16 +6471,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(percent_encoding_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6741,16 +6498,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(public_headers_must_be_c89
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6772,16 +6526,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(resolve_address_using_ares_resolver_posix_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -6803,16 +6554,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(resolve_address_using_ares_resolver_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6834,16 +6582,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(resolve_address_using_native_resolver_posix_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -6865,16 +6610,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(resolve_address_using_native_resolver_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6895,16 +6637,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(resource_quota_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6925,16 +6664,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(secure_channel_create_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6956,16 +6692,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(secure_endpoint_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -6986,16 +6719,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(security_connector_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7016,16 +6746,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(sequential_connectivity_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7048,16 +6775,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(server_ssl_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -7079,16 +6803,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(server_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7109,16 +6830,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(slice_buffer_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7139,16 +6857,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(slice_string_helpers_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7169,46 +6884,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(sockaddr_resolver_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
-)
-
-
-endif()
-if(gRPC_BUILD_TESTS)
-
-add_executable(sockaddr_utils_test
-  test/core/iomgr/sockaddr_utils_test.cc
-)
-
-target_include_directories(sockaddr_utils_test
-  PRIVATE
-    ${CMAKE_CURRENT_SOURCE_DIR}
-    ${CMAKE_CURRENT_SOURCE_DIR}/include
-    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
-    ${_gRPC_RE2_INCLUDE_DIR}
-    ${_gRPC_SSL_INCLUDE_DIR}
-    ${_gRPC_UPB_GENERATED_DIR}
-    ${_gRPC_UPB_GRPC_GENERATED_DIR}
-    ${_gRPC_UPB_INCLUDE_DIR}
-    ${_gRPC_ZLIB_INCLUDE_DIR}
-)
-
-target_link_libraries(sockaddr_utils_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7230,16 +6912,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(socket_utils_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -7261,16 +6940,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(spinlock_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7291,16 +6967,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(ssl_credentials_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7323,16 +6996,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(ssl_transport_security_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -7354,16 +7024,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(status_conversion_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7384,16 +7051,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(stream_compression_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7414,16 +7078,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(stream_map_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7444,16 +7105,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(stream_owned_slice_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7474,16 +7132,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(string_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7504,16 +7159,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(sync_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7535,16 +7187,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(tcp_client_posix_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -7568,16 +7217,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(tcp_posix_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -7600,16 +7246,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(tcp_server_posix_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -7631,16 +7274,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(test_core_gpr_time_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7661,16 +7301,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(test_core_security_credentials_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7691,16 +7328,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(test_core_slice_slice_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7721,16 +7355,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(thd_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7751,16 +7382,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(threadpool_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7781,16 +7409,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(time_averaged_stats_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7811,16 +7436,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(timeout_encoding_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7841,16 +7463,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(timer_heap_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7871,16 +7490,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(timer_list_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7901,16 +7517,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(tls_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7931,16 +7544,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(transport_security_common_api_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7961,16 +7571,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(transport_security_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -7992,16 +7599,13 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
   )
 
   target_link_libraries(udp_server_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -8023,16 +7627,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(useful_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -8053,16 +7654,13 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
 )
 
 target_link_libraries(varint_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -8086,6 +7684,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8097,14 +7696,8 @@
   target_link_libraries(address_sorting_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc++_test_util
-    grpc_test_util
-    grpc++
     grpc++_test_config
-    grpc
-    gpr
-    address_sorting
-    upb
+    grpc++_test_util
   )
 
 
@@ -8132,6 +7725,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8143,19 +7737,70 @@
   target_link_libraries(address_sorting_test_unsecure
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc_test_util_unsecure
     grpc++_unsecure
-    grpc_unsecure
+    grpc_test_util_unsecure
     grpc++_test_config
-    gpr
-    address_sorting
-    upb
   )
 
 
 endif()
 endif()
 if(gRPC_BUILD_TESTS)
+
+add_executable(admin_services_end2end_test
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.h
+  src/cpp/server/admin/admin_services.cc
+  src/cpp/server/csds/csds.cc
+  test/cpp/end2end/admin_services_end2end_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(admin_services_end2end_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(admin_services_end2end_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_reflection
+  grpcpp_channelz
+  grpc++_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
   add_executable(alarm_test
@@ -8174,6 +7819,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8185,12 +7831,8 @@
   target_link_libraries(alarm_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc_test_util_unsecure
     grpc++_unsecure
-    grpc_unsecure
-    gpr
-    address_sorting
-    upb
+    grpc_test_util_unsecure
   )
 
 
@@ -8225,6 +7867,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8236,12 +7879,8 @@
   target_link_libraries(alts_concurrent_connectivity_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc_test_util
     grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
+    grpc_test_util
   )
 
 
@@ -8265,6 +7904,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -8276,14 +7916,8 @@
 target_link_libraries(alts_util_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
   grpc++_alts
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc++_test_util
 )
 
 
@@ -8326,6 +7960,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -8338,12 +7973,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -8366,6 +7995,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -8378,25 +8008,23 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
 endif()
 if(gRPC_BUILD_TESTS)
 
-add_executable(authorization_engine_test
-  test/core/security/authorization_engine_test.cc
+add_executable(authorization_matchers_test
+  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
+  src/core/lib/security/authorization/rbac_policy.cc
+  test/core/security/authorization_matchers_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
 )
 
-target_include_directories(authorization_engine_test
+target_include_directories(authorization_matchers_test
   PRIVATE
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_CURRENT_SOURCE_DIR}/include
@@ -8406,6 +8034,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -8414,14 +8043,10 @@
     ${_gRPC_PROTO_GENS_DIR}
 )
 
-target_link_libraries(authorization_engine_test
+target_link_libraries(authorization_matchers_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -8444,6 +8069,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -8456,10 +8082,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -8482,6 +8104,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -8494,10 +8117,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -8522,6 +8141,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -8534,10 +8154,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -8562,6 +8178,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -8574,10 +8191,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -8601,6 +8214,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8613,10 +8227,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -8641,6 +8251,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8653,14 +8264,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -8685,6 +8288,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8697,14 +8301,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -8729,6 +8325,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8741,14 +8338,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -8773,6 +8362,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8785,14 +8375,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -8821,6 +8403,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8833,14 +8416,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -8869,6 +8444,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8881,14 +8457,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -8913,6 +8481,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8925,14 +8494,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -8957,6 +8518,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -8969,14 +8531,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9001,6 +8555,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9013,14 +8568,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9045,6 +8592,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9057,14 +8605,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9089,6 +8629,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9101,14 +8642,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9133,6 +8666,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9145,14 +8679,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9177,6 +8703,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9189,14 +8716,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9221,6 +8740,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9233,14 +8753,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9265,6 +8777,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9277,14 +8790,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9309,6 +8814,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9320,16 +8826,8 @@
   target_link_libraries(bm_fullstack_trickle
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
     absl::flags
+    benchmark_helpers
   )
 
 
@@ -9354,6 +8852,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9366,14 +8865,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9398,6 +8889,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9410,14 +8902,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9442,6 +8926,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9454,14 +8939,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9486,6 +8963,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9498,14 +8976,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9530,6 +9000,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -9542,14 +9013,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     benchmark_helpers
-    grpc_test_util_unsecure
-    grpc++_unsecure
-    grpc_unsecure
-    grpc++_test_config
-    gpr
-    address_sorting
-    upb
-    ${_gRPC_BENCHMARK_LIBRARIES}
   )
 
 
@@ -9573,6 +9036,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9585,12 +9049,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -9613,6 +9071,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9625,10 +9084,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -9653,6 +9108,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9664,14 +9120,49 @@
 target_link_libraries(cancel_ares_query_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc++_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(cel_authorization_engine_test
+  src/core/lib/security/authorization/cel_authorization_engine.cc
+  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
+  src/core/lib/security/authorization/rbac_policy.cc
+  test/core/security/cel_authorization_engine_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(cel_authorization_engine_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(cel_authorization_engine_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flat_hash_set
+  grpc_test_util
 )
 
 
@@ -9694,6 +9185,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9706,10 +9198,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -9732,6 +9220,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9744,10 +9233,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -9783,6 +9268,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9795,12 +9281,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -9823,6 +9303,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9834,12 +9315,8 @@
 target_link_libraries(channel_arguments_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -9862,6 +9339,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9873,12 +9351,8 @@
 target_link_libraries(channel_filter_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -9906,6 +9380,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9917,12 +9392,8 @@
 target_link_libraries(channel_trace_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -9945,6 +9416,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -9956,12 +9428,8 @@
 target_link_libraries(channelz_registry_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -9997,6 +9465,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10010,12 +9479,6 @@
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpcpp_channelz
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10043,6 +9506,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10054,12 +9518,8 @@
 target_link_libraries(channelz_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -10104,6 +9564,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10116,13 +9577,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -10159,6 +9613,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10171,12 +9626,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10221,6 +9670,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -10233,12 +9683,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc++_test_util
-    grpc_test_util
-    grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -10276,6 +9720,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10288,12 +9733,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10339,6 +9778,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -10351,12 +9791,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc++_test_util
-    grpc_test_util
-    grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -10380,6 +9814,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10391,12 +9826,8 @@
 target_link_libraries(codegen_test_full
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -10419,6 +9850,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10430,12 +9862,8 @@
 target_link_libraries(codegen_test_minimal
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -10460,6 +9888,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10472,10 +9901,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10498,6 +9923,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10510,10 +9936,54 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(context_allocator_end2end_test
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
+  test/cpp/end2end/context_allocator_end2end_test.cc
+  test/cpp/end2end/test_service_impl.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(context_allocator_end2end_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(context_allocator_end2end_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test_util
 )
 
 
@@ -10536,6 +10006,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10548,10 +10019,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10587,6 +10054,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10599,12 +10067,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10627,6 +10089,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10639,12 +10102,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10667,6 +10124,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10679,10 +10137,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10707,6 +10161,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10719,10 +10174,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10763,6 +10214,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10774,14 +10226,8 @@
 target_link_libraries(end2end_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
   grpc++_test
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc++_test_util
 )
 
 
@@ -10789,6 +10235,10 @@
 if(gRPC_BUILD_TESTS)
 
 add_executable(error_details_test
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.grpc.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h
@@ -10808,6 +10258,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10821,11 +10272,41 @@
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_error_details
   grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(error_utils_test
+  test/core/transport/error_utils_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(error_utils_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(error_utils_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
 )
 
 
@@ -10833,6 +10314,10 @@
 if(gRPC_BUILD_TESTS)
 
 add_executable(evaluate_args_test
+  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
+  src/core/lib/security/authorization/rbac_policy.cc
   test/core/security/evaluate_args_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
@@ -10848,6 +10333,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10860,48 +10346,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
-)
-
-
-endif()
-if(gRPC_BUILD_TESTS)
-
-add_executable(eventmanager_libuv_test
-  test/core/iomgr/poller/eventmanager_libuv_test.cc
-  third_party/googletest/googletest/src/gtest-all.cc
-  third_party/googletest/googlemock/src/gmock-all.cc
-)
-
-target_include_directories(eventmanager_libuv_test
-  PRIVATE
-    ${CMAKE_CURRENT_SOURCE_DIR}
-    ${CMAKE_CURRENT_SOURCE_DIR}/include
-    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
-    ${_gRPC_RE2_INCLUDE_DIR}
-    ${_gRPC_SSL_INCLUDE_DIR}
-    ${_gRPC_UPB_GENERATED_DIR}
-    ${_gRPC_UPB_GRPC_GENERATED_DIR}
-    ${_gRPC_UPB_INCLUDE_DIR}
-    ${_gRPC_ZLIB_INCLUDE_DIR}
-    third_party/googletest/googletest/include
-    third_party/googletest/googletest
-    third_party/googletest/googlemock/include
-    third_party/googletest/googlemock
-    ${_gRPC_PROTO_GENS_DIR}
-)
-
-target_link_libraries(eventmanager_libuv_test
-  ${_gRPC_PROTOBUF_LIBRARIES}
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -10925,6 +10369,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -10937,12 +10382,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
-    absl::symbolize
-    absl::stacktrace
   )
 
 
@@ -10978,6 +10417,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -10990,12 +10430,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11018,6 +10452,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11030,10 +10465,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11072,6 +10503,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11084,12 +10516,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11125,6 +10551,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11137,12 +10564,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11181,6 +10602,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11193,12 +10615,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11222,6 +10638,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -11234,10 +10651,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -11261,6 +10674,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11273,10 +10687,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11300,6 +10710,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11312,10 +10723,45 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(grpc_authorization_engine_test
+  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
+  src/core/lib/security/authorization/rbac_policy.cc
+  test/core/security/grpc_authorization_engine_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(grpc_authorization_engine_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(grpc_authorization_engine_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
 )
 
 
@@ -11348,6 +10794,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11359,13 +10806,9 @@
 target_link_libraries(grpc_cli
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -11386,6 +10829,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -11424,6 +10868,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -11462,6 +10907,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -11500,6 +10946,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -11538,6 +10985,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -11576,6 +11024,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -11614,6 +11063,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     ${_gRPC_PROTO_GENS_DIR}
 )
@@ -11654,6 +11104,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11666,10 +11117,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11692,6 +11139,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11704,10 +11152,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11730,6 +11174,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11742,10 +11187,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11787,6 +11228,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -11798,15 +11240,8 @@
   target_link_libraries(grpc_tool_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc++_test_util
     grpc++_reflection
-    grpc_test_util
-    grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
-    absl::flags
+    grpc++_test_util
   )
 
 
@@ -11834,6 +11269,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11846,12 +11282,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11896,6 +11326,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -11908,12 +11339,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc++_test_util
-    grpc_test_util
-    grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -11937,6 +11362,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11949,11 +11375,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   end2end_tests
-  grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -11978,6 +11399,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -11990,10 +11412,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12018,6 +11436,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12030,10 +11449,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12078,6 +11493,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12090,12 +11506,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12130,6 +11540,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12141,15 +11552,8 @@
 target_link_libraries(http2_client
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
+  grpc++_test_util
 )
 
 
@@ -12189,6 +11593,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12201,12 +11606,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12229,6 +11628,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12241,10 +11641,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12269,6 +11665,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12281,10 +11678,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12307,6 +11700,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12319,10 +11713,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12360,6 +11750,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12371,15 +11762,8 @@
 target_link_libraries(interop_client
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
+  grpc++_test_util
 )
 
 
@@ -12416,6 +11800,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12427,15 +11812,8 @@
 target_link_libraries(interop_server
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
+  grpc++_test_util
 )
 
 
@@ -12459,6 +11837,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -12470,15 +11849,8 @@
   target_link_libraries(interop_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc++_test_util
-    grpc_test_util
-    grpc++
     grpc++_test_config
-    grpc
-    gpr
-    address_sorting
-    upb
-    absl::flags
+    grpc++_test_util
   )
 
 
@@ -12502,6 +11874,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12514,10 +11887,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12542,6 +11911,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12554,10 +11924,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12584,6 +11950,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12595,12 +11962,8 @@
 target_link_libraries(lb_get_cpu_stats_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -12624,6 +11987,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12635,12 +11999,8 @@
 target_link_libraries(lb_load_data_store_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -12663,6 +12023,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12675,10 +12036,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12701,6 +12058,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12713,10 +12071,41 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(matchers_test
+  test/core/security/matchers_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(matchers_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(matchers_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
 )
 
 
@@ -12752,6 +12141,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12764,12 +12154,54 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(mock_stream_test
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
+  test/cpp/test/mock_stream_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(mock_stream_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(mock_stream_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test
+  grpc++_test_util
 )
 
 
@@ -12808,6 +12240,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12819,14 +12252,8 @@
 target_link_libraries(mock_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
   grpc++_test
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc++_test_util
 )
 
 
@@ -12861,6 +12288,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12873,12 +12301,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12901,6 +12323,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12912,12 +12335,8 @@
 target_link_libraries(noop-benchmark
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
   ${_gRPC_BENCHMARK_LIBRARIES}
+  grpc_test_util
 )
 
 
@@ -12940,6 +12359,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12952,10 +12372,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -12980,6 +12396,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -12992,10 +12409,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13018,6 +12431,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13030,10 +12444,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13069,6 +12479,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13081,12 +12492,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13127,6 +12532,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13138,14 +12544,8 @@
 target_link_libraries(proto_server_reflection_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
   grpc++_reflection
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc++_test_util
 )
 
 
@@ -13168,6 +12568,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13179,12 +12580,8 @@
 target_link_libraries(proto_utils_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -13253,6 +12650,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13264,15 +12662,8 @@
 target_link_libraries(qps_json_driver
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
+  grpc++_test_util
 )
 
 
@@ -13333,6 +12724,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13344,15 +12736,8 @@
 target_link_libraries(qps_worker
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
+  grpc++_test_util
 )
 
 
@@ -13392,6 +12777,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13404,12 +12790,46 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(rbac_translator_test
+  src/core/lib/security/authorization/evaluate_args.cc
+  src/core/lib/security/authorization/grpc_authorization_engine.cc
+  src/core/lib/security/authorization/matchers.cc
+  src/core/lib/security/authorization/rbac_policy.cc
+  src/core/lib/security/authorization/rbac_translator.cc
+  test/core/security/rbac_translator_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(rbac_translator_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(rbac_translator_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13432,6 +12852,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13444,10 +12865,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13470,6 +12887,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13482,10 +12900,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13509,6 +12923,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -13521,10 +12936,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -13548,6 +12959,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13560,10 +12972,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13586,6 +12994,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13598,12 +13007,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13643,6 +13046,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13655,12 +13059,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13696,6 +13094,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -13707,12 +13106,8 @@
   target_link_libraries(server_builder_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc_test_util_unsecure
     grpc++_unsecure
-    grpc_unsecure
-    gpr
-    address_sorting
-    upb
+    grpc_test_util_unsecure
   )
 
 
@@ -13749,6 +13144,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -13760,12 +13156,8 @@
   target_link_libraries(server_builder_with_socket_mutator_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc_test_util_unsecure
     grpc++_unsecure
-    grpc_unsecure
-    gpr
-    address_sorting
-    upb
+    grpc_test_util_unsecure
   )
 
 
@@ -13789,6 +13181,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13801,10 +13194,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13827,6 +13216,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13838,14 +13228,8 @@
 target_link_libraries(server_context_test_spouse_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
   grpc++_test
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc++_test_util
 )
 
 
@@ -13880,6 +13264,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13892,12 +13277,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13934,6 +13313,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13946,12 +13326,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -13976,6 +13350,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -13988,10 +13363,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14027,6 +13398,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -14038,12 +13410,8 @@
   target_link_libraries(server_request_call_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc_test_util_unsecure
     grpc++_unsecure
-    grpc_unsecure
-    gpr
-    address_sorting
-    upb
+    grpc_test_util_unsecure
   )
 
 
@@ -14084,6 +13452,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14096,12 +13465,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14124,6 +13487,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14136,10 +13500,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14162,6 +13522,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14174,10 +13535,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14216,6 +13573,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14228,12 +13586,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14258,6 +13610,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14270,10 +13623,41 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(sockaddr_utils_test
+  test/core/address_utils/sockaddr_utils_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(sockaddr_utils_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(sockaddr_utils_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
 )
 
 
@@ -14297,6 +13681,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -14309,11 +13694,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
-    absl::symbolize
   )
 
 
@@ -14337,6 +13717,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14349,10 +13730,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14375,6 +13752,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14387,10 +13765,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14413,6 +13787,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14425,10 +13800,41 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(status_helper_test
+  test/core/gprpp/status_helper_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(status_helper_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(status_helper_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
 )
 
 
@@ -14451,6 +13857,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14463,10 +13870,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14489,6 +13892,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14501,10 +13905,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14529,6 +13929,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -14541,10 +13942,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -14585,6 +13982,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -14597,12 +13995,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc++_test_util
-    grpc_test_util
-    grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -14626,6 +14018,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14637,12 +14030,8 @@
 target_link_libraries(string_ref_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -14665,6 +14054,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14676,12 +14066,8 @@
 target_link_libraries(test_cpp_client_credentials_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -14704,6 +14090,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14715,12 +14102,8 @@
 target_link_libraries(test_cpp_server_credentials_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -14743,6 +14126,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14755,12 +14139,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14783,6 +14161,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14795,12 +14174,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -14823,6 +14196,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14834,14 +14208,8 @@
 target_link_libraries(thread_manager_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc++_test_util
 )
 
 
@@ -14881,6 +14249,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -14893,12 +14262,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc++_test_util
-    grpc_test_util
-    grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -14923,6 +14286,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -14934,12 +14298,8 @@
   target_link_libraries(time_jump_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc_test_util
     grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
+    grpc_test_util
   )
 
 
@@ -14947,6 +14307,41 @@
 endif()
 if(gRPC_BUILD_TESTS)
 
+add_executable(time_util_test
+  test/core/gprpp/time_util_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(time_util_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(time_util_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
 add_executable(timer_test
   test/cpp/common/timer_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -14963,6 +14358,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -14974,12 +14370,8 @@
 target_link_libraries(timer_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
   grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc_test_util
 )
 
 
@@ -15002,6 +14394,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15014,10 +14407,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -15041,6 +14430,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15052,14 +14442,8 @@
 target_link_libraries(too_many_pings_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
+  grpc++_test_util
 )
 
 
@@ -15084,6 +14468,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15096,10 +14481,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -15122,6 +14503,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15134,10 +14516,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -15162,6 +14540,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15174,10 +14553,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -15201,6 +14576,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -15213,10 +14589,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc_test_util
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -15239,7 +14611,6 @@
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
     test/core/util/cmdline.cc
-    test/core/util/eval_args_mock_endpoint.cc
     test/core/util/fuzzer_util.cc
     test/core/util/grpc_profiler.cc
     test/core/util/histogram.cc
@@ -15275,6 +14646,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -15286,14 +14658,10 @@
   target_link_libraries(writes_per_rpc_test
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
-    grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
-    absl::symbolize
-    absl::stacktrace
     absl::failure_signal_handler
+    absl::stacktrace
+    absl::symbolize
+    grpc++
   )
 
 
@@ -15317,6 +14685,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15329,10 +14698,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -15355,6 +14720,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15367,10 +14733,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -15406,6 +14768,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15418,12 +14781,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -15446,6 +14803,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15458,10 +14816,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   grpc_test_util
-  grpc
-  gpr
-  address_sorting
-  upb
 )
 
 
@@ -15514,6 +14868,10 @@
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/ads.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/ads.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/ads.grpc.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/aggregate_cluster.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/aggregate_cluster.grpc.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/aggregate_cluster.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/aggregate_cluster.grpc.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.h
@@ -15522,10 +14880,18 @@
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/cluster.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/cluster.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/cluster.grpc.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.grpc.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.grpc.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.grpc.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/discovery.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/discovery.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/discovery.pb.h
@@ -15534,6 +14900,14 @@
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.grpc.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.grpc.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault.grpc.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
@@ -15570,6 +14944,10 @@
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.grpc.pb.cc
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.pb.h
+    ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.grpc.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.h
@@ -15578,6 +14956,7 @@
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.grpc.pb.cc
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.pb.h
     ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.grpc.pb.h
+    src/cpp/server/csds/csds.cc
     test/cpp/end2end/test_service_impl.cc
     test/cpp/end2end/xds_end2end_test.cc
     third_party/googletest/googletest/src/gtest-all.cc
@@ -15594,6 +14973,7 @@
       ${_gRPC_UPB_GENERATED_DIR}
       ${_gRPC_UPB_GRPC_GENERATED_DIR}
       ${_gRPC_UPB_INCLUDE_DIR}
+      ${_gRPC_XXHASH_INCLUDE_DIR}
       ${_gRPC_ZLIB_INCLUDE_DIR}
       third_party/googletest/googletest/include
       third_party/googletest/googletest
@@ -15606,12 +14986,6 @@
     ${_gRPC_PROTOBUF_LIBRARIES}
     ${_gRPC_ALLTARGETS_LIBRARIES}
     grpc++_test_util
-    grpc_test_util
-    grpc++
-    grpc
-    gpr
-    address_sorting
-    upb
   )
 
 
@@ -15632,6 +15006,24 @@
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.h
+  src/cpp/server/admin/admin_services.cc
+  src/cpp/server/csds/csds.cc
   test/cpp/interop/xds_interop_client.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
@@ -15647,6 +15039,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15658,14 +15051,11 @@
 target_link_libraries(xds_interop_client
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc++
-  grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
   absl::flags
+  grpc++_reflection
+  grpcpp_channelz
+  grpc_test_util
+  grpc++_test_config
 )
 
 
@@ -15673,6 +15063,10 @@
 if(gRPC_BUILD_TESTS)
 
 add_executable(xds_interop_server
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.grpc.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.h
@@ -15685,6 +15079,25 @@
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_dump.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/csds.grpc.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.h
+  src/cpp/server/admin/admin_services.cc
+  src/cpp/server/csds/csds.cc
+  test/cpp/end2end/test_health_check_service_impl.cc
   test/cpp/interop/xds_interop_server.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
@@ -15700,6 +15113,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15711,14 +15125,11 @@
 target_link_libraries(xds_interop_server
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc++
-  grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
   absl::flags
+  grpc++_reflection
+  grpcpp_channelz
+  grpc_test_util
+  grpc++_test_config
 )
 
 
@@ -15742,6 +15153,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15753,13 +15165,9 @@
 target_link_libraries(alts_credentials_fuzzer_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -15783,6 +15191,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15794,13 +15203,9 @@
 target_link_libraries(client_fuzzer_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -15824,6 +15229,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15835,13 +15241,9 @@
 target_link_libraries(hpack_parser_fuzzer_test_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -15865,6 +15267,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15876,13 +15279,9 @@
 target_link_libraries(http_request_fuzzer_test_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -15906,6 +15305,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15917,13 +15317,9 @@
 target_link_libraries(http_response_fuzzer_test_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -15947,6 +15343,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15958,13 +15355,9 @@
 target_link_libraries(json_fuzzer_test_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -15988,6 +15381,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -15999,13 +15393,9 @@
 target_link_libraries(nanopb_fuzzer_response_test_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -16029,6 +15419,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -16040,13 +15431,9 @@
 target_link_libraries(nanopb_fuzzer_serverlist_test_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -16070,6 +15457,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -16081,13 +15469,9 @@
 target_link_libraries(percent_decode_fuzzer_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -16111,6 +15495,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -16122,13 +15507,9 @@
 target_link_libraries(percent_encode_fuzzer_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -16152,6 +15533,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -16163,13 +15545,9 @@
 target_link_libraries(server_fuzzer_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -16193,6 +15571,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -16204,13 +15583,9 @@
 target_link_libraries(ssl_server_fuzzer_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -16234,6 +15609,7 @@
     ${_gRPC_UPB_GENERATED_DIR}
     ${_gRPC_UPB_GRPC_GENERATED_DIR}
     ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
     ${_gRPC_ZLIB_INCLUDE_DIR}
     third_party/googletest/googletest/include
     third_party/googletest/googletest
@@ -16245,13 +15621,9 @@
 target_link_libraries(uri_fuzzer_test_one_entry
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::flags
   grpc_test_util
   grpc++_test_config
-  grpc
-  gpr
-  address_sorting
-  upb
-  absl::flags
 )
 
 
@@ -16314,8 +15686,8 @@
   "gpr"
   "gRPC platform support library"
   "${gRPC_CORE_VERSION}"
-  ""
-  "-lgpr -labsl_status -labsl_cord -labsl_str_format_internal -labsl_synchronization -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_stacktrace -labsl_debugging_internal -labsl_malloc_internal -labsl_time -labsl_time_zone -labsl_civil_time -labsl_strings -labsl_strings_internal -labsl_throw_delegate -labsl_int128 -labsl_base -labsl_spinlock_wait -labsl_bad_optional_access -labsl_raw_logging_internal -labsl_log_severity"
+  "absl_base absl_memory absl_optional absl_status absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgpr"
   ""
   "gpr.pc")
 
@@ -16324,8 +15696,8 @@
   "gRPC"
   "high performance general RPC framework"
   "${gRPC_CORE_VERSION}"
-  "gpr openssl"
-  "-lgrpc -laddress_sorting -lre2 -lupb -lcares -lz -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_exponential_biased -labsl_hash -labsl_city -labsl_statusor -labsl_bad_variant_access -labsl_status -labsl_cord -labsl_str_format_internal -labsl_synchronization -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_stacktrace -labsl_debugging_internal -labsl_malloc_internal -labsl_time -labsl_time_zone -labsl_civil_time -labsl_strings -labsl_strings_internal -labsl_throw_delegate -labsl_int128 -labsl_base -labsl_spinlock_wait -labsl_bad_optional_access -labsl_raw_logging_internal -labsl_log_severity"
+  "gpr openssl absl_base absl_bind_front absl_flat_hash_map absl_inlined_vector absl_memory absl_optional absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgrpc -laddress_sorting -lre2 -lupb -lcares -lz"
   ""
   "grpc.pc")
 
@@ -16334,8 +15706,8 @@
   "gRPC unsecure"
   "high performance general RPC framework without SSL"
   "${gRPC_CORE_VERSION}"
-  "gpr"
-  "-lgrpc_unsecure -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_exponential_biased -labsl_hash -labsl_city -labsl_statusor -labsl_bad_variant_access -labsl_status -labsl_cord -labsl_str_format_internal -labsl_synchronization -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_stacktrace -labsl_debugging_internal -labsl_malloc_internal -labsl_time -labsl_time_zone -labsl_civil_time -labsl_strings -labsl_strings_internal -labsl_throw_delegate -labsl_int128 -labsl_base -labsl_spinlock_wait -labsl_bad_optional_access -labsl_raw_logging_internal -labsl_log_severity"
+  "gpr absl_base absl_flat_hash_map absl_inlined_vector absl_memory absl_optional absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgrpc_unsecure"
   ""
   "grpc_unsecure.pc")
 
@@ -16344,8 +15716,8 @@
   "gRPC++"
   "C++ wrapper for gRPC"
   "${gRPC_CPP_VERSION}"
-  "grpc"
-  "-lgrpc++ -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_exponential_biased -labsl_hash -labsl_city -labsl_statusor -labsl_bad_variant_access -labsl_status -labsl_cord -labsl_str_format_internal -labsl_synchronization -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_stacktrace -labsl_debugging_internal -labsl_malloc_internal -labsl_time -labsl_time_zone -labsl_civil_time -labsl_strings -labsl_strings_internal -labsl_throw_delegate -labsl_int128 -labsl_base -labsl_spinlock_wait -labsl_bad_optional_access -labsl_raw_logging_internal -labsl_log_severity"
+  "grpc absl_base absl_bind_front absl_flat_hash_map absl_inlined_vector absl_memory absl_optional absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgrpc++"
   ""
   "grpc++.pc")
 
@@ -16354,7 +15726,7 @@
   "gRPC++ unsecure"
   "C++ wrapper for gRPC without SSL"
   "${gRPC_CPP_VERSION}"
-  "grpc_unsecure"
-  "-lgrpc++_unsecure -labsl_raw_hash_set -labsl_hashtablez_sampler -labsl_exponential_biased -labsl_hash -labsl_city -labsl_statusor -labsl_bad_variant_access -labsl_status -labsl_cord -labsl_str_format_internal -labsl_synchronization -labsl_graphcycles_internal -labsl_symbolize -labsl_demangle_internal -labsl_stacktrace -labsl_debugging_internal -labsl_malloc_internal -labsl_time -labsl_time_zone -labsl_civil_time -labsl_strings -labsl_strings_internal -labsl_throw_delegate -labsl_int128 -labsl_base -labsl_spinlock_wait -labsl_bad_optional_access -labsl_raw_logging_internal -labsl_log_severity"
+  "grpc_unsecure absl_base absl_flat_hash_map absl_inlined_vector absl_memory absl_optional absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time"
+  "-lgrpc++_unsecure"
   ""
   "grpc++_unsecure.pc")
diff --git a/grpc/PYTHON-MANIFEST.in b/grpc/PYTHON-MANIFEST.in
index 391de4e..890a2fa 100644
--- a/grpc/PYTHON-MANIFEST.in
+++ b/grpc/PYTHON-MANIFEST.in
@@ -10,6 +10,7 @@
 graft third_party/cares
 graft third_party/re2
 graft third_party/upb
+graft third_party/xxhash
 graft third_party/zlib
 include src/python/grpcio/_parallel_compile_patch.py
 include src/python/grpcio/_spawn_patch.py
diff --git a/grpc/Package.swift b/grpc/Package.swift
index 23d0f82..66e4a74 100644
--- a/grpc/Package.swift
+++ b/grpc/Package.swift
@@ -40,28 +40,36 @@
       ],
       path: ".",
       exclude: [
-        "src/core/ext/filters/load_reporting/",
         "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc",
         "src/core/ext/filters/client_channel/xds/xds_channel.cc",
+        "src/core/ext/filters/load_reporting/",
         "src/core/ext/transport/cronet/",
         "src/core/ext/upb-generated/third_party/",
+        "src/core/ext/upb-generated/src/proto/grpc/auth/",
         "src/core/ext/upbdefs-generated/envoy/config/rbac/",
         "src/core/ext/upbdefs-generated/google/api/expr/",
         "src/core/ext/upbdefs-generated/src/",
         "src/core/ext/upbdefs-generated/third_party/",
         "src/core/ext/upbdefs-generated/udpa/data/",
+        "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h",
+        "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc",
         "src/core/lib/surface/init_unsecure.cc",
-        "src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h",
-        "src/core/lib/security/authorization/mock_cel/cel_expression.h",
-        "src/core/lib/security/authorization/mock_cel/evaluator_core.h",
-        "src/core/lib/security/authorization/mock_cel/flat_expr_builder.h",
-        "src/core/lib/security/authorization/mock_cel/statusor.h",
+        "src/core/lib/security/authorization/",
         "src/core/plugin_registry/grpc_unsecure_plugin_registry.cc",
         "third_party/re2/re2/testing/",
         "third_party/re2/re2/fuzzing/",
         "third_party/re2/util/benchmark.cc",
         "third_party/re2/util/test.cc",
         "third_party/re2/util/fuzz.cc",
+        "third_party/upb/upb/sink.c",
+        "third_party/upb/upb/json_decode.c",
+        "third_party/upb/upb/json_encode.c",
+        "third_party/upb/upb/handlers.h",
+        "third_party/upb/upb/sink.h",
+        "third_party/upb/upb/json_encode.h",
+        "third_party/upb/upb/json_decode.h",
+        "third_party/upb/upb/handlers-inl.h",
+        "third_party/upb/upb/handlers.c",
         "third_party/upb/upb/bindings/",
         "third_party/upb/upb/json/",
         "third_party/upb/upb/pb/",
@@ -78,6 +86,8 @@
         "third_party/re2/re2/",
         "third_party/re2/util/",
         "third_party/upb/upb/",
+        "third_party/upb/third_party/wyhash/wyhash.h",
+        "third_party/xxhash/xxhash.h",
       ],
       publicHeadersPath: "spm-core-include",
       cSettings: [
@@ -85,9 +95,15 @@
         .headerSearchPath("include/"),
         .headerSearchPath("third_party/re2/"),
         .headerSearchPath("third_party/upb/"),
+        .headerSearchPath("third_party/xxhash/"),
         .headerSearchPath("src/core/ext/upb-generated/"),
         .headerSearchPath("src/core/ext/upbdefs-generated/"),
         .define("GRPC_ARES", to: "0"),
+        .unsafeFlags(["-Wno-module-import-in-extern-c"]),
+      ],
+      linkerSettings: [
+        .linkedFramework("CoreFoundation"),
+        .linkedLibrary("z"),
       ]
     ),
     .target(
@@ -99,10 +115,15 @@
       path: ".",
       exclude: [
         "src/cpp/client/cronet_credentials.cc",
+        "src/cpp/client/channel_test_peer.cc",
+        "src/cpp/common/alts_util.cc",
+        "src/cpp/common/alts_context.cc",
         "src/cpp/common/insecure_create_auth_context.cc",
-        "src/cpp/ext/",
+        "src/cpp/server/admin/",
         "src/cpp/server/channelz/",
+        "src/cpp/server/csds/",
         "src/cpp/server/load_reporter/",
+        "src/cpp/ext/",
         "src/cpp/util/core_stats.cc",
         "src/cpp/util/core_stats.h",
         "src/cpp/util/error_details.cc",
@@ -116,6 +137,7 @@
         .headerSearchPath("include/"),
         .headerSearchPath("third_party/upb/"),
         .headerSearchPath("src/core/ext/upb-generated"),
+        .unsafeFlags(["-Wno-module-import-in-extern-c"]),
       ]
     ),
   ],
diff --git a/grpc/Rakefile b/grpc/Rakefile
index c4cb314..faae210 100755
--- a/grpc/Rakefile
+++ b/grpc/Rakefile
@@ -121,7 +121,7 @@
   verbose = ENV['V'] || '0'
 
   grpc_config = ENV['GRPC_CONFIG'] || 'opt'
-  ruby_cc_versions = ['3.0.0', '2.7.0', '2.6.0', '2.5.0', '2.4.0', '2.3.0'].join(':')
+  ruby_cc_versions = ['3.0.0', '2.7.0', '2.6.0', '2.5.0', '2.4.0'].join(':')
 
   if RUBY_PLATFORM =~ /darwin/
     FileUtils.touch 'grpc_c.32.ruby'
diff --git a/grpc/SECURITY.md b/grpc/SECURITY.md
new file mode 100644
index 0000000..be6e108
--- /dev/null
+++ b/grpc/SECURITY.md
@@ -0,0 +1,3 @@
+# Security Policy
+
+For information on gRPC Security Policy and reporting potentional security issues, please see [gRPC CVE Process](https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md).
diff --git a/grpc/bazel/copts.bzl b/grpc/bazel/copts.bzl
new file mode 100644
index 0000000..91f0bc8
--- /dev/null
+++ b/grpc/bazel/copts.bzl
@@ -0,0 +1,52 @@
+# Copyright 2021 the 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.
+
+# This is a list of llvm flags to be used when being built with use_strict_warning=1
+GRPC_LLVM_WARNING_FLAGS = [
+    # Enable all & extra waninrgs
+    "-Wall",
+    "-Wextra",
+    # Consider warnings as errors
+    "-Werror",
+    # Ignore unknown warning flags
+    "-Wno-unknown-warning-option",
+    # A list of flags coming from internal build system
+    "-Wc++20-extensions",
+    "-Wctad-maybe-unsupported",
+    "-Wdeprecated-increment-bool",
+    "-Wfloat-overflow-conversion",
+    "-Wfloat-zero-conversion",
+    "-Wfor-loop-analysis",
+    "-Wformat-security",
+    "-Wgnu-redeclared-enum",
+    "-Winfinite-recursion",
+    "-Wliteral-conversion",
+    "-Wnon-virtual-dtor",
+    "-Woverloaded-virtual",
+    "-Wself-assign",
+    "-Wstring-conversion",
+    "-Wtautological-overlap-compare",
+    "-Wthread-safety-analysis",
+    "-Wthread-safety-beta",
+    "-Wunused-comparison",
+    "-Wvla",
+    # Exceptions but will be removed
+    "-Wno-deprecated-declarations",
+    "-Wno-unused-function",
+]
+
+GRPC_DEFAULT_COPTS = select({
+    "//:use_strict_warning": GRPC_LLVM_WARNING_FLAGS,
+    "//conditions:default": [],
+})
diff --git a/grpc/bazel/grpc_build_system.bzl b/grpc/bazel/grpc_build_system.bzl
index 3452788..85ec2d6 100644
--- a/grpc/bazel/grpc_build_system.bzl
+++ b/grpc/bazel/grpc_build_system.bzl
@@ -24,6 +24,7 @@
 #
 
 load("//bazel:cc_grpc_library.bzl", "cc_grpc_library")
+load("//bazel:copts.bzl", "GRPC_DEFAULT_COPTS")
 load("@upb//bazel:upb_proto_library.bzl", "upb_proto_library")
 load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
 
@@ -48,6 +49,8 @@
     for dep in external_deps:
         if dep == "address_sorting":
             ret += ["//third_party/address_sorting"]
+        elif dep == "xxhash":
+            ret += ["//third_party/xxhash"]
         elif dep == "cares":
             ret += select({
                 "//:grpc_no_ares": [],
@@ -77,7 +80,8 @@
         alwayslink = 0,
         data = [],
         use_cfstream = False,
-        tags = []):
+        tags = [],
+        linkstatic = False):
     copts = []
     if use_cfstream:
         copts = if_mac(["-DGRPC_CFSTREAM"])
@@ -109,7 +113,7 @@
                   }),
         hdrs = hdrs + public_hdrs,
         deps = deps + _get_external_deps(external_deps),
-        copts = copts,
+        copts = GRPC_DEFAULT_COPTS + copts,
         visibility = visibility,
         testonly = testonly,
         linkopts = linkopts,
@@ -121,6 +125,7 @@
         alwayslink = alwayslink,
         data = data,
         tags = tags,
+        linkstatic = linkstatic,
     )
 
 def grpc_proto_plugin(name, srcs = [], deps = []):
@@ -175,8 +180,8 @@
             deps = ios_test_deps,
         )
 
-def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = None, tags = [], exec_compatible_with = [], exec_properties = {}, shard_count = None, flaky = None):
-    copts = if_mac(["-DGRPC_CFSTREAM"])
+def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = None, tags = [], exec_compatible_with = [], exec_properties = {}, shard_count = None, flaky = None, copts = []):
+    copts = copts + if_mac(["-DGRPC_CFSTREAM"])
     if language.upper() == "C":
         copts = copts + if_not_windows(["-std=c99"])
 
@@ -187,7 +192,7 @@
         "args": args,
         "data": data,
         "deps": deps + _get_external_deps(external_deps),
-        "copts": copts,
+        "copts": GRPC_DEFAULT_COPTS + copts,
         "linkopts": if_not_windows(["-pthread"]),
         "size": size,
         "timeout": timeout,
@@ -249,7 +254,7 @@
         testonly = testonly,
         linkshared = linkshared,
         deps = deps + _get_external_deps(external_deps),
-        copts = copts,
+        copts = GRPC_DEFAULT_COPTS + copts,
         linkopts = if_not_windows(["-pthread"]) + linkopts,
         tags = tags,
         features = features,
diff --git a/grpc/bazel/grpc_deps.bzl b/grpc/bazel/grpc_deps.bzl
index 0d13c28..a463d01 100644
--- a/grpc/bazel/grpc_deps.bzl
+++ b/grpc/bazel/grpc_deps.bzl
@@ -17,6 +17,11 @@
     )
 
     native.bind(
+        name = "upb_lib_descriptor_reflection",
+        actual = "@upb//:descriptor_upb_proto_reflection",
+    )
+
+    native.bind(
         name = "upb_textformat_lib",
         actual = "@upb//:textformat",
     )
@@ -88,7 +93,7 @@
 
     native.bind(
         name = "re2",
-        actual = "@com_github_google_re2//:re2",
+        actual = "@com_googlesource_code_re2//:re2",
     )
 
     native.bind(
@@ -117,6 +122,11 @@
     )
 
     native.bind(
+        name = "opencensus-trace-propagation",
+        actual = "@io_opencensus_cpp//opencensus/trace:grpc_trace_bin",
+    )
+
+    native.bind(
         name = "opencensus-stats",
         actual = "@io_opencensus_cpp//opencensus/stats:stats",
     )
@@ -146,11 +156,11 @@
             name = "boringssl",
             # Use github mirror instead of https://boringssl.googlesource.com/boringssl
             # to obtain a boringssl archive with consistent sha256
-            sha256 = "e8c02bb7043644dc138e422a9a3412108732b6ff30590db4a05664476b209c03",
-            strip_prefix = "boringssl-29c6e0e27268f5a43e039cd2ed4e849d6b736fc1",
+            sha256 = "f8616dff15cb8aad6705af53c7caf7a5f1103b6aaf59c76b55995e179d47f89c",
+            strip_prefix = "boringssl-688fc5cf5428868679d2ae1072cad81055752068",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/boringssl/archive/29c6e0e27268f5a43e039cd2ed4e849d6b736fc1.tar.gz",
-                "https://github.com/google/boringssl/archive/29c6e0e27268f5a43e039cd2ed4e849d6b736fc1.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/boringssl/archive/688fc5cf5428868679d2ae1072cad81055752068.tar.gz",
+                "https://github.com/google/boringssl/archive/688fc5cf5428868679d2ae1072cad81055752068.tar.gz",
             ],
         )
 
@@ -169,11 +179,11 @@
     if "com_google_protobuf" not in native.existing_rules():
         http_archive(
             name = "com_google_protobuf",
-            sha256 = "88f7b3d062759e9428394cd2b854722c7142de6d9ea1cc0514a251dcec91bc0b",
-            strip_prefix = "protobuf-19fb89416f3fdc2d6668f3738f444885575285bc",
+            sha256 = "cf63d46ef743f4c30b0e36a562caf83cabed3f10e6ca49eb476913c4655394d5",
+            strip_prefix = "protobuf-436bd7880e458532901c58f4d9d1ea23fa7edd52",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/protobuf/archive/19fb89416f3fdc2d6668f3738f444885575285bc.tar.gz",
-                "https://github.com/google/protobuf/archive/19fb89416f3fdc2d6668f3738f444885575285bc.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/protobuf/archive/436bd7880e458532901c58f4d9d1ea23fa7edd52.tar.gz",
+                "https://github.com/google/protobuf/archive/436bd7880e458532901c58f4d9d1ea23fa7edd52.tar.gz",
             ],
             patches = ["@com_github_grpc_grpc//third_party:protobuf.patch"],
             patch_args = ["-p1"],
@@ -206,17 +216,17 @@
     if "com_github_google_benchmark" not in native.existing_rules():
         http_archive(
             name = "com_github_google_benchmark",
-            sha256 = "f68aec93154d010324c05bcd8c5cc53468b87af88d87acb5ddcfaa1bba044837",
-            strip_prefix = "benchmark-090faecb454fbd6e6e17a75ef8146acb037118d4",
+            sha256 = "daa4a97e0547d76de300e325a49177b199f3689ce5a35e25d47696f7cb050f86",
+            strip_prefix = "benchmark-73d4d5e8d6d449fc8663765a42aa8aeeee844489",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/benchmark/archive/090faecb454fbd6e6e17a75ef8146acb037118d4.tar.gz",
-                "https://github.com/google/benchmark/archive/090faecb454fbd6e6e17a75ef8146acb037118d4.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/benchmark/archive/73d4d5e8d6d449fc8663765a42aa8aeeee844489.tar.gz",
+                "https://github.com/google/benchmark/archive/73d4d5e8d6d449fc8663765a42aa8aeeee844489.tar.gz",
             ],
         )
 
-    if "com_github_google_re2" not in native.existing_rules():
+    if "com_googlesource_code_re2" not in native.existing_rules():
         http_archive(
-            name = "com_github_google_re2",
+            name = "com_googlesource_code_re2",
             sha256 = "9f385e146410a8150b6f4cb1a57eab7ec806ced48d427554b1e754877ff26c3e",
             strip_prefix = "re2-aecba11114cf1fac5497aeb844b6966106de3eb6",
             urls = [
@@ -240,11 +250,11 @@
     if "com_google_absl" not in native.existing_rules():
         http_archive(
             name = "com_google_absl",
-            sha256 = "3d74cdc98b42fd4257d91f652575206de195e2c824fcd8d6e6d227f85cb143ef",
-            strip_prefix = "abseil-cpp-0f3bb466b868b523cf1dc9b2aaaed65c77b28862",
+            sha256 = "35f22ef5cb286f09954b7cc4c85b5a3f6221c9d4df6b8c4a1e9d399555b366ee",
+            strip_prefix = "abseil-cpp-997aaf3a28308eba1b9156aa35ab7bca9688e9f6",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/abseil/abseil-cpp/archive/0f3bb466b868b523cf1dc9b2aaaed65c77b28862.tar.gz",
-                "https://github.com/abseil/abseil-cpp/archive/0f3bb466b868b523cf1dc9b2aaaed65c77b28862.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/abseil/abseil-cpp/archive/997aaf3a28308eba1b9156aa35ab7bca9688e9f6.tar.gz",
+                "https://github.com/abseil/abseil-cpp/archive/997aaf3a28308eba1b9156aa35ab7bca9688e9f6.tar.gz",
             ],
         )
 
@@ -306,21 +316,21 @@
     if "envoy_api" not in native.existing_rules():
         http_archive(
             name = "envoy_api",
-            sha256 = "466585f253471259ce17641348149f458270316e81ec6702fdd8bf0b1b681256",
-            strip_prefix = "data-plane-api-9997e1137cdb59e622af13e57ca915a2f3c9f84f",
+            sha256 = "4423bef0ab15053dca0f723cbdaf4b48ab145e9d8158f02e33028c66fb1d20e0",
+            strip_prefix = "data-plane-api-18b54850c9b7ba29a4ab67cbd7ed7eab7b0bbdb2",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/envoyproxy/data-plane-api/archive/9997e1137cdb59e622af13e57ca915a2f3c9f84f.tar.gz",
-                "https://github.com/envoyproxy/data-plane-api/archive/9997e1137cdb59e622af13e57ca915a2f3c9f84f.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/envoyproxy/data-plane-api/archive/18b54850c9b7ba29a4ab67cbd7ed7eab7b0bbdb2.tar.gz",
+                "https://github.com/envoyproxy/data-plane-api/archive/18b54850c9b7ba29a4ab67cbd7ed7eab7b0bbdb2.tar.gz",
             ],
         )
 
     if "io_bazel_rules_go" not in native.existing_rules():
         http_archive(
             name = "io_bazel_rules_go",
-            sha256 = "a82a352bffae6bee4e95f68a8d80a70e87f42c4741e6a448bec11998fcc82329",
+            sha256 = "dbf5a9ef855684f84cac2e7ae7886c5a001d4f66ae23f6904da0faaaef0d61fc",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.18.5/rules_go-0.18.5.tar.gz",
-                "https://github.com/bazelbuild/rules_go/releases/download/0.18.5/rules_go-0.18.5.tar.gz",
+                "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.24.11/rules_go-v0.24.11.tar.gz",
+                "https://github.com/bazelbuild/rules_go/releases/download/v0.24.11/rules_go-v0.24.11.tar.gz",
             ],
         )
 
@@ -357,6 +367,50 @@
             ],
         )
 
+    if "com_google_googleapis" not in native.existing_rules():
+        http_archive(
+            name = "com_google_googleapis",
+            sha256 = "a45019af4d3290f02eaeb1ce10990166978c807cb33a9692141a076ba46d1405",
+            strip_prefix = "googleapis-82944da21578a53b74e547774cf62ed31a05b841",
+            urls = [
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/googleapis/googleapis/archive/82944da21578a53b74e547774cf62ed31a05b841.tar.gz",
+                "https://github.com/googleapis/googleapis/archive/82944da21578a53b74e547774cf62ed31a05b841.tar.gz",
+            ],
+        )
+
+    if "bazel_gazelle" not in native.existing_rules():
+        http_archive(
+            name = "bazel_gazelle",
+            sha256 = "d987004a72697334a095bbaa18d615804a28280201a50ed6c234c40ccc41e493",
+            strip_prefix = "bazel-gazelle-0.19.1",
+            urls = [
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/bazelbuild/bazel-gazelle/archive/v0.19.1.tar.gz",
+                "https://github.com/bazelbuild/bazel-gazelle/archive/v0.19.1.tar.gz",
+            ],
+        )
+
+    if "opencensus_proto" not in native.existing_rules():
+        http_archive(
+            name = "opencensus_proto",
+            sha256 = "b7e13f0b4259e80c3070b583c2f39e53153085a6918718b1c710caf7037572b0",
+            strip_prefix = "opencensus-proto-0.3.0/src",
+            urls = [
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/census-instrumentation/opencensus-proto/archive/v0.3.0.tar.gz",
+                "https://github.com/census-instrumentation/opencensus-proto/archive/v0.3.0.tar.gz",
+            ],
+        )
+
+    if "com_envoyproxy_protoc_gen_validate" not in native.existing_rules():
+        http_archive(
+            name = "com_envoyproxy_protoc_gen_validate",
+            sha256 = "e368733c9fb7f8489591ffaf269170d7658cc0cd1ee322b601512b769446d3c8",
+            strip_prefix = "protoc-gen-validate-278964a8052f96a2f514add0298098f63fb7f47f",
+            urls = [
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/envoyproxy/protoc-gen-validate/archive/278964a8052f96a2f514add0298098f63fb7f47f.tar.gz",
+                "https://github.com/envoyproxy/protoc-gen-validate/archive/278964a8052f96a2f514add0298098f63fb7f47f.tar.gz",
+            ],
+        )
+
     grpc_python_deps()
 
 # TODO: move some dependencies from "grpc_deps" here?
diff --git a/grpc/bazel/grpc_extra_deps.bzl b/grpc/bazel/grpc_extra_deps.bzl
index 9c3038f..2338a14 100644
--- a/grpc/bazel/grpc_extra_deps.bzl
+++ b/grpc/bazel/grpc_extra_deps.bzl
@@ -6,6 +6,7 @@
 load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
 load("@build_bazel_rules_apple//apple:repositories.bzl", "apple_rules_dependencies")
 load("@build_bazel_apple_support//lib:repositories.bzl", "apple_support_dependencies")
+load("@com_google_googleapis//:repository_rules.bzl", "switched_rules_by_language")
 
 def grpc_extra_deps(ignore_version_differences = False):
     """Loads the extra dependencies.
@@ -38,3 +39,11 @@
     apple_rules_dependencies(ignore_version_differences = ignore_version_differences)
 
     apple_support_dependencies()
+
+    # Initialize Google APIs with only C++ and Python targets
+    switched_rules_by_language(
+        name = "com_google_googleapis_imports",
+        cc = True,
+        grpc = True,
+        python = True,
+    )
diff --git a/grpc/bazel/grpc_python_deps.bzl b/grpc/bazel/grpc_python_deps.bzl
index b26c4fb..8f0c7db 100644
--- a/grpc/bazel/grpc_python_deps.bzl
+++ b/grpc/bazel/grpc_python_deps.bzl
@@ -40,14 +40,6 @@
             sha256 = "aa96a691d3a8177f3215b14b0edc9641787abaaa30363a080165d06ab65e1161",
         )
 
-    if "rules_python" not in native.existing_rules():
-        http_archive(
-            name = "rules_python",
-            url = "https://github.com/bazelbuild/rules_python/archive/9d68f24659e8ce8b736590ba1e4418af06ec2552.zip",
-            sha256 = "f7402f11691d657161f871e11968a984e5b48b023321935f5a55d7e56cf4758a",
-            strip_prefix = "rules_python-9d68f24659e8ce8b736590ba1e4418af06ec2552",
-        )
-
     python_configure(name = "local_config_python")
 
     native.bind(
@@ -59,9 +51,9 @@
         http_archive(
             name = "cython",
             build_file = "@com_github_grpc_grpc//third_party:cython.BUILD",
-            sha256 = "d68138a2381afbdd0876c3cb2a22389043fa01c4badede1228ee073032b07a27",
-            strip_prefix = "cython-c2b80d87658a8525ce091cbe146cb7eaa29fed5c",
+            sha256 = "e2e38e1f0572ca54d6085df3dec8b607d20e81515fb80215aed19c81e8fe2079",
+            strip_prefix = "cython-0.29.21",
             urls = [
-                "https://github.com/cython/cython/archive/c2b80d87658a8525ce091cbe146cb7eaa29fed5c.tar.gz",
+                "https://github.com/cython/cython/archive/0.29.21.tar.gz",
             ],
         )
diff --git a/grpc/bazel/test/python_test_repo/tools/bazel b/grpc/bazel/test/python_test_repo/tools/bazel
index 80633cc..aaa549a 100755
--- a/grpc/bazel/test/python_test_repo/tools/bazel
+++ b/grpc/bazel/test/python_test_repo/tools/bazel
@@ -55,6 +55,9 @@
   "Linux x86_64")
     suffix=linux-x86_64
     ;;
+  "Linux aarch64")
+    suffix=linux-arm64
+    ;;
   "Darwin x86_64")
     suffix=darwin-x86_64
     ;;
diff --git a/grpc/bazel/update_mirror.sh b/grpc/bazel/update_mirror.sh
index 4b754cf..274fe51 100755
--- a/grpc/bazel/update_mirror.sh
+++ b/grpc/bazel/update_mirror.sh
@@ -34,13 +34,18 @@
 function upload {
   local file="$1"
 
-  echo "Downloading https://${file}"
-  curl -L --fail --output "${tmpdir}/archive" "https://${file}"
+  if gsutil stat "gs://grpc-bazel-mirror/${file}" > /dev/null
+  then
+    echo "Skipping ${file}"
+  else
+    echo "Downloading https://${file}"
+    curl -L --fail --output "${tmpdir}/archive" "https://${file}"
 
-  echo "Uploading https://${file} to https://storage.googleapis.com/grpc-bazel-mirror/${file}"
-  gsutil cp -n "${tmpdir}/archive" "gs://grpc-bazel-mirror/${file}"  # "-n" will skip existing files
+    echo "Uploading https://${file} to https://storage.googleapis.com/grpc-bazel-mirror/${file}"
+    gsutil cp "${tmpdir}/archive" "gs://grpc-bazel-mirror/${file}"
 
-  rm -rf "${tmpdir}/archive"
+    rm -rf "${tmpdir}/archive"
+  fi
 }
 
 # How to check that all mirror URLs work:
diff --git a/grpc/build_autogenerated.yaml b/grpc/build_autogenerated.yaml
index e9245b7..31c9d54 100644
--- a/grpc/build_autogenerated.yaml
+++ b/grpc/build_autogenerated.yaml
@@ -12,7 +12,6 @@
   - third_party/address_sorting/address_sorting_posix.c
   - third_party/address_sorting/address_sorting_windows.c
   deps: []
-  secure: false
 - name: end2end_nosec_tests
   build: private
   language: c
@@ -25,6 +24,7 @@
   - test/core/end2end/fixtures/local_util.h
   - test/core/end2end/fixtures/proxy.h
   - test/core/end2end/tests/cancel_test_helpers.h
+  - test/core/util/test_lb_policies.h
   src:
   - test/core/end2end/cq_verifier.cc
   - test/core/end2end/data/client_certs.cc
@@ -84,10 +84,12 @@
   - test/core/end2end/tests/request_with_payload.cc
   - test/core/end2end/tests/resource_quota_server.cc
   - test/core/end2end/tests/retry.cc
+  - test/core/end2end/tests/retry_cancel_during_delay.cc
   - test/core/end2end/tests/retry_cancellation.cc
   - test/core/end2end/tests/retry_disabled.cc
   - test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   - test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  - test/core/end2end/tests/retry_lb_drop.cc
   - test/core/end2end/tests/retry_non_retriable_status.cc
   - test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   - test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -115,13 +117,9 @@
   - test/core/end2end/tests/workaround_cronet_compression.cc
   - test/core/end2end/tests/write_buffering.cc
   - test/core/end2end/tests/write_buffering_at_end.cc
+  - test/core/util/test_lb_policies.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  secure: false
 - name: end2end_tests
   build: private
   language: c
@@ -134,6 +132,7 @@
   - test/core/end2end/fixtures/local_util.h
   - test/core/end2end/fixtures/proxy.h
   - test/core/end2end/tests/cancel_test_helpers.h
+  - test/core/util/test_lb_policies.h
   src:
   - test/core/end2end/cq_verifier.cc
   - test/core/end2end/data/client_certs.cc
@@ -194,10 +193,12 @@
   - test/core/end2end/tests/request_with_payload.cc
   - test/core/end2end/tests/resource_quota_server.cc
   - test/core/end2end/tests/retry.cc
+  - test/core/end2end/tests/retry_cancel_during_delay.cc
   - test/core/end2end/tests/retry_cancellation.cc
   - test/core/end2end/tests/retry_disabled.cc
   - test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   - test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  - test/core/end2end/tests/retry_lb_drop.cc
   - test/core/end2end/tests/retry_non_retriable_status.cc
   - test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   - test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -225,13 +226,9 @@
   - test/core/end2end/tests/workaround_cronet_compression.cc
   - test/core/end2end/tests/write_buffering.cc
   - test/core/end2end/tests/write_buffering_at_end.cc
+  - test/core/util/test_lb_policies.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  secure: true
 - name: gpr
   build: all
   language: c
@@ -278,6 +275,17 @@
   - include/grpc/support/thd_id.h
   - include/grpc/support/time.h
   headers:
+  - src/core/ext/upb-generated/google/api/annotations.upb.h
+  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h
+  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
+  - src/core/ext/upb-generated/google/api/http.upb.h
+  - src/core/ext/upb-generated/google/protobuf/any.upb.h
+  - src/core/ext/upb-generated/google/protobuf/duration.upb.h
+  - src/core/ext/upb-generated/google/protobuf/empty.upb.h
+  - src/core/ext/upb-generated/google/protobuf/struct.upb.h
+  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.h
+  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.h
+  - src/core/ext/upb-generated/google/rpc/status.upb.h
   - src/core/lib/gpr/alloc.h
   - src/core/lib/gpr/arena.h
   - src/core/lib/gpr/env.h
@@ -295,6 +303,7 @@
   - src/core/lib/gpr/useful.h
   - src/core/lib/gprpp/arena.h
   - src/core/lib/gprpp/atomic.h
+  - src/core/lib/gprpp/debug_location.h
   - src/core/lib/gprpp/examine_stack.h
   - src/core/lib/gprpp/fork.h
   - src/core/lib/gprpp/global_config.h
@@ -306,10 +315,23 @@
   - src/core/lib/gprpp/memory.h
   - src/core/lib/gprpp/mpscq.h
   - src/core/lib/gprpp/stat.h
+  - src/core/lib/gprpp/status_helper.h
   - src/core/lib/gprpp/sync.h
   - src/core/lib/gprpp/thd.h
+  - src/core/lib/gprpp/time_util.h
   - src/core/lib/profiling/timers.h
   src:
+  - src/core/ext/upb-generated/google/api/annotations.upb.c
+  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
+  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
+  - src/core/ext/upb-generated/google/api/http.upb.c
+  - src/core/ext/upb-generated/google/protobuf/any.upb.c
+  - src/core/ext/upb-generated/google/protobuf/duration.upb.c
+  - src/core/ext/upb-generated/google/protobuf/empty.upb.c
+  - src/core/ext/upb-generated/google/protobuf/struct.upb.c
+  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
+  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
+  - src/core/ext/upb-generated/google/rpc/status.upb.c
   - src/core/lib/gpr/alloc.cc
   - src/core/lib/gpr/atm.cc
   - src/core/lib/gpr/cpu_iphone.cc
@@ -350,20 +372,22 @@
   - src/core/lib/gprpp/mpscq.cc
   - src/core/lib/gprpp/stat_posix.cc
   - src/core/lib/gprpp/stat_windows.cc
+  - src/core/lib/gprpp/status_helper.cc
   - src/core/lib/gprpp/thd_posix.cc
   - src/core/lib/gprpp/thd_windows.cc
+  - src/core/lib/gprpp/time_util.cc
   - src/core/lib/profiling/basic_timers.cc
   - src/core/lib/profiling/stap_timers.cc
   deps:
-  - absl/types:optional
-  - absl/time:time
-  - absl/synchronization:synchronization
-  - absl/strings:strings
-  - absl/strings:str_format
-  - absl/status:status
-  - absl/memory:memory
   - absl/base:base
-  secure: false
+  - absl/memory:memory
+  - absl/status:status
+  - absl/strings:str_format
+  - absl/strings:strings
+  - absl/synchronization:synchronization
+  - absl/time:time
+  - absl/types:optional
+  - upb
 - name: grpc
   build: all
   language: c
@@ -372,6 +396,10 @@
   - include/grpc/byte_buffer_reader.h
   - include/grpc/census.h
   - include/grpc/compression.h
+  - include/grpc/event_engine/channel_args.h
+  - include/grpc/event_engine/event_engine.h
+  - include/grpc/event_engine/port.h
+  - include/grpc/event_engine/slice_allocator.h
   - include/grpc/fork.h
   - include/grpc/grpc.h
   - include/grpc/grpc_posix.h
@@ -404,6 +432,7 @@
   - 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
@@ -421,6 +450,8 @@
   - src/core/ext/filters/client_channel/resolver_factory.h
   - src/core/ext/filters/client_channel/resolver_registry.h
   - src/core/ext/filters/client_channel/resolver_result_parsing.h
+  - src/core/ext/filters/client_channel/retry_filter.h
+  - src/core/ext/filters/client_channel/retry_service_config.h
   - src/core/ext/filters/client_channel/retry_throttle.h
   - src/core/ext/filters/client_channel/server_address.h
   - src/core/ext/filters/client_channel/service_config.h
@@ -430,6 +461,8 @@
   - src/core/ext/filters/client_channel/subchannel_interface.h
   - src/core/ext/filters/client_channel/subchannel_pool_interface.h
   - src/core/ext/filters/deadline/deadline_filter.h
+  - src/core/ext/filters/fault_injection/fault_injection_filter.h
+  - src/core/ext/filters/fault_injection/service_config_parser.h
   - src/core/ext/filters/http/client/http_client_filter.h
   - src/core/ext/filters/http/client_authority_filter.h
   - src/core/ext/filters/http/message_compress/message_compress_filter.h
@@ -465,9 +498,11 @@
   - src/core/ext/transport/chttp2/transport/stream_map.h
   - src/core/ext/transport/chttp2/transport/varint.h
   - src/core/ext/transport/inproc/inproc_transport.h
+  - src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h
   - src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h
   - src/core/ext/upb-generated/envoy/annotations/resource.upb.h
   - src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h
+  - src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h
   - src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h
   - src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h
   - src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.h
@@ -492,11 +527,17 @@
   - src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h
   - src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h
   - src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h
+  - src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h
+  - src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h
   - src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h
   - src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h
   - src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h
   - src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h
   - src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h
+  - src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h
+  - src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h
+  - src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h
+  - src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h
   - src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h
   - src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.h
   - src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h
@@ -510,11 +551,14 @@
   - src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.h
   - src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h
   - src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h
+  - src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h
   - src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h
+  - src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h
   - src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h
   - src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.h
   - src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h
   - src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h
+  - src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h
   - src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h
   - src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.h
   - src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.h
@@ -522,17 +566,6 @@
   - src/core/ext/upb-generated/envoy/type/v3/percent.upb.h
   - src/core/ext/upb-generated/envoy/type/v3/range.upb.h
   - src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.h
-  - src/core/ext/upb-generated/google/api/annotations.upb.h
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
-  - src/core/ext/upb-generated/google/api/http.upb.h
-  - src/core/ext/upb-generated/google/protobuf/any.upb.h
-  - src/core/ext/upb-generated/google/protobuf/duration.upb.h
-  - src/core/ext/upb-generated/google/protobuf/empty.upb.h
-  - src/core/ext/upb-generated/google/protobuf/struct.upb.h
-  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.h
-  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.h
-  - src/core/ext/upb-generated/google/rpc/status.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.h
@@ -543,17 +576,20 @@
   - src/core/ext/upb-generated/udpa/annotations/sensitive.upb.h
   - src/core/ext/upb-generated/udpa/annotations/status.upb.h
   - src/core/ext/upb-generated/udpa/annotations/versioning.upb.h
-  - src/core/ext/upb-generated/udpa/core/v1/authority.upb.h
-  - src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h
-  - src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h
-  - src/core/ext/upb-generated/udpa/core/v1/resource.upb.h
-  - src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h
-  - src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h
   - src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h
+  - src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h
   - src/core/ext/upb-generated/validate/validate.upb.h
+  - src/core/ext/upb-generated/xds/core/v3/authority.upb.h
+  - src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h
+  - src/core/ext/upb-generated/xds/core/v3/context_params.upb.h
+  - src/core/ext/upb-generated/xds/core/v3/resource.upb.h
+  - src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h
+  - src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h
+  - src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.h
@@ -578,10 +614,16 @@
   - src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.h
@@ -595,11 +637,14 @@
   - src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h
+  - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.h
   - src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.h
@@ -610,7 +655,6 @@
   - src/core/ext/upbdefs-generated/google/api/annotations.upbdefs.h
   - src/core/ext/upbdefs-generated/google/api/http.upbdefs.h
   - src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.h
-  - src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.h
   - src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.h
   - src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.h
   - src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.h
@@ -622,13 +666,14 @@
   - src/core/ext/upbdefs-generated/udpa/annotations/sensitive.upbdefs.h
   - src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h
   - src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h
-  - src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h
-  - src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h
-  - src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h
-  - src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h
-  - src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h
-  - src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h
+  - src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h
   - src/core/ext/upbdefs-generated/validate/validate.upbdefs.h
+  - src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h
+  - src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h
+  - src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h
+  - src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h
+  - src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h
+  - src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h
   - src/core/ext/xds/certificate_provider_factory.h
   - src/core/ext/xds/certificate_provider_registry.h
   - src/core/ext/xds/certificate_provider_store.h
@@ -639,6 +684,10 @@
   - src/core/ext/xds/xds_channel_args.h
   - src/core/ext/xds/xds_client.h
   - src/core/ext/xds/xds_client_stats.h
+  - src/core/ext/xds/xds_http_fault_filter.h
+  - src/core/ext/xds/xds_http_filters.h
+  - src/core/lib/address_utils/parse_address.h
+  - src/core/lib/address_utils/sockaddr_utils.h
   - src/core/lib/avl/avl.h
   - src/core/lib/backoff/backoff.h
   - src/core/lib/channel/channel_args.h
@@ -664,7 +713,6 @@
   - src/core/lib/debug/stats_data.h
   - src/core/lib/debug/trace.h
   - src/core/lib/gprpp/atomic.h
-  - src/core/lib/gprpp/debug_location.h
   - src/core/lib/gprpp/dual_ref_counted.h
   - src/core/lib/gprpp/orphanable.h
   - src/core/lib/gprpp/ref_counted.h
@@ -701,13 +749,10 @@
   - src/core/lib/iomgr/iomgr.h
   - src/core/lib/iomgr/iomgr_custom.h
   - src/core/lib/iomgr/iomgr_internal.h
-  - src/core/lib/iomgr/iomgr_posix.h
   - src/core/lib/iomgr/is_epollexclusive_available.h
   - src/core/lib/iomgr/load_file.h
   - src/core/lib/iomgr/lockfree_event.h
   - src/core/lib/iomgr/nameser.h
-  - src/core/lib/iomgr/parse_address.h
-  - src/core/lib/iomgr/poller/eventmanager_libuv.h
   - src/core/lib/iomgr/polling_entity.h
   - src/core/lib/iomgr/pollset.h
   - src/core/lib/iomgr/pollset_custom.h
@@ -724,7 +769,6 @@
   - src/core/lib/iomgr/sockaddr.h
   - src/core/lib/iomgr/sockaddr_custom.h
   - src/core/lib/iomgr/sockaddr_posix.h
-  - src/core/lib/iomgr/sockaddr_utils.h
   - src/core/lib/iomgr/sockaddr_windows.h
   - src/core/lib/iomgr/socket_factory_posix.h
   - src/core/lib/iomgr/socket_mutator.h
@@ -752,14 +796,7 @@
   - src/core/lib/iomgr/work_serializer.h
   - src/core/lib/json/json.h
   - src/core/lib/json/json_util.h
-  - src/core/lib/security/authorization/authorization_engine.h
-  - src/core/lib/security/authorization/evaluate_args.h
-  - src/core/lib/security/authorization/mock_cel/activation.h
-  - src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h
-  - src/core/lib/security/authorization/mock_cel/cel_expression.h
-  - src/core/lib/security/authorization/mock_cel/cel_value.h
-  - src/core/lib/security/authorization/mock_cel/evaluator_core.h
-  - src/core/lib/security/authorization/mock_cel/flat_expr_builder.h
+  - src/core/lib/matchers/matchers.h
   - src/core/lib/security/context/security_context.h
   - src/core/lib/security/credentials/alts/alts_credentials.h
   - src/core/lib/security/credentials/alts/check_gcp_environment.h
@@ -864,6 +901,7 @@
   - src/core/tsi/transport_security.h
   - src/core/tsi/transport_security_grpc.h
   - src/core/tsi/transport_security_interface.h
+  - third_party/xxhash/xxhash.h
   src:
   - src/core/ext/filters/census/grpc_context.cc
   - src/core/ext/filters/client_channel/backend_metric.cc
@@ -890,6 +928,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
@@ -911,10 +950,13 @@
   - src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc
   - src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
   - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+  - src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
   - src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
   - src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
   - src/core/ext/filters/client_channel/resolver_registry.cc
   - src/core/ext/filters/client_channel/resolver_result_parsing.cc
+  - src/core/ext/filters/client_channel/retry_filter.cc
+  - src/core/ext/filters/client_channel/retry_service_config.cc
   - src/core/ext/filters/client_channel/retry_throttle.cc
   - src/core/ext/filters/client_channel/server_address.cc
   - src/core/ext/filters/client_channel/service_config.cc
@@ -924,6 +966,8 @@
   - src/core/ext/filters/client_channel/subchannel_pool_interface.cc
   - src/core/ext/filters/client_idle/client_idle_filter.cc
   - src/core/ext/filters/deadline/deadline_filter.cc
+  - src/core/ext/filters/fault_injection/fault_injection_filter.cc
+  - src/core/ext/filters/fault_injection/service_config_parser.cc
   - src/core/ext/filters/http/client/http_client_filter.cc
   - src/core/ext/filters/http/client_authority_filter.cc
   - src/core/ext/filters/http/http_filters_plugin.cc
@@ -969,9 +1013,11 @@
   - src/core/ext/transport/chttp2/transport/writing.cc
   - src/core/ext/transport/inproc/inproc_plugin.cc
   - src/core/ext/transport/inproc/inproc_transport.cc
+  - src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c
   - src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c
   - src/core/ext/upb-generated/envoy/annotations/resource.upb.c
   - src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c
+  - src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c
   - src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c
   - src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c
   - src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.c
@@ -996,11 +1042,17 @@
   - src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c
   - src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c
   - src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c
+  - src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c
+  - src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c
   - src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c
   - src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c
   - src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c
   - src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.c
   - src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c
+  - src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c
+  - src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c
+  - src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c
+  - src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c
   - src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c
   - src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c
   - src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c
@@ -1014,11 +1066,14 @@
   - src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c
   - src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c
   - src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c
+  - src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c
   - src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c
+  - src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c
   - src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c
   - src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c
   - src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.c
   - src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c
+  - src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c
   - src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c
   - src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c
   - src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.c
@@ -1026,17 +1081,6 @@
   - src/core/ext/upb-generated/envoy/type/v3/percent.upb.c
   - src/core/ext/upb-generated/envoy/type/v3/range.upb.c
   - src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c
-  - src/core/ext/upb-generated/google/api/annotations.upb.c
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
-  - src/core/ext/upb-generated/google/api/http.upb.c
-  - src/core/ext/upb-generated/google/protobuf/any.upb.c
-  - src/core/ext/upb-generated/google/protobuf/duration.upb.c
-  - src/core/ext/upb-generated/google/protobuf/empty.upb.c
-  - src/core/ext/upb-generated/google/protobuf/struct.upb.c
-  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
-  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
-  - src/core/ext/upb-generated/google/rpc/status.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c
@@ -1047,17 +1091,20 @@
   - src/core/ext/upb-generated/udpa/annotations/sensitive.upb.c
   - src/core/ext/upb-generated/udpa/annotations/status.upb.c
   - src/core/ext/upb-generated/udpa/annotations/versioning.upb.c
-  - src/core/ext/upb-generated/udpa/core/v1/authority.upb.c
-  - src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c
-  - src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c
-  - src/core/ext/upb-generated/udpa/core/v1/resource.upb.c
-  - src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c
-  - src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c
   - src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
+  - src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c
   - src/core/ext/upb-generated/validate/validate.upb.c
+  - src/core/ext/upb-generated/xds/core/v3/authority.upb.c
+  - src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c
+  - src/core/ext/upb-generated/xds/core/v3/context_params.upb.c
+  - src/core/ext/upb-generated/xds/core/v3/resource.upb.c
+  - src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c
+  - src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c
+  - src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.c
@@ -1082,10 +1129,16 @@
   - src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c
@@ -1099,11 +1152,14 @@
   - src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c
+  - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c
   - src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.c
@@ -1114,7 +1170,6 @@
   - src/core/ext/upbdefs-generated/google/api/annotations.upbdefs.c
   - src/core/ext/upbdefs-generated/google/api/http.upbdefs.c
   - src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c
-  - src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c
   - src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c
   - src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c
   - src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.c
@@ -1126,13 +1181,14 @@
   - src/core/ext/upbdefs-generated/udpa/annotations/sensitive.upbdefs.c
   - src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.c
   - src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c
-  - src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c
-  - src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c
-  - src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c
-  - src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c
-  - src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c
-  - src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c
+  - src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c
   - src/core/ext/upbdefs-generated/validate/validate.upbdefs.c
+  - src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c
+  - src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c
+  - src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c
+  - src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c
+  - src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c
+  - src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c
   - src/core/ext/xds/certificate_provider_registry.cc
   - src/core/ext/xds/certificate_provider_store.cc
   - src/core/ext/xds/file_watcher_certificate_provider_factory.cc
@@ -1141,7 +1197,11 @@
   - src/core/ext/xds/xds_certificate_provider.cc
   - src/core/ext/xds/xds_client.cc
   - src/core/ext/xds/xds_client_stats.cc
+  - src/core/ext/xds/xds_http_fault_filter.cc
+  - src/core/ext/xds/xds_http_filters.cc
   - src/core/ext/xds/xds_server_config_fetcher.cc
+  - src/core/lib/address_utils/parse_address.cc
+  - src/core/lib/address_utils/sockaddr_utils.cc
   - src/core/lib/avl/avl.cc
   - src/core/lib/backoff/backoff.cc
   - src/core/lib/channel/channel_args.cc
@@ -1164,6 +1224,8 @@
   - src/core/lib/debug/stats.cc
   - src/core/lib/debug/stats_data.cc
   - src/core/lib/debug/trace.cc
+  - src/core/lib/event_engine/slice_allocator.cc
+  - src/core/lib/event_engine/sockaddr.cc
   - src/core/lib/http/format_request.cc
   - src/core/lib/http/httpcli.cc
   - src/core/lib/http/httpcli_security_connector.cc
@@ -1209,8 +1271,6 @@
   - src/core/lib/iomgr/is_epollexclusive_available.cc
   - src/core/lib/iomgr/load_file.cc
   - src/core/lib/iomgr/lockfree_event.cc
-  - src/core/lib/iomgr/parse_address.cc
-  - src/core/lib/iomgr/poller/eventmanager_libuv.cc
   - src/core/lib/iomgr/polling_entity.cc
   - src/core/lib/iomgr/pollset.cc
   - src/core/lib/iomgr/pollset_custom.cc
@@ -1224,7 +1284,6 @@
   - src/core/lib/iomgr/resolve_address_posix.cc
   - src/core/lib/iomgr/resolve_address_windows.cc
   - src/core/lib/iomgr/resource_quota.cc
-  - src/core/lib/iomgr/sockaddr_utils.cc
   - src/core/lib/iomgr/socket_factory_posix.cc
   - src/core/lib/iomgr/socket_mutator.cc
   - src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -1267,8 +1326,7 @@
   - src/core/lib/json/json_reader.cc
   - src/core/lib/json/json_util.cc
   - src/core/lib/json/json_writer.cc
-  - src/core/lib/security/authorization/authorization_engine.cc
-  - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/matchers/matchers.cc
   - src/core/lib/security/context/security_context.cc
   - src/core/lib/security/credentials/alts/alts_credentials.cc
   - src/core/lib/security/credentials/alts/check_gcp_environment.cc
@@ -1391,22 +1449,15 @@
   - src/core/tsi/transport_security.cc
   - src/core/tsi/transport_security_grpc.cc
   deps:
-  - gpr
-  - address_sorting
-  - upb
-  - absl/types:optional
-  - absl/strings:strings
-  - absl/status:statusor
-  - absl/status:status
-  - absl/functional:bind_front
-  - absl/container:inlined_vector
-  - absl/container:flat_hash_set
   - absl/container:flat_hash_map
+  - absl/container:inlined_vector
+  - absl/functional:bind_front
+  - absl/status:statusor
+  - gpr
+  - libssl
+  - address_sorting
   baselib: true
-  deps_linkage: static
-  dll: true
   generate_plugin_registry: true
-  secure: true
 - name: grpc_csharp_ext
   build: all
   language: c
@@ -1416,22 +1467,18 @@
   - src/csharp/ext/grpc_csharp_ext.c
   deps:
   - grpc
-  - gpr
-  - address_sorting
-  - upb
-  deps_linkage: static
-  dll: only
 - name: grpc_test_util
   build: private
   language: c
   public_headers: []
   headers:
   - test/core/util/cmdline.h
-  - test/core/util/eval_args_mock_endpoint.h
+  - test/core/util/evaluate_args_test_util.h
   - test/core/util/fuzzer_util.h
   - test/core/util/grpc_profiler.h
   - test/core/util/histogram.h
   - test/core/util/memory_counters.h
+  - test/core/util/mock_authorization_endpoint.h
   - test/core/util/mock_endpoint.h
   - test/core/util/parse_hexstring.h
   - test/core/util/passthru_endpoint.h
@@ -1449,7 +1496,6 @@
   - test/core/util/trickle_endpoint.h
   src:
   - test/core/util/cmdline.cc
-  - test/core/util/eval_args_mock_endpoint.cc
   - test/core/util/fuzzer_util.cc
   - test/core/util/grpc_profiler.cc
   - test/core/util/histogram.cc
@@ -1472,24 +1518,22 @@
   - test/core/util/tracer_util.cc
   - test/core/util/trickle_endpoint.cc
   deps:
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/debugging:symbolize
-  - absl/debugging:stacktrace
   - absl/debugging:failure_signal_handler
+  - absl/debugging:stacktrace
+  - absl/debugging:symbolize
+  - grpc
 - name: grpc_test_util_unsecure
   build: private
   language: c
   public_headers: []
   headers:
   - test/core/util/cmdline.h
-  - test/core/util/eval_args_mock_endpoint.h
+  - test/core/util/evaluate_args_test_util.h
   - test/core/util/fuzzer_util.h
   - test/core/util/grpc_profiler.h
   - test/core/util/histogram.h
   - test/core/util/memory_counters.h
+  - test/core/util/mock_authorization_endpoint.h
   - test/core/util/mock_endpoint.h
   - test/core/util/parse_hexstring.h
   - test/core/util/passthru_endpoint.h
@@ -1506,7 +1550,6 @@
   - test/core/util/trickle_endpoint.h
   src:
   - test/core/util/cmdline.cc
-  - test/core/util/eval_args_mock_endpoint.cc
   - test/core/util/fuzzer_util.cc
   - test/core/util/grpc_profiler.cc
   - test/core/util/histogram.cc
@@ -1528,14 +1571,10 @@
   - test/core/util/tracer_util.cc
   - test/core/util/trickle_endpoint.cc
   deps:
-  - grpc_unsecure
-  - gpr
-  - address_sorting
-  - upb
-  - absl/debugging:symbolize
-  - absl/debugging:stacktrace
   - absl/debugging:failure_signal_handler
-  secure: false
+  - absl/debugging:stacktrace
+  - absl/debugging:symbolize
+  - grpc_unsecure
 - name: grpc_unsecure
   build: all
   language: c
@@ -1544,6 +1583,10 @@
   - include/grpc/byte_buffer_reader.h
   - include/grpc/census.h
   - include/grpc/compression.h
+  - include/grpc/event_engine/channel_args.h
+  - include/grpc/event_engine/event_engine.h
+  - include/grpc/event_engine/port.h
+  - include/grpc/event_engine/slice_allocator.h
   - include/grpc/fork.h
   - include/grpc/grpc.h
   - include/grpc/grpc_posix.h
@@ -1589,6 +1632,8 @@
   - src/core/ext/filters/client_channel/resolver_factory.h
   - src/core/ext/filters/client_channel/resolver_registry.h
   - src/core/ext/filters/client_channel/resolver_result_parsing.h
+  - src/core/ext/filters/client_channel/retry_filter.h
+  - src/core/ext/filters/client_channel/retry_service_config.h
   - src/core/ext/filters/client_channel/retry_throttle.h
   - src/core/ext/filters/client_channel/server_address.h
   - src/core/ext/filters/client_channel/service_config.h
@@ -1598,6 +1643,8 @@
   - src/core/ext/filters/client_channel/subchannel_interface.h
   - src/core/ext/filters/client_channel/subchannel_pool_interface.h
   - src/core/ext/filters/deadline/deadline_filter.h
+  - src/core/ext/filters/fault_injection/fault_injection_filter.h
+  - src/core/ext/filters/fault_injection/service_config_parser.h
   - src/core/ext/filters/http/client/http_client_filter.h
   - src/core/ext/filters/http/client_authority_filter.h
   - src/core/ext/filters/http/message_compress/message_compress_filter.h
@@ -1633,21 +1680,12 @@
   - src/core/ext/transport/chttp2/transport/stream_map.h
   - src/core/ext/transport/chttp2/transport/varint.h
   - src/core/ext/transport/inproc/inproc_transport.h
-  - src/core/ext/upb-generated/google/api/annotations.upb.h
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.h
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
-  - src/core/ext/upb-generated/google/api/http.upb.h
-  - src/core/ext/upb-generated/google/protobuf/any.upb.h
-  - src/core/ext/upb-generated/google/protobuf/duration.upb.h
-  - src/core/ext/upb-generated/google/protobuf/empty.upb.h
-  - src/core/ext/upb-generated/google/protobuf/struct.upb.h
-  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.h
-  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.h
-  - src/core/ext/upb-generated/google/rpc/status.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.h
   - src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.h
   - src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h
   - src/core/ext/upb-generated/validate/validate.upb.h
+  - src/core/lib/address_utils/parse_address.h
+  - src/core/lib/address_utils/sockaddr_utils.h
   - src/core/lib/avl/avl.h
   - src/core/lib/backoff/backoff.h
   - src/core/lib/channel/channel_args.h
@@ -1673,7 +1711,6 @@
   - src/core/lib/debug/stats_data.h
   - src/core/lib/debug/trace.h
   - src/core/lib/gprpp/atomic.h
-  - src/core/lib/gprpp/debug_location.h
   - src/core/lib/gprpp/dual_ref_counted.h
   - src/core/lib/gprpp/orphanable.h
   - src/core/lib/gprpp/ref_counted.h
@@ -1710,13 +1747,10 @@
   - src/core/lib/iomgr/iomgr.h
   - src/core/lib/iomgr/iomgr_custom.h
   - src/core/lib/iomgr/iomgr_internal.h
-  - src/core/lib/iomgr/iomgr_posix.h
   - src/core/lib/iomgr/is_epollexclusive_available.h
   - src/core/lib/iomgr/load_file.h
   - src/core/lib/iomgr/lockfree_event.h
   - src/core/lib/iomgr/nameser.h
-  - src/core/lib/iomgr/parse_address.h
-  - src/core/lib/iomgr/poller/eventmanager_libuv.h
   - src/core/lib/iomgr/polling_entity.h
   - src/core/lib/iomgr/pollset.h
   - src/core/lib/iomgr/pollset_custom.h
@@ -1733,7 +1767,6 @@
   - src/core/lib/iomgr/sockaddr.h
   - src/core/lib/iomgr/sockaddr_custom.h
   - src/core/lib/iomgr/sockaddr_posix.h
-  - src/core/lib/iomgr/sockaddr_utils.h
   - src/core/lib/iomgr/sockaddr_windows.h
   - src/core/lib/iomgr/socket_factory_posix.h
   - src/core/lib/iomgr/socket_mutator.h
@@ -1841,6 +1874,8 @@
   - src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
   - src/core/ext/filters/client_channel/resolver_registry.cc
   - src/core/ext/filters/client_channel/resolver_result_parsing.cc
+  - src/core/ext/filters/client_channel/retry_filter.cc
+  - src/core/ext/filters/client_channel/retry_service_config.cc
   - src/core/ext/filters/client_channel/retry_throttle.cc
   - src/core/ext/filters/client_channel/server_address.cc
   - src/core/ext/filters/client_channel/service_config.cc
@@ -1850,6 +1885,8 @@
   - src/core/ext/filters/client_channel/subchannel_pool_interface.cc
   - src/core/ext/filters/client_idle/client_idle_filter.cc
   - src/core/ext/filters/deadline/deadline_filter.cc
+  - src/core/ext/filters/fault_injection/fault_injection_filter.cc
+  - src/core/ext/filters/fault_injection/service_config_parser.cc
   - src/core/ext/filters/http/client/http_client_filter.cc
   - src/core/ext/filters/http/client_authority_filter.cc
   - src/core/ext/filters/http/http_filters_plugin.cc
@@ -1893,21 +1930,12 @@
   - src/core/ext/transport/chttp2/transport/writing.cc
   - src/core/ext/transport/inproc/inproc_plugin.cc
   - src/core/ext/transport/inproc/inproc_transport.cc
-  - src/core/ext/upb-generated/google/api/annotations.upb.c
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c
-  - src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
-  - src/core/ext/upb-generated/google/api/http.upb.c
-  - src/core/ext/upb-generated/google/protobuf/any.upb.c
-  - src/core/ext/upb-generated/google/protobuf/duration.upb.c
-  - src/core/ext/upb-generated/google/protobuf/empty.upb.c
-  - src/core/ext/upb-generated/google/protobuf/struct.upb.c
-  - src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
-  - src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
-  - src/core/ext/upb-generated/google/rpc/status.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c
   - src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c
   - src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
   - src/core/ext/upb-generated/validate/validate.upb.c
+  - src/core/lib/address_utils/parse_address.cc
+  - src/core/lib/address_utils/sockaddr_utils.cc
   - src/core/lib/avl/avl.cc
   - src/core/lib/backoff/backoff.cc
   - src/core/lib/channel/channel_args.cc
@@ -1930,6 +1958,8 @@
   - src/core/lib/debug/stats.cc
   - src/core/lib/debug/stats_data.cc
   - src/core/lib/debug/trace.cc
+  - src/core/lib/event_engine/slice_allocator.cc
+  - src/core/lib/event_engine/sockaddr.cc
   - src/core/lib/http/format_request.cc
   - src/core/lib/http/httpcli.cc
   - src/core/lib/http/parser.cc
@@ -1974,8 +2004,6 @@
   - src/core/lib/iomgr/is_epollexclusive_available.cc
   - src/core/lib/iomgr/load_file.cc
   - src/core/lib/iomgr/lockfree_event.cc
-  - src/core/lib/iomgr/parse_address.cc
-  - src/core/lib/iomgr/poller/eventmanager_libuv.cc
   - src/core/lib/iomgr/polling_entity.cc
   - src/core/lib/iomgr/pollset.cc
   - src/core/lib/iomgr/pollset_custom.cc
@@ -1989,7 +2017,6 @@
   - src/core/lib/iomgr/resolve_address_posix.cc
   - src/core/lib/iomgr/resolve_address_windows.cc
   - src/core/lib/iomgr/resource_quota.cc
-  - src/core/lib/iomgr/sockaddr_utils.cc
   - src/core/lib/iomgr/socket_factory_posix.cc
   - src/core/lib/iomgr/socket_mutator.cc
   - src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -2075,20 +2102,13 @@
   - src/core/lib/uri/uri_parser.cc
   - src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
   deps:
+  - absl/container:flat_hash_map
+  - absl/container:inlined_vector
+  - absl/status:statusor
   - gpr
   - address_sorting
-  - upb
-  - absl/types:optional
-  - absl/strings:strings
-  - absl/status:statusor
-  - absl/status:status
-  - absl/container:inlined_vector
-  - absl/container:flat_hash_map
   baselib: true
-  deps_linkage: static
-  dll: true
   generate_plugin_registry: true
-  secure: false
 - name: benchmark_helpers
   build: test
   language: c++
@@ -2103,14 +2123,10 @@
   - src/proto/grpc/testing/simple_messages.proto
   - test/cpp/microbenchmarks/helpers.cc
   deps:
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
   - benchmark
+  - grpc++_unsecure
+  - grpc_test_util_unsecure
+  - grpc++_test_config
   defaults: benchmark
 - name: grpc++
   build: all
@@ -2236,6 +2252,7 @@
   - include/grpcpp/impl/codegen/message_allocator.h
   - include/grpcpp/impl/codegen/metadata_map.h
   - include/grpcpp/impl/codegen/method_handler.h
+  - include/grpcpp/impl/codegen/method_handler_impl.h
   - include/grpcpp/impl/codegen/proto_buffer_reader.h
   - include/grpcpp/impl/codegen/proto_buffer_writer.h
   - include/grpcpp/impl/codegen/proto_utils.h
@@ -2365,11 +2382,7 @@
   - src/cpp/util/time_cc.cc
   deps:
   - grpc
-  - gpr
-  - address_sorting
-  - upb
   baselib: true
-  dll: true
 - name: grpc++_alts
   build: all
   language: c++
@@ -2382,10 +2395,6 @@
   - src/cpp/common/alts_util.cc
   deps:
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   baselib: true
 - name: grpc++_error_details
   build: all
@@ -2395,14 +2404,9 @@
   - include/grpcpp/support/error_details.h
   headers: []
   src:
-  - src/proto/grpc/status/status.proto
   - src/cpp/util/error_details.cc
   deps:
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc++_reflection
   build: all
   language: c++
@@ -2417,10 +2421,6 @@
   - src/cpp/ext/proto_server_reflection_plugin.cc
   deps:
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc++_test
   build: private
   language: c++
@@ -2436,10 +2436,6 @@
   - src/cpp/client/channel_test_peer.cc
   deps:
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc++_test_config
   build: private
   language: c++
@@ -2449,8 +2445,8 @@
   src:
   - test/cpp/util/test_config_cc.cc
   deps:
-  - gpr
   - absl/flags:parse
+  - gpr
 - name: grpc++_test_util
   build: private
   language: c++
@@ -2473,13 +2469,9 @@
   - test/cpp/util/subprocess.cc
   - test/cpp/util/test_credentials_provider.cc
   deps:
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   - absl/flags:flag
+  - grpc++
+  - grpc_test_util
 - name: grpc++_unsecure
   build: all
   language: c++
@@ -2604,6 +2596,7 @@
   - include/grpcpp/impl/codegen/message_allocator.h
   - include/grpcpp/impl/codegen/metadata_map.h
   - include/grpcpp/impl/codegen/method_handler.h
+  - include/grpcpp/impl/codegen/method_handler_impl.h
   - include/grpcpp/impl/codegen/proto_buffer_reader.h
   - include/grpcpp/impl/codegen/proto_buffer_writer.h
   - include/grpcpp/impl/codegen/proto_utils.h
@@ -2718,12 +2711,7 @@
   - src/cpp/util/time_cc.cc
   deps:
   - grpc_unsecure
-  - gpr
-  - address_sorting
-  - upb
   baselib: true
-  dll: true
-  secure: false
 - name: grpc_plugin_support
   build: protoc
   language: c++
@@ -2763,7 +2751,6 @@
   - src/compiler/python_generator.cc
   - src/compiler/ruby_generator.cc
   deps: []
-  secure: false
 - name: grpcpp_channelz
   build: all
   language: c++
@@ -2777,10 +2764,6 @@
   - src/cpp/server/channelz/channelz_service_plugin.cc
   deps:
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 targets:
 - name: algorithm_test
   build: test
@@ -2790,10 +2773,6 @@
   - test/core/compression/algorithm_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: alloc_test
   build: test
@@ -2803,10 +2782,6 @@
   - test/core/gpr/alloc_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: alpn_test
   build: test
@@ -2816,10 +2791,6 @@
   - test/core/transport/chttp2/alpn_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_counter_test
   build: test
   language: c
@@ -2830,10 +2801,6 @@
   - test/core/tsi/alts/frame_protector/alts_counter_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_crypt_test
   build: test
   language: c
@@ -2844,10 +2811,6 @@
   - test/core/tsi/alts/crypt/gsec_test_util.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_crypter_test
   build: test
   language: c
@@ -2858,10 +2821,6 @@
   - test/core/tsi/alts/frame_protector/alts_crypter_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_frame_protector_test
   build: test
   language: c
@@ -2874,10 +2833,6 @@
   - test/core/tsi/transport_security_test_lib.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_grpc_record_protocol_test
   build: test
   language: c
@@ -2888,10 +2843,6 @@
   - test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_handshaker_client_test
   build: test
   language: c
@@ -2902,10 +2853,6 @@
   - test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_iovec_record_protocol_test
   build: test
   language: c
@@ -2916,10 +2863,6 @@
   - test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_security_connector_test
   build: test
   language: c
@@ -2928,10 +2871,6 @@
   - test/core/security/alts_security_connector_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_tsi_handshaker_test
   build: test
   language: c
@@ -2942,10 +2881,6 @@
   - test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_tsi_utils_test
   build: test
   language: c
@@ -2956,10 +2891,6 @@
   - test/core/tsi/alts/handshaker/alts_tsi_utils_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: alts_zero_copy_grpc_protector_test
   build: test
   language: c
@@ -2970,10 +2901,6 @@
   - test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: arena_test
   build: test
   language: c
@@ -2982,10 +2909,6 @@
   - test/core/gpr/arena_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: auth_context_test
   build: test
@@ -2995,10 +2918,6 @@
   - test/core/security/auth_context_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: avl_test
   build: test
@@ -3008,10 +2927,6 @@
   - test/core/avl/avl_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: b64_test
   build: test
@@ -3021,10 +2936,6 @@
   - test/core/slice/b64_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: bad_server_response_test
   build: test
@@ -3036,10 +2947,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: bad_ssl_alpn_test
   build: test
   language: c
@@ -3050,10 +2957,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3068,10 +2971,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3084,10 +2983,6 @@
   - test/core/transport/chttp2/bin_decoder_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: bin_encoder_test
   build: test
@@ -3097,10 +2992,6 @@
   - test/core/transport/chttp2/bin_encoder_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: buffer_list_test
   build: test
@@ -3110,10 +3001,6 @@
   - test/core/iomgr/buffer_list_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: channel_args_test
   build: test
   language: c
@@ -3122,10 +3009,6 @@
   - test/core/channel/channel_args_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: channel_create_test
   build: test
@@ -3135,10 +3018,6 @@
   - test/core/surface/channel_create_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: channel_stack_builder_test
   build: test
   language: c
@@ -3147,10 +3026,6 @@
   - test/core/channel/channel_stack_builder_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: channel_stack_test
   build: test
   language: c
@@ -3159,10 +3034,6 @@
   - test/core/channel/channel_stack_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: check_gcp_environment_linux_test
   build: test
@@ -3172,10 +3043,6 @@
   - test/core/security/check_gcp_environment_linux_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: check_gcp_environment_windows_test
   build: test
   language: c
@@ -3184,10 +3051,6 @@
   - test/core/security/check_gcp_environment_windows_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: client_ssl_test
   build: test
   language: c
@@ -3196,10 +3059,6 @@
   - test/core/handshake/client_ssl.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3212,10 +3071,6 @@
   - test/core/util/cmdline_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: combiner_test
   build: test
@@ -3225,10 +3080,6 @@
   - test/core/iomgr/combiner_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3242,10 +3093,6 @@
   - test/core/surface/completion_queue_threading_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: compression_test
   build: test
   language: c
@@ -3254,10 +3101,6 @@
   - test/core/compression/compression_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: concurrent_connectivity_test
   build: test
@@ -3267,10 +3110,6 @@
   - test/core/surface/concurrent_connectivity_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: connection_refused_test
   build: test
   language: c
@@ -3281,10 +3120,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: cpu_test
   build: test
   language: c
@@ -3293,10 +3128,6 @@
   - test/core/gpr/cpu_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: dns_resolver_connectivity_using_ares_test
   build: test
@@ -3306,10 +3137,6 @@
   - test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   args:
   - --resolver=ares
 - name: dns_resolver_connectivity_using_native_test
@@ -3320,10 +3147,6 @@
   - test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   args:
   - --resolver=native
 - name: dns_resolver_cooldown_test
@@ -3334,10 +3157,6 @@
   - test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: dns_resolver_test
   build: test
   language: c
@@ -3346,10 +3165,6 @@
   - test/core/client_channel/resolvers/dns_resolver_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: dualstack_socket_test
   build: test
   language: c
@@ -3360,10 +3175,6 @@
   - test/core/end2end/dualstack_socket_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3378,10 +3189,6 @@
   - test/core/iomgr/endpoint_tests.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: env_test
   build: test
   language: c
@@ -3390,10 +3197,6 @@
   - test/core/gpr/env_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: error_test
   build: test
@@ -3405,10 +3208,6 @@
   - test/core/iomgr/error_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: ev_epollex_linux_test
   build: test
@@ -3418,10 +3217,6 @@
   - test/core/iomgr/ev_epollex_linux_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3434,10 +3229,6 @@
   - test/core/client_channel/resolvers/fake_resolver_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: fake_transport_security_test
   build: test
   language: c
@@ -3448,10 +3239,6 @@
   - test/core/tsi/transport_security_test_lib.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: fd_conservation_posix_test
   build: test
   language: c
@@ -3460,10 +3247,6 @@
   - test/core/iomgr/fd_conservation_posix_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3476,10 +3259,6 @@
   - test/core/iomgr/fd_posix_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3497,10 +3276,6 @@
   - test/core/fling/fling_stream_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3518,10 +3293,6 @@
   - test/core/fling/fling_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3534,10 +3305,6 @@
   - test/core/gprpp/fork_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3556,10 +3323,6 @@
   - test/core/http/format_request_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: frame_handler_test
   build: test
   language: c
@@ -3570,10 +3333,6 @@
   - test/core/tsi/alts/frame_protector/frame_handler_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: goaway_server_test
   build: test
   language: c
@@ -3584,10 +3343,6 @@
   - test/core/end2end/goaway_server_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc_alts_credentials_options_test
   build: test
   language: c
@@ -3596,10 +3351,6 @@
   - test/core/security/grpc_alts_credentials_options_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc_byte_buffer_reader_test
   build: test
   language: c
@@ -3608,10 +3359,6 @@
   - test/core/surface/byte_buffer_reader_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: grpc_completion_queue_test
   build: test
@@ -3621,10 +3368,6 @@
   - test/core/surface/completion_queue_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc_ipv6_loopback_available_test
   build: test
   language: c
@@ -3633,10 +3376,6 @@
   - test/core/iomgr/grpc_ipv6_loopback_available_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: handshake_server_with_readahead_handshaker_test
   build: test
   language: c
@@ -3647,10 +3386,6 @@
   - test/core/handshake/server_ssl_common.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3663,10 +3398,6 @@
   - test/core/handshake/verify_peer_options.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3679,10 +3410,6 @@
   - test/core/util/histogram_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: host_port_test
   build: test
@@ -3692,10 +3419,6 @@
   - test/core/gprpp/host_port_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: hpack_encoder_test
   build: test
@@ -3705,10 +3428,6 @@
   - test/core/transport/chttp2/hpack_encoder_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: hpack_parser_test
   build: test
@@ -3718,10 +3437,6 @@
   - test/core/transport/chttp2/hpack_parser_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: hpack_table_test
   build: test
@@ -3731,10 +3446,6 @@
   - test/core/transport/chttp2/hpack_table_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: httpcli_test
   build: test
@@ -3749,10 +3460,6 @@
   - test/core/http/httpcli_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3770,10 +3477,6 @@
   - test/core/http/httpscli_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3786,11 +3489,6 @@
   - test/core/end2end/inproc_callback_test.cc
   deps:
   - end2end_tests
-  - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: invalid_call_argument_test
   build: test
@@ -3802,10 +3500,6 @@
   - test/core/end2end/invalid_call_argument_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: json_token_test
   build: test
   language: c
@@ -3814,10 +3508,6 @@
   - test/core/security/json_token_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: jwt_verifier_test
   build: test
@@ -3827,10 +3517,6 @@
   - test/core/security/jwt_verifier_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: lame_client_test
   build: test
@@ -3842,10 +3528,6 @@
   - test/core/surface/lame_client_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: load_file_test
   build: test
   language: c
@@ -3854,10 +3536,6 @@
   - test/core/iomgr/load_file_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: manual_constructor_test
   build: test
@@ -3867,10 +3545,6 @@
   - test/core/gprpp/manual_constructor_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: message_compress_test
   build: test
@@ -3880,10 +3554,6 @@
   - test/core/compression/message_compress_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: metadata_test
   build: test
@@ -3893,10 +3563,6 @@
   - test/core/transport/metadata_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: minimal_stack_is_minimal_test
   build: test
   language: c
@@ -3905,10 +3571,6 @@
   - test/core/channel/minimal_stack_is_minimal_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: mpmcqueue_test
   build: test
@@ -3918,10 +3580,6 @@
   - test/core/iomgr/mpmcqueue_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: mpscq_test
   build: test
@@ -3931,10 +3589,6 @@
   - test/core/gprpp/mpscq_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -3950,10 +3604,6 @@
   - test/core/end2end/multiple_server_queues_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: murmur_hash_test
   build: test
   language: c
@@ -3962,10 +3612,6 @@
   - test/core/gpr/murmur_hash_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: no_server_test
   build: test
@@ -3977,10 +3623,6 @@
   - test/core/end2end/no_server_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: num_external_connectivity_watchers_test
   build: test
   language: c
@@ -3989,34 +3631,22 @@
   - test/core/surface/num_external_connectivity_watchers_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: parse_address_test
   build: test
   language: c
   headers: []
   src:
-  - test/core/iomgr/parse_address_test.cc
+  - test/core/address_utils/parse_address_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: parse_address_with_named_scope_id_test
   build: test
   language: c
   headers: []
   src:
-  - test/core/iomgr/parse_address_with_named_scope_id_test.cc
+  - test/core/address_utils/parse_address_with_named_scope_id_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4035,10 +3665,6 @@
   - test/core/http/parser_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: percent_encoding_test
   build: test
@@ -4048,10 +3674,6 @@
   - test/core/slice/percent_encoding_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: public_headers_must_be_c89
   build: test
@@ -4061,10 +3683,6 @@
   - test/core/surface/public_headers_must_be_c89.c
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: resolve_address_using_ares_resolver_posix_test
   build: test
   language: c
@@ -4073,10 +3691,6 @@
   - test/core/iomgr/resolve_address_posix_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   args:
   - --resolver=ares
   platforms:
@@ -4091,10 +3705,6 @@
   - test/core/iomgr/resolve_address_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   args:
   - --resolver=ares
 - name: resolve_address_using_native_resolver_posix_test
@@ -4105,10 +3715,6 @@
   - test/core/iomgr/resolve_address_posix_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   args:
   - --resolver=native
   platforms:
@@ -4123,10 +3729,6 @@
   - test/core/iomgr/resolve_address_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   args:
   - --resolver=native
 - name: resource_quota_test
@@ -4137,10 +3739,6 @@
   - test/core/iomgr/resource_quota_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: secure_channel_create_test
   build: test
   language: c
@@ -4149,10 +3747,6 @@
   - test/core/surface/secure_channel_create_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: secure_endpoint_test
   build: test
   language: c
@@ -4163,10 +3757,6 @@
   - test/core/security/secure_endpoint_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: security_connector_test
   build: test
   language: c
@@ -4175,10 +3765,6 @@
   - test/core/security/security_connector_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: sequential_connectivity_test
   build: test
   run: false
@@ -4188,10 +3774,6 @@
   - test/core/surface/sequential_connectivity_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: server_ssl_test
   build: test
   language: c
@@ -4202,10 +3784,6 @@
   - test/core/handshake/server_ssl_common.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4218,10 +3796,6 @@
   - test/core/surface/server_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: slice_buffer_test
   build: test
   language: c
@@ -4230,10 +3804,6 @@
   - test/core/slice/slice_buffer_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: slice_string_helpers_test
   build: test
@@ -4243,10 +3813,6 @@
   - test/core/slice/slice_string_helpers_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: sockaddr_resolver_test
   build: test
@@ -4256,22 +3822,6 @@
   - test/core/client_channel/resolvers/sockaddr_resolver_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-- name: sockaddr_utils_test
-  build: test
-  language: c
-  headers: []
-  src:
-  - test/core/iomgr/sockaddr_utils_test.cc
-  deps:
-  - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: socket_utils_test
   build: test
   language: c
@@ -4280,10 +3830,6 @@
   - test/core/iomgr/socket_utils_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4296,10 +3842,6 @@
   - test/core/gpr/spinlock_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: ssl_credentials_test
   build: test
@@ -4309,10 +3851,6 @@
   - test/core/security/ssl_credentials_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: ssl_transport_security_test
   build: test
   language: c
@@ -4323,10 +3861,6 @@
   - test/core/tsi/transport_security_test_lib.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4339,10 +3873,6 @@
   - test/core/transport/status_conversion_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: stream_compression_test
   build: test
@@ -4352,10 +3882,6 @@
   - test/core/compression/stream_compression_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: stream_map_test
   build: test
@@ -4365,10 +3891,6 @@
   - test/core/transport/chttp2/stream_map_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: stream_owned_slice_test
   build: test
   language: c
@@ -4377,10 +3899,6 @@
   - test/core/transport/stream_owned_slice_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: string_test
   build: test
@@ -4390,10 +3908,6 @@
   - test/core/gpr/string_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: sync_test
   build: test
@@ -4403,10 +3917,6 @@
   - test/core/gpr/sync_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: tcp_client_posix_test
   build: test
@@ -4416,10 +3926,6 @@
   - test/core/iomgr/tcp_client_posix_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4434,10 +3940,6 @@
   - test/core/iomgr/tcp_posix_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4449,10 +3951,6 @@
   - test/core/iomgr/tcp_server_posix_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4465,10 +3963,6 @@
   - test/core/gpr/time_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: test_core_security_credentials_test
   build: test
@@ -4478,10 +3972,6 @@
   - test/core/security/credentials_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: test_core_slice_slice_test
   build: test
   language: c
@@ -4490,10 +3980,6 @@
   - test/core/slice/slice_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: thd_test
   build: test
@@ -4503,10 +3989,6 @@
   - test/core/gprpp/thd_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: threadpool_test
   build: test
@@ -4516,10 +3998,6 @@
   - test/core/iomgr/threadpool_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: time_averaged_stats_test
   build: test
@@ -4529,10 +4007,6 @@
   - test/core/iomgr/time_averaged_stats_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: timeout_encoding_test
   build: test
@@ -4542,10 +4016,6 @@
   - test/core/transport/timeout_encoding_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: timer_heap_test
   build: test
@@ -4555,10 +4025,6 @@
   - test/core/iomgr/timer_heap_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: timer_list_test
   build: test
@@ -4568,10 +4034,6 @@
   - test/core/iomgr/timer_list_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: tls_test
   build: test
@@ -4581,10 +4043,6 @@
   - test/core/gpr/tls_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: transport_security_common_api_test
   build: test
@@ -4594,10 +4052,6 @@
   - test/core/tsi/alts/handshaker/transport_security_common_api_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: transport_security_test
   build: test
   language: c
@@ -4606,10 +4060,6 @@
   - test/core/tsi/transport_security_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: udp_server_test
   build: test
   language: c
@@ -4618,10 +4068,6 @@
   - test/core/iomgr/udp_server_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4634,10 +4080,6 @@
   - test/core/gpr/useful_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: varint_test
   build: test
@@ -4647,10 +4089,6 @@
   - test/core/transport/chttp2/varint_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: address_sorting_test
   gtest: true
@@ -4660,14 +4098,8 @@
   src:
   - test/cpp/naming/address_sorting_test.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
   platforms:
   - linux
   - posix
@@ -4686,17 +4118,31 @@
   - test/cpp/util/string_ref_helper.cc
   - test/cpp/util/subprocess.cc
   deps:
-  - grpc_test_util_unsecure
   - grpc++_unsecure
-  - grpc_unsecure
+  - grpc_test_util_unsecure
   - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
   - mac
+- name: admin_services_end2end_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - src/cpp/server/csds/csds.h
+  src:
+  - src/proto/grpc/testing/xds/v3/base.proto
+  - src/proto/grpc/testing/xds/v3/config_dump.proto
+  - src/proto/grpc/testing/xds/v3/csds.proto
+  - src/proto/grpc/testing/xds/v3/percent.proto
+  - src/cpp/server/admin/admin_services.cc
+  - src/cpp/server/csds/csds.cc
+  - test/cpp/end2end/admin_services_end2end_test.cc
+  deps:
+  - grpc++_reflection
+  - grpcpp_channelz
+  - grpc++_test_util
 - name: alarm_test
   gtest: true
   build: test
@@ -4705,12 +4151,8 @@
   src:
   - test/cpp/common/alarm_test.cc
   deps:
-  - grpc_test_util_unsecure
   - grpc++_unsecure
-  - grpc_unsecure
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util_unsecure
   platforms:
   - linux
   - posix
@@ -4729,12 +4171,8 @@
   - test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc
   - test/core/tsi/alts/handshaker/alts_concurrent_connectivity_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   platforms:
   - linux
   - posix
@@ -4746,13 +4184,9 @@
   - test/core/security/alts_credentials_fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/security/corpus/alts_credentials_corpus
   maxlen: 2048
@@ -4764,14 +4198,8 @@
   src:
   - test/cpp/common/alts_util_test.cc
   deps:
-  - grpc++_test_util
   - grpc++_alts
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
 - name: async_end2end_test
   gtest: true
   build: test
@@ -4786,12 +4214,6 @@
   - test/cpp/end2end/async_end2end_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: auth_property_iterator_test
   gtest: true
   build: test
@@ -4801,26 +4223,25 @@
   - test/cpp/common/auth_property_iterator_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
-- name: authorization_engine_test
+- name: authorization_matchers_test
   gtest: true
   build: test
   language: c++
-  headers: []
+  headers:
+  - src/core/lib/security/authorization/authorization_engine.h
+  - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
+  - src/core/lib/security/authorization/rbac_policy.h
   src:
-  - test/core/security/authorization_engine_test.cc
+  - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
+  - src/core/lib/security/authorization/rbac_policy.cc
+  - test/core/security/authorization_matchers_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: aws_request_signer_test
   gtest: true
   build: test
@@ -4830,10 +4251,6 @@
   - test/core/security/aws_request_signer_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: backoff_test
   gtest: true
   build: test
@@ -4843,10 +4260,6 @@
   - test/core/backoff/backoff_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: bad_streaming_id_bad_client_test
   gtest: true
@@ -4861,10 +4274,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: badreq_bad_client_test
   gtest: true
   build: test
@@ -4878,10 +4287,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: bdp_estimator_test
   gtest: true
   build: test
@@ -4891,10 +4296,6 @@
   - test/core/transport/bdp_estimator_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -4908,14 +4309,6 @@
   - test/cpp/microbenchmarks/bm_alarm.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -4929,14 +4322,6 @@
   - test/cpp/microbenchmarks/bm_arena.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -4951,14 +4336,6 @@
   - test/cpp/microbenchmarks/bm_byte_buffer.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -4973,14 +4350,6 @@
   - test/cpp/microbenchmarks/bm_call_create.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -4989,6 +4358,7 @@
   uses_polling: false
 - name: bm_callback_streaming_ping_pong
   build: test
+  run: false
   language: c++
   headers:
   - test/cpp/microbenchmarks/callback_streaming_ping_pong.h
@@ -5004,14 +4374,6 @@
   - test/cpp/util/subprocess.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5019,6 +4381,7 @@
   - posix
 - name: bm_callback_unary_ping_pong
   build: test
+  run: false
   language: c++
   headers:
   - test/cpp/microbenchmarks/callback_test_service.h
@@ -5034,14 +4397,6 @@
   - test/cpp/util/subprocess.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5055,14 +4410,6 @@
   - test/cpp/microbenchmarks/bm_channel.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5077,14 +4424,6 @@
   - test/cpp/microbenchmarks/bm_chttp2_hpack.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5099,14 +4438,6 @@
   - test/cpp/microbenchmarks/bm_chttp2_transport.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5120,14 +4451,6 @@
   - test/cpp/microbenchmarks/bm_closure.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5141,14 +4464,6 @@
   - test/cpp/microbenchmarks/bm_cq.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5162,14 +4477,6 @@
   - test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5184,14 +4491,6 @@
   - test/cpp/microbenchmarks/bm_error.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5207,14 +4506,6 @@
   - test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5229,14 +4520,6 @@
   - test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5250,16 +4533,8 @@
   src:
   - test/cpp/microbenchmarks/bm_fullstack_trickle.cc
   deps:
-  - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   - absl/flags:flag
+  - benchmark_helpers
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5275,14 +4550,6 @@
   - test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5296,14 +4563,6 @@
   - test/cpp/microbenchmarks/bm_metadata.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5318,14 +4577,6 @@
   - test/cpp/microbenchmarks/bm_pollset.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5340,14 +4591,6 @@
   - test/cpp/microbenchmarks/bm_threadpool.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5363,14 +4606,6 @@
   - test/cpp/microbenchmarks/bm_timer.cc
   deps:
   - benchmark_helpers
-  - grpc_test_util_unsecure
-  - grpc++_unsecure
-  - grpc_unsecure
-  - grpc++_test_config
-  - gpr
-  - address_sorting
-  - upb
-  - benchmark
   benchmark: true
   defaults: benchmark
   platforms:
@@ -5386,12 +4621,6 @@
   - test/cpp/util/byte_buffer_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: byte_stream_test
   gtest: true
@@ -5402,10 +4631,6 @@
   - test/core/transport/byte_stream_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: cancel_ares_query_test
   gtest: true
@@ -5419,14 +4644,35 @@
   - test/cpp/naming/cancel_ares_query_test.cc
   - test/cpp/naming/dns_test_util.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
+- name: cel_authorization_engine_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - src/core/lib/security/authorization/authorization_engine.h
+  - src/core/lib/security/authorization/cel_authorization_engine.h
+  - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
+  - src/core/lib/security/authorization/mock_cel/activation.h
+  - src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h
+  - src/core/lib/security/authorization/mock_cel/cel_expression.h
+  - src/core/lib/security/authorization/mock_cel/cel_value.h
+  - src/core/lib/security/authorization/mock_cel/evaluator_core.h
+  - src/core/lib/security/authorization/mock_cel/flat_expr_builder.h
+  - src/core/lib/security/authorization/rbac_policy.h
+  src:
+  - src/core/lib/security/authorization/cel_authorization_engine.cc
+  - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
+  - src/core/lib/security/authorization/rbac_policy.cc
+  - test/core/security/cel_authorization_engine_test.cc
+  deps:
+  - absl/container:flat_hash_set
+  - grpc_test_util
 - name: certificate_provider_registry_test
   gtest: true
   build: test
@@ -5436,10 +4682,6 @@
   - test/core/client_channel/certificate_provider_registry_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: certificate_provider_store_test
   gtest: true
   build: test
@@ -5449,10 +4691,6 @@
   - test/core/xds/certificate_provider_store_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: cfstream_test
   gtest: true
   build: test
@@ -5468,12 +4706,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: channel_arguments_test
   gtest: true
   build: test
@@ -5482,12 +4714,8 @@
   src:
   - test/cpp/common/channel_arguments_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   uses_polling: false
 - name: channel_filter_test
   gtest: true
@@ -5497,12 +4725,8 @@
   src:
   - test/cpp/common/channel_filter_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   uses_polling: false
 - name: channel_trace_test
   gtest: true
@@ -5515,12 +4739,8 @@
   - test/core/channel/channel_trace_test.cc
   - test/cpp/util/channel_trace_proto_helper.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
 - name: channelz_registry_test
   gtest: true
   build: test
@@ -5529,12 +4749,8 @@
   src:
   - test/core/channel/channelz_registry_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   uses_polling: false
 - name: channelz_service_test
   gtest: true
@@ -5551,12 +4767,6 @@
   deps:
   - grpcpp_channelz
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: channelz_test
   gtest: true
   build: test
@@ -5568,12 +4778,8 @@
   - test/core/channel/channelz_test.cc
   - test/cpp/util/channel_trace_proto_helper.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
 - name: cli_call_test
   gtest: true
   build: test
@@ -5600,13 +4806,6 @@
   - test/cpp/util/service_describer.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
 - name: client_callback_end2end_test
   gtest: true
   build: test
@@ -5623,12 +4822,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: client_channel_stress_test
   gtest: true
   build: test
@@ -5646,12 +4839,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -5664,13 +4851,9 @@
   - test/core/end2end/fuzzers/client_fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/end2end/fuzzers/client_fuzzer_corpus
   dict: test/core/end2end/fuzzers/hpack.dictionary
@@ -5691,12 +4874,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: client_lb_end2end_test
   gtest: true
   build: test
@@ -5716,12 +4893,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -5734,12 +4905,8 @@
   src:
   - test/cpp/codegen/codegen_test_full.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   uses_polling: false
 - name: codegen_test_minimal
   gtest: true
@@ -5749,12 +4916,8 @@
   src:
   - test/cpp/codegen/codegen_test_minimal.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   uses_polling: false
 - name: connection_prefix_bad_client_test
   gtest: true
@@ -5769,10 +4932,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: connectivity_state_test
   gtest: true
   build: test
@@ -5782,10 +4941,20 @@
   - test/core/transport/connectivity_state_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+- name: context_allocator_end2end_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - test/cpp/end2end/test_service_impl.h
+  src:
+  - src/proto/grpc/testing/echo.proto
+  - src/proto/grpc/testing/echo_messages.proto
+  - src/proto/grpc/testing/simple_messages.proto
+  - test/cpp/end2end/context_allocator_end2end_test.cc
+  - test/cpp/end2end/test_service_impl.cc
+  deps:
+  - grpc++_test_util
 - name: context_list_test
   gtest: true
   build: test
@@ -5795,10 +4964,6 @@
   - test/core/transport/chttp2/context_list_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: delegating_channel_test
   gtest: true
@@ -5814,12 +4979,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: destroy_grpclb_channel_with_active_connect_stress_test
   gtest: true
   build: test
@@ -5829,12 +4988,6 @@
   - test/cpp/client/destroy_grpclb_channel_with_active_connect_stress_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: dual_ref_counted_test
   gtest: true
   build: test
@@ -5844,10 +4997,6 @@
   - test/core/gprpp/dual_ref_counted_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: duplicate_header_bad_client_test
   gtest: true
   build: test
@@ -5861,10 +5010,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: end2end_test
   gtest: true
   build: test
@@ -5882,57 +5027,47 @@
   - test/cpp/end2end/interceptors_util.cc
   - test/cpp/end2end/test_service_impl.cc
   deps:
-  - grpc++_test_util
   - grpc++_test
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
 - name: error_details_test
   gtest: true
   build: test
   language: c++
   headers: []
   src:
+  - src/proto/grpc/status/status.proto
   - src/proto/grpc/testing/echo_messages.proto
   - test/cpp/util/error_details_test.cc
   deps:
   - grpc++_error_details
   - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+- name: error_utils_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - test/core/transport/error_utils_test.cc
+  deps:
+  - grpc_test_util
 - name: evaluate_args_test
   gtest: true
   build: test
   language: c++
-  headers: []
+  headers:
+  - src/core/lib/security/authorization/authorization_engine.h
+  - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
+  - src/core/lib/security/authorization/rbac_policy.h
   src:
+  - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
+  - src/core/lib/security/authorization/rbac_policy.cc
   - test/core/security/evaluate_args_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-- name: eventmanager_libuv_test
-  gtest: true
-  build: test
-  language: c++
-  headers: []
-  src:
-  - test/core/iomgr/poller/eventmanager_libuv_test.cc
-  deps:
-  - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  uses_polling: false
 - name: examine_stack_test
   gtest: true
   build: test
@@ -5942,12 +5077,6 @@
   - test/core/gprpp/examine_stack_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/debugging:symbolize
-  - absl/debugging:stacktrace
   platforms:
   - linux
   - posix
@@ -5965,12 +5094,6 @@
   - test/cpp/end2end/exception_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: file_watcher_certificate_provider_factory_test
   gtest: true
   build: test
@@ -5980,10 +5103,6 @@
   - test/core/xds/file_watcher_certificate_provider_factory_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: filter_end2end_test
   gtest: true
   build: test
@@ -5997,12 +5116,6 @@
   - test/cpp/end2end/filter_end2end_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: flaky_network_test
   gtest: true
   build: test
@@ -6018,12 +5131,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: generic_end2end_test
   gtest: true
   build: test
@@ -6037,12 +5144,6 @@
   - test/cpp/end2end/generic_end2end_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: global_config_env_test
   gtest: true
   build: test
@@ -6052,10 +5153,6 @@
   - test/core/gprpp/global_config_env_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -6070,10 +5167,6 @@
   - test/core/gprpp/global_config_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: google_mesh_ca_certificate_provider_factory_test
   gtest: true
@@ -6086,10 +5179,24 @@
   - test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+- name: grpc_authorization_engine_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - src/core/lib/security/authorization/authorization_engine.h
+  - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
+  - src/core/lib/security/authorization/rbac_policy.h
+  src:
+  - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
+  - src/core/lib/security/authorization/rbac_policy.cc
+  - test/core/security/grpc_authorization_engine_test.cc
+  deps:
+  - grpc_test_util
 - name: grpc_cli
   build: test
   run: false
@@ -6112,13 +5219,9 @@
   - test/cpp/util/proto_reflection_descriptor_database.cc
   - test/cpp/util/service_describer.cc
   deps:
+  - absl/flags:flag
   - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
 - name: grpc_cpp_plugin
   build: protoc
   language: c++
@@ -6127,7 +5230,6 @@
   - src/compiler/cpp_plugin.cc
   deps:
   - grpc_plugin_support
-  secure: false
 - name: grpc_csharp_plugin
   build: protoc
   language: c++
@@ -6136,7 +5238,6 @@
   - src/compiler/csharp_plugin.cc
   deps:
   - grpc_plugin_support
-  secure: false
 - name: grpc_node_plugin
   build: protoc
   language: c++
@@ -6145,7 +5246,6 @@
   - src/compiler/node_plugin.cc
   deps:
   - grpc_plugin_support
-  secure: false
 - name: grpc_objective_c_plugin
   build: protoc
   language: c++
@@ -6154,7 +5254,6 @@
   - src/compiler/objective_c_plugin.cc
   deps:
   - grpc_plugin_support
-  secure: false
 - name: grpc_php_plugin
   build: protoc
   language: c++
@@ -6163,7 +5262,6 @@
   - src/compiler/php_plugin.cc
   deps:
   - grpc_plugin_support
-  secure: false
 - name: grpc_python_plugin
   build: protoc
   language: c++
@@ -6172,7 +5270,6 @@
   - src/compiler/python_plugin.cc
   deps:
   - grpc_plugin_support
-  secure: false
 - name: grpc_ruby_plugin
   build: protoc
   language: c++
@@ -6181,7 +5278,6 @@
   - src/compiler/ruby_plugin.cc
   deps:
   - grpc_plugin_support
-  secure: false
 - name: grpc_tls_certificate_distributor_test
   gtest: true
   build: test
@@ -6191,10 +5287,6 @@
   - test/core/security/grpc_tls_certificate_distributor_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc_tls_certificate_provider_test
   gtest: true
   build: test
@@ -6204,10 +5296,6 @@
   - test/core/security/grpc_tls_certificate_provider_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc_tls_credentials_options_test
   gtest: true
   build: test
@@ -6217,10 +5305,6 @@
   - test/core/security/grpc_tls_credentials_options_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpc_tool_test
   gtest: true
   build: test
@@ -6245,15 +5329,8 @@
   - test/cpp/util/proto_reflection_descriptor_database.cc
   - test/cpp/util/service_describer.cc
   deps:
-  - grpc++_test_util
   - grpc++_reflection
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
+  - grpc++_test_util
   platforms:
   - linux
   - posix
@@ -6268,12 +5345,6 @@
   - test/cpp/grpclb/grpclb_api_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: grpclb_end2end_test
   gtest: true
   build: test
@@ -6291,12 +5362,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -6310,11 +5375,6 @@
   - test/core/end2end/h2_ssl_session_reuse_test.cc
   deps:
   - end2end_tests
-  - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: head_of_line_blocking_bad_client_test
   gtest: true
   build: test
@@ -6328,10 +5388,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: headers_bad_client_test
   gtest: true
   build: test
@@ -6345,10 +5401,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: health_service_end2end_test
   gtest: true
   build: test
@@ -6367,12 +5419,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: hpack_parser_fuzzer_test
   build: fuzzer
   language: c++
@@ -6381,13 +5427,9 @@
   - test/core/transport/chttp2/hpack_parser_fuzzer_test.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/transport/chttp2/hpack_parser_corpus
   dict: test/core/end2end/fuzzers/hpack.dictionary
@@ -6403,15 +5445,8 @@
   - src/proto/grpc/testing/test.proto
   - test/cpp/interop/http2_client.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
+  - grpc++_test_util
 - name: http_request_fuzzer_test
   build: fuzzer
   language: c++
@@ -6420,13 +5455,9 @@
   - test/core/http/request_fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/http/request_corpus
   maxlen: 2048
@@ -6438,13 +5469,9 @@
   - test/core/http/response_fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/http/response_corpus
   maxlen: 2048
@@ -6463,12 +5490,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: init_test
   gtest: true
   build: test
@@ -6478,10 +5499,6 @@
   - test/core/surface/init_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: initial_settings_frame_bad_client_test
   gtest: true
@@ -6496,10 +5513,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: insecure_security_connector_test
   gtest: true
   build: test
@@ -6509,10 +5522,6 @@
   - test/core/security/insecure_security_connector_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: interop_client
   build: test
   run: false
@@ -6530,15 +5539,8 @@
   - test/cpp/interop/client_helper.cc
   - test/cpp/interop/interop_client.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
+  - grpc++_test_util
 - name: interop_server
   build: test
   run: false
@@ -6553,15 +5555,8 @@
   - test/cpp/interop/interop_server_bootstrap.cc
   - test/cpp/interop/server_helper.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
+  - grpc++_test_util
 - name: interop_test
   build: test
   language: c++
@@ -6569,15 +5564,8 @@
   src:
   - test/cpp/interop/interop_test.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
+  - grpc++_test_util
   platforms:
   - linux
   - posix
@@ -6590,13 +5578,9 @@
   - test/core/json/fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/json/corpus
   maxlen: 512
@@ -6609,10 +5593,6 @@
   - test/core/json/json_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: large_metadata_bad_client_test
   gtest: true
@@ -6627,10 +5607,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: lb_get_cpu_stats_test
   gtest: true
   build: test
@@ -6644,12 +5620,8 @@
   - src/cpp/server/load_reporter/get_cpu_stats_windows.cc
   - test/cpp/server/load_reporter/get_cpu_stats_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
 - name: lb_load_data_store_test
   gtest: true
   build: test
@@ -6661,12 +5633,8 @@
   - src/cpp/server/load_reporter/load_data_store.cc
   - test/cpp/server/load_reporter/load_data_store_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
 - name: linux_system_roots_test
   gtest: true
   build: test
@@ -6676,10 +5644,6 @@
   - test/core/security/linux_system_roots_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: log_test
   gtest: true
   build: test
@@ -6689,11 +5653,16 @@
   - test/core/gpr/log_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
+- name: matchers_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - test/core/security/matchers_test.cc
+  deps:
+  - grpc_test_util
 - name: message_allocator_end2end_test
   gtest: true
   build: test
@@ -6708,12 +5677,19 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+- name: mock_stream_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - src/proto/grpc/testing/echo.proto
+  - src/proto/grpc/testing/echo_messages.proto
+  - src/proto/grpc/testing/simple_messages.proto
+  - test/cpp/test/mock_stream_test.cc
+  deps:
+  - grpc++_test
+  - grpc++_test_util
 - name: mock_test
   gtest: true
   build: test
@@ -6726,14 +5702,8 @@
   - src/proto/grpc/testing/simple_messages.proto
   - test/cpp/end2end/mock_test.cc
   deps:
-  - grpc++_test_util
   - grpc++_test
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
 - name: nanopb_fuzzer_response_test
   build: fuzzer
   language: c++
@@ -6742,13 +5712,9 @@
   - test/core/nanopb/fuzzer_response.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/nanopb/corpus_response
   maxlen: 128
@@ -6760,13 +5726,9 @@
   - test/core/nanopb/fuzzer_serverlist.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/nanopb/corpus_serverlist
   maxlen: 128
@@ -6782,12 +5744,6 @@
   - test/cpp/end2end/nonblocking_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: noop-benchmark
   build: test
   language: c++
@@ -6795,12 +5751,8 @@
   src:
   - test/cpp/microbenchmarks/noop-benchmark.cc
   deps:
-  - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   - benchmark
+  - grpc_test_util
   benchmark: true
   defaults: benchmark
 - name: orphanable_test
@@ -6812,10 +5764,6 @@
   - test/core/gprpp/orphanable_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: out_of_bounds_bad_client_test
   gtest: true
   build: test
@@ -6829,10 +5777,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: percent_decode_fuzzer
   build: fuzzer
   language: c++
@@ -6841,13 +5785,9 @@
   - test/core/slice/percent_decode_fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/slice/percent_decode_corpus
   maxlen: 32
@@ -6859,13 +5799,9 @@
   - test/core/slice/percent_encode_fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/slice/percent_encode_corpus
   maxlen: 32
@@ -6878,10 +5814,6 @@
   - test/core/transport/pid_controller_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: port_sharing_end2end_test
   gtest: true
   build: test
@@ -6896,12 +5828,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: proto_server_reflection_test
   gtest: true
   build: test
@@ -6918,14 +5844,8 @@
   - test/cpp/end2end/test_service_impl.cc
   - test/cpp/util/proto_reflection_descriptor_database.cc
   deps:
-  - grpc++_test_util
   - grpc++_reflection
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
 - name: proto_utils_test
   gtest: true
   build: test
@@ -6934,12 +5854,8 @@
   src:
   - test/cpp/codegen/proto_utils_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   uses_polling: false
 - name: qps_json_driver
   build: test
@@ -6984,15 +5900,8 @@
   - test/cpp/qps/server_sync.cc
   - test/cpp/qps/usage_timer.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
+  - grpc++_test_util
 - name: qps_worker
   build: test
   run: false
@@ -7027,15 +5936,8 @@
   - test/cpp/qps/usage_timer.cc
   - test/cpp/qps/worker.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
+  - grpc++_test_util
 - name: raw_end2end_test
   gtest: true
   build: test
@@ -7051,12 +5953,26 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
+- name: rbac_translator_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - src/core/lib/security/authorization/authorization_engine.h
+  - src/core/lib/security/authorization/evaluate_args.h
+  - src/core/lib/security/authorization/grpc_authorization_engine.h
+  - src/core/lib/security/authorization/matchers.h
+  - src/core/lib/security/authorization/rbac_policy.h
+  - src/core/lib/security/authorization/rbac_translator.h
+  src:
+  - src/core/lib/security/authorization/evaluate_args.cc
+  - src/core/lib/security/authorization/grpc_authorization_engine.cc
+  - src/core/lib/security/authorization/matchers.cc
+  - src/core/lib/security/authorization/rbac_policy.cc
+  - src/core/lib/security/authorization/rbac_translator.cc
+  - test/core/security/rbac_translator_test.cc
+  deps:
   - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: ref_counted_ptr_test
   gtest: true
   build: test
@@ -7066,10 +5982,6 @@
   - test/core/gprpp/ref_counted_ptr_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: ref_counted_test
   gtest: true
   build: test
@@ -7079,10 +5991,6 @@
   - test/core/gprpp/ref_counted_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: remove_stream_from_stalled_lists_test
   gtest: true
   build: test
@@ -7092,10 +6000,6 @@
   - test/core/transport/chttp2/remove_stream_from_stalled_lists_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -7109,10 +6013,6 @@
   - test/core/client_channel/retry_throttle_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: secure_auth_context_test
   gtest: true
@@ -7123,12 +6023,6 @@
   - test/cpp/common/secure_auth_context_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: server_builder_plugin_test
   gtest: true
   build: test
@@ -7144,12 +6038,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: server_builder_test
   gtest: true
   build: test
@@ -7161,12 +6049,8 @@
   - src/proto/grpc/testing/simple_messages.proto
   - test/cpp/server/server_builder_test.cc
   deps:
-  - grpc_test_util_unsecure
   - grpc++_unsecure
-  - grpc_unsecure
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util_unsecure
   platforms:
   - linux
   - posix
@@ -7182,12 +6066,8 @@
   - src/proto/grpc/testing/simple_messages.proto
   - test/cpp/server/server_builder_with_socket_mutator_test.cc
   deps:
-  - grpc_test_util_unsecure
   - grpc++_unsecure
-  - grpc_unsecure
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util_unsecure
   platforms:
   - linux
   - posix
@@ -7201,10 +6081,6 @@
   - test/core/surface/server_chttp2_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: server_context_test_spouse_test
   gtest: true
   build: test
@@ -7213,14 +6089,8 @@
   src:
   - test/cpp/test/server_context_test_spouse_test.cc
   deps:
-  - grpc++_test_util
   - grpc++_test
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
 - name: server_early_return_test
   gtest: true
   build: test
@@ -7233,12 +6103,6 @@
   - test/cpp/end2end/server_early_return_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: server_fuzzer
   build: fuzzer
   language: c++
@@ -7247,13 +6111,9 @@
   - test/core/end2end/fuzzers/server_fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/end2end/fuzzers/server_fuzzer_corpus
   dict: test/core/end2end/fuzzers/hpack.dictionary
@@ -7274,12 +6134,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: server_registered_method_bad_client_test
   gtest: true
   build: test
@@ -7293,10 +6147,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: server_request_call_test
   gtest: true
   build: test
@@ -7308,12 +6158,8 @@
   - src/proto/grpc/testing/simple_messages.proto
   - test/cpp/server/server_request_call_test.cc
   deps:
-  - grpc_test_util_unsecure
   - grpc++_unsecure
-  - grpc_unsecure
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util_unsecure
   platforms:
   - linux
   - posix
@@ -7333,12 +6179,6 @@
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: service_config_test
   gtest: true
   build: test
@@ -7348,10 +6188,6 @@
   - test/core/client_channel/service_config_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: settings_timeout_test
   gtest: true
   build: test
@@ -7362,10 +6198,6 @@
   - test/core/transport/chttp2/settings_timeout_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: shutdown_test
   gtest: true
   build: test
@@ -7379,12 +6211,6 @@
   - test/cpp/end2end/shutdown_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: simple_request_bad_client_test
   gtest: true
   build: test
@@ -7398,10 +6224,15 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+- name: sockaddr_utils_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - test/core/address_utils/sockaddr_utils_test.cc
+  deps:
+  - grpc_test_util
 - name: ssl_server_fuzzer
   build: fuzzer
   language: c++
@@ -7410,13 +6241,9 @@
   - test/core/security/ssl_server_fuzzer.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/security/corpus/ssl_server_corpus
   maxlen: 2048
@@ -7429,11 +6256,6 @@
   - test/core/util/stack_tracer_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/debugging:symbolize
   platforms:
   - linux
   - posix
@@ -7448,10 +6270,6 @@
   - test/core/gprpp/stat_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: static_metadata_test
   gtest: true
@@ -7462,10 +6280,6 @@
   - test/core/transport/static_metadata_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: stats_test
   gtest: true
   build: test
@@ -7475,10 +6289,16 @@
   - test/core/debug/stats_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  uses_polling: false
+- name: status_helper_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - test/core/gprpp/status_helper_test.cc
+  deps:
+  - grpc_test_util
   uses_polling: false
 - name: status_metadata_test
   gtest: true
@@ -7489,10 +6309,6 @@
   - test/core/transport/status_metadata_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: status_util_test
   gtest: true
@@ -7503,10 +6319,6 @@
   - test/core/channel/status_util_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: stranded_event_test
   gtest: true
@@ -7519,10 +6331,6 @@
   - test/core/iomgr/stranded_event_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -7540,12 +6348,6 @@
   - test/cpp/end2end/streaming_throughput_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -7558,12 +6360,8 @@
   src:
   - test/cpp/util/string_ref_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   uses_polling: false
 - name: test_cpp_client_credentials_test
   gtest: true
@@ -7573,12 +6371,8 @@
   src:
   - test/cpp/client/credentials_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
 - name: test_cpp_server_credentials_test
   gtest: true
   build: test
@@ -7587,12 +6381,8 @@
   src:
   - test/cpp/server/credentials_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
 - name: test_cpp_util_slice_test
   gtest: true
   build: test
@@ -7602,12 +6392,6 @@
   - test/cpp/util/slice_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: test_cpp_util_time_test
   gtest: true
@@ -7618,12 +6402,6 @@
   - test/cpp/util/time_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   uses_polling: false
 - name: thread_manager_test
   gtest: true
@@ -7633,14 +6411,8 @@
   src:
   - test/cpp/thread_manager/thread_manager_test.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
 - name: thread_stress_test
   gtest: true
   build: test
@@ -7654,12 +6426,6 @@
   - test/cpp/end2end/thread_stress_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -7673,16 +6439,22 @@
   src:
   - test/cpp/common/time_jump_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
   platforms:
   - linux
   - posix
   - mac
+- name: time_util_test
+  gtest: true
+  build: test
+  language: c++
+  headers: []
+  src:
+  - test/core/gprpp/time_util_test.cc
+  deps:
+  - grpc_test_util
+  uses_polling: false
 - name: timer_test
   gtest: true
   build: test
@@ -7691,12 +6463,8 @@
   src:
   - test/cpp/common/timer_test.cc
   deps:
-  - grpc_test_util
   - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc_test_util
 - name: tls_security_connector_test
   gtest: true
   build: test
@@ -7706,10 +6474,6 @@
   - test/core/security/tls_security_connector_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: too_many_pings_test
   gtest: true
   build: test
@@ -7720,14 +6484,8 @@
   - test/core/end2end/cq_verifier.cc
   - test/core/transport/chttp2/too_many_pings_test.cc
   deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
+  - grpc++_test_util
 - name: unknown_frame_bad_client_test
   gtest: true
   build: test
@@ -7741,10 +6499,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: uri_fuzzer_test
   build: fuzzer
   language: c++
@@ -7753,13 +6507,9 @@
   - test/core/uri/uri_fuzzer_test.cc
   - test/core/util/fuzzer_corpus_test.cc
   deps:
+  - absl/flags:flag
   - grpc_test_util
   - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/flags:flag
   corpus_dirs:
   - test/core/uri/uri_corpus
   maxlen: 128
@@ -7772,10 +6522,6 @@
   - test/core/uri/uri_parser_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: window_overflow_bad_client_test
   gtest: true
   build: test
@@ -7789,10 +6535,6 @@
   - test/core/end2end/cq_verifier.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: work_serializer_test
   gtest: true
   build: test
@@ -7802,10 +6544,6 @@
   - test/core/iomgr/work_serializer_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -7816,11 +6554,12 @@
   language: c++
   headers:
   - test/core/util/cmdline.h
-  - test/core/util/eval_args_mock_endpoint.h
+  - test/core/util/evaluate_args_test_util.h
   - test/core/util/fuzzer_util.h
   - test/core/util/grpc_profiler.h
   - test/core/util/histogram.h
   - test/core/util/memory_counters.h
+  - test/core/util/mock_authorization_endpoint.h
   - test/core/util/mock_endpoint.h
   - test/core/util/parse_hexstring.h
   - test/core/util/passthru_endpoint.h
@@ -7840,7 +6579,6 @@
   - src/proto/grpc/testing/echo_messages.proto
   - src/proto/grpc/testing/simple_messages.proto
   - test/core/util/cmdline.cc
-  - test/core/util/eval_args_mock_endpoint.cc
   - test/core/util/fuzzer_util.cc
   - test/core/util/grpc_profiler.cc
   - test/core/util/histogram.cc
@@ -7863,14 +6601,10 @@
   - test/core/util/trickle_endpoint.cc
   - test/cpp/performance/writes_per_rpc_test.cc
   deps:
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
-  - absl/debugging:symbolize
-  - absl/debugging:stacktrace
   - absl/debugging:failure_signal_handler
+  - absl/debugging:stacktrace
+  - absl/debugging:symbolize
+  - grpc++
   platforms:
   - linux
   - posix
@@ -7884,10 +6618,6 @@
   - test/core/xds/xds_bootstrap_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: xds_certificate_provider_test
   gtest: true
   build: test
@@ -7897,10 +6627,6 @@
   - test/core/xds/xds_certificate_provider_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: xds_credentials_end2end_test
   gtest: true
   build: test
@@ -7915,12 +6641,6 @@
   - test/cpp/end2end/xds_credentials_end2end_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: xds_credentials_test
   gtest: true
   build: test
@@ -7930,16 +6650,13 @@
   - test/core/security/xds_credentials_test.cc
   deps:
   - grpc_test_util
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
 - name: xds_end2end_test
   gtest: true
   build: test
   run: false
   language: c++
   headers:
+  - src/cpp/server/csds/csds.h
   - test/cpp/end2end/test_service_impl.h
   src:
   - src/proto/grpc/testing/duplicate/echo_duplicate.proto
@@ -7953,11 +6670,16 @@
   - src/proto/grpc/testing/xds/lrs_for_test.proto
   - src/proto/grpc/testing/xds/v3/address.proto
   - src/proto/grpc/testing/xds/v3/ads.proto
+  - src/proto/grpc/testing/xds/v3/aggregate_cluster.proto
   - src/proto/grpc/testing/xds/v3/base.proto
   - src/proto/grpc/testing/xds/v3/cluster.proto
+  - src/proto/grpc/testing/xds/v3/config_dump.proto
   - src/proto/grpc/testing/xds/v3/config_source.proto
+  - src/proto/grpc/testing/xds/v3/csds.proto
   - src/proto/grpc/testing/xds/v3/discovery.proto
   - src/proto/grpc/testing/xds/v3/endpoint.proto
+  - src/proto/grpc/testing/xds/v3/fault.proto
+  - src/proto/grpc/testing/xds/v3/fault_common.proto
   - src/proto/grpc/testing/xds/v3/http_connection_manager.proto
   - src/proto/grpc/testing/xds/v3/listener.proto
   - src/proto/grpc/testing/xds/v3/load_report.proto
@@ -7967,18 +6689,14 @@
   - src/proto/grpc/testing/xds/v3/range.proto
   - src/proto/grpc/testing/xds/v3/regex.proto
   - src/proto/grpc/testing/xds/v3/route.proto
+  - src/proto/grpc/testing/xds/v3/router.proto
   - src/proto/grpc/testing/xds/v3/string.proto
   - src/proto/grpc/testing/xds/v3/tls.proto
+  - src/cpp/server/csds/csds.cc
   - test/cpp/end2end/test_service_impl.cc
   - test/cpp/end2end/xds_end2end_test.cc
   deps:
   - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   platforms:
   - linux
   - posix
@@ -7987,38 +6705,49 @@
   build: test
   run: false
   language: c++
-  headers: []
+  headers:
+  - src/cpp/server/csds/csds.h
   src:
   - src/proto/grpc/testing/empty.proto
   - src/proto/grpc/testing/messages.proto
   - src/proto/grpc/testing/test.proto
+  - src/proto/grpc/testing/xds/v3/base.proto
+  - src/proto/grpc/testing/xds/v3/config_dump.proto
+  - src/proto/grpc/testing/xds/v3/csds.proto
+  - src/proto/grpc/testing/xds/v3/percent.proto
+  - src/cpp/server/admin/admin_services.cc
+  - src/cpp/server/csds/csds.cc
   - test/cpp/interop/xds_interop_client.cc
   deps:
-  - grpc_test_util
-  - grpc++
-  - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   - absl/flags:flag
+  - grpc++_reflection
+  - grpcpp_channelz
+  - grpc_test_util
+  - grpc++_test_config
 - name: xds_interop_server
   build: test
   run: false
   language: c++
-  headers: []
+  headers:
+  - src/cpp/server/csds/csds.h
+  - test/cpp/end2end/test_health_check_service_impl.h
   src:
+  - src/proto/grpc/health/v1/health.proto
   - src/proto/grpc/testing/empty.proto
   - src/proto/grpc/testing/messages.proto
   - src/proto/grpc/testing/test.proto
+  - src/proto/grpc/testing/xds/v3/base.proto
+  - src/proto/grpc/testing/xds/v3/config_dump.proto
+  - src/proto/grpc/testing/xds/v3/csds.proto
+  - src/proto/grpc/testing/xds/v3/percent.proto
+  - src/cpp/server/admin/admin_services.cc
+  - src/cpp/server/csds/csds.cc
+  - test/cpp/end2end/test_health_check_service_impl.cc
   - test/cpp/interop/xds_interop_server.cc
   deps:
-  - grpc_test_util
-  - grpc++
-  - grpc++_test_config
-  - grpc
-  - gpr
-  - address_sorting
-  - upb
   - absl/flags:flag
+  - grpc++_reflection
+  - grpcpp_channelz
+  - grpc_test_util
+  - grpc++_test_config
 tests: []
diff --git a/grpc/build_config.rb b/grpc/build_config.rb
index 7b776c9..98253e2 100644
--- a/grpc/build_config.rb
+++ b/grpc/build_config.rb
@@ -13,5 +13,5 @@
 # limitations under the License.
 
 module GrpcBuildConfig
-  CORE_WINDOWS_DLL = '/tmp/libs/opt/grpc-14.dll'
+  CORE_WINDOWS_DLL = '/tmp/libs/opt/grpc-16.dll'
 end
diff --git a/grpc/build_handwritten.yaml b/grpc/build_handwritten.yaml
index c4c9c6a..49a93de 100644
--- a/grpc/build_handwritten.yaml
+++ b/grpc/build_handwritten.yaml
@@ -12,11 +12,11 @@
   '#08': Use "-preN" suffixes to identify pre-release versions
   '#09': Per-language overrides are possible with (eg) ruby_version tag here
   '#10': See the expand_version.py for all the quirks here
-  core_version: 14.0.0
+  core_version: 16.0.0
   csharp_major_version: 2
-  g_stands_for: gecko
-  protobuf_version: 3.14.0
-  version: 1.35.0
+  g_stands_for: guadalupe_river_park_conservancy
+  protobuf_version: 3.15.8
+  version: 1.38.0
 targets:
 - name: check_epollexclusive
   build: tool
@@ -48,21 +48,6 @@
   - tools/codegen/core/gen_percent_encoding_tables.cc
   deps: []
   uses_polling: false
-vspackages:
-- linkage: static
-  name: grpc.dependencies.zlib
-  props: false
-  redist: true
-  version: 1.2.8.10
-- linkage: static
-  name: grpc.dependencies.openssl
-  props: true
-  redist: true
-  version: 1.0.204.1
-- name: gtest
-  props: false
-  redist: false
-  version: 1.7.0.1
 configs:
   asan:
     CC: clang
@@ -213,6 +198,7 @@
     COREFLAGS: -fno-exceptions
     CPPFLAGS: -g -Wall -Wextra -DOSATOMIC_USE_INLINED=1 -Ithird_party/abseil-cpp -Ithird_party/re2
       -Ithird_party/upb -Isrc/core/ext/upb-generated -Isrc/core/ext/upbdefs-generated
+      -Ithird_party/xxhash
     LDFLAGS: -g
   zlib:
     CFLAGS: -fvisibility=hidden
diff --git a/grpc/cmake/modules/Findre2.cmake b/grpc/cmake/modules/Findre2.cmake
index 41df454..e4f8e4d 100644
--- a/grpc/cmake/modules/Findre2.cmake
+++ b/grpc/cmake/modules/Findre2.cmake
@@ -18,6 +18,13 @@
   return()
 endif()
 
+# As per https://github.com/grpc/grpc/issues/25434, idempotence is necessary
+# because CMake fails when another target with the same name already exists.
+if(TARGET re2::re2)
+  message(STATUS "Found RE2 via pkg-config already?")
+  return()
+endif()
+
 find_package(PkgConfig REQUIRED)
 # TODO(junyer): Use the IMPORTED_TARGET option whenever CMake 3.6 (or newer)
 # becomes the minimum required: that will take care of the add_library() and
diff --git a/grpc/cmake/xxhash.cmake b/grpc/cmake/xxhash.cmake
new file mode 100644
index 0000000..268ecef
--- /dev/null
+++ b/grpc/cmake/xxhash.cmake
@@ -0,0 +1,15 @@
+# Copyright 2017 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.
+
+set(_gRPC_XXHASH_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/xxhash")
diff --git a/grpc/config.m4 b/grpc/config.m4
index 3c620e5..5965358 100644
--- a/grpc/config.m4
+++ b/grpc/config.m4
@@ -14,6 +14,7 @@
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl-with-bazel/src/include)
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/re2)
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/upb)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/xxhash)
 
   LIBS="-lpthread $LIBS"
 
@@ -64,6 +65,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 \
@@ -85,10 +87,13 @@
     src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc \
     src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \
     src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
+    src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \
     src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
     src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/resolver_result_parsing.cc \
+    src/core/ext/filters/client_channel/retry_filter.cc \
+    src/core/ext/filters/client_channel/retry_service_config.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/server_address.cc \
     src/core/ext/filters/client_channel/service_config.cc \
@@ -98,6 +103,8 @@
     src/core/ext/filters/client_channel/subchannel_pool_interface.cc \
     src/core/ext/filters/client_idle/client_idle_filter.cc \
     src/core/ext/filters/deadline/deadline_filter.cc \
+    src/core/ext/filters/fault_injection/fault_injection_filter.cc \
+    src/core/ext/filters/fault_injection/service_config_parser.cc \
     src/core/ext/filters/http/client/http_client_filter.cc \
     src/core/ext/filters/http/client_authority_filter.cc \
     src/core/ext/filters/http/http_filters_plugin.cc \
@@ -143,9 +150,11 @@
     src/core/ext/transport/chttp2/transport/writing.cc \
     src/core/ext/transport/inproc/inproc_plugin.cc \
     src/core/ext/transport/inproc/inproc_transport.cc \
+    src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c \
     src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c \
     src/core/ext/upb-generated/envoy/annotations/resource.upb.c \
     src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c \
+    src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c \
     src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c \
     src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c \
     src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.c \
@@ -170,11 +179,17 @@
     src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c \
     src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c \
     src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c \
+    src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c \
+    src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c \
     src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c \
     src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c \
     src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c \
     src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.c \
     src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c \
+    src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c \
+    src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c \
+    src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c \
+    src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c \
     src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c \
     src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c \
     src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c \
@@ -188,11 +203,14 @@
     src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c \
     src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c \
     src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c \
+    src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c \
     src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c \
+    src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c \
     src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c \
     src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c \
     src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.c \
     src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c \
+    src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c \
     src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c \
     src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c \
     src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.c \
@@ -222,17 +240,20 @@
     src/core/ext/upb-generated/udpa/annotations/sensitive.upb.c \
     src/core/ext/upb-generated/udpa/annotations/status.upb.c \
     src/core/ext/upb-generated/udpa/annotations/versioning.upb.c \
-    src/core/ext/upb-generated/udpa/core/v1/authority.upb.c \
-    src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c \
-    src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c \
-    src/core/ext/upb-generated/udpa/core/v1/resource.upb.c \
-    src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c \
-    src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c \
     src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
+    src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c \
     src/core/ext/upb-generated/validate/validate.upb.c \
+    src/core/ext/upb-generated/xds/core/v3/authority.upb.c \
+    src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c \
+    src/core/ext/upb-generated/xds/core/v3/context_params.upb.c \
+    src/core/ext/upb-generated/xds/core/v3/resource.upb.c \
+    src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c \
+    src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c \
+    src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.c \
@@ -257,10 +278,16 @@
     src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c \
@@ -274,11 +301,14 @@
     src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c \
+    src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c \
     src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.c \
@@ -301,13 +331,14 @@
     src/core/ext/upbdefs-generated/udpa/annotations/sensitive.upbdefs.c \
     src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.c \
     src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c \
-    src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c \
-    src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c \
-    src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c \
-    src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c \
-    src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c \
-    src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c \
+    src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c \
     src/core/ext/upbdefs-generated/validate/validate.upbdefs.c \
+    src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c \
+    src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c \
+    src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c \
+    src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c \
+    src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c \
+    src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c \
     src/core/ext/xds/certificate_provider_registry.cc \
     src/core/ext/xds/certificate_provider_store.cc \
     src/core/ext/xds/file_watcher_certificate_provider_factory.cc \
@@ -316,7 +347,11 @@
     src/core/ext/xds/xds_certificate_provider.cc \
     src/core/ext/xds/xds_client.cc \
     src/core/ext/xds/xds_client_stats.cc \
+    src/core/ext/xds/xds_http_fault_filter.cc \
+    src/core/ext/xds/xds_http_filters.cc \
     src/core/ext/xds/xds_server_config_fetcher.cc \
+    src/core/lib/address_utils/parse_address.cc \
+    src/core/lib/address_utils/sockaddr_utils.cc \
     src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
@@ -339,6 +374,8 @@
     src/core/lib/debug/stats.cc \
     src/core/lib/debug/stats_data.cc \
     src/core/lib/debug/trace.cc \
+    src/core/lib/event_engine/slice_allocator.cc \
+    src/core/lib/event_engine/sockaddr.cc \
     src/core/lib/gpr/alloc.cc \
     src/core/lib/gpr/atm.cc \
     src/core/lib/gpr/cpu_iphone.cc \
@@ -379,8 +416,10 @@
     src/core/lib/gprpp/mpscq.cc \
     src/core/lib/gprpp/stat_posix.cc \
     src/core/lib/gprpp/stat_windows.cc \
+    src/core/lib/gprpp/status_helper.cc \
     src/core/lib/gprpp/thd_posix.cc \
     src/core/lib/gprpp/thd_windows.cc \
+    src/core/lib/gprpp/time_util.cc \
     src/core/lib/http/format_request.cc \
     src/core/lib/http/httpcli.cc \
     src/core/lib/http/httpcli_security_connector.cc \
@@ -426,8 +465,6 @@
     src/core/lib/iomgr/is_epollexclusive_available.cc \
     src/core/lib/iomgr/load_file.cc \
     src/core/lib/iomgr/lockfree_event.cc \
-    src/core/lib/iomgr/parse_address.cc \
-    src/core/lib/iomgr/poller/eventmanager_libuv.cc \
     src/core/lib/iomgr/polling_entity.cc \
     src/core/lib/iomgr/pollset.cc \
     src/core/lib/iomgr/pollset_custom.cc \
@@ -441,7 +478,6 @@
     src/core/lib/iomgr/resolve_address_posix.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
-    src/core/lib/iomgr/sockaddr_utils.cc \
     src/core/lib/iomgr/socket_factory_posix.cc \
     src/core/lib/iomgr/socket_mutator.cc \
     src/core/lib/iomgr/socket_utils_common_posix.cc \
@@ -484,10 +520,9 @@
     src/core/lib/json/json_reader.cc \
     src/core/lib/json/json_util.cc \
     src/core/lib/json/json_writer.cc \
+    src/core/lib/matchers/matchers.cc \
     src/core/lib/profiling/basic_timers.cc \
     src/core/lib/profiling/stap_timers.cc \
-    src/core/lib/security/authorization/authorization_engine.cc \
-    src/core/lib/security/authorization/evaluate_args.cc \
     src/core/lib/security/context/security_context.cc \
     src/core/lib/security/credentials/alts/alts_credentials.cc \
     src/core/lib/security/credentials/alts/check_gcp_environment.cc \
@@ -641,6 +676,7 @@
     third_party/abseil-cpp/absl/debugging/symbolize.cc \
     third_party/abseil-cpp/absl/hash/internal/city.cc \
     third_party/abseil-cpp/absl/hash/internal/hash.cc \
+    third_party/abseil-cpp/absl/hash/internal/wyhash.cc \
     third_party/abseil-cpp/absl/numeric/int128.cc \
     third_party/abseil-cpp/absl/status/status.cc \
     third_party/abseil-cpp/absl/status/status_payload_printer.cc \
@@ -651,6 +687,8 @@
     third_party/abseil-cpp/absl/strings/escaping.cc \
     third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc \
     third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc \
+    third_party/abseil-cpp/absl/strings/internal/cord_internal.cc \
+    third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc \
     third_party/abseil-cpp/absl/strings/internal/escaping.cc \
     third_party/abseil-cpp/absl/strings/internal/memutil.cc \
     third_party/abseil-cpp/absl/strings/internal/ostringstream.cc \
@@ -738,6 +776,7 @@
     third_party/boringssl-with-bazel/src/crypto/bio/printf.c \
     third_party/boringssl-with-bazel/src/crypto/bio/socket.c \
     third_party/boringssl-with-bazel/src/crypto/bio/socket_helper.c \
+    third_party/boringssl-with-bazel/src/crypto/blake2/blake2.c \
     third_party/boringssl-with-bazel/src/crypto/bn_extra/bn_asn1.c \
     third_party/boringssl-with-bazel/src/crypto/bn_extra/convert.c \
     third_party/boringssl-with-bazel/src/crypto/buf/buf.c \
@@ -762,6 +801,7 @@
     third_party/boringssl-with-bazel/src/crypto/conf/conf.c \
     third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-fuchsia.c \
     third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-linux.c \
+    third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-win.c \
     third_party/boringssl-with-bazel/src/crypto/cpu-arm-linux.c \
     third_party/boringssl-with-bazel/src/crypto/cpu-arm.c \
     third_party/boringssl-with-bazel/src/crypto/cpu-intel.c \
@@ -769,10 +809,8 @@
     third_party/boringssl-with-bazel/src/crypto/crypto.c \
     third_party/boringssl-with-bazel/src/crypto/curve25519/curve25519.c \
     third_party/boringssl-with-bazel/src/crypto/curve25519/spake25519.c \
-    third_party/boringssl-with-bazel/src/crypto/dh/check.c \
-    third_party/boringssl-with-bazel/src/crypto/dh/dh.c \
-    third_party/boringssl-with-bazel/src/crypto/dh/dh_asn1.c \
-    third_party/boringssl-with-bazel/src/crypto/dh/params.c \
+    third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c \
+    third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c \
     third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c \
     third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c \
     third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c \
@@ -803,7 +841,6 @@
     third_party/boringssl-with-bazel/src/crypto/ex_data.c \
     third_party/boringssl-with-bazel/src/crypto/fipsmodule/bcm.c \
     third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c \
-    third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c \
     third_party/boringssl-with-bazel/src/crypto/hkdf/hkdf.c \
     third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c \
     third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c \
@@ -831,6 +868,7 @@
     third_party/boringssl-with-bazel/src/crypto/rand_extra/deterministic.c \
     third_party/boringssl-with-bazel/src/crypto/rand_extra/forkunsafe.c \
     third_party/boringssl-with-bazel/src/crypto/rand_extra/fuchsia.c \
+    third_party/boringssl-with-bazel/src/crypto/rand_extra/passive.c \
     third_party/boringssl-with-bazel/src/crypto/rand_extra/rand_extra.c \
     third_party/boringssl-with-bazel/src/crypto/rand_extra/windows.c \
     third_party/boringssl-with-bazel/src/crypto/rc4/rc4.c \
@@ -869,7 +907,6 @@
     third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c \
-    third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c \
     third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c \
@@ -934,6 +971,7 @@
     third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc \
     third_party/boringssl-with-bazel/src/ssl/dtls_method.cc \
     third_party/boringssl-with-bazel/src/ssl/dtls_record.cc \
+    third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc \
     third_party/boringssl-with-bazel/src/ssl/handoff.cc \
     third_party/boringssl-with-bazel/src/ssl/handshake.cc \
     third_party/boringssl-with-bazel/src/ssl/handshake_client.cc \
@@ -990,8 +1028,6 @@
     third_party/upb/upb/decode_fast.c \
     third_party/upb/upb/def.c \
     third_party/upb/upb/encode.c \
-    third_party/upb/upb/json_decode.c \
-    third_party/upb/upb/json_encode.c \
     third_party/upb/upb/msg.c \
     third_party/upb/upb/reflection.c \
     third_party/upb/upb/table.c \
@@ -1009,6 +1045,7 @@
   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)
@@ -1016,10 +1053,12 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/c_ares)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/native)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/fake)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/google_c2p)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/sockaddr)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/xds)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_idle)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/deadline)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/fault_injection)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http/client)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http/message_compress)
@@ -1036,15 +1075,23 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/inproc)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/admin/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/annotations)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/accesslog/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/bootstrap/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/cluster/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/core/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/endpoint/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/listener/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/metrics/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/overload/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/rbac/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/route/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/config/trace/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/service/cluster/v3)
@@ -1053,6 +1100,7 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/service/listener/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/service/load_stats/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/service/route/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/service/status/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/type/matcher/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/type/metadata/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/envoy/type/tracing/v3)
@@ -1065,17 +1113,26 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/src/proto/grpc/health/v1)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/src/proto/grpc/lb/v1)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/udpa/annotations)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/udpa/core/v1)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/udpa/data/orca/v1)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/udpa/type/v1)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/validate)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/xds/core/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/admin/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/annotations)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/accesslog/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/cluster/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/core/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/endpoint/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/listener/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/metrics/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/overload/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/route/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/config/trace/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/service/cluster/v3)
@@ -1084,6 +1141,7 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/service/listener/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/service/load_stats/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/service/route/v3)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/service/status/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/type/matcher/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/type/metadata/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/type/tracing/v3)
@@ -1092,23 +1150,25 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/google/protobuf)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/google/rpc)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/udpa/annotations)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/udpa/core/v1)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/udpa/type/v1)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/validate)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/xds/core/v3)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/xds)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/address_utils)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/avl)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/backoff)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/event_engine)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gpr)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gprpp)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/http)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr/executor)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr/poller)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/json)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/matchers)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/profiling)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/authorization)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/context)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/alts)
@@ -1168,6 +1228,7 @@
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/asn1)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/base64)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/bio)
+  PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/blake2)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/bn_extra)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/buf)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/bytestring)
@@ -1176,7 +1237,7 @@
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/cmac)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/conf)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/curve25519)
-  PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/dh)
+  PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/dh_extra)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/digest_extra)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/dsa)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/ec_extra)
diff --git a/grpc/config.w32 b/grpc/config.w32
index b7bf079..1e65f5b 100644
--- a/grpc/config.w32
+++ b/grpc/config.w32
@@ -31,6 +31,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 " +
@@ -52,10 +53,13 @@
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\dns_resolver_selection.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native\\dns_resolver.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " +
+    "src\\core\\ext\\filters\\client_channel\\resolver\\google_c2p\\google_c2p_resolver.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\xds\\xds_resolver.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver_result_parsing.cc " +
+    "src\\core\\ext\\filters\\client_channel\\retry_filter.cc " +
+    "src\\core\\ext\\filters\\client_channel\\retry_service_config.cc " +
     "src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " +
     "src\\core\\ext\\filters\\client_channel\\server_address.cc " +
     "src\\core\\ext\\filters\\client_channel\\service_config.cc " +
@@ -65,6 +69,8 @@
     "src\\core\\ext\\filters\\client_channel\\subchannel_pool_interface.cc " +
     "src\\core\\ext\\filters\\client_idle\\client_idle_filter.cc " +
     "src\\core\\ext\\filters\\deadline\\deadline_filter.cc " +
+    "src\\core\\ext\\filters\\fault_injection\\fault_injection_filter.cc " +
+    "src\\core\\ext\\filters\\fault_injection\\service_config_parser.cc " +
     "src\\core\\ext\\filters\\http\\client\\http_client_filter.cc " +
     "src\\core\\ext\\filters\\http\\client_authority_filter.cc " +
     "src\\core\\ext\\filters\\http\\http_filters_plugin.cc " +
@@ -110,9 +116,11 @@
     "src\\core\\ext\\transport\\chttp2\\transport\\writing.cc " +
     "src\\core\\ext\\transport\\inproc\\inproc_plugin.cc " +
     "src\\core\\ext\\transport\\inproc\\inproc_transport.cc " +
+    "src\\core\\ext\\upb-generated\\envoy\\admin\\v3\\config_dump.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\annotations\\deprecation.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\annotations\\resource.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\accesslog\\v3\\accesslog.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\config\\bootstrap\\v3\\bootstrap.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\cluster\\v3\\circuit_breaker.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\cluster\\v3\\cluster.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\cluster\\v3\\filter.upb.c " +
@@ -137,11 +145,17 @@
     "src\\core\\ext\\upb-generated\\envoy\\config\\listener\\v3\\listener.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\listener\\v3\\listener_components.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\listener\\v3\\udp_listener_config.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\config\\metrics\\v3\\stats.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\config\\overload\\v3\\overload.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\rbac\\v3\\rbac.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\route\\v3\\route.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\route\\v3\\route_components.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\route\\v3\\scoped_route.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\config\\trace\\v3\\http_tracer.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\extensions\\clusters\\aggregate\\v3\\cluster.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\common\\fault\\v3\\fault.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\http\\fault\\v3\\fault.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\http\\router\\v3\\router.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\network\\http_connection_manager\\v3\\http_connection_manager.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\extensions\\transport_sockets\\tls\\v3\\cert.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\extensions\\transport_sockets\\tls\\v3\\common.upb.c " +
@@ -155,11 +169,14 @@
     "src\\core\\ext\\upb-generated\\envoy\\service\\load_stats\\v3\\lrs.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\service\\route\\v3\\rds.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\service\\route\\v3\\srds.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\service\\status\\v3\\csds.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3\\metadata.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3\\node.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3\\number.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3\\path.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3\\regex.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3\\string.upb.c " +
+    "src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3\\struct.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3\\value.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\type\\metadata\\v3\\metadata.upb.c " +
     "src\\core\\ext\\upb-generated\\envoy\\type\\tracing\\v3\\custom_tag.upb.c " +
@@ -189,17 +206,20 @@
     "src\\core\\ext\\upb-generated\\udpa\\annotations\\sensitive.upb.c " +
     "src\\core\\ext\\upb-generated\\udpa\\annotations\\status.upb.c " +
     "src\\core\\ext\\upb-generated\\udpa\\annotations\\versioning.upb.c " +
-    "src\\core\\ext\\upb-generated\\udpa\\core\\v1\\authority.upb.c " +
-    "src\\core\\ext\\upb-generated\\udpa\\core\\v1\\collection_entry.upb.c " +
-    "src\\core\\ext\\upb-generated\\udpa\\core\\v1\\context_params.upb.c " +
-    "src\\core\\ext\\upb-generated\\udpa\\core\\v1\\resource.upb.c " +
-    "src\\core\\ext\\upb-generated\\udpa\\core\\v1\\resource_locator.upb.c " +
-    "src\\core\\ext\\upb-generated\\udpa\\core\\v1\\resource_name.upb.c " +
     "src\\core\\ext\\upb-generated\\udpa\\data\\orca\\v1\\orca_load_report.upb.c " +
+    "src\\core\\ext\\upb-generated\\udpa\\type\\v1\\typed_struct.upb.c " +
     "src\\core\\ext\\upb-generated\\validate\\validate.upb.c " +
+    "src\\core\\ext\\upb-generated\\xds\\core\\v3\\authority.upb.c " +
+    "src\\core\\ext\\upb-generated\\xds\\core\\v3\\collection_entry.upb.c " +
+    "src\\core\\ext\\upb-generated\\xds\\core\\v3\\context_params.upb.c " +
+    "src\\core\\ext\\upb-generated\\xds\\core\\v3\\resource.upb.c " +
+    "src\\core\\ext\\upb-generated\\xds\\core\\v3\\resource_locator.upb.c " +
+    "src\\core\\ext\\upb-generated\\xds\\core\\v3\\resource_name.upb.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\admin\\v3\\config_dump.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\annotations\\deprecation.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\annotations\\resource.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\accesslog\\v3\\accesslog.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\config\\bootstrap\\v3\\bootstrap.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\cluster\\v3\\circuit_breaker.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\cluster\\v3\\cluster.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\cluster\\v3\\filter.upbdefs.c " +
@@ -224,10 +244,16 @@
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\listener\\v3\\listener.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\listener\\v3\\listener_components.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\listener\\v3\\udp_listener_config.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\config\\metrics\\v3\\stats.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\config\\overload\\v3\\overload.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\route\\v3\\route.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\route\\v3\\route_components.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\route\\v3\\scoped_route.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\config\\trace\\v3\\http_tracer.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\clusters\\aggregate\\v3\\cluster.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\common\\fault\\v3\\fault.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\http\\fault\\v3\\fault.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\http\\router\\v3\\router.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\network\\http_connection_manager\\v3\\http_connection_manager.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\transport_sockets\\tls\\v3\\cert.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\transport_sockets\\tls\\v3\\common.upbdefs.c " +
@@ -241,11 +267,14 @@
     "src\\core\\ext\\upbdefs-generated\\envoy\\service\\load_stats\\v3\\lrs.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\service\\route\\v3\\rds.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\service\\route\\v3\\srds.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\service\\status\\v3\\csds.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3\\metadata.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3\\node.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3\\number.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3\\path.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3\\regex.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3\\string.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3\\struct.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3\\value.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\type\\metadata\\v3\\metadata.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\envoy\\type\\tracing\\v3\\custom_tag.upbdefs.c " +
@@ -268,13 +297,14 @@
     "src\\core\\ext\\upbdefs-generated\\udpa\\annotations\\sensitive.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\udpa\\annotations\\status.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\udpa\\annotations\\versioning.upbdefs.c " +
-    "src\\core\\ext\\upbdefs-generated\\udpa\\core\\v1\\authority.upbdefs.c " +
-    "src\\core\\ext\\upbdefs-generated\\udpa\\core\\v1\\collection_entry.upbdefs.c " +
-    "src\\core\\ext\\upbdefs-generated\\udpa\\core\\v1\\context_params.upbdefs.c " +
-    "src\\core\\ext\\upbdefs-generated\\udpa\\core\\v1\\resource.upbdefs.c " +
-    "src\\core\\ext\\upbdefs-generated\\udpa\\core\\v1\\resource_locator.upbdefs.c " +
-    "src\\core\\ext\\upbdefs-generated\\udpa\\core\\v1\\resource_name.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\udpa\\type\\v1\\typed_struct.upbdefs.c " +
     "src\\core\\ext\\upbdefs-generated\\validate\\validate.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\xds\\core\\v3\\authority.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\xds\\core\\v3\\collection_entry.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\xds\\core\\v3\\context_params.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\xds\\core\\v3\\resource.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\xds\\core\\v3\\resource_locator.upbdefs.c " +
+    "src\\core\\ext\\upbdefs-generated\\xds\\core\\v3\\resource_name.upbdefs.c " +
     "src\\core\\ext\\xds\\certificate_provider_registry.cc " +
     "src\\core\\ext\\xds\\certificate_provider_store.cc " +
     "src\\core\\ext\\xds\\file_watcher_certificate_provider_factory.cc " +
@@ -283,7 +313,11 @@
     "src\\core\\ext\\xds\\xds_certificate_provider.cc " +
     "src\\core\\ext\\xds\\xds_client.cc " +
     "src\\core\\ext\\xds\\xds_client_stats.cc " +
+    "src\\core\\ext\\xds\\xds_http_fault_filter.cc " +
+    "src\\core\\ext\\xds\\xds_http_filters.cc " +
     "src\\core\\ext\\xds\\xds_server_config_fetcher.cc " +
+    "src\\core\\lib\\address_utils\\parse_address.cc " +
+    "src\\core\\lib\\address_utils\\sockaddr_utils.cc " +
     "src\\core\\lib\\avl\\avl.cc " +
     "src\\core\\lib\\backoff\\backoff.cc " +
     "src\\core\\lib\\channel\\channel_args.cc " +
@@ -306,6 +340,8 @@
     "src\\core\\lib\\debug\\stats.cc " +
     "src\\core\\lib\\debug\\stats_data.cc " +
     "src\\core\\lib\\debug\\trace.cc " +
+    "src\\core\\lib\\event_engine\\slice_allocator.cc " +
+    "src\\core\\lib\\event_engine\\sockaddr.cc " +
     "src\\core\\lib\\gpr\\alloc.cc " +
     "src\\core\\lib\\gpr\\atm.cc " +
     "src\\core\\lib\\gpr\\cpu_iphone.cc " +
@@ -346,8 +382,10 @@
     "src\\core\\lib\\gprpp\\mpscq.cc " +
     "src\\core\\lib\\gprpp\\stat_posix.cc " +
     "src\\core\\lib\\gprpp\\stat_windows.cc " +
+    "src\\core\\lib\\gprpp\\status_helper.cc " +
     "src\\core\\lib\\gprpp\\thd_posix.cc " +
     "src\\core\\lib\\gprpp\\thd_windows.cc " +
+    "src\\core\\lib\\gprpp\\time_util.cc " +
     "src\\core\\lib\\http\\format_request.cc " +
     "src\\core\\lib\\http\\httpcli.cc " +
     "src\\core\\lib\\http\\httpcli_security_connector.cc " +
@@ -393,8 +431,6 @@
     "src\\core\\lib\\iomgr\\is_epollexclusive_available.cc " +
     "src\\core\\lib\\iomgr\\load_file.cc " +
     "src\\core\\lib\\iomgr\\lockfree_event.cc " +
-    "src\\core\\lib\\iomgr\\parse_address.cc " +
-    "src\\core\\lib\\iomgr\\poller\\eventmanager_libuv.cc " +
     "src\\core\\lib\\iomgr\\polling_entity.cc " +
     "src\\core\\lib\\iomgr\\pollset.cc " +
     "src\\core\\lib\\iomgr\\pollset_custom.cc " +
@@ -408,7 +444,6 @@
     "src\\core\\lib\\iomgr\\resolve_address_posix.cc " +
     "src\\core\\lib\\iomgr\\resolve_address_windows.cc " +
     "src\\core\\lib\\iomgr\\resource_quota.cc " +
-    "src\\core\\lib\\iomgr\\sockaddr_utils.cc " +
     "src\\core\\lib\\iomgr\\socket_factory_posix.cc " +
     "src\\core\\lib\\iomgr\\socket_mutator.cc " +
     "src\\core\\lib\\iomgr\\socket_utils_common_posix.cc " +
@@ -451,10 +486,9 @@
     "src\\core\\lib\\json\\json_reader.cc " +
     "src\\core\\lib\\json\\json_util.cc " +
     "src\\core\\lib\\json\\json_writer.cc " +
+    "src\\core\\lib\\matchers\\matchers.cc " +
     "src\\core\\lib\\profiling\\basic_timers.cc " +
     "src\\core\\lib\\profiling\\stap_timers.cc " +
-    "src\\core\\lib\\security\\authorization\\authorization_engine.cc " +
-    "src\\core\\lib\\security\\authorization\\evaluate_args.cc " +
     "src\\core\\lib\\security\\context\\security_context.cc " +
     "src\\core\\lib\\security\\credentials\\alts\\alts_credentials.cc " +
     "src\\core\\lib\\security\\credentials\\alts\\check_gcp_environment.cc " +
@@ -608,6 +642,7 @@
     "third_party\\abseil-cpp\\absl\\debugging\\symbolize.cc " +
     "third_party\\abseil-cpp\\absl\\hash\\internal\\city.cc " +
     "third_party\\abseil-cpp\\absl\\hash\\internal\\hash.cc " +
+    "third_party\\abseil-cpp\\absl\\hash\\internal\\wyhash.cc " +
     "third_party\\abseil-cpp\\absl\\numeric\\int128.cc " +
     "third_party\\abseil-cpp\\absl\\status\\status.cc " +
     "third_party\\abseil-cpp\\absl\\status\\status_payload_printer.cc " +
@@ -618,6 +653,8 @@
     "third_party\\abseil-cpp\\absl\\strings\\escaping.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\charconv_bigint.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\charconv_parse.cc " +
+    "third_party\\abseil-cpp\\absl\\strings\\internal\\cord_internal.cc " +
+    "third_party\\abseil-cpp\\absl\\strings\\internal\\cord_rep_ring.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\escaping.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\memutil.cc " +
     "third_party\\abseil-cpp\\absl\\strings\\internal\\ostringstream.cc " +
@@ -705,6 +742,7 @@
     "third_party\\boringssl-with-bazel\\src\\crypto\\bio\\printf.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\bio\\socket.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\bio\\socket_helper.c " +
+    "third_party\\boringssl-with-bazel\\src\\crypto\\blake2\\blake2.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\bn_extra\\bn_asn1.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\bn_extra\\convert.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\buf\\buf.c " +
@@ -729,6 +767,7 @@
     "third_party\\boringssl-with-bazel\\src\\crypto\\conf\\conf.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\cpu-aarch64-fuchsia.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\cpu-aarch64-linux.c " +
+    "third_party\\boringssl-with-bazel\\src\\crypto\\cpu-aarch64-win.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\cpu-arm-linux.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\cpu-arm.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\cpu-intel.c " +
@@ -736,10 +775,8 @@
     "third_party\\boringssl-with-bazel\\src\\crypto\\crypto.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\curve25519\\curve25519.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\curve25519\\spake25519.c " +
-    "third_party\\boringssl-with-bazel\\src\\crypto\\dh\\check.c " +
-    "third_party\\boringssl-with-bazel\\src\\crypto\\dh\\dh.c " +
-    "third_party\\boringssl-with-bazel\\src\\crypto\\dh\\dh_asn1.c " +
-    "third_party\\boringssl-with-bazel\\src\\crypto\\dh\\params.c " +
+    "third_party\\boringssl-with-bazel\\src\\crypto\\dh_extra\\dh_asn1.c " +
+    "third_party\\boringssl-with-bazel\\src\\crypto\\dh_extra\\params.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\digest_extra\\digest_extra.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\dsa\\dsa.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\dsa\\dsa_asn1.c " +
@@ -770,7 +807,6 @@
     "third_party\\boringssl-with-bazel\\src\\crypto\\ex_data.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\fipsmodule\\bcm.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\fipsmodule\\fips_shared_support.c " +
-    "third_party\\boringssl-with-bazel\\src\\crypto\\fipsmodule\\is_fips.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\hkdf\\hkdf.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\hpke\\hpke.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\hrss\\hrss.c " +
@@ -798,6 +834,7 @@
     "third_party\\boringssl-with-bazel\\src\\crypto\\rand_extra\\deterministic.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\rand_extra\\forkunsafe.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\rand_extra\\fuchsia.c " +
+    "third_party\\boringssl-with-bazel\\src\\crypto\\rand_extra\\passive.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\rand_extra\\rand_extra.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\rand_extra\\windows.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\rc4\\rc4.c " +
@@ -836,7 +873,6 @@
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_ext.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_lu.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_obj.c " +
-    "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_r2x.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_req.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_set.c " +
     "third_party\\boringssl-with-bazel\\src\\crypto\\x509\\x509_trs.c " +
@@ -901,6 +937,7 @@
     "third_party\\boringssl-with-bazel\\src\\ssl\\d1_srtp.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\dtls_method.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\dtls_record.cc " +
+    "third_party\\boringssl-with-bazel\\src\\ssl\\encrypted_client_hello.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\handoff.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\handshake.cc " +
     "third_party\\boringssl-with-bazel\\src\\ssl\\handshake_client.cc " +
@@ -957,8 +994,6 @@
     "third_party\\upb\\upb\\decode_fast.c " +
     "third_party\\upb\\upb\\def.c " +
     "third_party\\upb\\upb\\encode.c " +
-    "third_party\\upb\\upb\\json_decode.c " +
-    "third_party\\upb\\upb\\json_encode.c " +
     "third_party\\upb\\upb\\msg.c " +
     "third_party\\upb\\upb\\reflection.c " +
     "third_party\\upb\\upb\\table.c " +
@@ -993,6 +1028,7 @@
     "/I"+configure_module_dirname+"\\third_party\\boringssl-with-bazel\\src\\include "+
     "/I"+configure_module_dirname+"\\third_party\\re2 "+
     "/I"+configure_module_dirname+"\\third_party\\upb "+
+    "/I"+configure_module_dirname+"\\third_party\\xxhash "+
     "/I"+configure_module_dirname+"\\third_party\\zlib ");
 
   base_dir = get_define('BUILD_DIR');
@@ -1009,6 +1045,7 @@
   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");
@@ -1017,10 +1054,12 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\fake");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\google_c2p");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\xds");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_idle");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\deadline");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\fault_injection");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\http");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\http\\client");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\http\\message_compress");
@@ -1041,10 +1080,14 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\inproc");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\admin");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\admin\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\annotations");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\accesslog");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\accesslog\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\bootstrap");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\bootstrap\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\cluster");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\cluster\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\core");
@@ -1053,6 +1096,10 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\endpoint\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\listener");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\listener\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\metrics");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\metrics\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\overload");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\overload\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\rbac");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\rbac\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\route");
@@ -1060,7 +1107,18 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\trace");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\config\\trace\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\clusters");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\clusters\\aggregate");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\clusters\\aggregate\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\common");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\common\\fault");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\common\\fault\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\http");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\http\\fault");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\http\\fault\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\http\\router");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\http\\router\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\network");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\network\\http_connection_manager");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\extensions\\filters\\network\\http_connection_manager\\v3");
@@ -1080,6 +1138,8 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\service\\load_stats\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\service\\route");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\service\\route\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\service\\status");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\service\\status\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\type");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\type\\matcher");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\envoy\\type\\matcher\\v3");
@@ -1104,18 +1164,25 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\src\\proto\\grpc\\lb\\v1");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa\\annotations");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa\\core");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa\\core\\v1");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa\\data");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa\\data\\orca");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa\\data\\orca\\v1");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa\\type");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\udpa\\type\\v1");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\validate");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\core");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\core\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\admin");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\admin\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\annotations");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\accesslog");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\accesslog\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\bootstrap");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\bootstrap\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\cluster");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\cluster\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\core");
@@ -1124,12 +1191,27 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\endpoint\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\listener");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\listener\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\metrics");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\metrics\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\overload");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\overload\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\route");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\route\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\trace");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\config\\trace\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\clusters");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\clusters\\aggregate");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\clusters\\aggregate\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\common");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\common\\fault");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\common\\fault\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\http");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\http\\fault");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\http\\fault\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\http\\router");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\http\\router\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\network");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\network\\http_connection_manager");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\extensions\\filters\\network\\http_connection_manager\\v3");
@@ -1149,6 +1231,8 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\service\\load_stats\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\service\\route");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\service\\route\\v3");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\service\\status");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\service\\status\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\type");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\envoy\\type\\matcher\\v3");
@@ -1163,26 +1247,30 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\google\\rpc");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\udpa");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\udpa\\annotations");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\udpa\\core");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\udpa\\core\\v1");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\udpa\\type");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\udpa\\type\\v1");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\validate");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\xds");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\xds\\core");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upbdefs-generated\\xds\\core\\v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\xds");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\address_utils");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\avl");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\backoff");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\channel");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\compression");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\debug");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\event_engine");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gpr");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gprpp");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\http");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr\\executor");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr\\poller");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\json");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\matchers");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\profiling");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\authorization");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\context");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\alts");
@@ -1254,6 +1342,7 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\asn1");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\base64");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\bio");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\blake2");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\bn_extra");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\buf");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\bytestring");
@@ -1262,7 +1351,7 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\cmac");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\conf");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\curve25519");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\dh");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\dh_extra");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\digest_extra");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\dsa");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\ec_extra");
diff --git a/grpc/gRPC-C++.podspec b/grpc/gRPC-C++.podspec
index 27702df..ce3ec33 100644
--- a/grpc/gRPC-C++.podspec
+++ b/grpc/gRPC-C++.podspec
@@ -22,7 +22,7 @@
 Pod::Spec.new do |s|
   s.name     = 'gRPC-C++'
   # TODO (mxyan): use version that match gRPC version when pod is stabilized
-  version = '1.35.0'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'gRPC C++ library'
   s.homepage = 'https://grpc.io'
@@ -118,6 +118,7 @@
                       'include/grpcpp/impl/codegen/message_allocator.h',
                       'include/grpcpp/impl/codegen/metadata_map.h',
                       'include/grpcpp/impl/codegen/method_handler.h',
+                      'include/grpcpp/impl/codegen/method_handler_impl.h',
                       'include/grpcpp/impl/codegen/rpc_method.h',
                       'include/grpcpp/impl/codegen/rpc_service_method.h',
                       'include/grpcpp/impl/codegen/security/auth_context.h',
@@ -185,10 +186,9 @@
     ss.header_mappings_dir = '.'
     ss.dependency "#{s.name}/Interface", version
     ss.dependency 'gRPC-Core', version
-    abseil_version = '1.20200923.2'
+    abseil_version = '1.20210324.0'
     ss.dependency 'abseil/base/base', abseil_version
     ss.dependency 'abseil/container/flat_hash_map', abseil_version
-    ss.dependency 'abseil/container/flat_hash_set', abseil_version
     ss.dependency 'abseil/container/inlined_vector', abseil_version
     ss.dependency 'abseil/functional/bind_front', abseil_version
     ss.dependency 'abseil/memory/memory', abseil_version
@@ -221,6 +221,7 @@
                       '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',
@@ -238,6 +239,8 @@
                       'src/core/ext/filters/client_channel/resolver_factory.h',
                       'src/core/ext/filters/client_channel/resolver_registry.h',
                       'src/core/ext/filters/client_channel/resolver_result_parsing.h',
+                      'src/core/ext/filters/client_channel/retry_filter.h',
+                      'src/core/ext/filters/client_channel/retry_service_config.h',
                       'src/core/ext/filters/client_channel/retry_throttle.h',
                       'src/core/ext/filters/client_channel/server_address.h',
                       'src/core/ext/filters/client_channel/service_config.h',
@@ -247,6 +250,8 @@
                       'src/core/ext/filters/client_channel/subchannel_interface.h',
                       'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
                       'src/core/ext/filters/deadline/deadline_filter.h',
+                      'src/core/ext/filters/fault_injection/fault_injection_filter.h',
+                      'src/core/ext/filters/fault_injection/service_config_parser.h',
                       'src/core/ext/filters/http/client/http_client_filter.h',
                       'src/core/ext/filters/http/client_authority_filter.h',
                       'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@@ -282,9 +287,11 @@
                       'src/core/ext/transport/chttp2/transport/stream_map.h',
                       'src/core/ext/transport/chttp2/transport/varint.h',
                       'src/core/ext/transport/inproc/inproc_transport.h',
+                      'src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h',
                       'src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h',
                       'src/core/ext/upb-generated/envoy/annotations/resource.upb.h',
                       'src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h',
+                      'src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h',
                       'src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h',
                       'src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h',
                       'src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.h',
@@ -309,11 +316,17 @@
                       'src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h',
                       'src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h',
                       'src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h',
+                      'src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h',
+                      'src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h',
                       'src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h',
                       'src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h',
                       'src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h',
                       'src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h',
                       'src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h',
+                      'src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h',
                       'src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h',
                       'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.h',
                       'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h',
@@ -327,11 +340,14 @@
                       'src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.h',
                       'src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h',
                       'src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h',
+                      'src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h',
+                      'src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h',
+                      'src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h',
                       'src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.h',
                       'src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.h',
@@ -361,17 +377,20 @@
                       'src/core/ext/upb-generated/udpa/annotations/sensitive.upb.h',
                       'src/core/ext/upb-generated/udpa/annotations/status.upb.h',
                       'src/core/ext/upb-generated/udpa/annotations/versioning.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/authority.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h',
                       'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h',
+                      'src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h',
                       'src/core/ext/upb-generated/validate/validate.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/authority.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/context_params.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/resource.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h',
+                      'src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.h',
@@ -396,10 +415,16 @@
                       'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.h',
@@ -413,11 +438,14 @@
                       'src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.h',
@@ -440,13 +468,14 @@
                       'src/core/ext/upbdefs-generated/udpa/annotations/sensitive.upbdefs.h',
                       'src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h',
                       'src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h',
                       'src/core/ext/upbdefs-generated/validate/validate.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h',
                       'src/core/ext/xds/certificate_provider_factory.h',
                       'src/core/ext/xds/certificate_provider_registry.h',
                       'src/core/ext/xds/certificate_provider_store.h',
@@ -457,6 +486,10 @@
                       'src/core/ext/xds/xds_channel_args.h',
                       'src/core/ext/xds/xds_client.h',
                       'src/core/ext/xds/xds_client_stats.h',
+                      'src/core/ext/xds/xds_http_fault_filter.h',
+                      'src/core/ext/xds/xds_http_filters.h',
+                      'src/core/lib/address_utils/parse_address.h',
+                      'src/core/lib/address_utils/sockaddr_utils.h',
                       'src/core/lib/avl/avl.h',
                       'src/core/lib/backoff/backoff.h',
                       'src/core/lib/channel/channel_args.h',
@@ -514,8 +547,10 @@
                       'src/core/lib/gprpp/ref_counted.h',
                       'src/core/lib/gprpp/ref_counted_ptr.h',
                       'src/core/lib/gprpp/stat.h',
+                      'src/core/lib/gprpp/status_helper.h',
                       'src/core/lib/gprpp/sync.h',
                       'src/core/lib/gprpp/thd.h',
+                      'src/core/lib/gprpp/time_util.h',
                       'src/core/lib/http/format_request.h',
                       'src/core/lib/http/httpcli.h',
                       'src/core/lib/http/parser.h',
@@ -548,13 +583,10 @@
                       'src/core/lib/iomgr/iomgr.h',
                       'src/core/lib/iomgr/iomgr_custom.h',
                       'src/core/lib/iomgr/iomgr_internal.h',
-                      'src/core/lib/iomgr/iomgr_posix.h',
                       'src/core/lib/iomgr/is_epollexclusive_available.h',
                       'src/core/lib/iomgr/load_file.h',
                       'src/core/lib/iomgr/lockfree_event.h',
                       'src/core/lib/iomgr/nameser.h',
-                      'src/core/lib/iomgr/parse_address.h',
-                      'src/core/lib/iomgr/poller/eventmanager_libuv.h',
                       'src/core/lib/iomgr/polling_entity.h',
                       'src/core/lib/iomgr/pollset.h',
                       'src/core/lib/iomgr/pollset_custom.h',
@@ -571,7 +603,6 @@
                       'src/core/lib/iomgr/sockaddr.h',
                       'src/core/lib/iomgr/sockaddr_custom.h',
                       'src/core/lib/iomgr/sockaddr_posix.h',
-                      'src/core/lib/iomgr/sockaddr_utils.h',
                       'src/core/lib/iomgr/sockaddr_windows.h',
                       'src/core/lib/iomgr/socket_factory_posix.h',
                       'src/core/lib/iomgr/socket_mutator.h',
@@ -599,15 +630,8 @@
                       'src/core/lib/iomgr/work_serializer.h',
                       'src/core/lib/json/json.h',
                       'src/core/lib/json/json_util.h',
+                      'src/core/lib/matchers/matchers.h',
                       'src/core/lib/profiling/timers.h',
-                      'src/core/lib/security/authorization/authorization_engine.h',
-                      'src/core/lib/security/authorization/evaluate_args.h',
-                      'src/core/lib/security/authorization/mock_cel/activation.h',
-                      'src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h',
-                      'src/core/lib/security/authorization/mock_cel/cel_expression.h',
-                      'src/core/lib/security/authorization/mock_cel/cel_value.h',
-                      'src/core/lib/security/authorization/mock_cel/evaluator_core.h',
-                      'src/core/lib/security/authorization/mock_cel/flat_expr_builder.h',
                       'src/core/lib/security/context/security_context.h',
                       'src/core/lib/security/credentials/alts/alts_credentials.h',
                       'src/core/lib/security/credentials/alts/check_gcp_environment.h',
@@ -806,8 +830,6 @@
                       'third_party/upb/upb/def.h',
                       'third_party/upb/upb/def.hpp',
                       'third_party/upb/upb/encode.h',
-                      'third_party/upb/upb/json_decode.h',
-                      'third_party/upb/upb/json_encode.h',
                       'third_party/upb/upb/msg.h',
                       'third_party/upb/upb/port_def.inc',
                       'third_party/upb/upb/port_undef.inc',
@@ -816,7 +838,8 @@
                       'third_party/upb/upb/text_encode.h',
                       'third_party/upb/upb/upb.h',
                       'third_party/upb/upb/upb.hpp',
-                      'third_party/upb/upb/upb.int.h'
+                      'third_party/upb/upb/upb.int.h',
+                      'third_party/xxhash/xxhash.h'
 
     ss.private_header_files = 'src/core/ext/filters/client_channel/backend_metric.h',
                               'src/core/ext/filters/client_channel/backup_poller.h',
@@ -839,6 +862,7 @@
                               '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',
@@ -856,6 +880,8 @@
                               'src/core/ext/filters/client_channel/resolver_factory.h',
                               'src/core/ext/filters/client_channel/resolver_registry.h',
                               'src/core/ext/filters/client_channel/resolver_result_parsing.h',
+                              'src/core/ext/filters/client_channel/retry_filter.h',
+                              'src/core/ext/filters/client_channel/retry_service_config.h',
                               'src/core/ext/filters/client_channel/retry_throttle.h',
                               'src/core/ext/filters/client_channel/server_address.h',
                               'src/core/ext/filters/client_channel/service_config.h',
@@ -865,6 +891,8 @@
                               'src/core/ext/filters/client_channel/subchannel_interface.h',
                               'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
                               'src/core/ext/filters/deadline/deadline_filter.h',
+                              'src/core/ext/filters/fault_injection/fault_injection_filter.h',
+                              'src/core/ext/filters/fault_injection/service_config_parser.h',
                               'src/core/ext/filters/http/client/http_client_filter.h',
                               'src/core/ext/filters/http/client_authority_filter.h',
                               'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@@ -900,9 +928,11 @@
                               'src/core/ext/transport/chttp2/transport/stream_map.h',
                               'src/core/ext/transport/chttp2/transport/varint.h',
                               'src/core/ext/transport/inproc/inproc_transport.h',
+                              'src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h',
                               'src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h',
                               'src/core/ext/upb-generated/envoy/annotations/resource.upb.h',
                               'src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h',
+                              'src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h',
                               'src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h',
                               'src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h',
                               'src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.h',
@@ -927,11 +957,17 @@
                               'src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h',
                               'src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h',
                               'src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h',
+                              'src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h',
+                              'src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h',
                               'src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h',
                               'src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h',
                               'src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h',
                               'src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h',
                               'src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h',
+                              'src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h',
+                              'src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h',
+                              'src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h',
+                              'src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h',
                               'src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h',
                               'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.h',
                               'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h',
@@ -945,11 +981,14 @@
                               'src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.h',
                               'src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h',
                               'src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h',
+                              'src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h',
+                              'src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h',
+                              'src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h',
                               'src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.h',
                               'src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.h',
@@ -979,17 +1018,20 @@
                               'src/core/ext/upb-generated/udpa/annotations/sensitive.upb.h',
                               'src/core/ext/upb-generated/udpa/annotations/status.upb.h',
                               'src/core/ext/upb-generated/udpa/annotations/versioning.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/authority.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/resource.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h',
                               'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h',
+                              'src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h',
                               'src/core/ext/upb-generated/validate/validate.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/authority.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/context_params.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/resource.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h',
+                              'src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.h',
@@ -1014,10 +1056,16 @@
                               'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.h',
@@ -1031,11 +1079,14 @@
                               'src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.h',
@@ -1058,13 +1109,14 @@
                               'src/core/ext/upbdefs-generated/udpa/annotations/sensitive.upbdefs.h',
                               'src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h',
                               'src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h',
                               'src/core/ext/upbdefs-generated/validate/validate.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h',
                               'src/core/ext/xds/certificate_provider_factory.h',
                               'src/core/ext/xds/certificate_provider_registry.h',
                               'src/core/ext/xds/certificate_provider_store.h',
@@ -1075,6 +1127,10 @@
                               'src/core/ext/xds/xds_channel_args.h',
                               'src/core/ext/xds/xds_client.h',
                               'src/core/ext/xds/xds_client_stats.h',
+                              'src/core/ext/xds/xds_http_fault_filter.h',
+                              'src/core/ext/xds/xds_http_filters.h',
+                              'src/core/lib/address_utils/parse_address.h',
+                              'src/core/lib/address_utils/sockaddr_utils.h',
                               'src/core/lib/avl/avl.h',
                               'src/core/lib/backoff/backoff.h',
                               'src/core/lib/channel/channel_args.h',
@@ -1132,8 +1188,10 @@
                               'src/core/lib/gprpp/ref_counted.h',
                               'src/core/lib/gprpp/ref_counted_ptr.h',
                               'src/core/lib/gprpp/stat.h',
+                              'src/core/lib/gprpp/status_helper.h',
                               'src/core/lib/gprpp/sync.h',
                               'src/core/lib/gprpp/thd.h',
+                              'src/core/lib/gprpp/time_util.h',
                               'src/core/lib/http/format_request.h',
                               'src/core/lib/http/httpcli.h',
                               'src/core/lib/http/parser.h',
@@ -1166,13 +1224,10 @@
                               'src/core/lib/iomgr/iomgr.h',
                               'src/core/lib/iomgr/iomgr_custom.h',
                               'src/core/lib/iomgr/iomgr_internal.h',
-                              'src/core/lib/iomgr/iomgr_posix.h',
                               'src/core/lib/iomgr/is_epollexclusive_available.h',
                               'src/core/lib/iomgr/load_file.h',
                               'src/core/lib/iomgr/lockfree_event.h',
                               'src/core/lib/iomgr/nameser.h',
-                              'src/core/lib/iomgr/parse_address.h',
-                              'src/core/lib/iomgr/poller/eventmanager_libuv.h',
                               'src/core/lib/iomgr/polling_entity.h',
                               'src/core/lib/iomgr/pollset.h',
                               'src/core/lib/iomgr/pollset_custom.h',
@@ -1189,7 +1244,6 @@
                               'src/core/lib/iomgr/sockaddr.h',
                               'src/core/lib/iomgr/sockaddr_custom.h',
                               'src/core/lib/iomgr/sockaddr_posix.h',
-                              'src/core/lib/iomgr/sockaddr_utils.h',
                               'src/core/lib/iomgr/sockaddr_windows.h',
                               'src/core/lib/iomgr/socket_factory_posix.h',
                               'src/core/lib/iomgr/socket_mutator.h',
@@ -1217,15 +1271,8 @@
                               'src/core/lib/iomgr/work_serializer.h',
                               'src/core/lib/json/json.h',
                               'src/core/lib/json/json_util.h',
+                              'src/core/lib/matchers/matchers.h',
                               'src/core/lib/profiling/timers.h',
-                              'src/core/lib/security/authorization/authorization_engine.h',
-                              'src/core/lib/security/authorization/evaluate_args.h',
-                              'src/core/lib/security/authorization/mock_cel/activation.h',
-                              'src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h',
-                              'src/core/lib/security/authorization/mock_cel/cel_expression.h',
-                              'src/core/lib/security/authorization/mock_cel/cel_value.h',
-                              'src/core/lib/security/authorization/mock_cel/evaluator_core.h',
-                              'src/core/lib/security/authorization/mock_cel/flat_expr_builder.h',
                               'src/core/lib/security/context/security_context.h',
                               'src/core/lib/security/credentials/alts/alts_credentials.h',
                               'src/core/lib/security/credentials/alts/check_gcp_environment.h',
@@ -1374,8 +1421,6 @@
                               'third_party/upb/upb/def.h',
                               'third_party/upb/upb/def.hpp',
                               'third_party/upb/upb/encode.h',
-                              'third_party/upb/upb/json_decode.h',
-                              'third_party/upb/upb/json_encode.h',
                               'third_party/upb/upb/msg.h',
                               'third_party/upb/upb/port_def.inc',
                               'third_party/upb/upb/port_undef.inc',
@@ -1384,7 +1429,8 @@
                               'third_party/upb/upb/text_encode.h',
                               'third_party/upb/upb/upb.h',
                               'third_party/upb/upb/upb.hpp',
-                              'third_party/upb/upb/upb.int.h'
+                              'third_party/upb/upb/upb.int.h',
+                              'third_party/xxhash/xxhash.h'
   end
 
   s.subspec 'Protobuf' do |ss|
@@ -1416,7 +1462,7 @@
   end
 
   s.prepare_command = <<-END_OF_COMMAND
-    sed -E -i '' 's;#include <openssl/(.*)>;#if COCOAPODS==1\\\n  #include <openssl_grpc/\\1>\\\n#else\\\n  #include <openssl/\\1>\\\n#endif;g' $(find src/core -type f \\( -path '*.h' -or -path '*.cc' \\) -print | xargs grep -H -c '#include <openssl_grpc/' | grep 0$ | cut -d':' -f1)
+    find src/core -type f \\( -path '*.h' -or -path '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/(.*)>;#if COCOAPODS==1\\\n  #include <openssl_grpc/\\1>\\\n#else\\\n  #include <openssl/\\1>\\\n#endif;g'
     find third_party/upb/ -type f \\( -name '*.h' -or -name '*.hpp' -or -name '*.c' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "third_party/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/upb/third_party/\\1"\\\n#else\\\n  #include  "third_party/\\1"\\\n#endif;g'
     find src/core/ src/cpp/ third_party/upb/ -type f \\( -name '*.h' -or -name '*.hpp' -or -name '*.c' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "upb/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/upb/upb/\\1"\\\n#else\\\n  #include  "upb/\\1"\\\n#endif;g'
     find src/core/ src/cpp/ third_party/upb/ -type f -name '*.grpc_back' -print0 | xargs -0 rm
@@ -1426,5 +1472,8 @@
     find third_party/re2/re2/ third_party/re2/util/ -type f \\( -name '*.h' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "re2/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/re2/re2/\\1"\\\n#else\\\n  #include  "re2/\\1"\\\n#endif;g;s;#include "util/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/re2/util/\\1"\\\n#else\\\n  #include  "util/\\1"\\\n#endif;g'
     find src/core/ -type f \\( -name '*.h' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "re2/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/re2/re2/\\1"\\\n#else\\\n  #include  "re2/\\1"\\\n#endif;g'
     find src/core/ third_party/re2/ -type f -name '*.grpc_back' -print0 | xargs -0 rm
+    find src/core/ -type f \\( -name '*.h' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "xxhash.h";#if COCOAPODS==1\\\n #include "third_party/xxhash/xxhash.h"\\\n#else\\\n #include "xxhash.h"\\\n#endif;g'
+    find third_party/xxhash  -type f -name xxhash.h -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;@param([^,]*),;@param\\1 ,;g'
+    find src/core/ third_party/xxhash/ -type f -name '*.grpc_back' -print0 | xargs -0 rm
   END_OF_COMMAND
 end
diff --git a/grpc/gRPC-Core.podspec b/grpc/gRPC-Core.podspec
index 5c48280..eb58ccc 100644
--- a/grpc/gRPC-Core.podspec
+++ b/grpc/gRPC-Core.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.35.0'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'https://grpc.io'
@@ -46,7 +46,7 @@
   s.requires_arc = false
 
   name = 'grpc'
-  abseil_version = '1.20200923.2'
+  abseil_version = '1.20210324.0'
 
   # When creating a dynamic framework, name it grpc.framework instead of gRPC-Core.framework.
   # This lets users write their includes like `#include <grpc/grpc.h>` as opposed to `#include
@@ -117,6 +117,7 @@
                       'include/grpc/byte_buffer_reader.h',
                       'include/grpc/census.h',
                       'include/grpc/compression.h',
+                      'include/grpc/event_engine/port.h',
                       'include/grpc/fork.h',
                       'include/grpc/grpc.h',
                       'include/grpc/grpc_posix.h',
@@ -173,10 +174,9 @@
     ss.header_mappings_dir = '.'
     ss.libraries = 'z'
     ss.dependency "#{s.name}/Interface", version
-    ss.dependency 'BoringSSL-GRPC', '0.0.14'
+    ss.dependency 'BoringSSL-GRPC', '0.0.18'
     ss.dependency 'abseil/base/base', abseil_version
     ss.dependency 'abseil/container/flat_hash_map', abseil_version
-    ss.dependency 'abseil/container/flat_hash_set', abseil_version
     ss.dependency 'abseil/container/inlined_vector', abseil_version
     ss.dependency 'abseil/functional/bind_front', abseil_version
     ss.dependency 'abseil/memory/memory', abseil_version
@@ -235,6 +235,8 @@
                       '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',
@@ -269,6 +271,7 @@
                       'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',
                       'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
                       'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
+                      'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc',
                       'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
                       'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
                       'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h',
@@ -277,6 +280,10 @@
                       'src/core/ext/filters/client_channel/resolver_registry.h',
                       'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
                       'src/core/ext/filters/client_channel/resolver_result_parsing.h',
+                      'src/core/ext/filters/client_channel/retry_filter.cc',
+                      'src/core/ext/filters/client_channel/retry_filter.h',
+                      'src/core/ext/filters/client_channel/retry_service_config.cc',
+                      'src/core/ext/filters/client_channel/retry_service_config.h',
                       'src/core/ext/filters/client_channel/retry_throttle.cc',
                       'src/core/ext/filters/client_channel/retry_throttle.h',
                       'src/core/ext/filters/client_channel/server_address.cc',
@@ -295,6 +302,10 @@
                       'src/core/ext/filters/client_idle/client_idle_filter.cc',
                       'src/core/ext/filters/deadline/deadline_filter.cc',
                       'src/core/ext/filters/deadline/deadline_filter.h',
+                      'src/core/ext/filters/fault_injection/fault_injection_filter.cc',
+                      'src/core/ext/filters/fault_injection/fault_injection_filter.h',
+                      'src/core/ext/filters/fault_injection/service_config_parser.cc',
+                      'src/core/ext/filters/fault_injection/service_config_parser.h',
                       'src/core/ext/filters/http/client/http_client_filter.cc',
                       'src/core/ext/filters/http/client/http_client_filter.h',
                       'src/core/ext/filters/http/client_authority_filter.cc',
@@ -375,12 +386,16 @@
                       'src/core/ext/transport/inproc/inproc_plugin.cc',
                       'src/core/ext/transport/inproc/inproc_transport.cc',
                       'src/core/ext/transport/inproc/inproc_transport.h',
+                      'src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c',
+                      'src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h',
                       'src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c',
                       'src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h',
                       'src/core/ext/upb-generated/envoy/annotations/resource.upb.c',
                       'src/core/ext/upb-generated/envoy/annotations/resource.upb.h',
                       'src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c',
                       'src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h',
+                      'src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c',
+                      'src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h',
                       'src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c',
                       'src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h',
                       'src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c',
@@ -429,6 +444,10 @@
                       'src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h',
                       'src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c',
                       'src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h',
+                      'src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c',
+                      'src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h',
+                      'src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c',
+                      'src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h',
                       'src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c',
                       'src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h',
                       'src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c',
@@ -439,6 +458,14 @@
                       'src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h',
                       'src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c',
                       'src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h',
+                      'src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c',
+                      'src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c',
+                      'src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h',
                       'src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c',
                       'src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h',
                       'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c',
@@ -465,8 +492,12 @@
                       'src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h',
                       'src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c',
                       'src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h',
+                      'src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c',
+                      'src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h',
+                      'src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c',
+                      'src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c',
@@ -475,6 +506,8 @@
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h',
+                      'src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c',
+                      'src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c',
                       'src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h',
                       'src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c',
@@ -533,28 +566,34 @@
                       'src/core/ext/upb-generated/udpa/annotations/status.upb.h',
                       'src/core/ext/upb-generated/udpa/annotations/versioning.upb.c',
                       'src/core/ext/upb-generated/udpa/annotations/versioning.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/authority.upb.c',
-                      'src/core/ext/upb-generated/udpa/core/v1/authority.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c',
-                      'src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c',
-                      'src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource.upb.c',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c',
-                      'src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h',
                       'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c',
                       'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h',
+                      'src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c',
+                      'src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h',
                       'src/core/ext/upb-generated/validate/validate.upb.c',
                       'src/core/ext/upb-generated/validate/validate.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/authority.upb.c',
+                      'src/core/ext/upb-generated/xds/core/v3/authority.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c',
+                      'src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/context_params.upb.c',
+                      'src/core/ext/upb-generated/xds/core/v3/context_params.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/resource.upb.c',
+                      'src/core/ext/upb-generated/xds/core/v3/resource.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c',
+                      'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h',
+                      'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c',
+                      'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h',
+                      'src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c',
@@ -603,6 +642,10 @@
                       'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c',
@@ -611,6 +654,14 @@
                       'src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c',
@@ -637,8 +688,12 @@
                       'src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c',
@@ -647,6 +702,8 @@
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c',
                       'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h',
                       'src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c',
@@ -691,20 +748,22 @@
                       'src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h',
                       'src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c',
                       'src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c',
-                      'src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h',
                       'src/core/ext/upbdefs-generated/validate/validate.upbdefs.c',
                       'src/core/ext/upbdefs-generated/validate/validate.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c',
+                      'src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h',
                       'src/core/ext/xds/certificate_provider_factory.h',
                       'src/core/ext/xds/certificate_provider_registry.cc',
                       'src/core/ext/xds/certificate_provider_registry.h',
@@ -723,7 +782,15 @@
                       'src/core/ext/xds/xds_client.h',
                       'src/core/ext/xds/xds_client_stats.cc',
                       'src/core/ext/xds/xds_client_stats.h',
+                      'src/core/ext/xds/xds_http_fault_filter.cc',
+                      'src/core/ext/xds/xds_http_fault_filter.h',
+                      'src/core/ext/xds/xds_http_filters.cc',
+                      'src/core/ext/xds/xds_http_filters.h',
                       'src/core/ext/xds/xds_server_config_fetcher.cc',
+                      'src/core/lib/address_utils/parse_address.cc',
+                      'src/core/lib/address_utils/parse_address.h',
+                      'src/core/lib/address_utils/sockaddr_utils.cc',
+                      'src/core/lib/address_utils/sockaddr_utils.h',
                       'src/core/lib/avl/avl.cc',
                       'src/core/lib/avl/avl.h',
                       'src/core/lib/backoff/backoff.cc',
@@ -843,10 +910,14 @@
                       'src/core/lib/gprpp/stat.h',
                       'src/core/lib/gprpp/stat_posix.cc',
                       'src/core/lib/gprpp/stat_windows.cc',
+                      'src/core/lib/gprpp/status_helper.cc',
+                      'src/core/lib/gprpp/status_helper.h',
                       'src/core/lib/gprpp/sync.h',
                       'src/core/lib/gprpp/thd.h',
                       'src/core/lib/gprpp/thd_posix.cc',
                       'src/core/lib/gprpp/thd_windows.cc',
+                      'src/core/lib/gprpp/time_util.cc',
+                      'src/core/lib/gprpp/time_util.h',
                       'src/core/lib/http/format_request.cc',
                       'src/core/lib/http/format_request.h',
                       'src/core/lib/http/httpcli.cc',
@@ -918,7 +989,6 @@
                       'src/core/lib/iomgr/iomgr_internal.cc',
                       'src/core/lib/iomgr/iomgr_internal.h',
                       'src/core/lib/iomgr/iomgr_posix.cc',
-                      'src/core/lib/iomgr/iomgr_posix.h',
                       'src/core/lib/iomgr/iomgr_posix_cfstream.cc',
                       'src/core/lib/iomgr/iomgr_uv.cc',
                       'src/core/lib/iomgr/iomgr_windows.cc',
@@ -929,10 +999,6 @@
                       'src/core/lib/iomgr/lockfree_event.cc',
                       'src/core/lib/iomgr/lockfree_event.h',
                       'src/core/lib/iomgr/nameser.h',
-                      'src/core/lib/iomgr/parse_address.cc',
-                      'src/core/lib/iomgr/parse_address.h',
-                      'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
-                      'src/core/lib/iomgr/poller/eventmanager_libuv.h',
                       'src/core/lib/iomgr/polling_entity.cc',
                       'src/core/lib/iomgr/polling_entity.h',
                       'src/core/lib/iomgr/pollset.cc',
@@ -962,8 +1028,6 @@
                       'src/core/lib/iomgr/sockaddr.h',
                       'src/core/lib/iomgr/sockaddr_custom.h',
                       'src/core/lib/iomgr/sockaddr_posix.h',
-                      'src/core/lib/iomgr/sockaddr_utils.cc',
-                      'src/core/lib/iomgr/sockaddr_utils.h',
                       'src/core/lib/iomgr/sockaddr_windows.h',
                       'src/core/lib/iomgr/socket_factory_posix.cc',
                       'src/core/lib/iomgr/socket_factory_posix.h',
@@ -1033,19 +1097,11 @@
                       'src/core/lib/json/json_util.cc',
                       'src/core/lib/json/json_util.h',
                       'src/core/lib/json/json_writer.cc',
+                      'src/core/lib/matchers/matchers.cc',
+                      'src/core/lib/matchers/matchers.h',
                       'src/core/lib/profiling/basic_timers.cc',
                       'src/core/lib/profiling/stap_timers.cc',
                       'src/core/lib/profiling/timers.h',
-                      'src/core/lib/security/authorization/authorization_engine.cc',
-                      'src/core/lib/security/authorization/authorization_engine.h',
-                      'src/core/lib/security/authorization/evaluate_args.cc',
-                      'src/core/lib/security/authorization/evaluate_args.h',
-                      'src/core/lib/security/authorization/mock_cel/activation.h',
-                      'src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h',
-                      'src/core/lib/security/authorization/mock_cel/cel_expression.h',
-                      'src/core/lib/security/authorization/mock_cel/cel_value.h',
-                      'src/core/lib/security/authorization/mock_cel/evaluator_core.h',
-                      'src/core/lib/security/authorization/mock_cel/flat_expr_builder.h',
                       'src/core/lib/security/context/security_context.cc',
                       'src/core/lib/security/context/security_context.h',
                       'src/core/lib/security/credentials/alts/alts_credentials.cc',
@@ -1331,10 +1387,6 @@
                       'third_party/upb/upb/def.hpp',
                       'third_party/upb/upb/encode.c',
                       'third_party/upb/upb/encode.h',
-                      'third_party/upb/upb/json_decode.c',
-                      'third_party/upb/upb/json_decode.h',
-                      'third_party/upb/upb/json_encode.c',
-                      'third_party/upb/upb/json_encode.h',
                       'third_party/upb/upb/msg.c',
                       'third_party/upb/upb/msg.h',
                       'third_party/upb/upb/port_def.inc',
@@ -1348,7 +1400,8 @@
                       'third_party/upb/upb/upb.c',
                       'third_party/upb/upb/upb.h',
                       'third_party/upb/upb/upb.hpp',
-                      'third_party/upb/upb/upb.int.h'
+                      'third_party/upb/upb/upb.int.h',
+                      'third_party/xxhash/xxhash.h'
     ss.private_header_files = 'src/core/ext/filters/client_channel/backend_metric.h',
                               'src/core/ext/filters/client_channel/backup_poller.h',
                               'src/core/ext/filters/client_channel/client_channel.h',
@@ -1370,6 +1423,7 @@
                               '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',
@@ -1387,6 +1441,8 @@
                               'src/core/ext/filters/client_channel/resolver_factory.h',
                               'src/core/ext/filters/client_channel/resolver_registry.h',
                               'src/core/ext/filters/client_channel/resolver_result_parsing.h',
+                              'src/core/ext/filters/client_channel/retry_filter.h',
+                              'src/core/ext/filters/client_channel/retry_service_config.h',
                               'src/core/ext/filters/client_channel/retry_throttle.h',
                               'src/core/ext/filters/client_channel/server_address.h',
                               'src/core/ext/filters/client_channel/service_config.h',
@@ -1396,6 +1452,8 @@
                               'src/core/ext/filters/client_channel/subchannel_interface.h',
                               'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
                               'src/core/ext/filters/deadline/deadline_filter.h',
+                              'src/core/ext/filters/fault_injection/fault_injection_filter.h',
+                              'src/core/ext/filters/fault_injection/service_config_parser.h',
                               'src/core/ext/filters/http/client/http_client_filter.h',
                               'src/core/ext/filters/http/client_authority_filter.h',
                               'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@@ -1431,9 +1489,11 @@
                               'src/core/ext/transport/chttp2/transport/stream_map.h',
                               'src/core/ext/transport/chttp2/transport/varint.h',
                               'src/core/ext/transport/inproc/inproc_transport.h',
+                              'src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h',
                               'src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h',
                               'src/core/ext/upb-generated/envoy/annotations/resource.upb.h',
                               'src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h',
+                              'src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h',
                               'src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h',
                               'src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h',
                               'src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.h',
@@ -1458,11 +1518,17 @@
                               'src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h',
                               'src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h',
                               'src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h',
+                              'src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h',
+                              'src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h',
                               'src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h',
                               'src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h',
                               'src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h',
                               'src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h',
                               'src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h',
+                              'src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h',
+                              'src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h',
+                              'src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h',
+                              'src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h',
                               'src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h',
                               'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.h',
                               'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h',
@@ -1476,11 +1542,14 @@
                               'src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.h',
                               'src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h',
                               'src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h',
+                              'src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h',
+                              'src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h',
+                              'src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h',
                               'src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h',
                               'src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.h',
                               'src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.h',
@@ -1510,17 +1579,20 @@
                               'src/core/ext/upb-generated/udpa/annotations/sensitive.upb.h',
                               'src/core/ext/upb-generated/udpa/annotations/status.upb.h',
                               'src/core/ext/upb-generated/udpa/annotations/versioning.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/authority.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/resource.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h',
-                              'src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h',
                               'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h',
+                              'src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h',
                               'src/core/ext/upb-generated/validate/validate.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/authority.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/context_params.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/resource.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h',
+                              'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h',
+                              'src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.h',
@@ -1545,10 +1617,16 @@
                               'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.h',
@@ -1562,11 +1640,14 @@
                               'src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.h',
                               'src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.h',
@@ -1589,13 +1670,14 @@
                               'src/core/ext/upbdefs-generated/udpa/annotations/sensitive.upbdefs.h',
                               'src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h',
                               'src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h',
-                              'src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h',
                               'src/core/ext/upbdefs-generated/validate/validate.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h',
+                              'src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h',
                               'src/core/ext/xds/certificate_provider_factory.h',
                               'src/core/ext/xds/certificate_provider_registry.h',
                               'src/core/ext/xds/certificate_provider_store.h',
@@ -1606,6 +1688,10 @@
                               'src/core/ext/xds/xds_channel_args.h',
                               'src/core/ext/xds/xds_client.h',
                               'src/core/ext/xds/xds_client_stats.h',
+                              'src/core/ext/xds/xds_http_fault_filter.h',
+                              'src/core/ext/xds/xds_http_filters.h',
+                              'src/core/lib/address_utils/parse_address.h',
+                              'src/core/lib/address_utils/sockaddr_utils.h',
                               'src/core/lib/avl/avl.h',
                               'src/core/lib/backoff/backoff.h',
                               'src/core/lib/channel/channel_args.h',
@@ -1663,8 +1749,10 @@
                               'src/core/lib/gprpp/ref_counted.h',
                               'src/core/lib/gprpp/ref_counted_ptr.h',
                               'src/core/lib/gprpp/stat.h',
+                              'src/core/lib/gprpp/status_helper.h',
                               'src/core/lib/gprpp/sync.h',
                               'src/core/lib/gprpp/thd.h',
+                              'src/core/lib/gprpp/time_util.h',
                               'src/core/lib/http/format_request.h',
                               'src/core/lib/http/httpcli.h',
                               'src/core/lib/http/parser.h',
@@ -1697,13 +1785,10 @@
                               'src/core/lib/iomgr/iomgr.h',
                               'src/core/lib/iomgr/iomgr_custom.h',
                               'src/core/lib/iomgr/iomgr_internal.h',
-                              'src/core/lib/iomgr/iomgr_posix.h',
                               'src/core/lib/iomgr/is_epollexclusive_available.h',
                               'src/core/lib/iomgr/load_file.h',
                               'src/core/lib/iomgr/lockfree_event.h',
                               'src/core/lib/iomgr/nameser.h',
-                              'src/core/lib/iomgr/parse_address.h',
-                              'src/core/lib/iomgr/poller/eventmanager_libuv.h',
                               'src/core/lib/iomgr/polling_entity.h',
                               'src/core/lib/iomgr/pollset.h',
                               'src/core/lib/iomgr/pollset_custom.h',
@@ -1720,7 +1805,6 @@
                               'src/core/lib/iomgr/sockaddr.h',
                               'src/core/lib/iomgr/sockaddr_custom.h',
                               'src/core/lib/iomgr/sockaddr_posix.h',
-                              'src/core/lib/iomgr/sockaddr_utils.h',
                               'src/core/lib/iomgr/sockaddr_windows.h',
                               'src/core/lib/iomgr/socket_factory_posix.h',
                               'src/core/lib/iomgr/socket_mutator.h',
@@ -1748,15 +1832,8 @@
                               'src/core/lib/iomgr/work_serializer.h',
                               'src/core/lib/json/json.h',
                               'src/core/lib/json/json_util.h',
+                              'src/core/lib/matchers/matchers.h',
                               'src/core/lib/profiling/timers.h',
-                              'src/core/lib/security/authorization/authorization_engine.h',
-                              'src/core/lib/security/authorization/evaluate_args.h',
-                              'src/core/lib/security/authorization/mock_cel/activation.h',
-                              'src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h',
-                              'src/core/lib/security/authorization/mock_cel/cel_expression.h',
-                              'src/core/lib/security/authorization/mock_cel/cel_value.h',
-                              'src/core/lib/security/authorization/mock_cel/evaluator_core.h',
-                              'src/core/lib/security/authorization/mock_cel/flat_expr_builder.h',
                               'src/core/lib/security/context/security_context.h',
                               'src/core/lib/security/credentials/alts/alts_credentials.h',
                               'src/core/lib/security/credentials/alts/check_gcp_environment.h',
@@ -1894,8 +1971,6 @@
                               'third_party/upb/upb/def.h',
                               'third_party/upb/upb/def.hpp',
                               'third_party/upb/upb/encode.h',
-                              'third_party/upb/upb/json_decode.h',
-                              'third_party/upb/upb/json_encode.h',
                               'third_party/upb/upb/msg.h',
                               'third_party/upb/upb/port_def.inc',
                               'third_party/upb/upb/port_undef.inc',
@@ -1904,7 +1979,8 @@
                               'third_party/upb/upb/text_encode.h',
                               'third_party/upb/upb/upb.h',
                               'third_party/upb/upb/upb.hpp',
-                              'third_party/upb/upb/upb.int.h'
+                              'third_party/upb/upb/upb.int.h',
+                              'third_party/xxhash/xxhash.h'
   end
 
   # CFStream is now default. Leaving this subspec only for compatibility purpose.
@@ -2008,10 +2084,12 @@
                       'test/core/end2end/tests/request_with_payload.cc',
                       'test/core/end2end/tests/resource_quota_server.cc',
                       'test/core/end2end/tests/retry.cc',
+                      'test/core/end2end/tests/retry_cancel_during_delay.cc',
                       'test/core/end2end/tests/retry_cancellation.cc',
                       'test/core/end2end/tests/retry_disabled.cc',
                       'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
                       'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+                      'test/core/end2end/tests/retry_lb_drop.cc',
                       'test/core/end2end/tests/retry_non_retriable_status.cc',
                       'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
                       'test/core/end2end/tests/retry_recv_initial_metadata.cc',
@@ -2041,8 +2119,7 @@
                       'test/core/end2end/tests/write_buffering_at_end.cc',
                       'test/core/util/cmdline.cc',
                       'test/core/util/cmdline.h',
-                      'test/core/util/eval_args_mock_endpoint.cc',
-                      'test/core/util/eval_args_mock_endpoint.h',
+                      'test/core/util/evaluate_args_test_util.h',
                       'test/core/util/fuzzer_util.cc',
                       'test/core/util/fuzzer_util.h',
                       'test/core/util/grpc_profiler.cc',
@@ -2051,6 +2128,7 @@
                       'test/core/util/histogram.h',
                       'test/core/util/memory_counters.cc',
                       'test/core/util/memory_counters.h',
+                      'test/core/util/mock_authorization_endpoint.h',
                       'test/core/util/mock_endpoint.cc',
                       'test/core/util/mock_endpoint.h',
                       'test/core/util/parse_hexstring.cc',
@@ -2074,6 +2152,8 @@
                       'test/core/util/subprocess_windows.cc',
                       'test/core/util/test_config.cc',
                       'test/core/util/test_config.h',
+                      'test/core/util/test_lb_policies.cc',
+                      'test/core/util/test_lb_policies.h',
                       'test/core/util/test_tcp_server.cc',
                       'test/core/util/test_tcp_server.h',
                       'test/core/util/tls_utils.cc',
@@ -2086,7 +2166,7 @@
 
   # TODO (mxyan): Instead of this hack, add include path "third_party" to C core's include path?
   s.prepare_command = <<-END_OF_COMMAND
-    sed -E -i '' 's;#include <openssl/(.*)>;#if COCOAPODS==1\\\n  #include <openssl_grpc/\\1>\\\n#else\\\n  #include <openssl/\\1>\\\n#endif;g' $(find src/core -type f \\( -path '*.h' -or -path '*.cc' \\) -print | xargs grep -H -c '#include <openssl_grpc/' | grep 0$ | cut -d':' -f1)
+    find src/core -type f \\( -path '*.h' -or -path '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/(.*)>;#if COCOAPODS==1\\\n  #include <openssl_grpc/\\1>\\\n#else\\\n  #include <openssl/\\1>\\\n#endif;g'
     find third_party/upb/ -type f \\( -name '*.h' -or -name '*.hpp' -or -name '*.c' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "third_party/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/upb/third_party/\\1"\\\n#else\\\n  #include  "third_party/\\1"\\\n#endif;g'
     find src/core/ src/cpp/ third_party/upb/ -type f \\( -name '*.h' -or -name '*.hpp' -or -name '*.c' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "upb/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/upb/upb/\\1"\\\n#else\\\n  #include  "upb/\\1"\\\n#endif;g'
     find src/core/ src/cpp/ third_party/upb/ -type f -name '*.grpc_back' -print0 | xargs -0 rm
@@ -2096,5 +2176,8 @@
     find third_party/re2/re2/ third_party/re2/util/ -type f \\( -name '*.h' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "re2/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/re2/re2/\\1"\\\n#else\\\n  #include  "re2/\\1"\\\n#endif;g;s;#include "util/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/re2/util/\\1"\\\n#else\\\n  #include  "util/\\1"\\\n#endif;g'
     find src/core/ -type f \\( -name '*.h' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "re2/(.*)";#if COCOAPODS==1\\\n  #include  "third_party/re2/re2/\\1"\\\n#else\\\n  #include  "re2/\\1"\\\n#endif;g'
     find src/core/ third_party/re2/ -type f -name '*.grpc_back' -print0 | xargs -0 rm
+    find src/core/ -type f \\( -name '*.h' -or -name '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "xxhash.h";#if COCOAPODS==1\\\n  #include  "third_party/xxhash/xxhash.h"\\\n#else\\\n  #include  "xxhash.h"\\\n#endif;g'
+    find third_party/xxhash  -type f -name xxhash.h -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;@param([^,]*),;@param\\1 ,;g'
+    find src/core/ third_party/xxhash/ -type f -name '*.grpc_back' -print0 | xargs -0 rm
   END_OF_COMMAND
 end
diff --git a/grpc/gRPC-ProtoRPC.podspec b/grpc/gRPC-ProtoRPC.podspec
index dfca5dc..68dcb4d 100644
--- a/grpc/gRPC-ProtoRPC.podspec
+++ b/grpc/gRPC-ProtoRPC.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.35.0'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'https://grpc.io'
diff --git a/grpc/gRPC-RxLibrary.podspec b/grpc/gRPC-RxLibrary.podspec
index bdd39fa..dbfc8de 100644
--- a/grpc/gRPC-RxLibrary.podspec
+++ b/grpc/gRPC-RxLibrary.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.35.0'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'https://grpc.io'
diff --git a/grpc/gRPC.podspec b/grpc/gRPC.podspec
index 330679a..af62f2e 100644
--- a/grpc/gRPC.podspec
+++ b/grpc/gRPC.podspec
@@ -20,7 +20,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.35.0'
+  version = '1.38.0'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'https://grpc.io'
diff --git a/grpc/grpc.def b/grpc/grpc.def
index 4dcb9ed..7be77a6 100644
--- a/grpc/grpc.def
+++ b/grpc/grpc.def
@@ -75,6 +75,7 @@
     grpc_resource_quota_unref
     grpc_resource_quota_resize
     grpc_resource_quota_set_max_threads
+    grpc_dump_xds_configs
     grpc_resource_quota_arg_vtable
     grpc_channelz_get_top_channels
     grpc_channelz_get_servers
diff --git a/grpc/grpc.gemspec b/grpc/grpc.gemspec
index 4359a21..2185cbf 100644
--- a/grpc/grpc.gemspec
+++ b/grpc/grpc.gemspec
@@ -13,7 +13,7 @@
   s.description   = 'Send RPCs from Ruby using GRPC'
   s.license       = 'Apache-2.0'
 
-  s.required_ruby_version = '>= 2.3.0'
+  s.required_ruby_version = '>= 2.4.0'
 
   s.files = %w( Makefile .yardopts )
   s.files += %w( etc/roots.pem )
@@ -32,7 +32,7 @@
   s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
   s.platform      = Gem::Platform::RUBY
 
-  s.add_dependency 'google-protobuf', '~> 3.14'
+  s.add_dependency 'google-protobuf', '~> 3.15'
   s.add_dependency 'googleapis-common-protos-types', '~> 1.0'
 
   s.add_development_dependency 'bundler',            '>= 1.9'
@@ -53,6 +53,10 @@
   s.files += %w( include/grpc/byte_buffer_reader.h )
   s.files += %w( include/grpc/census.h )
   s.files += %w( include/grpc/compression.h )
+  s.files += %w( include/grpc/event_engine/channel_args.h )
+  s.files += %w( include/grpc/event_engine/event_engine.h )
+  s.files += %w( include/grpc/event_engine/port.h )
+  s.files += %w( include/grpc/event_engine/slice_allocator.h )
   s.files += %w( include/grpc/fork.h )
   s.files += %w( include/grpc/grpc.h )
   s.files += %w( include/grpc/grpc_posix.h )
@@ -150,6 +154,8 @@
   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 )
@@ -184,6 +190,7 @@
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h )
@@ -192,6 +199,10 @@
   s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h )
   s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.h )
+  s.files += %w( src/core/ext/filters/client_channel/retry_filter.cc )
+  s.files += %w( src/core/ext/filters/client_channel/retry_filter.h )
+  s.files += %w( src/core/ext/filters/client_channel/retry_service_config.cc )
+  s.files += %w( src/core/ext/filters/client_channel/retry_service_config.h )
   s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc )
   s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h )
   s.files += %w( src/core/ext/filters/client_channel/server_address.cc )
@@ -210,6 +221,10 @@
   s.files += %w( src/core/ext/filters/client_idle/client_idle_filter.cc )
   s.files += %w( src/core/ext/filters/deadline/deadline_filter.cc )
   s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
+  s.files += %w( src/core/ext/filters/fault_injection/fault_injection_filter.cc )
+  s.files += %w( src/core/ext/filters/fault_injection/fault_injection_filter.h )
+  s.files += %w( src/core/ext/filters/fault_injection/service_config_parser.cc )
+  s.files += %w( src/core/ext/filters/fault_injection/service_config_parser.h )
   s.files += %w( src/core/ext/filters/http/client/http_client_filter.cc )
   s.files += %w( src/core/ext/filters/http/client/http_client_filter.h )
   s.files += %w( src/core/ext/filters/http/client_authority_filter.cc )
@@ -290,12 +305,16 @@
   s.files += %w( src/core/ext/transport/inproc/inproc_plugin.cc )
   s.files += %w( src/core/ext/transport/inproc/inproc_transport.cc )
   s.files += %w( src/core/ext/transport/inproc/inproc_transport.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/annotations/resource.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/annotations/resource.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c )
@@ -344,6 +363,10 @@
   s.files += %w( src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c )
@@ -354,6 +377,14 @@
   s.files += %w( src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c )
@@ -380,8 +411,12 @@
   s.files += %w( src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c )
@@ -390,6 +425,8 @@
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h )
+  s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c )
+  s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c )
   s.files += %w( src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h )
   s.files += %w( src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c )
@@ -448,28 +485,34 @@
   s.files += %w( src/core/ext/upb-generated/udpa/annotations/status.upb.h )
   s.files += %w( src/core/ext/upb-generated/udpa/annotations/versioning.upb.c )
   s.files += %w( src/core/ext/upb-generated/udpa/annotations/versioning.upb.h )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/authority.upb.c )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/authority.upb.h )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/resource.upb.c )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/resource.upb.h )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c )
-  s.files += %w( src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h )
   s.files += %w( src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c )
   s.files += %w( src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h )
+  s.files += %w( src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c )
+  s.files += %w( src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h )
   s.files += %w( src/core/ext/upb-generated/validate/validate.upb.c )
   s.files += %w( src/core/ext/upb-generated/validate/validate.upb.h )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/authority.upb.c )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/authority.upb.h )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/context_params.upb.c )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/context_params.upb.h )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/resource.upb.c )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/resource.upb.h )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c )
+  s.files += %w( src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c )
@@ -518,6 +561,10 @@
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c )
@@ -526,6 +573,14 @@
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c )
@@ -552,8 +607,12 @@
   s.files += %w( src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c )
@@ -562,6 +621,8 @@
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c )
@@ -606,20 +667,22 @@
   s.files += %w( src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c )
-  s.files += %w( src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h )
   s.files += %w( src/core/ext/upbdefs-generated/validate/validate.upbdefs.c )
   s.files += %w( src/core/ext/upbdefs-generated/validate/validate.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c )
+  s.files += %w( src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h )
   s.files += %w( src/core/ext/xds/certificate_provider_factory.h )
   s.files += %w( src/core/ext/xds/certificate_provider_registry.cc )
   s.files += %w( src/core/ext/xds/certificate_provider_registry.h )
@@ -638,7 +701,15 @@
   s.files += %w( src/core/ext/xds/xds_client.h )
   s.files += %w( src/core/ext/xds/xds_client_stats.cc )
   s.files += %w( src/core/ext/xds/xds_client_stats.h )
+  s.files += %w( src/core/ext/xds/xds_http_fault_filter.cc )
+  s.files += %w( src/core/ext/xds/xds_http_fault_filter.h )
+  s.files += %w( src/core/ext/xds/xds_http_filters.cc )
+  s.files += %w( src/core/ext/xds/xds_http_filters.h )
   s.files += %w( src/core/ext/xds/xds_server_config_fetcher.cc )
+  s.files += %w( src/core/lib/address_utils/parse_address.cc )
+  s.files += %w( src/core/lib/address_utils/parse_address.h )
+  s.files += %w( src/core/lib/address_utils/sockaddr_utils.cc )
+  s.files += %w( src/core/lib/address_utils/sockaddr_utils.h )
   s.files += %w( src/core/lib/avl/avl.cc )
   s.files += %w( src/core/lib/avl/avl.h )
   s.files += %w( src/core/lib/backoff/backoff.cc )
@@ -685,6 +756,8 @@
   s.files += %w( src/core/lib/debug/stats_data.h )
   s.files += %w( src/core/lib/debug/trace.cc )
   s.files += %w( src/core/lib/debug/trace.h )
+  s.files += %w( src/core/lib/event_engine/slice_allocator.cc )
+  s.files += %w( src/core/lib/event_engine/sockaddr.cc )
   s.files += %w( src/core/lib/gpr/alloc.cc )
   s.files += %w( src/core/lib/gpr/alloc.h )
   s.files += %w( src/core/lib/gpr/arena.h )
@@ -758,10 +831,14 @@
   s.files += %w( src/core/lib/gprpp/stat.h )
   s.files += %w( src/core/lib/gprpp/stat_posix.cc )
   s.files += %w( src/core/lib/gprpp/stat_windows.cc )
+  s.files += %w( src/core/lib/gprpp/status_helper.cc )
+  s.files += %w( src/core/lib/gprpp/status_helper.h )
   s.files += %w( src/core/lib/gprpp/sync.h )
   s.files += %w( src/core/lib/gprpp/thd.h )
   s.files += %w( src/core/lib/gprpp/thd_posix.cc )
   s.files += %w( src/core/lib/gprpp/thd_windows.cc )
+  s.files += %w( src/core/lib/gprpp/time_util.cc )
+  s.files += %w( src/core/lib/gprpp/time_util.h )
   s.files += %w( src/core/lib/http/format_request.cc )
   s.files += %w( src/core/lib/http/format_request.h )
   s.files += %w( src/core/lib/http/httpcli.cc )
@@ -833,7 +910,6 @@
   s.files += %w( src/core/lib/iomgr/iomgr_internal.cc )
   s.files += %w( src/core/lib/iomgr/iomgr_internal.h )
   s.files += %w( src/core/lib/iomgr/iomgr_posix.cc )
-  s.files += %w( src/core/lib/iomgr/iomgr_posix.h )
   s.files += %w( src/core/lib/iomgr/iomgr_posix_cfstream.cc )
   s.files += %w( src/core/lib/iomgr/iomgr_uv.cc )
   s.files += %w( src/core/lib/iomgr/iomgr_windows.cc )
@@ -844,10 +920,6 @@
   s.files += %w( src/core/lib/iomgr/lockfree_event.cc )
   s.files += %w( src/core/lib/iomgr/lockfree_event.h )
   s.files += %w( src/core/lib/iomgr/nameser.h )
-  s.files += %w( src/core/lib/iomgr/parse_address.cc )
-  s.files += %w( src/core/lib/iomgr/parse_address.h )
-  s.files += %w( src/core/lib/iomgr/poller/eventmanager_libuv.cc )
-  s.files += %w( src/core/lib/iomgr/poller/eventmanager_libuv.h )
   s.files += %w( src/core/lib/iomgr/polling_entity.cc )
   s.files += %w( src/core/lib/iomgr/polling_entity.h )
   s.files += %w( src/core/lib/iomgr/pollset.cc )
@@ -877,8 +949,6 @@
   s.files += %w( src/core/lib/iomgr/sockaddr.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_custom.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_posix.h )
-  s.files += %w( src/core/lib/iomgr/sockaddr_utils.cc )
-  s.files += %w( src/core/lib/iomgr/sockaddr_utils.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_windows.h )
   s.files += %w( src/core/lib/iomgr/socket_factory_posix.cc )
   s.files += %w( src/core/lib/iomgr/socket_factory_posix.h )
@@ -948,19 +1018,11 @@
   s.files += %w( src/core/lib/json/json_util.cc )
   s.files += %w( src/core/lib/json/json_util.h )
   s.files += %w( src/core/lib/json/json_writer.cc )
+  s.files += %w( src/core/lib/matchers/matchers.cc )
+  s.files += %w( src/core/lib/matchers/matchers.h )
   s.files += %w( src/core/lib/profiling/basic_timers.cc )
   s.files += %w( src/core/lib/profiling/stap_timers.cc )
   s.files += %w( src/core/lib/profiling/timers.h )
-  s.files += %w( src/core/lib/security/authorization/authorization_engine.cc )
-  s.files += %w( src/core/lib/security/authorization/authorization_engine.h )
-  s.files += %w( src/core/lib/security/authorization/evaluate_args.cc )
-  s.files += %w( src/core/lib/security/authorization/evaluate_args.h )
-  s.files += %w( src/core/lib/security/authorization/mock_cel/activation.h )
-  s.files += %w( src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h )
-  s.files += %w( src/core/lib/security/authorization/mock_cel/cel_expression.h )
-  s.files += %w( src/core/lib/security/authorization/mock_cel/cel_value.h )
-  s.files += %w( src/core/lib/security/authorization/mock_cel/evaluator_core.h )
-  s.files += %w( src/core/lib/security/authorization/mock_cel/flat_expr_builder.h )
   s.files += %w( src/core/lib/security/context/security_context.cc )
   s.files += %w( src/core/lib/security/context/security_context.h )
   s.files += %w( src/core/lib/security/credentials/alts/alts_credentials.cc )
@@ -1195,7 +1257,6 @@
   s.files += %w( third_party/abseil-cpp/absl/base/const_init.h )
   s.files += %w( third_party/abseil-cpp/absl/base/dynamic_annotations.h )
   s.files += %w( third_party/abseil-cpp/absl/base/internal/atomic_hook.h )
-  s.files += %w( third_party/abseil-cpp/absl/base/internal/bits.h )
   s.files += %w( third_party/abseil-cpp/absl/base/internal/cycleclock.cc )
   s.files += %w( third_party/abseil-cpp/absl/base/internal/cycleclock.h )
   s.files += %w( third_party/abseil-cpp/absl/base/internal/direct_mmap.h )
@@ -1244,7 +1305,6 @@
   s.files += %w( third_party/abseil-cpp/absl/base/thread_annotations.h )
   s.files += %w( third_party/abseil-cpp/absl/container/fixed_array.h )
   s.files += %w( third_party/abseil-cpp/absl/container/flat_hash_map.h )
-  s.files += %w( third_party/abseil-cpp/absl/container/flat_hash_set.h )
   s.files += %w( third_party/abseil-cpp/absl/container/inlined_vector.h )
   s.files += %w( third_party/abseil-cpp/absl/container/internal/common.h )
   s.files += %w( third_party/abseil-cpp/absl/container/internal/compressed_tuple.h )
@@ -1295,12 +1355,17 @@
   s.files += %w( third_party/abseil-cpp/absl/hash/internal/city.h )
   s.files += %w( third_party/abseil-cpp/absl/hash/internal/hash.cc )
   s.files += %w( third_party/abseil-cpp/absl/hash/internal/hash.h )
+  s.files += %w( third_party/abseil-cpp/absl/hash/internal/wyhash.cc )
+  s.files += %w( third_party/abseil-cpp/absl/hash/internal/wyhash.h )
   s.files += %w( third_party/abseil-cpp/absl/memory/memory.h )
   s.files += %w( third_party/abseil-cpp/absl/meta/type_traits.h )
+  s.files += %w( third_party/abseil-cpp/absl/numeric/bits.h )
   s.files += %w( third_party/abseil-cpp/absl/numeric/int128.cc )
   s.files += %w( third_party/abseil-cpp/absl/numeric/int128.h )
   s.files += %w( third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc )
   s.files += %w( third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc )
+  s.files += %w( third_party/abseil-cpp/absl/numeric/internal/bits.h )
+  s.files += %w( third_party/abseil-cpp/absl/numeric/internal/representation.h )
   s.files += %w( third_party/abseil-cpp/absl/status/internal/status_internal.h )
   s.files += %w( third_party/abseil-cpp/absl/status/internal/statusor_internal.h )
   s.files += %w( third_party/abseil-cpp/absl/status/status.cc )
@@ -1322,7 +1387,12 @@
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/charconv_bigint.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/charconv_parse.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_internal.cc )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_internal.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/escaping.cc )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/escaping.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/memutil.cc )
@@ -1346,6 +1416,7 @@
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/str_format/parser.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/str_join_internal.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/str_split_internal.h )
+  s.files += %w( third_party/abseil-cpp/absl/strings/internal/string_constant.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/utf8.cc )
   s.files += %w( third_party/abseil-cpp/absl/strings/internal/utf8.h )
   s.files += %w( third_party/abseil-cpp/absl/strings/match.cc )
@@ -1371,10 +1442,10 @@
   s.files += %w( third_party/abseil-cpp/absl/synchronization/blocking_counter.h )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h )
+  s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/futex.h )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h )
-  s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h )
   s.files += %w( third_party/abseil-cpp/absl/synchronization/internal/waiter.cc )
@@ -1474,6 +1545,7 @@
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/bio/printf.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/bio/socket.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/bio/socket_helper.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/blake2/blake2.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/bn_extra/bn_asn1.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/bn_extra/convert.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/buf/buf.c )
@@ -1503,6 +1575,7 @@
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/conf/internal.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-fuchsia.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-linux.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-win.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/cpu-arm-linux.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/cpu-arm-linux.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/cpu-arm.c )
@@ -1513,10 +1586,8 @@
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/curve25519/curve25519_tables.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/curve25519/internal.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/curve25519/spake25519.c )
-  s.files += %w( third_party/boringssl-with-bazel/src/crypto/dh/check.c )
-  s.files += %w( third_party/boringssl-with-bazel/src/crypto/dh/dh.c )
-  s.files += %w( third_party/boringssl-with-bazel/src/crypto/dh/dh_asn1.c )
-  s.files += %w( third_party/boringssl-with-bazel/src/crypto/dh/params.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c )
@@ -1586,6 +1657,8 @@
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/delocate.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/des/des.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/des/internal.h )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/dh/check.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/dh/dh.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/digest/digest.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/digest/digests.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/digest/internal.h )
@@ -1609,9 +1682,9 @@
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/wnaf.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdh/ecdh.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdsa/ecdsa.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdsa/internal.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/hmac/hmac.c )
-  s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/md4/md4.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/md5/internal.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/md5/md5.c )
@@ -1635,6 +1708,7 @@
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/padding.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/rsa.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/rsa_impl.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/self_check/fips.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/self_check/self_check.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/sha/internal.h )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/fipsmodule/sha/sha1-altivec.c )
@@ -1678,6 +1752,7 @@
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/rand_extra/deterministic.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/rand_extra/forkunsafe.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/rand_extra/fuchsia.c )
+  s.files += %w( third_party/boringssl-with-bazel/src/crypto/rand_extra/passive.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/rand_extra/rand_extra.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/rand_extra/windows.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/rc4/rc4.c )
@@ -1720,7 +1795,6 @@
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c )
-  s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c )
   s.files += %w( third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c )
@@ -1790,6 +1864,7 @@
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/base.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/base64.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/bio.h )
+  s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/blake2.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/blowfish.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/bn.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/buf.h )
@@ -1816,6 +1891,7 @@
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/engine.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/err.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/evp.h )
+  s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/evp_errors.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/ex_data.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/hkdf.h )
   s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/hmac.h )
@@ -1864,6 +1940,7 @@
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/dtls_method.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/dtls_record.cc )
+  s.files += %w( third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/handoff.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/handshake.cc )
   s.files += %w( third_party/boringssl-with-bazel/src/ssl/handshake_client.cc )
@@ -2035,10 +2112,6 @@
   s.files += %w( third_party/upb/upb/def.hpp )
   s.files += %w( third_party/upb/upb/encode.c )
   s.files += %w( third_party/upb/upb/encode.h )
-  s.files += %w( third_party/upb/upb/json_decode.c )
-  s.files += %w( third_party/upb/upb/json_decode.h )
-  s.files += %w( third_party/upb/upb/json_encode.c )
-  s.files += %w( third_party/upb/upb/json_encode.h )
   s.files += %w( third_party/upb/upb/msg.c )
   s.files += %w( third_party/upb/upb/msg.h )
   s.files += %w( third_party/upb/upb/port_def.inc )
@@ -2053,6 +2126,7 @@
   s.files += %w( third_party/upb/upb/upb.h )
   s.files += %w( third_party/upb/upb/upb.hpp )
   s.files += %w( third_party/upb/upb/upb.int.h )
+  s.files += %w( third_party/xxhash/xxhash.h )
   s.files += %w( third_party/zlib/adler32.c )
   s.files += %w( third_party/zlib/compress.c )
   s.files += %w( third_party/zlib/crc32.c )
diff --git a/grpc/grpc.gyp b/grpc/grpc.gyp
index 0432bb5..2418290 100644
--- a/grpc/grpc.gyp
+++ b/grpc/grpc.gyp
@@ -60,6 +60,7 @@
       '-Ithird_party/upb',
       '-Isrc/core/ext/upb-generated',
       '-Isrc/core/ext/upbdefs-generated',
+      '-Ithird_party/xxhash',
     ],
     'ldflags': [
       '-g',
@@ -139,6 +140,7 @@
             '-Ithird_party/upb',
             '-Isrc/core/ext/upb-generated',
             '-Isrc/core/ext/upbdefs-generated',
+            '-Ithird_party/xxhash',
           ],
           'OTHER_CPLUSPLUSFLAGS': [
             '-g',
@@ -150,6 +152,7 @@
             '-Ithird_party/upb',
             '-Isrc/core/ext/upb-generated',
             '-Isrc/core/ext/upbdefs-generated',
+            '-Ithird_party/xxhash',
             '-stdlib=libc++',
             '-std=c++11',
             '-Wno-error=deprecated-declarations',
@@ -175,10 +178,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc_test_util',
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'test/core/end2end/cq_verifier.cc',
@@ -239,10 +238,12 @@
         'test/core/end2end/tests/request_with_payload.cc',
         'test/core/end2end/tests/resource_quota_server.cc',
         'test/core/end2end/tests/retry.cc',
+        'test/core/end2end/tests/retry_cancel_during_delay.cc',
         'test/core/end2end/tests/retry_cancellation.cc',
         'test/core/end2end/tests/retry_disabled.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+        'test/core/end2end/tests/retry_lb_drop.cc',
         'test/core/end2end/tests/retry_non_retriable_status.cc',
         'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
         'test/core/end2end/tests/retry_recv_initial_metadata.cc',
@@ -270,6 +271,7 @@
         'test/core/end2end/tests/workaround_cronet_compression.cc',
         'test/core/end2end/tests/write_buffering.cc',
         'test/core/end2end/tests/write_buffering_at_end.cc',
+        'test/core/util/test_lb_policies.cc',
       ],
     },
     {
@@ -277,10 +279,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc_test_util',
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'test/core/end2end/cq_verifier.cc',
@@ -342,10 +340,12 @@
         'test/core/end2end/tests/request_with_payload.cc',
         'test/core/end2end/tests/resource_quota_server.cc',
         'test/core/end2end/tests/retry.cc',
+        'test/core/end2end/tests/retry_cancel_during_delay.cc',
         'test/core/end2end/tests/retry_cancellation.cc',
         'test/core/end2end/tests/retry_disabled.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+        'test/core/end2end/tests/retry_lb_drop.cc',
         'test/core/end2end/tests/retry_non_retriable_status.cc',
         'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
         'test/core/end2end/tests/retry_recv_initial_metadata.cc',
@@ -373,22 +373,35 @@
         'test/core/end2end/tests/workaround_cronet_compression.cc',
         'test/core/end2end/tests/write_buffering.cc',
         'test/core/end2end/tests/write_buffering_at_end.cc',
+        'test/core/util/test_lb_policies.cc',
       ],
     },
     {
       'target_name': 'gpr',
       'type': 'static_library',
       'dependencies': [
-        'absl/types:optional',
-        'absl/time:time',
-        'absl/synchronization:synchronization',
-        'absl/strings:strings',
-        'absl/strings:str_format',
-        'absl/status:status',
-        'absl/memory:memory',
         'absl/base:base',
+        'absl/memory:memory',
+        'absl/status:status',
+        'absl/strings:str_format',
+        'absl/strings:strings',
+        'absl/synchronization:synchronization',
+        'absl/time:time',
+        'absl/types:optional',
+        'upb',
       ],
       'sources': [
+        'src/core/ext/upb-generated/google/api/annotations.upb.c',
+        'src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c',
+        'src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c',
+        'src/core/ext/upb-generated/google/api/http.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/any.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/duration.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/empty.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/struct.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c',
+        'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c',
+        'src/core/ext/upb-generated/google/rpc/status.upb.c',
         'src/core/lib/gpr/alloc.cc',
         'src/core/lib/gpr/atm.cc',
         'src/core/lib/gpr/cpu_iphone.cc',
@@ -429,8 +442,10 @@
         'src/core/lib/gprpp/mpscq.cc',
         'src/core/lib/gprpp/stat_posix.cc',
         'src/core/lib/gprpp/stat_windows.cc',
+        'src/core/lib/gprpp/status_helper.cc',
         'src/core/lib/gprpp/thd_posix.cc',
         'src/core/lib/gprpp/thd_windows.cc',
+        'src/core/lib/gprpp/time_util.cc',
         'src/core/lib/profiling/basic_timers.cc',
         'src/core/lib/profiling/stap_timers.cc',
       ],
@@ -439,17 +454,12 @@
       'target_name': 'grpc',
       'type': 'static_library',
       'dependencies': [
+        'absl/container:flat_hash_map',
+        'absl/container:inlined_vector',
+        'absl/functional:bind_front',
+        'absl/status:statusor',
         'gpr',
         'address_sorting',
-        'upb',
-        'absl/types:optional',
-        'absl/strings:strings',
-        'absl/status:statusor',
-        'absl/status:status',
-        'absl/functional:bind_front',
-        'absl/container:inlined_vector',
-        'absl/container:flat_hash_set',
-        'absl/container:flat_hash_map',
       ],
       'sources': [
         'src/core/ext/filters/census/grpc_context.cc',
@@ -477,6 +487,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',
@@ -498,10 +509,13 @@
         'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc',
         'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',
         'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
+        'src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc',
         'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
         'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
         'src/core/ext/filters/client_channel/resolver_registry.cc',
         'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
+        'src/core/ext/filters/client_channel/retry_filter.cc',
+        'src/core/ext/filters/client_channel/retry_service_config.cc',
         'src/core/ext/filters/client_channel/retry_throttle.cc',
         'src/core/ext/filters/client_channel/server_address.cc',
         'src/core/ext/filters/client_channel/service_config.cc',
@@ -511,6 +525,8 @@
         'src/core/ext/filters/client_channel/subchannel_pool_interface.cc',
         'src/core/ext/filters/client_idle/client_idle_filter.cc',
         'src/core/ext/filters/deadline/deadline_filter.cc',
+        'src/core/ext/filters/fault_injection/fault_injection_filter.cc',
+        'src/core/ext/filters/fault_injection/service_config_parser.cc',
         'src/core/ext/filters/http/client/http_client_filter.cc',
         'src/core/ext/filters/http/client_authority_filter.cc',
         'src/core/ext/filters/http/http_filters_plugin.cc',
@@ -556,9 +572,11 @@
         'src/core/ext/transport/chttp2/transport/writing.cc',
         'src/core/ext/transport/inproc/inproc_plugin.cc',
         'src/core/ext/transport/inproc/inproc_transport.cc',
+        'src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c',
         'src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c',
         'src/core/ext/upb-generated/envoy/annotations/resource.upb.c',
         'src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c',
+        'src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c',
         'src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c',
         'src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c',
         'src/core/ext/upb-generated/envoy/config/cluster/v3/filter.upb.c',
@@ -583,11 +601,17 @@
         'src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c',
         'src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c',
         'src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c',
+        'src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c',
+        'src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c',
         'src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c',
         'src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c',
         'src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c',
         'src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.c',
         'src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c',
+        'src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c',
+        'src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c',
+        'src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c',
+        'src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c',
         'src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c',
         'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c',
         'src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c',
@@ -601,11 +625,14 @@
         'src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c',
         'src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c',
         'src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c',
+        'src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c',
         'src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c',
+        'src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c',
         'src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c',
         'src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c',
         'src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.c',
         'src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c',
+        'src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c',
         'src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c',
         'src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c',
         'src/core/ext/upb-generated/envoy/type/tracing/v3/custom_tag.upb.c',
@@ -613,17 +640,6 @@
         'src/core/ext/upb-generated/envoy/type/v3/percent.upb.c',
         'src/core/ext/upb-generated/envoy/type/v3/range.upb.c',
         'src/core/ext/upb-generated/envoy/type/v3/semantic_version.upb.c',
-        'src/core/ext/upb-generated/google/api/annotations.upb.c',
-        'src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c',
-        'src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c',
-        'src/core/ext/upb-generated/google/api/http.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/any.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/duration.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/empty.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/struct.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c',
-        'src/core/ext/upb-generated/google/rpc/status.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c',
@@ -634,17 +650,20 @@
         'src/core/ext/upb-generated/udpa/annotations/sensitive.upb.c',
         'src/core/ext/upb-generated/udpa/annotations/status.upb.c',
         'src/core/ext/upb-generated/udpa/annotations/versioning.upb.c',
-        'src/core/ext/upb-generated/udpa/core/v1/authority.upb.c',
-        'src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c',
-        'src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c',
-        'src/core/ext/upb-generated/udpa/core/v1/resource.upb.c',
-        'src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c',
-        'src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c',
         'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c',
+        'src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c',
         'src/core/ext/upb-generated/validate/validate.upb.c',
+        'src/core/ext/upb-generated/xds/core/v3/authority.upb.c',
+        'src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c',
+        'src/core/ext/upb-generated/xds/core/v3/context_params.upb.c',
+        'src/core/ext/upb-generated/xds/core/v3/resource.upb.c',
+        'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c',
+        'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c',
+        'src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/cluster/v3/filter.upbdefs.c',
@@ -669,10 +688,16 @@
         'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c',
@@ -686,11 +711,14 @@
         'src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c',
+        'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c',
         'src/core/ext/upbdefs-generated/envoy/type/tracing/v3/custom_tag.upbdefs.c',
@@ -701,7 +729,6 @@
         'src/core/ext/upbdefs-generated/google/api/annotations.upbdefs.c',
         'src/core/ext/upbdefs-generated/google/api/http.upbdefs.c',
         'src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c',
-        'src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c',
         'src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c',
         'src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c',
         'src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.c',
@@ -713,13 +740,14 @@
         'src/core/ext/upbdefs-generated/udpa/annotations/sensitive.upbdefs.c',
         'src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.c',
         'src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c',
-        'src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c',
-        'src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c',
-        'src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c',
-        'src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c',
-        'src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c',
-        'src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c',
+        'src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c',
         'src/core/ext/upbdefs-generated/validate/validate.upbdefs.c',
+        'src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c',
+        'src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c',
+        'src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c',
+        'src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c',
+        'src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c',
+        'src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c',
         'src/core/ext/xds/certificate_provider_registry.cc',
         'src/core/ext/xds/certificate_provider_store.cc',
         'src/core/ext/xds/file_watcher_certificate_provider_factory.cc',
@@ -728,7 +756,11 @@
         'src/core/ext/xds/xds_certificate_provider.cc',
         'src/core/ext/xds/xds_client.cc',
         'src/core/ext/xds/xds_client_stats.cc',
+        'src/core/ext/xds/xds_http_fault_filter.cc',
+        'src/core/ext/xds/xds_http_filters.cc',
         'src/core/ext/xds/xds_server_config_fetcher.cc',
+        'src/core/lib/address_utils/parse_address.cc',
+        'src/core/lib/address_utils/sockaddr_utils.cc',
         'src/core/lib/avl/avl.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
@@ -751,6 +783,8 @@
         'src/core/lib/debug/stats.cc',
         'src/core/lib/debug/stats_data.cc',
         'src/core/lib/debug/trace.cc',
+        'src/core/lib/event_engine/slice_allocator.cc',
+        'src/core/lib/event_engine/sockaddr.cc',
         'src/core/lib/http/format_request.cc',
         'src/core/lib/http/httpcli.cc',
         'src/core/lib/http/httpcli_security_connector.cc',
@@ -796,8 +830,6 @@
         'src/core/lib/iomgr/is_epollexclusive_available.cc',
         'src/core/lib/iomgr/load_file.cc',
         'src/core/lib/iomgr/lockfree_event.cc',
-        'src/core/lib/iomgr/parse_address.cc',
-        'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
         'src/core/lib/iomgr/polling_entity.cc',
         'src/core/lib/iomgr/pollset.cc',
         'src/core/lib/iomgr/pollset_custom.cc',
@@ -811,7 +843,6 @@
         'src/core/lib/iomgr/resolve_address_posix.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
         'src/core/lib/iomgr/resource_quota.cc',
-        'src/core/lib/iomgr/sockaddr_utils.cc',
         'src/core/lib/iomgr/socket_factory_posix.cc',
         'src/core/lib/iomgr/socket_mutator.cc',
         'src/core/lib/iomgr/socket_utils_common_posix.cc',
@@ -854,8 +885,7 @@
         'src/core/lib/json/json_reader.cc',
         'src/core/lib/json/json_util.cc',
         'src/core/lib/json/json_writer.cc',
-        'src/core/lib/security/authorization/authorization_engine.cc',
-        'src/core/lib/security/authorization/evaluate_args.cc',
+        'src/core/lib/matchers/matchers.cc',
         'src/core/lib/security/context/security_context.cc',
         'src/core/lib/security/credentials/alts/alts_credentials.cc',
         'src/core/lib/security/credentials/alts/check_gcp_environment.cc',
@@ -984,9 +1014,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/csharp/ext/grpc_csharp_ext.c',
@@ -996,17 +1023,13 @@
       'target_name': 'grpc_test_util',
       'type': 'static_library',
       'dependencies': [
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
-        'absl/debugging:symbolize',
-        'absl/debugging:stacktrace',
         'absl/debugging:failure_signal_handler',
+        'absl/debugging:stacktrace',
+        'absl/debugging:symbolize',
+        'grpc',
       ],
       'sources': [
         'test/core/util/cmdline.cc',
-        'test/core/util/eval_args_mock_endpoint.cc',
         'test/core/util/fuzzer_util.cc',
         'test/core/util/grpc_profiler.cc',
         'test/core/util/histogram.cc',
@@ -1034,17 +1057,13 @@
       'target_name': 'grpc_test_util_unsecure',
       'type': 'static_library',
       'dependencies': [
-        'grpc_unsecure',
-        'gpr',
-        'address_sorting',
-        'upb',
-        'absl/debugging:symbolize',
-        'absl/debugging:stacktrace',
         'absl/debugging:failure_signal_handler',
+        'absl/debugging:stacktrace',
+        'absl/debugging:symbolize',
+        'grpc_unsecure',
       ],
       'sources': [
         'test/core/util/cmdline.cc',
-        'test/core/util/eval_args_mock_endpoint.cc',
         'test/core/util/fuzzer_util.cc',
         'test/core/util/grpc_profiler.cc',
         'test/core/util/histogram.cc',
@@ -1071,15 +1090,11 @@
       'target_name': 'grpc_unsecure',
       'type': 'static_library',
       'dependencies': [
+        'absl/container:flat_hash_map',
+        'absl/container:inlined_vector',
+        'absl/status:statusor',
         'gpr',
         'address_sorting',
-        'upb',
-        'absl/types:optional',
-        'absl/strings:strings',
-        'absl/status:statusor',
-        'absl/status:status',
-        'absl/container:inlined_vector',
-        'absl/container:flat_hash_map',
       ],
       'sources': [
         'src/core/ext/filters/census/grpc_context.cc',
@@ -1127,6 +1142,8 @@
         'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
         'src/core/ext/filters/client_channel/resolver_registry.cc',
         'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
+        'src/core/ext/filters/client_channel/retry_filter.cc',
+        'src/core/ext/filters/client_channel/retry_service_config.cc',
         'src/core/ext/filters/client_channel/retry_throttle.cc',
         'src/core/ext/filters/client_channel/server_address.cc',
         'src/core/ext/filters/client_channel/service_config.cc',
@@ -1136,6 +1153,8 @@
         'src/core/ext/filters/client_channel/subchannel_pool_interface.cc',
         'src/core/ext/filters/client_idle/client_idle_filter.cc',
         'src/core/ext/filters/deadline/deadline_filter.cc',
+        'src/core/ext/filters/fault_injection/fault_injection_filter.cc',
+        'src/core/ext/filters/fault_injection/service_config_parser.cc',
         'src/core/ext/filters/http/client/http_client_filter.cc',
         'src/core/ext/filters/http/client_authority_filter.cc',
         'src/core/ext/filters/http/http_filters_plugin.cc',
@@ -1179,21 +1198,12 @@
         'src/core/ext/transport/chttp2/transport/writing.cc',
         'src/core/ext/transport/inproc/inproc_plugin.cc',
         'src/core/ext/transport/inproc/inproc_transport.cc',
-        'src/core/ext/upb-generated/google/api/annotations.upb.c',
-        'src/core/ext/upb-generated/google/api/expr/v1alpha1/checked.upb.c',
-        'src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c',
-        'src/core/ext/upb-generated/google/api/http.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/any.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/duration.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/empty.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/struct.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c',
-        'src/core/ext/upb-generated/google/rpc/status.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c',
         'src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c',
         'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c',
         'src/core/ext/upb-generated/validate/validate.upb.c',
+        'src/core/lib/address_utils/parse_address.cc',
+        'src/core/lib/address_utils/sockaddr_utils.cc',
         'src/core/lib/avl/avl.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
@@ -1216,6 +1226,8 @@
         'src/core/lib/debug/stats.cc',
         'src/core/lib/debug/stats_data.cc',
         'src/core/lib/debug/trace.cc',
+        'src/core/lib/event_engine/slice_allocator.cc',
+        'src/core/lib/event_engine/sockaddr.cc',
         'src/core/lib/http/format_request.cc',
         'src/core/lib/http/httpcli.cc',
         'src/core/lib/http/parser.cc',
@@ -1260,8 +1272,6 @@
         'src/core/lib/iomgr/is_epollexclusive_available.cc',
         'src/core/lib/iomgr/load_file.cc',
         'src/core/lib/iomgr/lockfree_event.cc',
-        'src/core/lib/iomgr/parse_address.cc',
-        'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
         'src/core/lib/iomgr/polling_entity.cc',
         'src/core/lib/iomgr/pollset.cc',
         'src/core/lib/iomgr/pollset_custom.cc',
@@ -1275,7 +1285,6 @@
         'src/core/lib/iomgr/resolve_address_posix.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
         'src/core/lib/iomgr/resource_quota.cc',
-        'src/core/lib/iomgr/sockaddr_utils.cc',
         'src/core/lib/iomgr/socket_factory_posix.cc',
         'src/core/lib/iomgr/socket_mutator.cc',
         'src/core/lib/iomgr/socket_utils_common_posix.cc',
@@ -1366,14 +1375,10 @@
       'target_name': 'benchmark_helpers',
       'type': 'static_library',
       'dependencies': [
-        'grpc_test_util_unsecure',
-        'grpc++_unsecure',
-        'grpc_unsecure',
-        'grpc++_test_config',
-        'gpr',
-        'address_sorting',
-        'upb',
         'benchmark',
+        'grpc++_unsecure',
+        'grpc_test_util_unsecure',
+        'grpc++_test_config',
       ],
       'sources': [
         'src/proto/grpc/testing/echo.proto',
@@ -1387,9 +1392,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/cpp/client/channel_cc.cc',
@@ -1449,10 +1451,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc++',
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/cpp/common/alts_context.cc',
@@ -1464,13 +1462,8 @@
       'type': 'static_library',
       'dependencies': [
         'grpc++',
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
-        'src/proto/grpc/status/status.proto',
         'src/cpp/util/error_details.cc',
       ],
     },
@@ -1479,10 +1472,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc++',
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/proto/grpc/reflection/v1alpha/reflection.proto',
@@ -1495,10 +1484,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc++',
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/cpp/client/channel_test_peer.cc',
@@ -1508,8 +1493,8 @@
       'target_name': 'grpc++_test_config',
       'type': 'static_library',
       'dependencies': [
-        'gpr',
         'absl/flags:parse',
+        'gpr',
       ],
       'sources': [
         'test/cpp/util/test_config_cc.cc',
@@ -1519,13 +1504,9 @@
       'target_name': 'grpc++_test_util',
       'type': 'static_library',
       'dependencies': [
-        'grpc_test_util',
-        'grpc++',
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
         'absl/flags:flag',
+        'grpc++',
+        'grpc_test_util',
       ],
       'sources': [
         'test/core/end2end/data/client_certs.cc',
@@ -1544,9 +1525,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc_unsecure',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/cpp/client/channel_cc.cc',
@@ -1611,10 +1589,6 @@
       'type': 'static_library',
       'dependencies': [
         'grpc++',
-        'grpc',
-        'gpr',
-        'address_sorting',
-        'upb',
       ],
       'sources': [
         'src/proto/grpc/channelz/channelz.proto',
@@ -1670,6 +1644,7 @@
         'third_party/boringssl-with-bazel/src/crypto/bio/printf.c',
         'third_party/boringssl-with-bazel/src/crypto/bio/socket.c',
         'third_party/boringssl-with-bazel/src/crypto/bio/socket_helper.c',
+        'third_party/boringssl-with-bazel/src/crypto/blake2/blake2.c',
         'third_party/boringssl-with-bazel/src/crypto/bn_extra/bn_asn1.c',
         'third_party/boringssl-with-bazel/src/crypto/bn_extra/convert.c',
         'third_party/boringssl-with-bazel/src/crypto/buf/buf.c',
@@ -1694,6 +1669,7 @@
         'third_party/boringssl-with-bazel/src/crypto/conf/conf.c',
         'third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-fuchsia.c',
         'third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-linux.c',
+        'third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-win.c',
         'third_party/boringssl-with-bazel/src/crypto/cpu-arm-linux.c',
         'third_party/boringssl-with-bazel/src/crypto/cpu-arm.c',
         'third_party/boringssl-with-bazel/src/crypto/cpu-intel.c',
@@ -1701,10 +1677,8 @@
         'third_party/boringssl-with-bazel/src/crypto/crypto.c',
         'third_party/boringssl-with-bazel/src/crypto/curve25519/curve25519.c',
         'third_party/boringssl-with-bazel/src/crypto/curve25519/spake25519.c',
-        'third_party/boringssl-with-bazel/src/crypto/dh/check.c',
-        'third_party/boringssl-with-bazel/src/crypto/dh/dh.c',
-        'third_party/boringssl-with-bazel/src/crypto/dh/dh_asn1.c',
-        'third_party/boringssl-with-bazel/src/crypto/dh/params.c',
+        'third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c',
+        'third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c',
         'third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c',
         'third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c',
         'third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c',
@@ -1735,7 +1709,6 @@
         'third_party/boringssl-with-bazel/src/crypto/ex_data.c',
         'third_party/boringssl-with-bazel/src/crypto/fipsmodule/bcm.c',
         'third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c',
-        'third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c',
         'third_party/boringssl-with-bazel/src/crypto/hkdf/hkdf.c',
         'third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c',
         'third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c',
@@ -1763,6 +1736,7 @@
         'third_party/boringssl-with-bazel/src/crypto/rand_extra/deterministic.c',
         'third_party/boringssl-with-bazel/src/crypto/rand_extra/forkunsafe.c',
         'third_party/boringssl-with-bazel/src/crypto/rand_extra/fuchsia.c',
+        'third_party/boringssl-with-bazel/src/crypto/rand_extra/passive.c',
         'third_party/boringssl-with-bazel/src/crypto/rand_extra/rand_extra.c',
         'third_party/boringssl-with-bazel/src/crypto/rand_extra/windows.c',
         'third_party/boringssl-with-bazel/src/crypto/rc4/rc4.c',
@@ -1801,7 +1775,6 @@
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c',
-        'third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c',
         'third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c',
@@ -1866,6 +1839,7 @@
         'third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc',
         'third_party/boringssl-with-bazel/src/ssl/dtls_method.cc',
         'third_party/boringssl-with-bazel/src/ssl/dtls_record.cc',
+        'third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc',
         'third_party/boringssl-with-bazel/src/ssl/handoff.cc',
         'third_party/boringssl-with-bazel/src/ssl/handshake.cc',
         'third_party/boringssl-with-bazel/src/ssl/handshake_client.cc',
@@ -1977,27 +1951,13 @@
         'third_party/upb/upb/decode.c',
         'third_party/upb/upb/def.c',
         'third_party/upb/upb/encode.c',
-        'third_party/upb/upb/json_decode.c',
-        'third_party/upb/upb/json_encode.c',
         'third_party/upb/upb/msg.c',
         'third_party/upb/upb/reflection.c',
         'third_party/upb/upb/table.c',
         'third_party/upb/upb/text_encode.c',
         'third_party/upb/upb/upb.c',
-        'src/core/ext/upb-generated/google/protobuf/any.upb.c',
         'src/core/ext/upb-generated/google/protobuf/descriptor.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/duration.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/empty.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/struct.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/timestamp.upb.c',
-        'src/core/ext/upb-generated/google/protobuf/wrappers.upb.c',
-        'src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c',
         'src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c',
-        'src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c',
-        'src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c',
-        'src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.c',
-        'src/core/ext/upbdefs-generated/google/protobuf/timestamp.upbdefs.c',
-        'src/core/ext/upbdefs-generated/google/protobuf/wrappers.upbdefs.c',
       ],
     },
     {
diff --git a/grpc/include/grpc++/README.md b/grpc/include/grpc++/README.md
new file mode 100644
index 0000000..5842eb3
--- /dev/null
+++ b/grpc/include/grpc++/README.md
@@ -0,0 +1,7 @@
+# include/grpc++
+
+This was the original directory name for all C++ header files but it
+conflicted with the naming scheme required for some build systems. It
+is superseded by `include/grpcpp` but the old directory structure is
+still present to avoid breaking code that used the old include files.
+All new include files are only in `include/grpcpp`.
diff --git a/grpc/include/grpc/event_engine/README.md b/grpc/include/grpc/event_engine/README.md
new file mode 100644
index 0000000..b2d4fef
--- /dev/null
+++ b/grpc/include/grpc/event_engine/README.md
@@ -0,0 +1,38 @@
+# gRPC EventEngine
+
+An EventEngine handles all cross-platform I/O, task execution, and DNS
+resolution for gRPC. A default, cross-platform implementation is provided with
+gRPC, but part of the intent here is to provide an interface for external
+integrators to bring their own functionality. This allows for integration with
+external event loops, siloing I/O and task execution between channels or
+servers, and other custom integrations that were previously unsupported.
+
+*WARNING*: This is experimental code and is subject to change.
+
+## High level expectations of an EventEngine implementation
+
+### Provide their own I/O threads
+EventEngines are expected to internally create whatever threads are required to
+perform I/O and execute callbacks. For example, an EventEngine implementation
+may want to spawn separate thread pools for polling and callback execution.
+
+### Provisioning data buffers via Slice allocation
+At a high level, gRPC provides a `ResourceQuota` system that allows gRPC to
+reclaim memory and degrade gracefully when memory reaches application-defined
+thresholds. To enable this feature, the memory allocation of read/write buffers
+within an EventEngine must be acquired in the form of Slices from
+SliceAllocators. This is covered more fully in the gRFC and code.
+
+### Documentating expectations around callback execution
+Some callbacks may be expensive to run. EventEngines should decide on and
+document whether callback execution might block polling operations. This way,
+application developers can plan accordingly (e.g., run their expensive callbacks
+on a separate thread if necessary).
+
+### Handling concurrent usage
+Assume that gRPC may use an EventEngine concurrently across multiple threads.
+
+## TODO: documentation
+
+* Example usage
+* Link to gRFC
diff --git a/grpc/include/grpc/event_engine/channel_args.h b/grpc/include/grpc/event_engine/channel_args.h
new file mode 100644
index 0000000..d809b1f
--- /dev/null
+++ b/grpc/include/grpc/event_engine/channel_args.h
@@ -0,0 +1,28 @@
+// Copyright 2021 The 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_EVENT_ENGINE_CHANNEL_ARGS_H
+#define GRPC_EVENT_ENGINE_CHANNEL_ARGS_H
+
+#include <grpc/support/port_platform.h>
+
+namespace grpc_event_engine {
+namespace experimental {
+
+// TODO(hork): define
+class ChannelArgs;
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_CHANNEL_ARGS_H
diff --git a/grpc/include/grpc/event_engine/event_engine.h b/grpc/include/grpc/event_engine/event_engine.h
new file mode 100644
index 0000000..cdb5966
--- /dev/null
+++ b/grpc/include/grpc/event_engine/event_engine.h
@@ -0,0 +1,336 @@
+// Copyright 2021 The 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_EVENT_ENGINE_EVENT_ENGINE_H
+#define GRPC_EVENT_ENGINE_EVENT_ENGINE_H
+
+#include <grpc/support/port_platform.h>
+
+#include <functional>
+#include <vector>
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/time/time.h"
+
+#include "grpc/event_engine/channel_args.h"
+#include "grpc/event_engine/port.h"
+#include "grpc/event_engine/slice_allocator.h"
+
+// TODO(hork): explicitly define lifetimes and ownership of all objects.
+// TODO(hork): Define the Endpoint::Write metrics collection system
+
+namespace grpc_event_engine {
+namespace experimental {
+
+////////////////////////////////////////////////////////////////////////////////
+/// The EventEngine encapsulates all platform-specific behaviors related to low
+/// level network I/O, timers, asynchronous execution, and DNS resolution.
+///
+/// This interface allows developers to provide their own event management and
+/// network stacks. Motivating uses cases for supporting custom EventEngines
+/// include the ability to hook into external event loops, and using different
+/// EventEngine instances for each channel to better insulate network I/O and
+/// callback processing from other channels.
+///
+/// A default cross-platform EventEngine instance is provided by gRPC.
+///
+/// LIFESPAN AND OWNERSHIP
+///
+/// gRPC takes shared ownership of EventEngines via std::shared_ptrs to ensure
+/// that the engines remain available until they are no longer needed. Depending
+/// on the use case, engines may live until gRPC is shut down.
+///
+/// EXAMPLE USAGE (Not yet implemented)
+///
+/// Custom EventEngines can be specified per channel, and allow configuration
+/// for both clients and servers. To set a custom EventEngine for a client
+/// channel, you can do something like the following:
+///
+///    ChannelArguments args;
+///    std::shared_ptr<EventEngine> engine = std::make_shared<MyEngine>(...);
+///    args.SetEventEngine(engine);
+///    MyAppClient client(grpc::CreateCustomChannel(
+///        "localhost:50051", grpc::InsecureChannelCredentials(), args));
+///
+/// A gRPC server can use a custom EventEngine by calling the
+/// ServerBuilder::SetEventEngine method:
+///
+///    ServerBuilder builder;
+///    std::shared_ptr<EventEngine> engine = std::make_shared<MyEngine>(...);
+///    builder.SetEventEngine(engine);
+///    std::unique_ptr<Server> server(builder.BuildAndStart());
+///    server->Wait();
+///
+////////////////////////////////////////////////////////////////////////////////
+class EventEngine {
+ public:
+  /// A basic callable function. The first argument to all callbacks is an
+  /// absl::Status indicating the status of the operation associated with this
+  /// callback. Each EventEngine method that takes a callback parameter, defines
+  /// the expected sets and meanings of statuses for that use case.
+  using Callback = std::function<void(absl::Status)>;
+  /// A callback handle, used to cancel a callback.
+  struct TaskHandle {
+    intptr_t key;
+  };
+  /// A thin wrapper around a platform-specific sockaddr type. A sockaddr struct
+  /// exists on all platforms that gRPC supports.
+  ///
+  /// Platforms are expected to provide definitions for:
+  /// * sockaddr
+  /// * sockaddr_in
+  /// * sockaddr_in6
+  class ResolvedAddress {
+   public:
+    static constexpr socklen_t MAX_SIZE_BYTES = 128;
+
+    ResolvedAddress(const sockaddr* address, socklen_t size);
+    const struct sockaddr* address() const;
+    socklen_t size() const;
+
+   private:
+    char address_[MAX_SIZE_BYTES];
+    socklen_t size_;
+  };
+
+  /// An Endpoint represents one end of a connection between a gRPC client and
+  /// server. Endpoints are created when connections are established, and
+  /// Endpoint operations are gRPC's primary means of communication.
+  ///
+  /// Endpoints must use the provided SliceAllocator for all data buffer memory
+  /// allocations. gRPC allows applications to set memory constraints per
+  /// Channel or Server, and the implementation depends on all dynamic memory
+  /// allocation being handled by the quota system.
+  class Endpoint {
+   public:
+    /// The Endpoint destructor is responsible for shutting down all connections
+    /// and invoking all pending read or write callbacks with an error status.
+    virtual ~Endpoint() = default;
+    /// Read data from the Endpoint.
+    ///
+    /// When data is available on the connection, that data is moved into the
+    /// \a buffer, and the \a on_read callback is called. The caller must ensure
+    /// that the callback has access to the buffer when executed later.
+    /// Ownership of the buffer is not transferred. Valid slices *may* be placed
+    /// into the buffer even if the callback is invoked with a non-OK Status.
+    ///
+    /// For failed read operations, implementations should pass the appropriate
+    /// statuses to \a on_read. For example, callbacks might expect to receive
+    /// DEADLINE_EXCEEDED when the deadline is exceeded, and CANCELLED on
+    /// endpoint shutdown.
+    virtual void Read(Callback on_read, SliceBuffer* buffer,
+                      absl::Time deadline) = 0;
+    /// Write data out on the connection.
+    ///
+    /// \a on_writable is called when the connection is ready for more data. The
+    /// Slices within the \a data buffer may be mutated at will by the Endpoint
+    /// until \a on_writable is called. The \a data SliceBuffer will remain
+    /// valid after calling \a Write, but its state is otherwise undefined.
+    ///
+    /// For failed write operations, implementations should pass the appropriate
+    /// statuses to \a on_writable. For example, callbacks might expect to
+    /// receive DEADLINE_EXCEEDED when the deadline is exceeded, and CANCELLED
+    /// on endpoint shutdown.
+    virtual void Write(Callback on_writable, SliceBuffer* data,
+                       absl::Time deadline) = 0;
+    // TODO(hork): define status codes for the callback
+    // TODO(hork): define cleanup operations, lifetimes, responsibilities.
+    virtual void Close(Callback on_close) = 0;
+    /// These methods return an address in the format described in DNSResolver.
+    /// The returned values are owned by the Endpoint and are expected to remain
+    /// valid for the life of the Endpoint.
+    virtual const ResolvedAddress* GetPeerAddress() const = 0;
+    virtual const ResolvedAddress* GetLocalAddress() const = 0;
+  };
+
+  /// Called when a new connection is established.
+  ///
+  /// If the connection attempt was not successful, implementations should pass
+  /// the appropriate statuses to this callback. For example, callbacks might
+  /// expect to receive DEADLINE_EXCEEDED statuses when appropriate, or
+  /// CANCELLED statuses on EventEngine shutdown.
+  using OnConnectCallback =
+      std::function<void(absl::StatusOr<std::unique_ptr<Endpoint>>)>;
+
+  /// An EventEngine Listener listens for incoming connection requests from gRPC
+  /// clients and initiates request processing once connections are established.
+  class Listener {
+   public:
+    /// Called when the listener has accepted a new client connection.
+    using AcceptCallback = std::function<void(std::unique_ptr<Endpoint>)>;
+    virtual ~Listener() = default;
+    /// Bind an address/port to this Listener.
+    ///
+    /// It is expected that multiple addresses/ports can be bound to this
+    /// Listener before Listener::Start has been called. Returns either the
+    /// bound port or an appropriate error status.
+    virtual absl::StatusOr<int> Bind(const ResolvedAddress& addr) = 0;
+    virtual absl::Status Start() = 0;
+  };
+
+  /// Factory method to create a network listener / server.
+  ///
+  /// Once a \a Listener is created and started, the \a on_accept callback will
+  /// be called once asynchronously for each established connection. Note that
+  /// unlike other callbacks, there is no status code parameter since the
+  /// callback will only be called in healthy scenarios where connections can be
+  /// accepted.
+  ///
+  /// This method may return a non-OK status immediately if an error was
+  /// encountered in any synchronous steps required to create the Listener. In
+  /// this case, \a on_shutdown will never be called.
+  ///
+  /// If this method returns a Listener, then \a on_shutdown will be invoked
+  /// exactly once, when the Listener is shut down. The status passed to it will
+  /// indicate if there was a problem during shutdown.
+  ///
+  /// The provided \a SliceAllocatorFactory is used to create \a SliceAllocators
+  /// for Endpoint construction.
+  virtual absl::StatusOr<std::unique_ptr<Listener>> CreateListener(
+      Listener::AcceptCallback on_accept, Callback on_shutdown,
+      const ChannelArgs& args,
+      SliceAllocatorFactory slice_allocator_factory) = 0;
+  /// Creates a client network connection to a remote network listener.
+  ///
+  /// \a Connect may return an error status immediately if there was a failure
+  /// in the synchronous part of establishing a connection. In that event, the
+  /// \a on_connect callback *will not* have been executed. Otherwise, it is
+  /// expected that the \a on_connect callback will be asynchronously executed
+  /// exactly once by the EventEngine.
+  ///
+  /// Implementation Note: it is important that the \a slice_allocator be used
+  /// for all read/write buffer allocations in the EventEngine implementation.
+  /// This allows gRPC's \a ResourceQuota system to monitor and control memory
+  /// usage with graceful degradation mechanisms. Please see the \a
+  /// SliceAllocator API for more information.
+  virtual absl::Status Connect(OnConnectCallback on_connect,
+                               const ResolvedAddress& addr,
+                               const ChannelArgs& args,
+                               SliceAllocator slice_allocator,
+                               absl::Time deadline) = 0;
+
+  /// The DNSResolver that provides asynchronous resolution.
+  class DNSResolver {
+   public:
+    /// A task handle for DNS Resolution requests.
+    struct LookupTaskHandle {
+      intptr_t key;
+    };
+    /// A DNS SRV record type.
+    struct SRVRecord {
+      std::string host;
+      int port = 0;
+      int priority = 0;
+      int weight = 0;
+    };
+    /// Called with the collection of sockaddrs that were resolved from a given
+    /// target address.
+    using LookupHostnameCallback =
+        std::function<void(absl::StatusOr<std::vector<ResolvedAddress>>)>;
+    /// Called with a collection of SRV records.
+    using LookupSRVCallback =
+        std::function<void(absl::StatusOr<std::vector<SRVRecord>>)>;
+    /// Called with the result of a TXT record lookup
+    using LookupTXTCallback = std::function<void(absl::StatusOr<std::string>)>;
+
+    virtual ~DNSResolver() = default;
+
+    /// Asynchronously resolve an address.
+    ///
+    /// \a default_port may be a non-numeric named service port, and will only
+    /// be used if \a address does not already contain a port component.
+    ///
+    /// When the lookup is complete, the \a on_resolve callback will be invoked
+    /// with a status indicating the success or failure of the lookup.
+    /// Implementations should pass the appropriate statuses to the callback.
+    /// For example, callbacks might expect to receive DEADLINE_EXCEEDED when
+    /// the deadline is exceeded or CANCELLED if the lookup was cancelled.
+    virtual LookupTaskHandle LookupHostname(LookupHostnameCallback on_resolve,
+                                            absl::string_view address,
+                                            absl::string_view default_port,
+                                            absl::Time deadline) = 0;
+    /// Asynchronously perform an SRV record lookup.
+    ///
+    /// \a on_resolve has the same meaning and expectations as \a
+    /// LookupHostname's \a on_resolve callback.
+    virtual LookupTaskHandle LookupSRV(LookupSRVCallback on_resolve,
+                                       absl::string_view name,
+                                       absl::Time deadline) = 0;
+    /// Asynchronously perform a TXT record lookup.
+    ///
+    /// \a on_resolve has the same meaning and expectations as \a
+    /// LookupHostname's \a on_resolve callback.
+    virtual LookupTaskHandle LookupTXT(LookupTXTCallback on_resolve,
+                                       absl::string_view name,
+                                       absl::Time deadline) = 0;
+    /// Cancel an asynchronous lookup operation.
+    virtual void TryCancelLookup(LookupTaskHandle handle) = 0;
+  };
+
+  virtual ~EventEngine() = default;
+
+  // TODO(hork): define return status codes
+  /// Retrieves an instance of a DNSResolver.
+  virtual absl::StatusOr<std::unique_ptr<DNSResolver>> GetDNSResolver() = 0;
+
+  /// Intended for future expansion of Task run functionality.
+  struct RunOptions {};
+  // TODO(hork): consider recommendation to make TaskHandle an output arg
+  /// Run a callback as soon as possible.
+  ///
+  /// The \a fn callback's \a status argument is used to indicate whether it was
+  /// executed normally. For example, the status may be CANCELLED if
+  /// \a TryCancel was called, or if the EventEngine is being shut down.
+  virtual TaskHandle Run(Callback fn, RunOptions opts) = 0;
+  /// Synonymous with scheduling an alarm to run at time \a when.
+  ///
+  /// The callback \a fn will execute when either when time \a when arrives
+  /// (receiving status OK), or when the \a fn is cancelled (reveiving status
+  /// CANCELLED). The callback is guaranteed to be called exactly once.
+  virtual TaskHandle RunAt(absl::Time when, Callback fn, RunOptions opts) = 0;
+  /// Immediately tries to cancel a callback.
+  /// Note that this is a "best effort" cancellation. No guarantee is made that
+  /// the callback will be cancelled, the call could be in any stage.
+  ///
+  /// There are three scenarios in which we may cancel a scheduled function:
+  ///   1. We cancel the execution before it has run.
+  ///   2. The callback has already run.
+  ///   3. We can't cancel it because it is "in flight".
+  ///
+  /// In all cases, the cancellation is still considered successful, the
+  /// callback will be run exactly once from either cancellation or from its
+  /// activation.
+  virtual void TryCancel(TaskHandle handle) = 0;
+  /// Immediately run all callbacks with status indicating the shutdown. Every
+  /// EventEngine is expected to shut down exactly once. No new callbacks/tasks
+  /// should be scheduled after shutdown has begun, no new connections should be
+  /// created.
+  ///
+  /// If the \a on_shutdown_complete callback is given a non-OK status, errors
+  /// are expected to be unrecoverable. For example, an implementation could
+  /// warn callers about leaks if memory cannot be freed within a certain
+  /// timeframe.
+  virtual void Shutdown(Callback on_shutdown_complete) = 0;
+};
+
+/// Lazily instantiate and return a default global EventEngine instance if no
+/// custom instance is provided. If a custom EventEngine is provided for every
+/// channel/server via ChannelArgs, this method should never be called, and the
+/// default instance will never be instantiated.
+std::shared_ptr<EventEngine> GetDefaultEventEngine();
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_EVENT_ENGINE_H
diff --git a/grpc/include/grpc/event_engine/port.h b/grpc/include/grpc/event_engine/port.h
new file mode 100644
index 0000000..c24b8f9
--- /dev/null
+++ b/grpc/include/grpc/event_engine/port.h
@@ -0,0 +1,39 @@
+// Copyright 2021 The 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_EVENT_ENGINE_PORT_H
+#define GRPC_EVENT_ENGINE_PORT_H
+
+#include <grpc/support/port_platform.h>
+
+// Platform-specific sockaddr includes
+#ifdef GRPC_UV
+#include <uv.h>
+#elif defined(GPR_ANDROID) || defined(GPR_LINUX) || defined(GPR_APPLE) ||   \
+    defined(GPR_FREEBSD) || defined(GPR_OPENBSD) || defined(GPR_SOLARIS) || \
+    defined(GPR_AIX) || defined(GPR_NACL) || defined(GPR_FUCHSIA) ||        \
+    defined(GRPC_POSIX_SOCKET)
+#define GRPC_EVENT_ENGINE_POSIX
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#elif defined(GPR_WINDOWS)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+// must be included after the above
+#include <mswsock.h>
+#else
+#error UNKNOWN PLATFORM
+#endif
+
+#endif  // GRPC_EVENT_ENGINE_PORT_H
diff --git a/grpc/include/grpc/event_engine/slice_allocator.h b/grpc/include/grpc/event_engine/slice_allocator.h
new file mode 100644
index 0000000..4370cd5
--- /dev/null
+++ b/grpc/include/grpc/event_engine/slice_allocator.h
@@ -0,0 +1,81 @@
+// Copyright 2021 The 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_EVENT_ENGINE_SLICE_ALLOCATOR_H
+#define GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include <functional>
+
+#include "absl/status/status.h"
+
+// forward-declaring an internal struct, not used publicly.
+struct grpc_resource_quota;
+struct grpc_resource_user;
+
+namespace grpc_event_engine {
+namespace experimental {
+
+// TODO(nnoble): forward declared here, needs definition.
+class SliceBuffer;
+
+class SliceAllocator {
+ public:
+  // gRPC-internal constructor
+  explicit SliceAllocator(grpc_resource_user* user);
+  // Not copyable
+  SliceAllocator(SliceAllocator& other) = delete;
+  SliceAllocator& operator=(const SliceAllocator& other) = delete;
+  // Moveable
+  SliceAllocator(SliceAllocator&& other) = default;
+  SliceAllocator& operator=(SliceAllocator&& other) = default;
+  ~SliceAllocator();
+
+  using AllocateCallback =
+      std::function<void(absl::Status, SliceBuffer* buffer)>;
+  // TODO(hork): explain what happens under resource exhaustion.
+  /// Requests \a size bytes from gRPC, and populates \a dest with the allocated
+  /// slices. Ownership of the \a SliceBuffer is not transferred.
+  absl::Status Allocate(size_t size, SliceBuffer* dest,
+                        SliceAllocator::AllocateCallback cb);
+
+ private:
+  grpc_resource_user* resource_user_;
+};
+
+class SliceAllocatorFactory {
+ public:
+  // gRPC-internal constructor
+  explicit SliceAllocatorFactory(grpc_resource_quota* quota);
+  // Not copyable
+  SliceAllocatorFactory(SliceAllocatorFactory& other) = delete;
+  SliceAllocatorFactory& operator=(const SliceAllocatorFactory& other) = delete;
+  // Moveable
+  SliceAllocatorFactory(SliceAllocatorFactory&& other) = default;
+  SliceAllocatorFactory& operator=(SliceAllocatorFactory&& other) = default;
+  ~SliceAllocatorFactory();
+
+  /// On Endpoint creation, call \a CreateSliceAllocator with the name of the
+  /// endpoint peer (a URI string, most likely). Note: \a peer_name must outlive
+  /// the Endpoint.
+  SliceAllocator CreateSliceAllocator(absl::string_view peer_name);
+
+ private:
+  grpc_resource_quota* resource_quota_;
+};
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H
diff --git a/grpc/include/grpc/grpc.h b/grpc/include/grpc/grpc.h
index 09bb106..f4408e1 100644
--- a/grpc/include/grpc/grpc.h
+++ b/grpc/include/grpc/grpc.h
@@ -411,10 +411,20 @@
                                                    grpc_completion_queue* cq,
                                                    void* reserved);
 
+// There might be more methods added later, so users should take care to memset
+// this to 0 before using it.
+typedef struct {
+  void (*on_serving_status_update)(void* user_data, const char* uri,
+                                   grpc_status_code code,
+                                   const char* error_message);
+  void* user_data;
+} grpc_server_xds_status_notifier;
+
 typedef struct grpc_server_config_fetcher grpc_server_config_fetcher;
 
 /** EXPERIMENTAL.  Creates an xDS config fetcher. */
-GRPCAPI grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create();
+GRPCAPI grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create(
+    grpc_server_xds_status_notifier notifier, const grpc_channel_args* args);
 
 /** EXPERIMENTAL.  Destroys a config fetcher. */
 GRPCAPI void grpc_server_config_fetcher_destroy(
@@ -495,6 +505,10 @@
 GRPCAPI void grpc_resource_quota_set_max_threads(
     grpc_resource_quota* resource_quota, int new_max_threads);
 
+/** EXPERIMENTAL.  Dumps xDS configs as a serialized ClientConfig proto.
+    The full name of the proto is envoy.service.status.v3.ClientConfig. */
+GRPCAPI grpc_slice grpc_dump_xds_configs();
+
 /** Fetch a vtable for a grpc_channel_arg that points to a grpc_resource_quota
  */
 GRPCAPI const grpc_arg_pointer_vtable* grpc_resource_quota_arg_vtable(void);
diff --git a/grpc/include/grpc/grpc_security.h b/grpc/include/grpc/grpc_security.h
index c1d7295..b5dafe1 100644
--- a/grpc/include/grpc/grpc_security.h
+++ b/grpc/include/grpc/grpc_security.h
@@ -856,8 +856,8 @@
 
 /**
  * Sets the options of whether to request and verify client certs. This should
- * be called only on the server side. It returns 1 on success and 0 on failure.
- * It is used for experimental purpose for now and subject to change.
+ * be called only on the server side. It is used for experimental purpose for
+ * now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_set_cert_request_type(
     grpc_tls_credentials_options* options,
@@ -868,8 +868,7 @@
  * hostname check, etc. This should be called only on the client side. If
  * |server_verification_option| is not GRPC_TLS_SERVER_VERIFICATION, use of a
  * custom authorization check (grpc_tls_server_authorization_check_config) is
- * mandatory. It returns 1 on success and 0 on failure. It is used for
- * experimental purpose for now and subject to change.
+ * mandatory. It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_set_server_verification_option(
     grpc_tls_credentials_options* options,
@@ -878,7 +877,6 @@
 /**
  * Sets the credential provider in the options.
  * The |options| will implicitly take a new ref to the |provider|.
- * It returns 1 on success and 0 on failure.
  * It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_set_certificate_provider(
@@ -887,8 +885,14 @@
 
 /**
  * If set, gRPC stack will keep watching the root certificates with
- * name |root_cert_name|. It returns 1 on success and 0 on failure. It is used
- * for experimental purpose for now and subject to change.
+ * name |root_cert_name|.
+ * If this is not set on the client side, we will use the root certificates
+ * stored in the default system location, since client side must provide root
+ * certificates in TLS.
+ * If this is not set on the server side, we will not watch any root certificate
+ * updates, and assume no root certificates needed for the server(single-side
+ * TLS). Default root certs on the server side is not supported.
+ * It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_watch_root_certs(
     grpc_tls_credentials_options* options);
@@ -903,8 +907,9 @@
 
 /**
  * If set, gRPC stack will keep watching the identity key-cert pairs
- * with name |identity_cert_name|. It returns 1 on success and 0 on failure. It
- * is used for experimental purpose for now and subject to change.
+ * with name |identity_cert_name|.
+ * This is required on the server side, and optional on the client side.
+ * It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_watch_identity_key_cert_pairs(
     grpc_tls_credentials_options* options);
@@ -920,8 +925,8 @@
 /**
  * Sets the configuration for a custom authorization check performed at the end
  * of the handshake. The |options| will implicitly take a new ref to the
- * |config|. It returns 1 on success and 0 on failure. It is used for
- * experimental purpose for now and subject to change.
+ * |config|.
+ * It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_set_server_authorization_check_config(
     grpc_tls_credentials_options* options,
diff --git a/grpc/include/grpc/grpc_security_constants.h b/grpc/include/grpc/grpc_security_constants.h
index a62f767..4d7f078 100644
--- a/grpc/include/grpc/grpc_security_constants.h
+++ b/grpc/include/grpc/grpc_security_constants.h
@@ -29,10 +29,24 @@
 #define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
 #define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
 #define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert"
+// Please note that internally, we just faithfully pass whatever value we got by
+// calling SSL_get_peer_cert_chain() in OpenSSL/BoringSSL. This will mean in
+// OpenSSL, the following conditions might apply:
+// 1. On the client side, this property returns the full certificate chain. On
+// the server side, this property will return the certificate chain without the
+// leaf certificate. Application can use GRPC_X509_PEM_CERT_PROPERTY_NAME to
+// get the peer leaf certificate.
+// 2. If the session is resumed, this property could be empty for OpenSSL (but
+// not for BoringSSL).
+// For more, please refer to the official OpenSSL manual:
+// https://www.openssl.org/docs/man1.1.0/man3/SSL_get_peer_cert_chain.html.
 #define GRPC_X509_PEM_CERT_CHAIN_PROPERTY_NAME "x509_pem_cert_chain"
 #define GRPC_SSL_SESSION_REUSED_PROPERTY "ssl_session_reused"
 #define GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME "security_level"
+#define GRPC_PEER_DNS_PROPERTY_NAME "peer_dns"
 #define GRPC_PEER_SPIFFE_ID_PROPERTY_NAME "peer_spiffe_id"
+#define GRPC_PEER_EMAIL_PROPERTY_NAME "peer_email"
+#define GRPC_PEER_IP_PROPERTY_NAME "peer_ip"
 
 /** Environment variable that points to the default SSL roots file. This file
    must be a PEM encoded file with all the roots such as the one that can be
diff --git a/grpc/include/grpc/impl/codegen/grpc_types.h b/grpc/include/grpc/impl/codegen/grpc_types.h
index d67a9e9..9cf6d83 100644
--- a/grpc/include/grpc/impl/codegen/grpc_types.h
+++ b/grpc/include/grpc/impl/codegen/grpc_types.h
@@ -353,6 +353,17 @@
 /* Timeout in milliseconds to use for calls to the grpclb load balancer.
    If 0 or unset, the balancer calls will have no deadline. */
 #define GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS "grpc.grpclb_call_timeout_ms"
+/* Specifies the xDS bootstrap config as a JSON string.
+   FOR TESTING PURPOSES ONLY -- DO NOT USE IN PRODUCTION.
+   This option allows controlling the bootstrap configuration on a
+   per-channel basis, which is useful in tests.  However, this results
+   in having a separate xDS client instance per channel rather than
+   using the global instance, which is not the intended way to use xDS.
+   Currently, this will (a) add unnecessary load on the xDS server and
+   (b) break use of CSDS, and there may be additional side effects in
+   the future. */
+#define GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG \
+  "grpc.TEST_ONLY_DO_NOT_USE_IN_PROD.xds_bootstrap_config"
 /* Timeout in milliseconds to wait for the serverlist from the grpclb load
    balancer before using fallback backend addresses from the resolver.
    If 0, enter fallback mode immediately. Default value is 10000. */
diff --git a/grpc/include/grpc/impl/codegen/port_platform.h b/grpc/include/grpc/impl/codegen/port_platform.h
index c1bada1..387639b 100644
--- a/grpc/include/grpc/impl/codegen/port_platform.h
+++ b/grpc/include/grpc/impl/codegen/port_platform.h
@@ -39,6 +39,11 @@
 #endif
 #endif  // GPR_ABSEIL_SYNC
 
+/*
+ * Defines GRPC_ERROR_IS_ABSEIL_STATUS to use absl::Status for grpc_error_handle
+ */
+// #define GRPC_ERROR_IS_ABSEIL_STATUS 1
+
 /* Get windows.h included everywhere (we need it) */
 #if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
 #ifndef WIN32_LEAN_AND_MEAN
@@ -366,6 +371,7 @@
 #define GPR_ARCH_32 1
 #endif /* _LP64 */
 #elif defined(__Fuchsia__)
+#define GRPC_ARES 0
 #define GPR_FUCHSIA 1
 #define GPR_ARCH_64 1
 #define GPR_PLATFORM_STRING "fuchsia"
@@ -387,6 +393,7 @@
 #define GPR_POSIX_TIME 1
 #define GPR_HAS_PTHREAD_H 1
 #define GPR_GETPID_IN_UNISTD_H 1
+#define GRPC_ROOT_PEM_PATH "/config/ssl/cert.pem"
 #else
 #error "Could not auto-detect platform"
 #endif
diff --git a/grpc/include/grpc/module.modulemap b/grpc/include/grpc/module.modulemap
index 06c1e97..40606e5 100644
--- a/grpc/include/grpc/module.modulemap
+++ b/grpc/include/grpc/module.modulemap
@@ -2,6 +2,15 @@
 framework module grpc {
   umbrella header "grpc.h"
 
+header "byte_buffer.h"
+  header "byte_buffer_reader.h"
+  header "census.h"
+  header "compression.h"
+  header "fork.h"
+  header "grpc.h"
+  header "grpc_posix.h"
+  header "grpc_security.h"
+  header "grpc_security_constants.h"
   header "impl/codegen/atm.h"
   header "impl/codegen/byte_buffer.h"
   header "impl/codegen/byte_buffer_reader.h"
@@ -19,6 +28,10 @@
   header "impl/codegen/sync.h"
   header "impl/codegen/sync_abseil.h"
   header "impl/codegen/sync_generic.h"
+  header "load_reporting.h"
+  header "slice.h"
+  header "slice_buffer.h"
+  header "status.h"
   header "support/alloc.h"
   header "support/atm.h"
   header "support/cpu.h"
@@ -31,22 +44,9 @@
   header "support/sync_generic.h"
   header "support/thd_id.h"
   header "support/time.h"
-  header "byte_buffer.h"
-  header "byte_buffer_reader.h"
-  header "census.h"
-  header "compression.h"
-  header "fork.h"
-  header "grpc.h"
-  header "grpc_posix.h"
-  header "grpc_security.h"
-  header "grpc_security_constants.h"
-  header "load_reporting.h"
-  header "slice.h"
-  header "slice_buffer.h"
-  header "status.h"
   header "support/workaround_list.h"
 
-  textual header "impl/codegen/atm_gcc_atomic.h"
+textual header "impl/codegen/atm_gcc_atomic.h"
   textual header "impl/codegen/atm_gcc_sync.h"
   textual header "impl/codegen/atm_windows.h"
   textual header "impl/codegen/sync_custom.h"
diff --git a/grpc/include/grpcpp/alarm.h b/grpc/include/grpcpp/alarm.h
index 1405590..6723e13 100644
--- a/grpc/include/grpcpp/alarm.h
+++ b/grpc/include/grpcpp/alarm.h
@@ -56,6 +56,10 @@
   /// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
   /// an event with tag \a tag will be added to \a cq. If the alarm expired, the
   /// event's success bit will be true, false otherwise (ie, upon cancellation).
+  //
+  // USAGE NOTE: This is frequently used to inject arbitrary tags into \a cq by
+  // setting an immediate deadline. Such usage allows synchronizing an external
+  // event with an application's \a grpc::CompletionQueue::Next loop.
   template <typename T>
   void Set(::grpc::CompletionQueue* cq, const T& deadline, void* tag) {
     SetInternal(cq, ::grpc::TimePoint<T>(deadline).raw_time(), tag);
diff --git a/grpc/include/grpcpp/channel.h b/grpc/include/grpcpp/channel.h
index 5e67c64..65cc46d 100644
--- a/grpc/include/grpcpp/channel.h
+++ b/grpc/include/grpcpp/channel.h
@@ -114,7 +114,7 @@
   // with this channel (if any). It is set on the first call to CallbackCQ().
   // It is _not owned_ by the channel; ownership belongs with its internal
   // shutdown callback tag (invoked when the CQ is fully shutdown).
-  ::grpc::CompletionQueue* callback_cq_ = nullptr;
+  std::atomic<CompletionQueue*> callback_cq_{nullptr};
 
   std::vector<
       std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>>
diff --git a/grpc/include/grpcpp/ext/admin_services.h b/grpc/include/grpcpp/ext/admin_services.h
new file mode 100644
index 0000000..898a87e
--- /dev/null
+++ b/grpc/include/grpcpp/ext/admin_services.h
@@ -0,0 +1,33 @@
+//
+//
+// Copyright 2021 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 GRPCPP_EXT_ADMIN_SERVICES_H
+#define GRPCPP_EXT_ADMIN_SERVICES_H
+
+#include <grpcpp/server_builder.h>
+
+namespace grpc {
+
+// Registers admin services to the given ServerBuilder. This function will add
+// admin services based on build time dependencies, for example, it only adds
+// CSDS service if xDS is enabled in this binary.
+void AddAdminServices(grpc::ServerBuilder* builder);
+
+}  // namespace grpc
+
+#endif  // GRPCPP_EXT_ADMIN_SERVICES_H
diff --git a/grpc/include/grpcpp/generic/generic_stub.h b/grpc/include/grpcpp/generic/generic_stub.h
index e4576af..e9564c3 100644
--- a/grpc/include/grpcpp/generic/generic_stub.h
+++ b/grpc/include/grpcpp/generic/generic_stub.h
@@ -22,6 +22,7 @@
 #include <functional>
 
 #include <grpcpp/client_context.h>
+#include <grpcpp/impl/codegen/stub_options.h>
 #include <grpcpp/impl/rpc_method.h>
 #include <grpcpp/support/async_stream.h>
 #include <grpcpp/support/async_unary_call.h>
@@ -53,7 +54,8 @@
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
   PrepareCall(ClientContext* context, const std::string& method,
               ::grpc::CompletionQueue* cq) {
-    return CallInternal(channel_.get(), context, method, cq, false, nullptr);
+    return CallInternal(channel_.get(), context, method, /*options=*/{}, cq,
+                        false, nullptr);
   }
 
   /// Setup a unary call to a named method \a method using \a context, and don't
@@ -67,6 +69,7 @@
         internal::ClientAsyncResponseReaderHelper::Create<ResponseType>(
             channel_.get(), cq,
             grpc::internal::RpcMethod(method.c_str(),
+                                      /*suffix_for_stats=*/nullptr,
                                       grpc::internal::RpcMethod::NORMAL_RPC),
             context, request));
   }
@@ -80,7 +83,8 @@
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> Call(
       ClientContext* context, const std::string& method,
       ::grpc::CompletionQueue* cq, void* tag) {
-    return CallInternal(channel_.get(), context, method, cq, true, tag);
+    return CallInternal(channel_.get(), context, method, /*options=*/{}, cq,
+                        true, tag);
   }
 
 #ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
@@ -89,7 +93,7 @@
   void UnaryCall(ClientContext* context, const std::string& method,
                  const RequestType* request, ResponseType* response,
                  std::function<void(grpc::Status)> on_completion) {
-    UnaryCallInternal(context, method, request, response,
+    UnaryCallInternal(context, method, /*options=*/{}, request, response,
                       std::move(on_completion));
   }
 
@@ -100,7 +104,8 @@
   void PrepareUnaryCall(ClientContext* context, const std::string& method,
                         const RequestType* request, ResponseType* response,
                         ClientUnaryReactor* reactor) {
-    PrepareUnaryCallInternal(context, method, request, response, reactor);
+    PrepareUnaryCallInternal(context, method, /*options=*/{}, request, response,
+                             reactor);
   }
 
   /// Setup a call to a named method \a method using \a context and tied to
@@ -109,7 +114,7 @@
   void PrepareBidiStreamingCall(
       ClientContext* context, const std::string& method,
       ClientBidiReactor<RequestType, ResponseType>* reactor) {
-    PrepareBidiStreamingCallInternal(context, method, reactor);
+    PrepareBidiStreamingCallInternal(context, method, /*options=*/{}, reactor);
   }
 #endif
 
@@ -123,9 +128,10 @@
     /// Setup and start a unary call to a named method \a method using
     /// \a context and specifying the \a request and \a response buffers.
     void UnaryCall(ClientContext* context, const std::string& method,
-                   const RequestType* request, ResponseType* response,
+                   StubOptions options, const RequestType* request,
+                   ResponseType* response,
                    std::function<void(grpc::Status)> on_completion) {
-      stub_->UnaryCallInternal(context, method, request, response,
+      stub_->UnaryCallInternal(context, method, options, request, response,
                                std::move(on_completion));
     }
 
@@ -134,19 +140,20 @@
     /// Like any other reactor-based RPC, it will not be activated until
     /// StartCall is invoked on its reactor.
     void PrepareUnaryCall(ClientContext* context, const std::string& method,
-                          const RequestType* request, ResponseType* response,
-                          ClientUnaryReactor* reactor) {
-      stub_->PrepareUnaryCallInternal(context, method, request, response,
-                                      reactor);
+                          StubOptions options, const RequestType* request,
+                          ResponseType* response, ClientUnaryReactor* reactor) {
+      stub_->PrepareUnaryCallInternal(context, method, options, request,
+                                      response, reactor);
     }
 
     /// Setup a call to a named method \a method using \a context and tied to
     /// \a reactor . Like any other bidi streaming RPC, it will not be activated
     /// until StartCall is invoked on its reactor.
     void PrepareBidiStreamingCall(
-        ClientContext* context, const std::string& method,
+        ClientContext* context, const std::string& method, StubOptions options,
         ClientBidiReactor<RequestType, ResponseType>* reactor) {
-      stub_->PrepareBidiStreamingCallInternal(context, method, reactor);
+      stub_->PrepareBidiStreamingCallInternal(context, method, options,
+                                              reactor);
     }
 
    private:
@@ -162,48 +169,50 @@
   std::shared_ptr<grpc::ChannelInterface> channel_;
 
   void UnaryCallInternal(ClientContext* context, const std::string& method,
-                         const RequestType* request, ResponseType* response,
+                         StubOptions options, const RequestType* request,
+                         ResponseType* response,
                          std::function<void(grpc::Status)> on_completion) {
     internal::CallbackUnaryCall(
         channel_.get(),
-        grpc::internal::RpcMethod(method.c_str(),
+        grpc::internal::RpcMethod(method.c_str(), options.suffix_for_stats(),
                                   grpc::internal::RpcMethod::NORMAL_RPC),
         context, request, response, std::move(on_completion));
   }
 
   void PrepareUnaryCallInternal(ClientContext* context,
-                                const std::string& method,
+                                const std::string& method, StubOptions options,
                                 const RequestType* request,
                                 ResponseType* response,
                                 ClientUnaryReactor* reactor) {
     internal::ClientCallbackUnaryFactory::Create<RequestType, ResponseType>(
         channel_.get(),
-        grpc::internal::RpcMethod(method.c_str(),
+        grpc::internal::RpcMethod(method.c_str(), options.suffix_for_stats(),
                                   grpc::internal::RpcMethod::NORMAL_RPC),
         context, request, response, reactor);
   }
 
   void PrepareBidiStreamingCallInternal(
-      ClientContext* context, const std::string& method,
+      ClientContext* context, const std::string& method, StubOptions options,
       ClientBidiReactor<RequestType, ResponseType>* reactor) {
     internal::ClientCallbackReaderWriterFactory<RequestType, ResponseType>::
         Create(channel_.get(),
                grpc::internal::RpcMethod(
-                   method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
+                   method.c_str(), options.suffix_for_stats(),
+                   grpc::internal::RpcMethod::BIDI_STREAMING),
                context, reactor);
   }
 
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
   CallInternal(grpc::ChannelInterface* channel, ClientContext* context,
-               const std::string& method, ::grpc::CompletionQueue* cq,
-               bool start, void* tag) {
+               const std::string& method, StubOptions options,
+               ::grpc::CompletionQueue* cq, bool start, void* tag) {
     return std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>(
         internal::ClientAsyncReaderWriterFactory<RequestType, ResponseType>::
-            Create(
-                channel, cq,
-                grpc::internal::RpcMethod(
-                    method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
-                context, start, tag));
+            Create(channel, cq,
+                   grpc::internal::RpcMethod(
+                       method.c_str(), options.suffix_for_stats(),
+                       grpc::internal::RpcMethod::BIDI_STREAMING),
+                   context, start, tag));
   }
 };
 
diff --git a/grpc/include/grpcpp/impl/codegen/async_unary_call.h b/grpc/include/grpcpp/impl/codegen/async_unary_call.h
index 7541fa3..7cb7cc6 100644
--- a/grpc/include/grpcpp/impl/codegen/async_unary_call.h
+++ b/grpc/include/grpcpp/impl/codegen/async_unary_call.h
@@ -250,7 +250,7 @@
     initial_metadata_read_ = true;
   }
 
-  /// See \a ClientAysncResponseReaderInterface::Finish for semantics.
+  /// See \a ClientAsyncResponseReaderInterface::Finish for semantics.
   ///
   /// Side effect:
   ///   - the \a ClientContext associated with this call is updated with
diff --git a/grpc/include/grpcpp/impl/codegen/byte_buffer.h b/grpc/include/grpcpp/impl/codegen/byte_buffer.h
index 4347745..2c015f2 100644
--- a/grpc/include/grpcpp/impl/codegen/byte_buffer.h
+++ b/grpc/include/grpcpp/impl/codegen/byte_buffer.h
@@ -41,8 +41,7 @@
 template <class RequestType, class ResponseType>
 class CallbackServerStreamingHandler;
 template <class RequestType>
-void* UnaryDeserializeHelper(grpc_call*, grpc_byte_buffer*, ::grpc::Status*,
-                             RequestType*);
+void* UnaryDeserializeHelper(grpc_byte_buffer*, ::grpc::Status*, RequestType*);
 template <class ServiceType, class RequestType, class ResponseType>
 class ServerStreamingHandler;
 template <::grpc::StatusCode code>
@@ -164,7 +163,7 @@
   friend class internal::CallOpRecvMessage;
   friend class internal::CallOpGenericRecvMessage;
   template <class RequestType>
-  friend void* internal::UnaryDeserializeHelper(grpc_call*, grpc_byte_buffer*,
+  friend void* internal::UnaryDeserializeHelper(grpc_byte_buffer*,
                                                 ::grpc::Status*, RequestType*);
   template <class ServiceType, class RequestType, class ResponseType>
   friend class internal::ServerStreamingHandler;
diff --git a/grpc/include/grpcpp/impl/codegen/call_op_set.h b/grpc/include/grpcpp/impl/codegen/call_op_set.h
index 370d519..7fde1ed 100644
--- a/grpc/include/grpcpp/impl/codegen/call_op_set.h
+++ b/grpc/include/grpcpp/impl/codegen/call_op_set.h
@@ -878,6 +878,9 @@
         interceptor_methods_(InterceptorBatchMethodsImpl()) {}
 
   CallOpSet& operator=(const CallOpSet& other) {
+    if (&other == this) {
+      return *this;
+    }
     core_cq_tag_ = this;
     return_tag_ = this;
     call_ = other.call_;
diff --git a/grpc/include/grpcpp/impl/codegen/client_callback.h b/grpc/include/grpcpp/impl/codegen/client_callback.h
index 77bc885..ba80290 100644
--- a/grpc/include/grpcpp/impl/codegen/client_callback.h
+++ b/grpc/include/grpcpp/impl/codegen/client_callback.h
@@ -27,6 +27,7 @@
 #include <grpcpp/impl/codegen/config.h>
 #include <grpcpp/impl/codegen/core_codegen_interface.h>
 #include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/sync.h>
 
 namespace grpc {
 class Channel;
@@ -110,6 +111,8 @@
 // Base class for public API classes.
 class ClientReactor {
  public:
+  virtual ~ClientReactor() = default;
+
   /// Called by the library when all operations associated with this RPC have
   /// completed and all Holds have been removed. OnDone provides the RPC status
   /// outcome for both successful and failed RPCs. If it is never called on an
@@ -211,16 +214,19 @@
 // activated by calling StartCall, possibly after initiating StartRead,
 // StartWrite, or AddHold operations on the streaming object. Note that none of
 // the classes are pure; all reactions have a default empty reaction so that the
-// user class only needs to override those classes that it cares about.
+// user class only needs to override those reactions that it cares about.
 // The reactor must be passed to the stub invocation before any of the below
-// operations can be called.
+// operations can be called and its reactions will be invoked by the library in
+// response to the completion of various operations. Reactions must not include
+// blocking operations (such as blocking I/O, starting synchronous RPCs, or
+// waiting on condition variables). Reactions may be invoked concurrently,
+// except that OnDone is called after all others (assuming proper API usage).
+// The reactor may not be deleted until OnDone is called.
 
 /// \a ClientBidiReactor is the interface for a bidirectional streaming RPC.
 template <class Request, class Response>
 class ClientBidiReactor : public internal::ClientReactor {
  public:
-  virtual ~ClientBidiReactor() {}
-
   /// Activate the RPC and initiate any reads or writes that have been Start'ed
   /// before this call. All streaming RPCs issued by the client MUST have
   /// StartCall invoked on them (even if they are canceled) as this call is the
@@ -357,8 +363,6 @@
 template <class Response>
 class ClientReadReactor : public internal::ClientReactor {
  public:
-  virtual ~ClientReadReactor() {}
-
   void StartCall() { reader_->StartCall(); }
   void StartRead(Response* resp) { reader_->Read(resp); }
 
@@ -384,8 +388,6 @@
 template <class Request>
 class ClientWriteReactor : public internal::ClientReactor {
  public:
-  virtual ~ClientWriteReactor() {}
-
   void StartCall() { writer_->StartCall(); }
   void StartWrite(const Request* req) {
     StartWrite(req, ::grpc::WriteOptions());
@@ -430,8 +432,6 @@
 /// initiation API among all the reactor flavors.
 class ClientUnaryReactor : public internal::ClientReactor {
  public:
-  virtual ~ClientUnaryReactor() {}
-
   void StartCall() { call_->StartCall(); }
   void OnDone(const ::grpc::Status& /*s*/) override {}
   virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
@@ -473,7 +473,7 @@
   // there are no tests catching the compiler warning.
   static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
 
-  void StartCall() override {
+  void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
     // This call initiates two batches, plus any backlog, each with a callback
     // 1. Send initial metadata (unless corked) + recv initial metadata
     // 2. Any read backlog
@@ -522,7 +522,8 @@
     call_.PerformOps(&read_ops_);
   }
 
-  void Write(const Request* msg, ::grpc::WriteOptions options) override {
+  void Write(const Request* msg, ::grpc::WriteOptions options)
+      ABSL_LOCKS_EXCLUDED(start_mu_) override {
     if (options.is_last_message()) {
       options.set_buffer_hint();
       write_ops_.ClientSendClose();
@@ -545,7 +546,7 @@
     }
     call_.PerformOps(&write_ops_);
   }
-  void WritesDone() override {
+  void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
     writes_done_ops_.ClientSendClose();
     writes_done_tag_.Set(
         call_.call(),
@@ -686,7 +687,7 @@
     bool writes_done_ops = false;
     bool read_ops = false;
   };
-  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;
+  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
 
   // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
   std::atomic<intptr_t> callbacks_outstanding_{3};
@@ -844,7 +845,7 @@
   struct StartCallBacklog {
     bool read_ops = false;
   };
-  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;
+  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
 
   // Minimum of 2 callbacks to pre-register for start and finish
   std::atomic<intptr_t> callbacks_outstanding_{2};
@@ -885,7 +886,7 @@
   // there are no tests catching the compiler warning.
   static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
 
-  void StartCall() override {
+  void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
     // This call initiates two batches, plus any backlog, each with a callback
     // 1. Send initial metadata (unless corked) + recv initial metadata
     // 2. Any backlog
@@ -917,7 +918,8 @@
     this->MaybeFinish(/*from_reaction=*/false);
   }
 
-  void Write(const Request* msg, ::grpc::WriteOptions options) override {
+  void Write(const Request* msg, ::grpc::WriteOptions options)
+      ABSL_LOCKS_EXCLUDED(start_mu_) override {
     if (GPR_UNLIKELY(options.is_last_message())) {
       options.set_buffer_hint();
       write_ops_.ClientSendClose();
@@ -942,7 +944,7 @@
     call_.PerformOps(&write_ops_);
   }
 
-  void WritesDone() override {
+  void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
     writes_done_ops_.ClientSendClose();
     writes_done_tag_.Set(
         call_.call(),
@@ -1071,7 +1073,7 @@
     bool write_ops = false;
     bool writes_done_ops = false;
   };
-  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;
+  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
 
   // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
   std::atomic<intptr_t> callbacks_outstanding_{3};
diff --git a/grpc/include/grpcpp/impl/codegen/client_context.h b/grpc/include/grpcpp/impl/codegen/client_context.h
index acf1d85..952a7ba 100644
--- a/grpc/include/grpcpp/impl/codegen/client_context.h
+++ b/grpc/include/grpcpp/impl/codegen/client_context.h
@@ -464,12 +464,13 @@
                 const std::shared_ptr<::grpc::Channel>& channel);
 
   grpc::experimental::ClientRpcInfo* set_client_rpc_info(
-      const char* method, grpc::internal::RpcMethod::RpcType type,
-      grpc::ChannelInterface* channel,
+      const char* method, const char* suffix_for_stats,
+      grpc::internal::RpcMethod::RpcType type, grpc::ChannelInterface* channel,
       const std::vector<std::unique_ptr<
           grpc::experimental::ClientInterceptorFactoryInterface>>& creators,
       size_t interceptor_pos) {
-    rpc_info_ = grpc::experimental::ClientRpcInfo(this, type, method, channel);
+    rpc_info_ = grpc::experimental::ClientRpcInfo(this, type, method,
+                                                  suffix_for_stats, channel);
     rpc_info_.RegisterInterceptors(creators, interceptor_pos);
     return &rpc_info_;
   }
diff --git a/grpc/include/grpcpp/impl/codegen/client_interceptor.h b/grpc/include/grpcpp/impl/codegen/client_interceptor.h
index 78be1f7..ec78074 100644
--- a/grpc/include/grpcpp/impl/codegen/client_interceptor.h
+++ b/grpc/include/grpcpp/impl/codegen/client_interceptor.h
@@ -87,6 +87,10 @@
   /// Return the fully-specified method name
   const char* method() const { return method_; }
 
+  /// Return an identifying suffix for the client stub, or nullptr if one wasn't
+  /// specified.
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
+
   /// Return a pointer to the channel on which the RPC is being sent
   ChannelInterface* channel() { return channel_; }
 
@@ -116,10 +120,12 @@
 
   // Constructor will only be called from ClientContext
   ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type,
-                const char* method, grpc::ChannelInterface* channel)
+                const char* method, const char* suffix_for_stats,
+                grpc::ChannelInterface* channel)
       : ctx_(ctx),
         type_(static_cast<Type>(type)),
         method_(method),
+        suffix_for_stats_(suffix_for_stats),
         channel_(channel) {}
 
   // Move assignment should only be used by ClientContext
@@ -162,6 +168,7 @@
   // TODO(yashykt): make type_ const once move-assignment is deleted
   Type type_{Type::UNKNOWN};
   const char* method_ = nullptr;
+  const char* suffix_for_stats_ = nullptr;
   grpc::ChannelInterface* channel_ = nullptr;
   std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
   bool hijacked_ = false;
diff --git a/grpc/include/grpcpp/impl/codegen/completion_queue.h b/grpc/include/grpcpp/impl/codegen/completion_queue.h
index f6589f0..d23e0e2 100644
--- a/grpc/include/grpcpp/impl/codegen/completion_queue.h
+++ b/grpc/include/grpcpp/impl/codegen/completion_queue.h
@@ -409,6 +409,9 @@
     return true;
   }
 
+  static CompletionQueue* CallbackAlternativeCQ();
+  static void ReleaseCallbackAlternativeCQ(CompletionQueue* cq);
+
   grpc_completion_queue* cq_;  // owned
 
   gpr_atm avalanches_in_flight_;
diff --git a/grpc/include/grpcpp/impl/codegen/interceptor_common.h b/grpc/include/grpcpp/impl/codegen/interceptor_common.h
index 520d981..b9a6ede 100644
--- a/grpc/include/grpcpp/impl/codegen/interceptor_common.h
+++ b/grpc/include/grpcpp/impl/codegen/interceptor_common.h
@@ -223,18 +223,11 @@
   bool InterceptorsListEmpty() {
     auto* client_rpc_info = call_->client_rpc_info();
     if (client_rpc_info != nullptr) {
-      if (client_rpc_info->interceptors_.empty()) {
-        return true;
-      } else {
-        return false;
-      }
+      return client_rpc_info->interceptors_.empty();
     }
 
     auto* server_rpc_info = call_->server_rpc_info();
-    if (server_rpc_info == nullptr || server_rpc_info->interceptors_.empty()) {
-      return true;
-    }
-    return false;
+    return server_rpc_info == nullptr || server_rpc_info->interceptors_.empty();
   }
 
   // This should be used only by subclasses of CallOpSetInterface. SetCall and
@@ -419,11 +412,7 @@
  public:
   bool QueryInterceptionHookPoint(
       experimental::InterceptionHookPoints type) override {
-    if (type == experimental::InterceptionHookPoints::PRE_SEND_CANCEL) {
-      return true;
-    } else {
-      return false;
-    }
+    return type == experimental::InterceptionHookPoints::PRE_SEND_CANCEL;
   }
 
   void Proceed() override {
diff --git a/grpc/include/grpcpp/impl/codegen/method_handler.h b/grpc/include/grpcpp/impl/codegen/method_handler.h
index 963423d..fb093f5 100644
--- a/grpc/include/grpcpp/impl/codegen/method_handler.h
+++ b/grpc/include/grpcpp/impl/codegen/method_handler.h
@@ -77,8 +77,8 @@
 /// A helper function with reduced templating to do deserializing.
 
 template <class RequestType>
-void* UnaryDeserializeHelper(grpc_call* call, grpc_byte_buffer* req,
-                             ::grpc::Status* status, RequestType* request) {
+void* UnaryDeserializeHelper(grpc_byte_buffer* req, ::grpc::Status* status,
+                             RequestType* request) {
   ::grpc::ByteBuffer buf;
   buf.set_buffer(req);
   *status = ::grpc::SerializationTraits<RequestType>::Deserialize(
@@ -123,7 +123,7 @@
     auto* request =
         new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
             call, sizeof(RequestType))) RequestType;
-    return UnaryDeserializeHelper(call, req, status,
+    return UnaryDeserializeHelper(req, status,
                                   static_cast<BaseRequestType*>(request));
   }
 
@@ -357,9 +357,12 @@
 template <::grpc::StatusCode code>
 class ErrorMethodHandler : public ::grpc::internal::MethodHandler {
  public:
+  explicit ErrorMethodHandler(const std::string& message) : message_(message) {}
+
   template <class T>
-  static void FillOps(::grpc::ServerContextBase* context, T* ops) {
-    ::grpc::Status status(code, "");
+  static void FillOps(::grpc::ServerContextBase* context,
+                      const std::string& message, T* ops) {
+    ::grpc::Status status(code, message);
     if (!context->sent_initial_metadata_) {
       ops->SendInitialMetadata(&context->initial_metadata_,
                                context->initial_metadata_flags());
@@ -375,7 +378,7 @@
     ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
                                 ::grpc::internal::CallOpServerSendStatus>
         ops;
-    FillOps(param.server_context, &ops);
+    FillOps(param.server_context, message_, &ops);
     param.call->PerformOps(&ops);
     param.call->cq()->Pluck(&ops);
   }
@@ -388,6 +391,9 @@
     }
     return nullptr;
   }
+
+ private:
+  const std::string message_;
 };
 
 typedef ErrorMethodHandler<::grpc::StatusCode::UNIMPLEMENTED>
diff --git a/grpc/include/grpcpp/impl/codegen/rpc_method.h b/grpc/include/grpcpp/impl/codegen/rpc_method.h
index 394a29b..388784e 100644
--- a/grpc/include/grpcpp/impl/codegen/rpc_method.h
+++ b/grpc/include/grpcpp/impl/codegen/rpc_method.h
@@ -36,21 +36,40 @@
   };
 
   RpcMethod(const char* name, RpcType type)
-      : name_(name), method_type_(type), channel_tag_(nullptr) {}
+      : name_(name),
+        suffix_for_stats_(nullptr),
+        method_type_(type),
+        channel_tag_(nullptr) {}
+
+  RpcMethod(const char* name, const char* suffix_for_stats, RpcType type)
+      : name_(name),
+        suffix_for_stats_(suffix_for_stats),
+        method_type_(type),
+        channel_tag_(nullptr) {}
 
   RpcMethod(const char* name, RpcType type,
             const std::shared_ptr<ChannelInterface>& channel)
       : name_(name),
+        suffix_for_stats_(nullptr),
+        method_type_(type),
+        channel_tag_(channel->RegisterMethod(name)) {}
+
+  RpcMethod(const char* name, const char* suffix_for_stats, RpcType type,
+            const std::shared_ptr<ChannelInterface>& channel)
+      : name_(name),
+        suffix_for_stats_(suffix_for_stats),
         method_type_(type),
         channel_tag_(channel->RegisterMethod(name)) {}
 
   const char* name() const { return name_; }
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
   RpcType method_type() const { return method_type_; }
   void SetMethodType(RpcType type) { method_type_ = type; }
   void* channel_tag() const { return channel_tag_; }
 
  private:
   const char* const name_;
+  const char* const suffix_for_stats_;
   RpcType method_type_;
   void* const channel_tag_;
 };
diff --git a/grpc/include/grpcpp/impl/codegen/security/auth_context.h b/grpc/include/grpcpp/impl/codegen/security/auth_context.h
index 728be37..cea6dbe 100644
--- a/grpc/include/grpcpp/impl/codegen/security/auth_context.h
+++ b/grpc/include/grpcpp/impl/codegen/security/auth_context.h
@@ -42,7 +42,7 @@
   AuthPropertyIterator operator++(int);
   bool operator==(const AuthPropertyIterator& rhs) const;
   bool operator!=(const AuthPropertyIterator& rhs) const;
-  const AuthProperty operator*();
+  AuthProperty operator*();
 
  protected:
   AuthPropertyIterator();
@@ -86,7 +86,7 @@
 
   /// Mutation functions: should only be used by an AuthMetadataProcessor.
   virtual void AddProperty(const std::string& key, const string_ref& value) = 0;
-  virtual bool SetPeerIdentityPropertyName(const string& name) = 0;
+  virtual bool SetPeerIdentityPropertyName(const std::string& name) = 0;
 };
 
 }  // namespace grpc
diff --git a/grpc/include/grpcpp/impl/codegen/server_callback.h b/grpc/include/grpcpp/impl/codegen/server_callback.h
index 9dda984..3ccabdb 100644
--- a/grpc/include/grpcpp/impl/codegen/server_callback.h
+++ b/grpc/include/grpcpp/impl/codegen/server_callback.h
@@ -29,6 +29,7 @@
 #include <grpcpp/impl/codegen/core_codegen_interface.h>
 #include <grpcpp/impl/codegen/message_allocator.h>
 #include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/sync.h>
 
 namespace grpc {
 
@@ -256,7 +257,12 @@
 // by the user, returned as the output parameter of the method handler for a
 // callback method. Note that none of the classes are pure; all reactions have a
 // default empty reaction so that the user class only needs to override those
-// classes that it cares about.
+// reactions that it cares about. The reaction methods will be invoked by the
+// library in response to the completion of various operations. Reactions must
+// not include blocking operations (such as blocking I/O, starting synchronous
+// RPCs, or waiting on condition variables). Reactions may be invoked
+// concurrently, except that OnDone is called after all others (assuming proper
+// API usage). The reactor may not be deleted until OnDone is called.
 
 /// \a ServerBidiReactor is the interface for a bidirectional streaming RPC.
 template <class Request, class Response>
@@ -273,7 +279,7 @@
   /// Send any initial metadata stored in the RPC context. If not invoked,
   /// any initial metadata will be passed along with the first Write or the
   /// Finish (if there are no writes).
-  void StartSendInitialMetadata() {
+  void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -291,7 +297,7 @@
   ///
   /// \param[out] req Where to eventually store the read message. Valid when
   ///                 the library calls OnReadDone
-  void StartRead(Request* req) {
+  void StartRead(Request* req) ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -320,7 +326,8 @@
   ///                 ownership but the caller must ensure that the message is
   ///                 not deleted or modified until OnWriteDone is called.
   /// \param[in] options The WriteOptions to use for writing this message
-  void StartWrite(const Response* resp, ::grpc::WriteOptions options) {
+  void StartWrite(const Response* resp, ::grpc::WriteOptions options)
+      ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -349,7 +356,7 @@
   /// \param[in] options The WriteOptions to use for writing this message
   /// \param[in] s The status outcome of this RPC
   void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options,
-                           ::grpc::Status s) {
+                           ::grpc::Status s) ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -384,7 +391,7 @@
   /// cancelled.
   ///
   /// \param[in] s The status outcome of this RPC
-  void Finish(::grpc::Status s) {
+  void Finish(::grpc::Status s) ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -476,7 +483,7 @@
     ::grpc::WriteOptions write_options_wanted;
     ::grpc::Status status_wanted;
   };
-  PreBindBacklog backlog_ /* GUARDED_BY(stream_mu_) */;
+  PreBindBacklog backlog_ ABSL_GUARDED_BY(stream_mu_);
 };
 
 /// \a ServerReadReactor is the interface for a client-streaming RPC.
@@ -487,7 +494,7 @@
   ~ServerReadReactor() override = default;
 
   /// The following operation initiations are exactly like ServerBidiReactor.
-  void StartSendInitialMetadata() {
+  void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(reader_mu_) {
     ServerCallbackReader<Request>* reader =
         reader_.load(std::memory_order_acquire);
     if (reader == nullptr) {
@@ -500,7 +507,7 @@
     }
     reader->SendInitialMetadata();
   }
-  void StartRead(Request* req) {
+  void StartRead(Request* req) ABSL_LOCKS_EXCLUDED(reader_mu_) {
     ServerCallbackReader<Request>* reader =
         reader_.load(std::memory_order_acquire);
     if (reader == nullptr) {
@@ -513,7 +520,7 @@
     }
     reader->Read(req);
   }
-  void Finish(::grpc::Status s) {
+  void Finish(::grpc::Status s) ABSL_LOCKS_EXCLUDED(reader_mu_) {
     ServerCallbackReader<Request>* reader =
         reader_.load(std::memory_order_acquire);
     if (reader == nullptr) {
@@ -539,7 +546,8 @@
 
   // May be overridden by internal implementation details. This is not a public
   // customization point.
-  virtual void InternalBindReader(ServerCallbackReader<Request>* reader) {
+  virtual void InternalBindReader(ServerCallbackReader<Request>* reader)
+      ABSL_LOCKS_EXCLUDED(reader_mu_) {
     grpc::internal::MutexLock l(&reader_mu_);
 
     if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
@@ -563,7 +571,7 @@
     Request* read_wanted = nullptr;
     ::grpc::Status status_wanted;
   };
-  PreBindBacklog backlog_ /* GUARDED_BY(reader_mu_) */;
+  PreBindBacklog backlog_ ABSL_GUARDED_BY(reader_mu_);
 };
 
 /// \a ServerWriteReactor is the interface for a server-streaming RPC.
@@ -574,7 +582,7 @@
   ~ServerWriteReactor() override = default;
 
   /// The following operation initiations are exactly like ServerBidiReactor.
-  void StartSendInitialMetadata() {
+  void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(writer_mu_) {
     ServerCallbackWriter<Response>* writer =
         writer_.load(std::memory_order_acquire);
     if (writer == nullptr) {
@@ -590,7 +598,8 @@
   void StartWrite(const Response* resp) {
     StartWrite(resp, ::grpc::WriteOptions());
   }
-  void StartWrite(const Response* resp, ::grpc::WriteOptions options) {
+  void StartWrite(const Response* resp, ::grpc::WriteOptions options)
+      ABSL_LOCKS_EXCLUDED(writer_mu_) {
     ServerCallbackWriter<Response>* writer =
         writer_.load(std::memory_order_acquire);
     if (writer == nullptr) {
@@ -605,7 +614,7 @@
     writer->Write(resp, options);
   }
   void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options,
-                           ::grpc::Status s) {
+                           ::grpc::Status s) ABSL_LOCKS_EXCLUDED(writer_mu_) {
     ServerCallbackWriter<Response>* writer =
         writer_.load(std::memory_order_acquire);
     if (writer == nullptr) {
@@ -624,7 +633,7 @@
   void StartWriteLast(const Response* resp, ::grpc::WriteOptions options) {
     StartWrite(resp, options.set_last_message());
   }
-  void Finish(::grpc::Status s) {
+  void Finish(::grpc::Status s) ABSL_LOCKS_EXCLUDED(writer_mu_) {
     ServerCallbackWriter<Response>* writer =
         writer_.load(std::memory_order_acquire);
     if (writer == nullptr) {
@@ -649,7 +658,8 @@
   friend class ServerCallbackWriter<Response>;
   // May be overridden by internal implementation details. This is not a public
   // customization point.
-  virtual void InternalBindWriter(ServerCallbackWriter<Response>* writer) {
+  virtual void InternalBindWriter(ServerCallbackWriter<Response>* writer)
+      ABSL_LOCKS_EXCLUDED(writer_mu_) {
     grpc::internal::MutexLock l(&writer_mu_);
 
     if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
@@ -682,7 +692,7 @@
     ::grpc::WriteOptions write_options_wanted;
     ::grpc::Status status_wanted;
   };
-  PreBindBacklog backlog_ /* GUARDED_BY(writer_mu_) */;
+  PreBindBacklog backlog_ ABSL_GUARDED_BY(writer_mu_);
 };
 
 class ServerUnaryReactor : public internal::ServerReactor {
@@ -691,7 +701,7 @@
   ~ServerUnaryReactor() override = default;
 
   /// StartSendInitialMetadata is exactly like ServerBidiReactor.
-  void StartSendInitialMetadata() {
+  void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(call_mu_) {
     ServerCallbackUnary* call = call_.load(std::memory_order_acquire);
     if (call == nullptr) {
       grpc::internal::MutexLock l(&call_mu_);
@@ -706,7 +716,7 @@
   /// Finish is similar to ServerBidiReactor except for one detail.
   /// If the status is non-OK, any message will not be sent. Instead,
   /// the client will only receive the status and any trailing metadata.
-  void Finish(::grpc::Status s) {
+  void Finish(::grpc::Status s) ABSL_LOCKS_EXCLUDED(call_mu_) {
     ServerCallbackUnary* call = call_.load(std::memory_order_acquire);
     if (call == nullptr) {
       grpc::internal::MutexLock l(&call_mu_);
@@ -729,7 +739,8 @@
   friend class ServerCallbackUnary;
   // May be overridden by internal implementation details. This is not a public
   // customization point.
-  virtual void InternalBindCall(ServerCallbackUnary* call) {
+  virtual void InternalBindCall(ServerCallbackUnary* call)
+      ABSL_LOCKS_EXCLUDED(call_mu_) {
     grpc::internal::MutexLock l(&call_mu_);
 
     if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
@@ -749,7 +760,7 @@
     bool finish_wanted = false;
     ::grpc::Status status_wanted;
   };
-  PreBindBacklog backlog_ /* GUARDED_BY(call_mu_) */;
+  PreBindBacklog backlog_ ABSL_GUARDED_BY(call_mu_);
 };
 
 namespace internal {
diff --git a/grpc/include/grpcpp/impl/codegen/server_callback_handlers.h b/grpc/include/grpcpp/impl/codegen/server_callback_handlers.h
index 4815cb4..76e655a 100644
--- a/grpc/include/grpcpp/impl/codegen/server_callback_handlers.h
+++ b/grpc/include/grpcpp/impl/codegen/server_callback_handlers.h
@@ -210,6 +210,9 @@
       grpc_call* call = call_.call();
       auto call_requester = std::move(call_requester_);
       allocator_state_->Release();
+      if (ctx_->context_allocator() != nullptr) {
+        ctx_->context_allocator()->Release(ctx_);
+      }
       this->~ServerCallbackUnaryImpl();  // explicitly call destructor
       ::grpc::g_core_codegen_interface->grpc_call_unref(call);
       call_requester();
@@ -402,6 +405,9 @@
       reactor_.load(std::memory_order_relaxed)->OnDone();
       grpc_call* call = call_.call();
       auto call_requester = std::move(call_requester_);
+      if (ctx_->context_allocator() != nullptr) {
+        ctx_->context_allocator()->Release(ctx_);
+      }
       this->~ServerCallbackReaderImpl();  // explicitly call destructor
       ::grpc::g_core_codegen_interface->grpc_call_unref(call);
       call_requester();
@@ -616,7 +622,11 @@
       // DefaultReactor (which is unary).
       this->MaybeDone(/*inlineable_ondone=*/false);
     }
-    ~ServerCallbackWriterImpl() { req_->~RequestType(); }
+    ~ServerCallbackWriterImpl() {
+      if (req_ != nullptr) {
+        req_->~RequestType();
+      }
+    }
 
     const RequestType* request() { return req_; }
 
@@ -624,6 +634,9 @@
       reactor_.load(std::memory_order_relaxed)->OnDone();
       grpc_call* call = call_.call();
       auto call_requester = std::move(call_requester_);
+      if (ctx_->context_allocator() != nullptr) {
+        ctx_->context_allocator()->Release(ctx_);
+      }
       this->~ServerCallbackWriterImpl();  // explicitly call destructor
       ::grpc::g_core_codegen_interface->grpc_call_unref(call);
       call_requester();
@@ -835,6 +848,9 @@
       reactor_.load(std::memory_order_relaxed)->OnDone();
       grpc_call* call = call_.call();
       auto call_requester = std::move(call_requester_);
+      if (ctx_->context_allocator() != nullptr) {
+        ctx_->context_allocator()->Release(ctx_);
+      }
       this->~ServerCallbackReaderWriterImpl();  // explicitly call destructor
       ::grpc::g_core_codegen_interface->grpc_call_unref(call);
       call_requester();
diff --git a/grpc/include/grpcpp/impl/codegen/server_context.h b/grpc/include/grpcpp/impl/codegen/server_context.h
index 5a62873..cbbd229 100644
--- a/grpc/include/grpcpp/impl/codegen/server_context.h
+++ b/grpc/include/grpcpp/impl/codegen/server_context.h
@@ -100,6 +100,7 @@
 class GenericServerContext;
 class Server;
 class ServerInterface;
+class ContextAllocator;
 
 // TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
 namespace experimental {
@@ -340,6 +341,12 @@
   ServerContextBase();
   ServerContextBase(gpr_timespec deadline, grpc_metadata_array* arr);
 
+  void set_context_allocator(ContextAllocator* context_allocator) {
+    context_allocator_ = context_allocator;
+  }
+
+  ContextAllocator* context_allocator() const { return context_allocator_; }
+
  private:
   friend class ::grpc::testing::InteropServerContextInspector;
   friend class ::grpc::testing::ServerContextTestSpouse;
@@ -463,6 +470,7 @@
 
   ::grpc::experimental::ServerRpcInfo* rpc_info_ = nullptr;
   ::grpc::experimental::RpcAllocatorState* message_allocator_state_ = nullptr;
+  ContextAllocator* context_allocator_ = nullptr;
 
   class Reactor : public ::grpc::ServerUnaryReactor {
    public:
@@ -590,12 +598,14 @@
   using ServerContextBase::compression_algorithm;
   using ServerContextBase::compression_level;
   using ServerContextBase::compression_level_set;
+  using ServerContextBase::context_allocator;
   using ServerContextBase::deadline;
   using ServerContextBase::IsCancelled;
   using ServerContextBase::peer;
   using ServerContextBase::raw_deadline;
   using ServerContextBase::set_compression_algorithm;
   using ServerContextBase::set_compression_level;
+  using ServerContextBase::set_context_allocator;
   using ServerContextBase::SetLoadReportingCosts;
   using ServerContextBase::TryCancel;
 
@@ -612,6 +622,37 @@
   CallbackServerContext& operator=(const CallbackServerContext&) = delete;
 };
 
+/// A CallbackServerContext allows users to use the contents of the
+/// CallbackServerContext or GenericCallbackServerContext structure for the
+/// callback API.
+/// The library will invoke the allocator any time a new call is initiated.
+/// and call the Release method after the server OnDone.
+class ContextAllocator {
+ public:
+  virtual ~ContextAllocator() {}
+
+  virtual CallbackServerContext* NewCallbackServerContext() { return nullptr; }
+
+#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
+  virtual experimental::GenericCallbackServerContext*
+  NewGenericCallbackServerContext() {
+    return nullptr;
+  }
+#else
+  virtual GenericCallbackServerContext* NewGenericCallbackServerContext() {
+    return nullptr;
+  }
+#endif
+
+  virtual void Release(CallbackServerContext*) {}
+
+#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
+  virtual void Release(experimental::GenericCallbackServerContext*) {}
+#else
+  virtual void Release(GenericCallbackServerContext*) {}
+#endif
+};
+
 }  // namespace grpc
 
 static_assert(
diff --git a/grpc/include/grpcpp/impl/codegen/server_interface.h b/grpc/include/grpcpp/impl/codegen/server_interface.h
index c4398f4..a44ab1f 100644
--- a/grpc/include/grpcpp/impl/codegen/server_interface.h
+++ b/grpc/include/grpcpp/impl/codegen/server_interface.h
@@ -147,6 +147,8 @@
     /// May not be abstract since this is a post-1.0 API addition
     virtual void RegisterCallbackGenericService(
         experimental::CallbackGenericService* /*service*/) {}
+    virtual void RegisterContextAllocator(
+        std::unique_ptr<ContextAllocator> context_allocator) {}
   };
 
   /// NOTE: The function experimental_registration() is not stable public API.
diff --git a/grpc/include/grpcpp/impl/codegen/string_ref.h b/grpc/include/grpcpp/impl/codegen/string_ref.h
index 153f371..4543e42 100644
--- a/grpc/include/grpcpp/impl/codegen/string_ref.h
+++ b/grpc/include/grpcpp/impl/codegen/string_ref.h
@@ -51,6 +51,7 @@
   string_ref() : data_(nullptr), length_(0) {}
   string_ref(const string_ref& other)
       : data_(other.data_), length_(other.length_) {}
+  // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
   string_ref& operator=(const string_ref& rhs) {
     data_ = rhs.data_;
     length_ = rhs.length_;
diff --git a/grpc/include/grpcpp/impl/codegen/stub_options.h b/grpc/include/grpcpp/impl/codegen/stub_options.h
index a56695a..30509c2 100644
--- a/grpc/include/grpcpp/impl/codegen/stub_options.h
+++ b/grpc/include/grpcpp/impl/codegen/stub_options.h
@@ -22,7 +22,20 @@
 namespace grpc {
 
 /// Useful interface for generated stubs
-class StubOptions {};
+class StubOptions {
+ public:
+  StubOptions() = default;
+  explicit StubOptions(const char* suffix_for_stats)
+      : suffix_for_stats_(suffix_for_stats) {}
+
+  void set_suffix_for_stats(const char* suffix_for_stats) {
+    suffix_for_stats_ = suffix_for_stats;
+  }
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
+
+ private:
+  const char* suffix_for_stats_ = nullptr;
+};
 
 }  // namespace grpc
 
diff --git a/grpc/include/grpcpp/impl/codegen/sync.h b/grpc/include/grpcpp/impl/codegen/sync.h
index 146f182..0c4effe 100644
--- a/grpc/include/grpcpp/impl/codegen/sync.h
+++ b/grpc/include/grpcpp/impl/codegen/sync.h
@@ -32,6 +32,8 @@
 
 #include <grpcpp/impl/codegen/core_codegen_interface.h>
 
+#include "absl/synchronization/mutex.h"
+
 // The core library is not accessible in C++ codegen headers, and vice versa.
 // Thus, we need to have duplicate headers with similar functionality.
 // Make sure any change to this file is also reflected in
@@ -44,7 +46,16 @@
 namespace grpc {
 namespace internal {
 
-class Mutex {
+#ifdef GRPCPP_ABSEIL_SYNC
+
+using Mutex = absl::Mutex;
+using MutexLock = absl::MutexLock;
+using ReleasableMutexLock = absl::ReleasableMutexLock;
+using CondVar = absl::CondVar;
+
+#else
+
+class ABSL_LOCKABLE Mutex {
  public:
   Mutex() { g_core_codegen_interface->gpr_mu_init(&mu_); }
   ~Mutex() { g_core_codegen_interface->gpr_mu_destroy(&mu_); }
@@ -52,8 +63,12 @@
   Mutex(const Mutex&) = delete;
   Mutex& operator=(const Mutex&) = delete;
 
-  gpr_mu* get() { return &mu_; }
-  const gpr_mu* get() const { return &mu_; }
+  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
+    g_core_codegen_interface->gpr_mu_lock(&mu_);
+  }
+  void Unlock() ABSL_UNLOCK_FUNCTION() {
+    g_core_codegen_interface->gpr_mu_unlock(&mu_);
+  }
 
  private:
   union {
@@ -63,55 +78,45 @@
     pthread_mutex_t do_not_use_pth_;
 #endif
   };
+
+  friend class CondVar;
 };
 
-// MutexLock is a std::
-class MutexLock {
+class ABSL_SCOPED_LOCKABLE MutexLock {
  public:
-  explicit MutexLock(Mutex* mu) : mu_(mu->get()) {
-    g_core_codegen_interface->gpr_mu_lock(mu_);
+  explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
+    mu_->Lock();
   }
-  explicit MutexLock(gpr_mu* mu) : mu_(mu) {
-    g_core_codegen_interface->gpr_mu_lock(mu_);
-  }
-  ~MutexLock() { g_core_codegen_interface->gpr_mu_unlock(mu_); }
+  ~MutexLock() ABSL_UNLOCK_FUNCTION() { mu_->Unlock(); }
 
   MutexLock(const MutexLock&) = delete;
   MutexLock& operator=(const MutexLock&) = delete;
 
  private:
-  gpr_mu* const mu_;
+  Mutex* const mu_;
 };
 
-class ReleasableMutexLock {
+class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
  public:
-  explicit ReleasableMutexLock(Mutex* mu) : mu_(mu->get()) {
-    g_core_codegen_interface->gpr_mu_lock(mu_);
+  explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu_->Lock();
   }
-  explicit ReleasableMutexLock(gpr_mu* mu) : mu_(mu) {
-    g_core_codegen_interface->gpr_mu_lock(mu_);
-  }
-  ~ReleasableMutexLock() {
-    if (!released_) g_core_codegen_interface->gpr_mu_unlock(mu_);
+  ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
+    if (!released_) mu_->Unlock();
   }
 
   ReleasableMutexLock(const ReleasableMutexLock&) = delete;
   ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
 
-  void Lock() {
-    GPR_DEBUG_ASSERT(released_);
-    g_core_codegen_interface->gpr_mu_lock(mu_);
-    released_ = false;
-  }
-
-  void Unlock() {
+  void Release() ABSL_UNLOCK_FUNCTION() {
     GPR_DEBUG_ASSERT(!released_);
     released_ = true;
-    g_core_codegen_interface->gpr_mu_unlock(mu_);
+    mu_->Unlock();
   }
 
  private:
-  gpr_mu* const mu_;
+  Mutex* const mu_;
   bool released_ = false;
 };
 
@@ -124,27 +129,27 @@
   CondVar& operator=(const CondVar&) = delete;
 
   void Signal() { g_core_codegen_interface->gpr_cv_signal(&cv_); }
-  void Broadcast() { g_core_codegen_interface->gpr_cv_broadcast(&cv_); }
+  void SignalAll() { g_core_codegen_interface->gpr_cv_broadcast(&cv_); }
 
-  int Wait(Mutex* mu) {
-    return Wait(mu,
-                g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
-  }
-  int Wait(Mutex* mu, const gpr_timespec& deadline) {
-    return g_core_codegen_interface->gpr_cv_wait(&cv_, mu->get(), deadline);
-  }
-
-  template <typename Predicate>
-  void WaitUntil(Mutex* mu, Predicate pred) {
-    while (!pred()) {
-      Wait(mu, g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
-    }
+  void Wait(Mutex* mu) {
+    g_core_codegen_interface->gpr_cv_wait(
+        &cv_, &mu->mu_,
+        g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
   }
 
  private:
   gpr_cv cv_;
 };
 
+#endif  // GRPCPP_ABSEIL_SYNC
+
+template <typename Predicate>
+static void WaitUntil(CondVar* cv, Mutex* mu, Predicate pred) {
+  while (!pred()) {
+    cv->Wait(mu);
+  }
+}
+
 }  // namespace internal
 }  // namespace grpc
 
diff --git a/grpc/include/grpcpp/security/credentials.h b/grpc/include/grpcpp/security/credentials.h
index 98b5d9a..1b1f994 100644
--- a/grpc/include/grpcpp/security/credentials.h
+++ b/grpc/include/grpcpp/security/credentials.h
@@ -277,6 +277,12 @@
 std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
     std::unique_ptr<MetadataCredentialsPlugin> plugin);
 
+/// Builds External Account credentials.
+/// json_string is the JSON string containing the credentials options.
+/// scopes contains the scopes to be binded with the credentials.
+std::shared_ptr<CallCredentials> ExternalAccountCredentials(
+    const grpc::string& json_string, const std::vector<grpc::string>& scopes);
+
 namespace experimental {
 
 /// Options for creating STS Oauth Token Exchange credentials following the IETF
@@ -307,12 +313,6 @@
 std::shared_ptr<CallCredentials> StsCredentials(
     const StsCredentialsOptions& options);
 
-/// Builds External Account credentials.
-/// json_string is the JSON string containing the credentials options.
-/// scopes contains the scopes to be binded with the credentials.
-std::shared_ptr<CallCredentials> ExternalAccountCredentials(
-    const grpc::string& json_string, const std::vector<grpc::string>& scopes);
-
 std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
     std::unique_ptr<MetadataCredentialsPlugin> plugin,
     grpc_security_level min_security_level);
diff --git a/grpc/include/grpcpp/security/server_credentials.h b/grpc/include/grpcpp/security/server_credentials.h
index ad7c0e7..0ce46a8 100644
--- a/grpc/include/grpcpp/security/server_credentials.h
+++ b/grpc/include/grpcpp/security/server_credentials.h
@@ -67,9 +67,10 @@
 }  // namespace experimental
 
 /// Wrapper around \a grpc_server_credentials, a way to authenticate a server.
-class ServerCredentials {
+class ServerCredentials : private grpc::GrpcLibraryCodegen {
  public:
-  virtual ~ServerCredentials();
+  ServerCredentials();
+  ~ServerCredentials() override;
 
   /// This method is not thread-safe and has to be called before the server is
   /// started. The last call to this function wins.
diff --git a/grpc/include/grpcpp/security/tls_credentials_options.h b/grpc/include/grpcpp/security/tls_credentials_options.h
index 6abdcaa..da2b595 100644
--- a/grpc/include/grpcpp/security/tls_credentials_options.h
+++ b/grpc/include/grpcpp/security/tls_credentials_options.h
@@ -155,13 +155,21 @@
   //
   // @param certificate_provider the provider which fetches TLS credentials that
   // will be used in the TLS handshake
-  explicit TlsCredentialsOptions(
-      std::shared_ptr<CertificateProviderInterface> certificate_provider);
+  TlsCredentialsOptions();
   // ---- Setters for member fields ----
+  // Sets the certificate provider used to store root certs and identity certs.
+  void set_certificate_provider(
+      std::shared_ptr<CertificateProviderInterface> certificate_provider);
   // Watches the updates of root certificates with name |root_cert_name|.
-  // If used in TLS credentials, it should always be set unless the root
-  // certificates are not needed(e.g. in the one-side TLS scenario, the server
-  // is not required to verify the client).
+  // If used in TLS credentials, setting this field is optional for both the
+  // client side and the server side.
+  // If this is not set on the client side, we will use the root certificates
+  // stored in the default system location, since client side must provide root
+  // certificates in TLS(no matter single-side TLS or mutual TLS).
+  // If this is not set on the server side, we will not watch any root
+  // certificate updates, and assume no root certificates needed for the server
+  // (in the one-side TLS scenario, the server is not required to provide root
+  // certs). We don't support default root certs on server side.
   void watch_root_certs();
   // Sets the name of root certificates being watched, if |watch_root_certs| is
   // called. If not set, an empty string will be used as the name.
@@ -169,9 +177,9 @@
   // @param root_cert_name the name of root certs being set.
   void set_root_cert_name(const std::string& root_cert_name);
   // Watches the updates of identity key-cert pairs with name
-  // |identity_cert_name|. If used in TLS credentials, it should always be set
-  // unless the identity certificates are not needed(e.g. in the one-side TLS
-  // scenario, the client is not required to provide certs).
+  // |identity_cert_name|. If used in TLS credentials, it is required to be set
+  // on the server side, and optional for the client side(in the one-side
+  // TLS scenario, the client is not required to provide identity certs).
   void watch_identity_key_cert_pairs();
   // Sets the name of identity key-cert pairs being watched, if
   // |watch_identity_key_cert_pairs| is called. If not set, an empty string will
@@ -192,13 +200,13 @@
 };
 
 // Contains configurable options on the client side.
+// Client side doesn't need to always use certificate provider. When the
+// certificate provider is not set, we will use the root certificates stored
+// in the system default locations, and assume client won't provide any
+// identity certificates(single side TLS).
 // It is used for experimental purposes for now and it is subject to change.
 class TlsChannelCredentialsOptions final : public TlsCredentialsOptions {
  public:
-  explicit TlsChannelCredentialsOptions(
-      std::shared_ptr<CertificateProviderInterface> certificate_provider)
-      : TlsCredentialsOptions(std::move(certificate_provider)) {}
-
   // Sets the option to verify the server.
   // The default is GRPC_TLS_SERVER_VERIFICATION.
   void set_server_verification_option(
@@ -215,9 +223,13 @@
 // It is used for experimental purposes for now and it is subject to change.
 class TlsServerCredentialsOptions final : public TlsCredentialsOptions {
  public:
+  // Server side is required to use a provider, because server always needs to
+  // use identity certs.
   explicit TlsServerCredentialsOptions(
       std::shared_ptr<CertificateProviderInterface> certificate_provider)
-      : TlsCredentialsOptions(std::move(certificate_provider)) {}
+      : TlsCredentialsOptions() {
+    set_certificate_provider(certificate_provider);
+  }
 
   // Sets option to request the certificates from the client.
   // The default is GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE.
diff --git a/grpc/include/grpcpp/server.h b/grpc/include/grpcpp/server.h
index 5dc73a1..a69e64b 100644
--- a/grpc/include/grpcpp/server.h
+++ b/grpc/include/grpcpp/server.h
@@ -58,13 +58,13 @@
 /// \a Server instances.
 class Server : public ServerInterface, private GrpcLibraryCodegen {
  public:
-  ~Server() override;
+  ~Server() ABSL_LOCKS_EXCLUDED(mu_) override;
 
   /// Block until the server shuts down.
   ///
   /// \warning The server must be either shutting down or some other thread must
   /// call \a Shutdown for this function to ever return.
-  void Wait() override;
+  void Wait() ABSL_LOCKS_EXCLUDED(mu_) override;
 
   /// Global callbacks are a set of hooks that are called when server
   /// events occur.  \a SetGlobalCallbacks method is used to register
@@ -203,6 +203,8 @@
     health_check_service_ = std::move(service);
   }
 
+  ContextAllocator* context_allocator() { return context_allocator_.get(); }
+
   /// NOTE: This method is not part of the public API for this class.
   bool health_check_service_disabled() const {
     return health_check_service_disabled_;
@@ -240,6 +242,12 @@
   /// ownership of theservice. The service must exist for the lifetime of the
   /// Server instance.
   void RegisterCallbackGenericService(CallbackGenericService* service) override;
+
+  void RegisterContextAllocator(
+      std::unique_ptr<ContextAllocator> context_allocator) {
+    context_allocator_ = std::move(context_allocator);
+  }
+
 #else
   /// NOTE: class experimental_registration_type is not part of the public API
   /// of this class
@@ -254,6 +262,11 @@
       server_->RegisterCallbackGenericService(service);
     }
 
+    void RegisterContextAllocator(
+        std::unique_ptr<ContextAllocator> context_allocator) override {
+      server_->context_allocator_ = std::move(context_allocator);
+    }
+
    private:
     Server* server_;
   };
@@ -273,13 +286,14 @@
   void PerformOpsOnCall(internal::CallOpSetInterface* ops,
                         internal::Call* call) override;
 
-  void ShutdownInternal(gpr_timespec deadline) override;
+  void ShutdownInternal(gpr_timespec deadline)
+      ABSL_LOCKS_EXCLUDED(mu_) override;
 
   int max_receive_message_size() const override {
     return max_receive_message_size_;
   }
 
-  CompletionQueue* CallbackCQ() override;
+  CompletionQueue* CallbackCQ() ABSL_LOCKS_EXCLUDED(mu_) override;
 
   ServerInitializer* initializer();
 
@@ -287,8 +301,8 @@
   // the ref count are the running state of the server (take a ref at start and
   // drop it at shutdown) and each running callback RPC.
   void Ref();
-  void UnrefWithPossibleNotify() /* LOCKS_EXCLUDED(mu_) */;
-  void UnrefAndWaitLocked() /* EXCLUSIVE_LOCKS_REQUIRED(mu_) */;
+  void UnrefWithPossibleNotify() ABSL_LOCKS_EXCLUDED(mu_);
+  void UnrefAndWaitLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   std::vector<std::shared_ptr<internal::ExternalConnectionAcceptorImpl>>
       acceptors_;
@@ -322,10 +336,11 @@
   // Server status
   internal::Mutex mu_;
   bool started_;
-  bool shutdown_;
-  bool shutdown_notified_;  // Was notify called on the shutdown_cv_
+  bool shutdown_ ABSL_GUARDED_BY(mu_);
+  bool shutdown_notified_
+      ABSL_GUARDED_BY(mu_);  // Was notify called on the shutdown_cv_
   internal::CondVar shutdown_done_cv_;
-  bool shutdown_done_ = false;
+  bool shutdown_done_ ABSL_GUARDED_BY(mu_) = false;
   std::atomic_int shutdown_refs_outstanding_{1};
 
   internal::CondVar shutdown_cv_;
@@ -342,6 +357,8 @@
 
   std::unique_ptr<ServerInitializer> server_initializer_;
 
+  std::unique_ptr<ContextAllocator> context_allocator_;
+
   std::unique_ptr<HealthCheckServiceInterface> health_check_service_;
   bool health_check_service_disabled_;
 
@@ -363,7 +380,7 @@
   // with this server (if any). It is set on the first call to CallbackCQ().
   // It is _not owned_ by the server; ownership belongs with its internal
   // shutdown callback tag (invoked when the CQ is fully shutdown).
-  CompletionQueue* callback_cq_ /* GUARDED_BY(mu_) */ = nullptr;
+  std::atomic<CompletionQueue*> callback_cq_{nullptr};
 
   // List of CQs passed in by user that must be Shutdown only after Server is
   // Shutdown.  Even though this is only used with NDEBUG, instantiate it in all
diff --git a/grpc/include/grpcpp/server_builder.h b/grpc/include/grpcpp/server_builder.h
index cb75d87..00e82a1 100644
--- a/grpc/include/grpcpp/server_builder.h
+++ b/grpc/include/grpcpp/server_builder.h
@@ -269,6 +269,11 @@
       builder_->interceptor_creators_ = std::move(interceptor_creators);
     }
 
+    /// Set the allocator for creating and releasing callback server context.
+    /// Takes the owndership of the allocator.
+    ServerBuilder& SetContextAllocator(
+        std::unique_ptr<grpc::ContextAllocator> context_allocator);
+
 #ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
     /// Register a generic service that uses the callback API.
     /// Matches requests with any :authority
@@ -352,6 +357,9 @@
     server_config_fetcher_ = server_config_fetcher;
   }
 
+  /// Experimental API, subject to change.
+  virtual ChannelArguments BuildChannelArgs();
+
  private:
   friend class ::grpc::testing::ServerBuilderPluginTest;
 
@@ -389,6 +397,7 @@
   std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>> plugins_;
   grpc_resource_quota* resource_quota_;
   grpc::AsyncGenericService* generic_service_{nullptr};
+  std::unique_ptr<ContextAllocator> context_allocator_;
 #ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
   grpc::CallbackGenericService* callback_generic_service_{nullptr};
 #else
diff --git a/grpc/include/grpcpp/support/channel_arguments.h b/grpc/include/grpcpp/support/channel_arguments.h
index 41a8ad3..a9514bc 100644
--- a/grpc/include/grpcpp/support/channel_arguments.h
+++ b/grpc/include/grpcpp/support/channel_arguments.h
@@ -98,14 +98,18 @@
   /// Primarily meant for use in unit tests.
   void SetServiceConfigJSON(const std::string& service_config_json);
 
-  // Generic channel argument setters. Only for advanced use cases.
+  // Generic channel argument setter. Only for advanced use cases.
   /// Set an integer argument \a value under \a key.
   void SetInt(const std::string& key, int value);
 
   // Generic channel argument setter. Only for advanced use cases.
-  /// Set a pointer argument \a value under \a key. Owership is not transferred.
+  /// Set a pointer argument \a value under \a key. Ownership is not
+  /// transferred.
   void SetPointer(const std::string& key, void* value);
 
+  /// Set a pointer argument \a value under \a key, transferring ownership of
+  /// \a value to the \a ChannelArguments object. The \a vtable::Delete function
+  /// is responsible for \a value cleanup/destruction when called.
   void SetPointerWithVtable(const std::string& key, void* value,
                             const grpc_arg_pointer_vtable* vtable);
 
diff --git a/grpc/include/grpcpp/support/error_details.h b/grpc/include/grpcpp/support/error_details.h
index 15b917f..72305e8 100644
--- a/grpc/include/grpcpp/support/error_details.h
+++ b/grpc/include/grpcpp/support/error_details.h
@@ -21,12 +21,6 @@
 
 #include <grpcpp/support/status.h>
 
-namespace google {
-namespace rpc {
-class Status;
-}  // namespace rpc
-}  // namespace google
-
 namespace grpc {
 
 /// Map a \a grpc::Status to a \a google::rpc::Status.
@@ -34,14 +28,48 @@
 /// On success, returns status with OK.
 /// Returns status with \a INVALID_ARGUMENT, if failed to deserialize.
 /// Returns status with \a FAILED_PRECONDITION, if \a to is nullptr.
-grpc::Status ExtractErrorDetails(const grpc::Status& from,
-                                 ::google::rpc::Status* to);
+///
+/// \note
+/// This function is a template to avoid a build dep on \a status.proto.
+/// However, this function still requires that \tparam T is of type
+/// \a google::rpc::Status, which is defined at
+/// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto
+template <typename T>
+grpc::Status ExtractErrorDetails(const grpc::Status& from, T* to) {
+  if (to == nullptr) {
+    return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "");
+  }
+  if (!to->ParseFromString(from.error_details())) {
+    return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "");
+  }
+  return grpc::Status::OK;
+}
+inline grpc::Status ExtractErrorDetails(const grpc::Status&, std::nullptr_t) {
+  return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "");
+}
 
 /// Map \a google::rpc::Status to a \a grpc::Status.
 /// Returns OK on success.
 /// Returns status with \a FAILED_PRECONDITION if \a to is nullptr.
-grpc::Status SetErrorDetails(const ::google::rpc::Status& from,
-                             grpc::Status* to);
+///
+/// \note
+/// This function is a template to avoid a build dep on \a status.proto.
+/// However, this function still requires that \tparam T is of type
+/// \a google::rpc::Status, which is defined at
+/// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto
+template <typename T>
+grpc::Status SetErrorDetails(const T& from, grpc::Status* to) {
+  if (to == nullptr) {
+    return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "");
+  }
+  grpc::StatusCode code = grpc::StatusCode::UNKNOWN;
+  if (from.code() >= grpc::StatusCode::OK &&
+      from.code() <= grpc::StatusCode::UNAUTHENTICATED) {
+    code = static_cast<grpc::StatusCode>(from.code());
+  }
+  *to = grpc::Status(code, from.message(), from.SerializeAsString());
+  return grpc::Status::OK;
+}
 
 }  // namespace grpc
 
diff --git a/grpc/include/grpcpp/test/mock_stream.h b/grpc/include/grpcpp/test/mock_stream.h
index e33595d..deffad3 100644
--- a/grpc/include/grpcpp/test/mock_stream.h
+++ b/grpc/include/grpcpp/test/mock_stream.h
@@ -90,6 +90,8 @@
  public:
   MockClientAsyncResponseReader() = default;
 
+  /// ClientAsyncResponseReaderInterface
+  MOCK_METHOD0_T(StartCall, void());
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD3_T(Finish, void(R*, Status*, void*));
 };
@@ -100,6 +102,7 @@
   MockClientAsyncReader() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
@@ -113,11 +116,13 @@
   MockClientAsyncWriter() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
   /// AsyncWriterInterface
   MOCK_METHOD2_T(Write, void(const W&, void*));
+  MOCK_METHOD3_T(Write, void(const W&, ::grpc::WriteOptions, void*));
 
   /// ClientAsyncWriterInterface
   MOCK_METHOD1_T(WritesDone, void(void*));
@@ -130,11 +135,13 @@
   MockClientAsyncReaderWriter() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
   /// AsyncWriterInterface
   MOCK_METHOD2_T(Write, void(const W&, void*));
+  MOCK_METHOD3_T(Write, void(const W&, ::grpc::WriteOptions, void*));
 
   /// AsyncReaderInterface
   MOCK_METHOD2_T(Read, void(R*, void*));
diff --git a/grpc/include/grpcpp/xds_server_builder.h b/grpc/include/grpcpp/xds_server_builder.h
index 1ed9e83..076c377 100644
--- a/grpc/include/grpcpp/xds_server_builder.h
+++ b/grpc/include/grpcpp/xds_server_builder.h
@@ -26,15 +26,52 @@
 namespace grpc {
 namespace experimental {
 
+class XdsServerServingStatusNotifierInterface {
+ public:
+  virtual ~XdsServerServingStatusNotifierInterface() = default;
+
+  // \a uri contains the listening target associated with the notification. Note
+  // that a single target provided to XdsServerBuilder can get resolved to
+  // multiple listening addresses.
+  // The callback is invoked each time there is an update to the serving status.
+  // The API does not provide any guarantees around duplicate updates.
+  // Status::OK signifies that the server is serving, while a non-OK status
+  // signifies that the server is not serving.
+  virtual void OnServingStatusUpdate(std::string uri, grpc::Status status) = 0;
+};
+
 class XdsServerBuilder : public ::grpc::ServerBuilder {
  public:
-  std::unique_ptr<Server> BuildAndStart() override {
-    grpc_server_config_fetcher* fetcher =
-        grpc_server_config_fetcher_xds_create();
-    if (fetcher == nullptr) return nullptr;
-    set_fetcher(fetcher);
-    return ServerBuilder::BuildAndStart();
+  // It is the responsibility of the application to make sure that \a notifier
+  // outlasts the life of the server. Notifications will start being made
+  // asynchronously once `BuildAndStart()` has been called. Note that it is
+  // possible for notifications to be made before `BuildAndStart()` returns.
+  void set_status_notifier(XdsServerServingStatusNotifierInterface* notifier) {
+    notifier_ = notifier;
   }
+
+ private:
+  // Called at the beginning of BuildAndStart().
+  ChannelArguments BuildChannelArgs() override {
+    ChannelArguments args = ServerBuilder::BuildChannelArgs();
+    grpc_channel_args c_channel_args = args.c_channel_args();
+    grpc_server_config_fetcher* fetcher = grpc_server_config_fetcher_xds_create(
+        {OnServingStatusUpdate, notifier_}, &c_channel_args);
+    if (fetcher != nullptr) set_fetcher(fetcher);
+    return args;
+  }
+
+  static void OnServingStatusUpdate(void* user_data, const char* uri,
+                                    grpc_status_code code,
+                                    const char* error_message) {
+    if (user_data == nullptr) return;
+    XdsServerServingStatusNotifierInterface* notifier =
+        static_cast<XdsServerServingStatusNotifierInterface*>(user_data);
+    notifier->OnServingStatusUpdate(
+        uri, grpc::Status(static_cast<StatusCode>(code), error_message));
+  }
+
+  XdsServerServingStatusNotifierInterface* notifier_ = nullptr;
 };
 
 }  // namespace experimental
diff --git a/grpc/package.xml b/grpc/package.xml
index ab68aa0..c8935d3 100644
--- a/grpc/package.xml
+++ b/grpc/package.xml
@@ -13,8 +13,8 @@
  <date>2019-09-24</date>
  <time>16:06:07</time>
  <version>
-  <release>1.35.0</release>
-  <api>1.35.0</api>
+  <release>1.38.0</release>
+  <api>1.38.0</api>
  </version>
  <stability>
   <release>stable</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>Apache 2.0</license>
  <notes>
-- gRPC Core 1.35.0 update
+- gRPC Core 1.38.0 update
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -33,6 +33,10 @@
     <file baseinstalldir="/" name="include/grpc/byte_buffer_reader.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/census.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/event_engine/channel_args.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/event_engine/event_engine.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/event_engine/port.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/event_engine/slice_allocator.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/fork.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc_posix.h" role="src" />
@@ -130,6 +134,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" />
@@ -164,6 +170,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h" role="src" />
@@ -172,6 +179,10 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_result_parsing.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_result_parsing.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_service_config.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_service_config.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/server_address.cc" role="src" />
@@ -190,6 +201,10 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_idle/client_idle_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_filter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/fault_injection/service_config_parser.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/fault_injection/service_config_parser.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/http/client_authority_filter.cc" role="src" />
@@ -270,12 +285,16 @@
     <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_plugin.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/annotations/resource.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/annotations/resource.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c" role="src" />
@@ -324,6 +343,10 @@
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c" role="src" />
@@ -334,6 +357,14 @@
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c" role="src" />
@@ -360,8 +391,12 @@
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c" role="src" />
@@ -370,6 +405,8 @@
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c" role="src" />
@@ -428,28 +465,34 @@
     <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/annotations/status.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/annotations/versioning.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/annotations/versioning.upb.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/authority.upb.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/authority.upb.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/resource.upb.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/resource.upb.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/validate/validate.upb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upb-generated/validate/validate.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/authority.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/authority.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/context_params.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/context_params.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/resource.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/resource.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c" role="src" />
@@ -498,6 +541,10 @@
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c" role="src" />
@@ -506,6 +553,14 @@
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c" role="src" />
@@ -532,8 +587,12 @@
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c" role="src" />
@@ -542,6 +601,8 @@
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c" role="src" />
@@ -586,20 +647,22 @@
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/validate/validate.upbdefs.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/validate/validate.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/certificate_provider_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/certificate_provider_registry.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/certificate_provider_registry.h" role="src" />
@@ -618,7 +681,15 @@
     <file baseinstalldir="/" name="src/core/ext/xds/xds_client.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/xds_client_stats.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/xds_client_stats.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/xds/xds_http_fault_filter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/xds/xds_http_fault_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/xds/xds_http_filters.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/xds/xds_http_filters.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/xds/xds_server_config_fetcher.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/address_utils/parse_address.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/address_utils/parse_address.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/address_utils/sockaddr_utils.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/address_utils/sockaddr_utils.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/avl/avl.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/avl/avl.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/backoff/backoff.cc" role="src" />
@@ -665,6 +736,8 @@
     <file baseinstalldir="/" name="src/core/lib/debug/stats_data.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/debug/trace.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/debug/trace.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/event_engine/slice_allocator.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/event_engine/sockaddr.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/alloc.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/alloc.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/arena.h" role="src" />
@@ -738,10 +811,14 @@
     <file baseinstalldir="/" name="src/core/lib/gprpp/stat.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/stat_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/stat_windows.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/status_helper.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/status_helper.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/sync.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/thd.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/thd_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/thd_windows.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/time_util.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/time_util.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/format_request.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/format_request.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/httpcli.cc" role="src" />
@@ -813,7 +890,6 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_internal.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix_cfstream.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_uv.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_windows.cc" role="src" />
@@ -824,10 +900,6 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/nameser.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/parse_address.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/parse_address.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/poller/eventmanager_libuv.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/poller/eventmanager_libuv.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset.cc" role="src" />
@@ -857,8 +929,6 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_windows.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_factory_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_factory_posix.h" role="src" />
@@ -928,19 +998,11 @@
     <file baseinstalldir="/" name="src/core/lib/json/json_util.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/json/json_util.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/json/json_writer.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/matchers/matchers.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/matchers/matchers.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/authorization_engine.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/authorization_engine.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/evaluate_args.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/evaluate_args.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/activation.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/cel_expression.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/cel_value.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/evaluator_core.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/flat_expr_builder.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/context/security_context.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/alts_credentials.cc" role="src" />
@@ -1197,7 +1259,6 @@
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/const_init.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/dynamic_annotations.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/atomic_hook.h" role="src" />
-    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/bits.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/cycleclock.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/cycleclock.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/internal/direct_mmap.h" role="src" />
@@ -1246,7 +1307,6 @@
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/thread_annotations.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/fixed_array.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/flat_hash_map.h" role="src" />
-    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/flat_hash_set.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/inlined_vector.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/internal/common.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/internal/compressed_tuple.h" role="src" />
@@ -1297,12 +1357,17 @@
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/city.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/hash.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/hash.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/wyhash.cc" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/hash/internal/wyhash.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/memory/memory.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/meta/type_traits.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/bits.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/int128.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/int128.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/internal/bits.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/numeric/internal/representation.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/status/internal/status_internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/status/internal/statusor_internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/status/status.cc" role="src" />
@@ -1324,7 +1389,12 @@
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/charconv_bigint.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/charconv_parse.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_internal.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/escaping.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/escaping.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/memutil.cc" role="src" />
@@ -1348,6 +1418,7 @@
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/str_format/parser.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/str_join_internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/str_split_internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/string_constant.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/utf8.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/internal/utf8.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/strings/match.cc" role="src" />
@@ -1373,10 +1444,10 @@
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/blocking_counter.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h" role="src" />
+    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/futex.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h" role="src" />
-    <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h" role="src" />
     <file baseinstalldir="/" name="third_party/abseil-cpp/absl/synchronization/internal/waiter.cc" role="src" />
@@ -1476,6 +1547,7 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/bio/printf.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/bio/socket.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/bio/socket_helper.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/blake2/blake2.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/bn_extra/bn_asn1.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/bn_extra/convert.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/buf/buf.c" role="src" />
@@ -1505,6 +1577,7 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/conf/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-fuchsia.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-linux.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/cpu-aarch64-win.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/cpu-arm-linux.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/cpu-arm-linux.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/cpu-arm.c" role="src" />
@@ -1515,10 +1588,8 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/curve25519/curve25519_tables.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/curve25519/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/curve25519/spake25519.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/dh/check.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/dh/dh.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/dh/dh_asn1.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/dh/params.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c" role="src" />
@@ -1588,6 +1659,8 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/delocate.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/des/des.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/des/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/dh/check.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/dh/dh.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/digest/digest.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/digest/digests.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/digest/internal.h" role="src" />
@@ -1611,9 +1684,9 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/ec/wnaf.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdh/ecdh.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdsa/ecdsa.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/ecdsa/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/hmac/hmac.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/is_fips.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/md4/md4.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/md5/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/md5/md5.c" role="src" />
@@ -1637,6 +1710,7 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/padding.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/rsa.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/rsa/rsa_impl.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/self_check/fips.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/self_check/self_check.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/sha/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/fipsmodule/sha/sha1-altivec.c" role="src" />
@@ -1680,6 +1754,7 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/rand_extra/deterministic.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/rand_extra/forkunsafe.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/rand_extra/fuchsia.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/rand_extra/passive.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/rand_extra/rand_extra.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/rand_extra/windows.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/rc4/rc4.c" role="src" />
@@ -1722,7 +1797,6 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_r2x.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c" role="src" />
@@ -1792,6 +1866,7 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/base.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/base64.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/bio.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/blake2.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/blowfish.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/bn.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/buf.h" role="src" />
@@ -1818,6 +1893,7 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/engine.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/err.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/evp.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/evp_errors.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/ex_data.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/hkdf.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/include/openssl/hmac.h" role="src" />
@@ -1866,6 +1942,7 @@
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/dtls_method.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/dtls_record.cc" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/handoff.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/handshake.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl-with-bazel/src/ssl/handshake_client.cc" role="src" />
@@ -1960,10 +2037,6 @@
     <file baseinstalldir="/" name="third_party/upb/upb/def.hpp" role="src" />
     <file baseinstalldir="/" name="third_party/upb/upb/encode.c" role="src" />
     <file baseinstalldir="/" name="third_party/upb/upb/encode.h" role="src" />
-    <file baseinstalldir="/" name="third_party/upb/upb/json_decode.c" role="src" />
-    <file baseinstalldir="/" name="third_party/upb/upb/json_decode.h" role="src" />
-    <file baseinstalldir="/" name="third_party/upb/upb/json_encode.c" role="src" />
-    <file baseinstalldir="/" name="third_party/upb/upb/json_encode.h" role="src" />
     <file baseinstalldir="/" name="third_party/upb/upb/msg.c" role="src" />
     <file baseinstalldir="/" name="third_party/upb/upb/msg.h" role="src" />
     <file baseinstalldir="/" name="third_party/upb/upb/port_def.inc" role="src" />
@@ -1978,6 +2051,7 @@
     <file baseinstalldir="/" name="third_party/upb/upb/upb.h" role="src" />
     <file baseinstalldir="/" name="third_party/upb/upb/upb.hpp" role="src" />
     <file baseinstalldir="/" name="third_party/upb/upb/upb.int.h" role="src" />
+    <file baseinstalldir="/" name="third_party/xxhash/xxhash.h" role="src" />
     <file baseinstalldir="/" name="third_party/zlib/adler32.c" role="src" />
     <file baseinstalldir="/" name="third_party/zlib/compress.c" role="src" />
     <file baseinstalldir="/" name="third_party/zlib/crc32.c" role="src" />
@@ -2179,7 +2253,7 @@
    <license>BSD</license>
    <notes>
 - GA release
-- Fix shutdown hang problem #4017
+- Fix shutdown freeze problem #4017
    </notes>
   </release>
   <release>
diff --git a/grpc/requirements.bazel.txt b/grpc/requirements.bazel.txt
index 09f161a..4b7135b 100644
--- a/grpc/requirements.bazel.txt
+++ b/grpc/requirements.bazel.txt
@@ -1,15 +1,15 @@
 # GRPC Python setup requirements
-coverage>=4.0
-cython>=0.29.8
-enum34>=1.0.4
+coverage==4.5.4
+cython==0.29.21
+enum34==1.1.10
 protobuf>=3.5.0.post1, < 4.0dev
-six>=1.10
-wheel>=0.29
-futures>=2.2.0
-google-auth>=1.17.2
+six==1.15.0
+wheel==0.36.2
+futures==3.1.1
+google-auth==1.24.0
 oauth2client==4.1.0
-requests>=2.14.2
-urllib3>=1.23
+requests==2.25.1
+urllib3==1.26.3
 chardet==3.0.4
 certifi==2017.4.17
 idna==2.7
diff --git a/grpc/setup.py b/grpc/setup.py
index 4b8c9d4..c93d419 100644
--- a/grpc/setup.py
+++ b/grpc/setup.py
@@ -73,6 +73,7 @@
                                            'upb-generated'),)
 UPBDEFS_GRPC_GENERATED_INCLUDE = (os.path.join('src', 'core', 'ext',
                                                'upbdefs-generated'),)
+XXHASH_INCLUDE = (os.path.join('third_party', 'xxhash'),)
 ZLIB_INCLUDE = (os.path.join('third_party', 'zlib'),)
 README = os.path.join(PYTHON_STEM, 'README.rst')
 
@@ -106,37 +107,62 @@
     'License :: OSI Approved :: Apache Software License',
 ]
 
-BUILD_WITH_BORING_SSL_ASM = os.environ.get('GRPC_BUILD_WITH_BORING_SSL_ASM',
-                                           True)
+
+def _env_bool_value(env_name, default):
+    """Parses a bool option from an environment variable"""
+    return os.environ.get(env_name, default).upper() not in ['FALSE', '0', '']
+
+
+BUILD_WITH_BORING_SSL_ASM = _env_bool_value('GRPC_BUILD_WITH_BORING_SSL_ASM',
+                                            'True')
+
+# Export this environment variable to override the platform variant that will
+# be chosen for boringssl assembly optimizations. This option is useful when
+# crosscompiling and the host platform as obtained by distutils.utils.get_platform()
+# doesn't match the platform we are targetting.
+# Example value: "linux-aarch64"
+BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM = os.environ.get(
+    'GRPC_BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM', '')
 
 # Environment variable to determine whether or not the Cython extension should
 # *use* Cython or use the generated C files. Note that this requires the C files
 # to have been generated by building first *with* Cython support. Even if this
 # is set to false, if the script detects that the generated `.c` file isn't
 # present, then it will still attempt to use Cython.
-BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
+BUILD_WITH_CYTHON = _env_bool_value('GRPC_PYTHON_BUILD_WITH_CYTHON', 'False')
 
 # Export this variable to use the system installation of openssl. You need to
 # have the header files installed (in /usr/include/openssl) and during
 # runtime, the shared library must be installed
-BUILD_WITH_SYSTEM_OPENSSL = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_OPENSSL',
-                                           False)
+BUILD_WITH_SYSTEM_OPENSSL = _env_bool_value('GRPC_PYTHON_BUILD_SYSTEM_OPENSSL',
+                                            'False')
 
 # Export this variable to use the system installation of zlib. You need to
 # have the header files installed (in /usr/include/) and during
 # runtime, the shared library must be installed
-BUILD_WITH_SYSTEM_ZLIB = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_ZLIB', False)
+BUILD_WITH_SYSTEM_ZLIB = _env_bool_value('GRPC_PYTHON_BUILD_SYSTEM_ZLIB',
+                                         'False')
 
 # Export this variable to use the system installation of cares. You need to
 # have the header files installed (in /usr/include/) and during
 # runtime, the shared library must be installed
-BUILD_WITH_SYSTEM_CARES = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_CARES',
-                                         False)
+BUILD_WITH_SYSTEM_CARES = _env_bool_value('GRPC_PYTHON_BUILD_SYSTEM_CARES',
+                                          'False')
 
 # Export this variable to use the system installation of re2. You need to
 # have the header files installed (in /usr/include/re2) and during
 # runtime, the shared library must be installed
-BUILD_WITH_SYSTEM_RE2 = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_RE2', False)
+BUILD_WITH_SYSTEM_RE2 = _env_bool_value('GRPC_PYTHON_BUILD_SYSTEM_RE2', 'False')
+
+# Export this variable to force building the python extension with a statically linked libstdc++.
+# At least on linux, this is normally not needed as we can build manylinux-compatible wheels on linux just fine
+# without statically linking libstdc++ (which leads to a slight increase in the wheel size).
+# This option is useful when crosscompiling wheels for aarch64 where
+# it's difficult to ensure that the crosscompilation toolchain has a high-enough version
+# of GCC (we require >4.9) but still uses old-enough libstdc++ symbols.
+# TODO(jtattermusch): remove this workaround once issues with crosscompiler version are resolved.
+BUILD_WITH_STATIC_LIBSTDCXX = _env_bool_value(
+    'GRPC_PYTHON_BUILD_WITH_STATIC_LIBSTDCXX', 'False')
 
 # For local development use only: This skips building gRPC Core and its
 # dependencies, including protobuf and boringssl. This allows "incremental"
@@ -149,23 +175,23 @@
 #    make HAS_SYSTEM_OPENSSL_ALPN=0
 #
 # TODO(ericgribkoff) Respect the BUILD_WITH_SYSTEM_* flags alongside this option
-USE_PREBUILT_GRPC_CORE = os.environ.get('GRPC_PYTHON_USE_PREBUILT_GRPC_CORE',
-                                        False)
+USE_PREBUILT_GRPC_CORE = _env_bool_value('GRPC_PYTHON_USE_PREBUILT_GRPC_CORE',
+                                         'False')
 
 # If this environmental variable is set, GRPC will not try to be compatible with
 # libc versions old than the one it was compiled against.
-DISABLE_LIBC_COMPATIBILITY = os.environ.get(
-    'GRPC_PYTHON_DISABLE_LIBC_COMPATIBILITY', False)
+DISABLE_LIBC_COMPATIBILITY = _env_bool_value(
+    'GRPC_PYTHON_DISABLE_LIBC_COMPATIBILITY', 'False')
 
 # Environment variable to determine whether or not to enable coverage analysis
 # in Cython modules.
-ENABLE_CYTHON_TRACING = os.environ.get('GRPC_PYTHON_ENABLE_CYTHON_TRACING',
-                                       False)
+ENABLE_CYTHON_TRACING = _env_bool_value('GRPC_PYTHON_ENABLE_CYTHON_TRACING',
+                                        'False')
 
 # Environment variable specifying whether or not there's interest in setting up
 # documentation building.
-ENABLE_DOCUMENTATION_BUILD = os.environ.get(
-    'GRPC_PYTHON_ENABLE_DOCUMENTATION_BUILD', False)
+ENABLE_DOCUMENTATION_BUILD = _env_bool_value(
+    'GRPC_PYTHON_ENABLE_DOCUMENTATION_BUILD', 'False')
 
 
 def check_linker_need_libatomic():
@@ -239,6 +265,9 @@
 EXTRA_COMPILE_ARGS = shlex.split(EXTRA_ENV_COMPILE_ARGS)
 EXTRA_LINK_ARGS = shlex.split(EXTRA_ENV_LINK_ARGS)
 
+if BUILD_WITH_STATIC_LIBSTDCXX:
+    EXTRA_LINK_ARGS.append('-static-libstdc++')
+
 CYTHON_EXTENSION_PACKAGE_NAMES = ()
 
 CYTHON_EXTENSION_MODULE_NAMES = ('grpc._cython.cygrpc',)
@@ -271,7 +300,8 @@
                                  ADDRESS_SORTING_INCLUDE + CARES_INCLUDE +
                                  RE2_INCLUDE + SSL_INCLUDE + UPB_INCLUDE +
                                  UPB_GRPC_GENERATED_INCLUDE +
-                                 UPBDEFS_GRPC_GENERATED_INCLUDE + ZLIB_INCLUDE)
+                                 UPBDEFS_GRPC_GENERATED_INCLUDE +
+                                 XXHASH_INCLUDE + ZLIB_INCLUDE)
 
 EXTENSION_LIBRARIES = ()
 if "linux" in sys.platform:
@@ -301,17 +331,22 @@
 
 asm_key = ''
 if BUILD_WITH_BORING_SSL_ASM and not BUILD_WITH_SYSTEM_OPENSSL:
+    boringssl_asm_platform = BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM if BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM else util.get_platform(
+    )
     LINUX_X86_64 = 'linux-x86_64'
     LINUX_ARM = 'linux-arm'
-    if LINUX_X86_64 == util.get_platform():
+    LINUX_AARCH64 = 'linux-aarch64'
+    if LINUX_X86_64 == boringssl_asm_platform:
         asm_key = 'crypto_linux_x86_64'
-    elif LINUX_ARM == util.get_platform():
+    elif LINUX_ARM == boringssl_asm_platform:
         asm_key = 'crypto_linux_arm'
-    elif "mac" in util.get_platform() and "x86_64" in util.get_platform():
+    elif LINUX_AARCH64 == boringssl_asm_platform:
+        asm_key = 'crypto_linux_aarch64'
+    elif "mac" in boringssl_asm_platform and "x86_64" in boringssl_asm_platform:
         asm_key = 'crypto_mac_x86_64'
     else:
         print("ASM Builds for BoringSSL currently not supported on:",
-              util.get_platform())
+              boringssl_asm_platform)
 if asm_key:
     asm_files = grpc_core_dependencies.ASM_SOURCE_FILES[asm_key]
 else:
@@ -354,14 +389,16 @@
 # By default, Python3 distutils enforces compatibility of
 # c plugins (.so files) with the OSX version Python was built with.
 # We need OSX 10.10, the oldest which supports C++ thread_local.
+# Python 3.9: Mac OS Big Sur sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') returns int (11)
 if 'darwin' in sys.platform:
     mac_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
-    if mac_target and (pkg_resources.parse_version(mac_target) <
-                       pkg_resources.parse_version('10.10.0')):
-        os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.10'
-        os.environ['_PYTHON_HOST_PLATFORM'] = re.sub(
-            r'macosx-[0-9]+\.[0-9]+-(.+)', r'macosx-10.10-\1',
-            util.get_platform())
+    if mac_target:
+        mac_target = pkg_resources.parse_version(str(mac_target))
+        if mac_target < pkg_resources.parse_version('10.10.0'):
+            os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.10'
+            os.environ['_PYTHON_HOST_PLATFORM'] = re.sub(
+                r'macosx-[0-9]+\.[0-9]+-(.+)', r'macosx-10.10-\1',
+                util.get_platform())
 
 
 def cython_extensions_and_necessity():
diff --git a/grpc/spm-core-include/grpc/event_engine/README.md b/grpc/spm-core-include/grpc/event_engine/README.md
new file mode 100644
index 0000000..b2d4fef
--- /dev/null
+++ b/grpc/spm-core-include/grpc/event_engine/README.md
@@ -0,0 +1,38 @@
+# gRPC EventEngine
+
+An EventEngine handles all cross-platform I/O, task execution, and DNS
+resolution for gRPC. A default, cross-platform implementation is provided with
+gRPC, but part of the intent here is to provide an interface for external
+integrators to bring their own functionality. This allows for integration with
+external event loops, siloing I/O and task execution between channels or
+servers, and other custom integrations that were previously unsupported.
+
+*WARNING*: This is experimental code and is subject to change.
+
+## High level expectations of an EventEngine implementation
+
+### Provide their own I/O threads
+EventEngines are expected to internally create whatever threads are required to
+perform I/O and execute callbacks. For example, an EventEngine implementation
+may want to spawn separate thread pools for polling and callback execution.
+
+### Provisioning data buffers via Slice allocation
+At a high level, gRPC provides a `ResourceQuota` system that allows gRPC to
+reclaim memory and degrade gracefully when memory reaches application-defined
+thresholds. To enable this feature, the memory allocation of read/write buffers
+within an EventEngine must be acquired in the form of Slices from
+SliceAllocators. This is covered more fully in the gRFC and code.
+
+### Documentating expectations around callback execution
+Some callbacks may be expensive to run. EventEngines should decide on and
+document whether callback execution might block polling operations. This way,
+application developers can plan accordingly (e.g., run their expensive callbacks
+on a separate thread if necessary).
+
+### Handling concurrent usage
+Assume that gRPC may use an EventEngine concurrently across multiple threads.
+
+## TODO: documentation
+
+* Example usage
+* Link to gRFC
diff --git a/grpc/spm-core-include/grpc/event_engine/channel_args.h b/grpc/spm-core-include/grpc/event_engine/channel_args.h
new file mode 100644
index 0000000..d809b1f
--- /dev/null
+++ b/grpc/spm-core-include/grpc/event_engine/channel_args.h
@@ -0,0 +1,28 @@
+// Copyright 2021 The 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_EVENT_ENGINE_CHANNEL_ARGS_H
+#define GRPC_EVENT_ENGINE_CHANNEL_ARGS_H
+
+#include <grpc/support/port_platform.h>
+
+namespace grpc_event_engine {
+namespace experimental {
+
+// TODO(hork): define
+class ChannelArgs;
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_CHANNEL_ARGS_H
diff --git a/grpc/spm-core-include/grpc/event_engine/event_engine.h b/grpc/spm-core-include/grpc/event_engine/event_engine.h
new file mode 100644
index 0000000..cdb5966
--- /dev/null
+++ b/grpc/spm-core-include/grpc/event_engine/event_engine.h
@@ -0,0 +1,336 @@
+// Copyright 2021 The 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_EVENT_ENGINE_EVENT_ENGINE_H
+#define GRPC_EVENT_ENGINE_EVENT_ENGINE_H
+
+#include <grpc/support/port_platform.h>
+
+#include <functional>
+#include <vector>
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/time/time.h"
+
+#include "grpc/event_engine/channel_args.h"
+#include "grpc/event_engine/port.h"
+#include "grpc/event_engine/slice_allocator.h"
+
+// TODO(hork): explicitly define lifetimes and ownership of all objects.
+// TODO(hork): Define the Endpoint::Write metrics collection system
+
+namespace grpc_event_engine {
+namespace experimental {
+
+////////////////////////////////////////////////////////////////////////////////
+/// The EventEngine encapsulates all platform-specific behaviors related to low
+/// level network I/O, timers, asynchronous execution, and DNS resolution.
+///
+/// This interface allows developers to provide their own event management and
+/// network stacks. Motivating uses cases for supporting custom EventEngines
+/// include the ability to hook into external event loops, and using different
+/// EventEngine instances for each channel to better insulate network I/O and
+/// callback processing from other channels.
+///
+/// A default cross-platform EventEngine instance is provided by gRPC.
+///
+/// LIFESPAN AND OWNERSHIP
+///
+/// gRPC takes shared ownership of EventEngines via std::shared_ptrs to ensure
+/// that the engines remain available until they are no longer needed. Depending
+/// on the use case, engines may live until gRPC is shut down.
+///
+/// EXAMPLE USAGE (Not yet implemented)
+///
+/// Custom EventEngines can be specified per channel, and allow configuration
+/// for both clients and servers. To set a custom EventEngine for a client
+/// channel, you can do something like the following:
+///
+///    ChannelArguments args;
+///    std::shared_ptr<EventEngine> engine = std::make_shared<MyEngine>(...);
+///    args.SetEventEngine(engine);
+///    MyAppClient client(grpc::CreateCustomChannel(
+///        "localhost:50051", grpc::InsecureChannelCredentials(), args));
+///
+/// A gRPC server can use a custom EventEngine by calling the
+/// ServerBuilder::SetEventEngine method:
+///
+///    ServerBuilder builder;
+///    std::shared_ptr<EventEngine> engine = std::make_shared<MyEngine>(...);
+///    builder.SetEventEngine(engine);
+///    std::unique_ptr<Server> server(builder.BuildAndStart());
+///    server->Wait();
+///
+////////////////////////////////////////////////////////////////////////////////
+class EventEngine {
+ public:
+  /// A basic callable function. The first argument to all callbacks is an
+  /// absl::Status indicating the status of the operation associated with this
+  /// callback. Each EventEngine method that takes a callback parameter, defines
+  /// the expected sets and meanings of statuses for that use case.
+  using Callback = std::function<void(absl::Status)>;
+  /// A callback handle, used to cancel a callback.
+  struct TaskHandle {
+    intptr_t key;
+  };
+  /// A thin wrapper around a platform-specific sockaddr type. A sockaddr struct
+  /// exists on all platforms that gRPC supports.
+  ///
+  /// Platforms are expected to provide definitions for:
+  /// * sockaddr
+  /// * sockaddr_in
+  /// * sockaddr_in6
+  class ResolvedAddress {
+   public:
+    static constexpr socklen_t MAX_SIZE_BYTES = 128;
+
+    ResolvedAddress(const sockaddr* address, socklen_t size);
+    const struct sockaddr* address() const;
+    socklen_t size() const;
+
+   private:
+    char address_[MAX_SIZE_BYTES];
+    socklen_t size_;
+  };
+
+  /// An Endpoint represents one end of a connection between a gRPC client and
+  /// server. Endpoints are created when connections are established, and
+  /// Endpoint operations are gRPC's primary means of communication.
+  ///
+  /// Endpoints must use the provided SliceAllocator for all data buffer memory
+  /// allocations. gRPC allows applications to set memory constraints per
+  /// Channel or Server, and the implementation depends on all dynamic memory
+  /// allocation being handled by the quota system.
+  class Endpoint {
+   public:
+    /// The Endpoint destructor is responsible for shutting down all connections
+    /// and invoking all pending read or write callbacks with an error status.
+    virtual ~Endpoint() = default;
+    /// Read data from the Endpoint.
+    ///
+    /// When data is available on the connection, that data is moved into the
+    /// \a buffer, and the \a on_read callback is called. The caller must ensure
+    /// that the callback has access to the buffer when executed later.
+    /// Ownership of the buffer is not transferred. Valid slices *may* be placed
+    /// into the buffer even if the callback is invoked with a non-OK Status.
+    ///
+    /// For failed read operations, implementations should pass the appropriate
+    /// statuses to \a on_read. For example, callbacks might expect to receive
+    /// DEADLINE_EXCEEDED when the deadline is exceeded, and CANCELLED on
+    /// endpoint shutdown.
+    virtual void Read(Callback on_read, SliceBuffer* buffer,
+                      absl::Time deadline) = 0;
+    /// Write data out on the connection.
+    ///
+    /// \a on_writable is called when the connection is ready for more data. The
+    /// Slices within the \a data buffer may be mutated at will by the Endpoint
+    /// until \a on_writable is called. The \a data SliceBuffer will remain
+    /// valid after calling \a Write, but its state is otherwise undefined.
+    ///
+    /// For failed write operations, implementations should pass the appropriate
+    /// statuses to \a on_writable. For example, callbacks might expect to
+    /// receive DEADLINE_EXCEEDED when the deadline is exceeded, and CANCELLED
+    /// on endpoint shutdown.
+    virtual void Write(Callback on_writable, SliceBuffer* data,
+                       absl::Time deadline) = 0;
+    // TODO(hork): define status codes for the callback
+    // TODO(hork): define cleanup operations, lifetimes, responsibilities.
+    virtual void Close(Callback on_close) = 0;
+    /// These methods return an address in the format described in DNSResolver.
+    /// The returned values are owned by the Endpoint and are expected to remain
+    /// valid for the life of the Endpoint.
+    virtual const ResolvedAddress* GetPeerAddress() const = 0;
+    virtual const ResolvedAddress* GetLocalAddress() const = 0;
+  };
+
+  /// Called when a new connection is established.
+  ///
+  /// If the connection attempt was not successful, implementations should pass
+  /// the appropriate statuses to this callback. For example, callbacks might
+  /// expect to receive DEADLINE_EXCEEDED statuses when appropriate, or
+  /// CANCELLED statuses on EventEngine shutdown.
+  using OnConnectCallback =
+      std::function<void(absl::StatusOr<std::unique_ptr<Endpoint>>)>;
+
+  /// An EventEngine Listener listens for incoming connection requests from gRPC
+  /// clients and initiates request processing once connections are established.
+  class Listener {
+   public:
+    /// Called when the listener has accepted a new client connection.
+    using AcceptCallback = std::function<void(std::unique_ptr<Endpoint>)>;
+    virtual ~Listener() = default;
+    /// Bind an address/port to this Listener.
+    ///
+    /// It is expected that multiple addresses/ports can be bound to this
+    /// Listener before Listener::Start has been called. Returns either the
+    /// bound port or an appropriate error status.
+    virtual absl::StatusOr<int> Bind(const ResolvedAddress& addr) = 0;
+    virtual absl::Status Start() = 0;
+  };
+
+  /// Factory method to create a network listener / server.
+  ///
+  /// Once a \a Listener is created and started, the \a on_accept callback will
+  /// be called once asynchronously for each established connection. Note that
+  /// unlike other callbacks, there is no status code parameter since the
+  /// callback will only be called in healthy scenarios where connections can be
+  /// accepted.
+  ///
+  /// This method may return a non-OK status immediately if an error was
+  /// encountered in any synchronous steps required to create the Listener. In
+  /// this case, \a on_shutdown will never be called.
+  ///
+  /// If this method returns a Listener, then \a on_shutdown will be invoked
+  /// exactly once, when the Listener is shut down. The status passed to it will
+  /// indicate if there was a problem during shutdown.
+  ///
+  /// The provided \a SliceAllocatorFactory is used to create \a SliceAllocators
+  /// for Endpoint construction.
+  virtual absl::StatusOr<std::unique_ptr<Listener>> CreateListener(
+      Listener::AcceptCallback on_accept, Callback on_shutdown,
+      const ChannelArgs& args,
+      SliceAllocatorFactory slice_allocator_factory) = 0;
+  /// Creates a client network connection to a remote network listener.
+  ///
+  /// \a Connect may return an error status immediately if there was a failure
+  /// in the synchronous part of establishing a connection. In that event, the
+  /// \a on_connect callback *will not* have been executed. Otherwise, it is
+  /// expected that the \a on_connect callback will be asynchronously executed
+  /// exactly once by the EventEngine.
+  ///
+  /// Implementation Note: it is important that the \a slice_allocator be used
+  /// for all read/write buffer allocations in the EventEngine implementation.
+  /// This allows gRPC's \a ResourceQuota system to monitor and control memory
+  /// usage with graceful degradation mechanisms. Please see the \a
+  /// SliceAllocator API for more information.
+  virtual absl::Status Connect(OnConnectCallback on_connect,
+                               const ResolvedAddress& addr,
+                               const ChannelArgs& args,
+                               SliceAllocator slice_allocator,
+                               absl::Time deadline) = 0;
+
+  /// The DNSResolver that provides asynchronous resolution.
+  class DNSResolver {
+   public:
+    /// A task handle for DNS Resolution requests.
+    struct LookupTaskHandle {
+      intptr_t key;
+    };
+    /// A DNS SRV record type.
+    struct SRVRecord {
+      std::string host;
+      int port = 0;
+      int priority = 0;
+      int weight = 0;
+    };
+    /// Called with the collection of sockaddrs that were resolved from a given
+    /// target address.
+    using LookupHostnameCallback =
+        std::function<void(absl::StatusOr<std::vector<ResolvedAddress>>)>;
+    /// Called with a collection of SRV records.
+    using LookupSRVCallback =
+        std::function<void(absl::StatusOr<std::vector<SRVRecord>>)>;
+    /// Called with the result of a TXT record lookup
+    using LookupTXTCallback = std::function<void(absl::StatusOr<std::string>)>;
+
+    virtual ~DNSResolver() = default;
+
+    /// Asynchronously resolve an address.
+    ///
+    /// \a default_port may be a non-numeric named service port, and will only
+    /// be used if \a address does not already contain a port component.
+    ///
+    /// When the lookup is complete, the \a on_resolve callback will be invoked
+    /// with a status indicating the success or failure of the lookup.
+    /// Implementations should pass the appropriate statuses to the callback.
+    /// For example, callbacks might expect to receive DEADLINE_EXCEEDED when
+    /// the deadline is exceeded or CANCELLED if the lookup was cancelled.
+    virtual LookupTaskHandle LookupHostname(LookupHostnameCallback on_resolve,
+                                            absl::string_view address,
+                                            absl::string_view default_port,
+                                            absl::Time deadline) = 0;
+    /// Asynchronously perform an SRV record lookup.
+    ///
+    /// \a on_resolve has the same meaning and expectations as \a
+    /// LookupHostname's \a on_resolve callback.
+    virtual LookupTaskHandle LookupSRV(LookupSRVCallback on_resolve,
+                                       absl::string_view name,
+                                       absl::Time deadline) = 0;
+    /// Asynchronously perform a TXT record lookup.
+    ///
+    /// \a on_resolve has the same meaning and expectations as \a
+    /// LookupHostname's \a on_resolve callback.
+    virtual LookupTaskHandle LookupTXT(LookupTXTCallback on_resolve,
+                                       absl::string_view name,
+                                       absl::Time deadline) = 0;
+    /// Cancel an asynchronous lookup operation.
+    virtual void TryCancelLookup(LookupTaskHandle handle) = 0;
+  };
+
+  virtual ~EventEngine() = default;
+
+  // TODO(hork): define return status codes
+  /// Retrieves an instance of a DNSResolver.
+  virtual absl::StatusOr<std::unique_ptr<DNSResolver>> GetDNSResolver() = 0;
+
+  /// Intended for future expansion of Task run functionality.
+  struct RunOptions {};
+  // TODO(hork): consider recommendation to make TaskHandle an output arg
+  /// Run a callback as soon as possible.
+  ///
+  /// The \a fn callback's \a status argument is used to indicate whether it was
+  /// executed normally. For example, the status may be CANCELLED if
+  /// \a TryCancel was called, or if the EventEngine is being shut down.
+  virtual TaskHandle Run(Callback fn, RunOptions opts) = 0;
+  /// Synonymous with scheduling an alarm to run at time \a when.
+  ///
+  /// The callback \a fn will execute when either when time \a when arrives
+  /// (receiving status OK), or when the \a fn is cancelled (reveiving status
+  /// CANCELLED). The callback is guaranteed to be called exactly once.
+  virtual TaskHandle RunAt(absl::Time when, Callback fn, RunOptions opts) = 0;
+  /// Immediately tries to cancel a callback.
+  /// Note that this is a "best effort" cancellation. No guarantee is made that
+  /// the callback will be cancelled, the call could be in any stage.
+  ///
+  /// There are three scenarios in which we may cancel a scheduled function:
+  ///   1. We cancel the execution before it has run.
+  ///   2. The callback has already run.
+  ///   3. We can't cancel it because it is "in flight".
+  ///
+  /// In all cases, the cancellation is still considered successful, the
+  /// callback will be run exactly once from either cancellation or from its
+  /// activation.
+  virtual void TryCancel(TaskHandle handle) = 0;
+  /// Immediately run all callbacks with status indicating the shutdown. Every
+  /// EventEngine is expected to shut down exactly once. No new callbacks/tasks
+  /// should be scheduled after shutdown has begun, no new connections should be
+  /// created.
+  ///
+  /// If the \a on_shutdown_complete callback is given a non-OK status, errors
+  /// are expected to be unrecoverable. For example, an implementation could
+  /// warn callers about leaks if memory cannot be freed within a certain
+  /// timeframe.
+  virtual void Shutdown(Callback on_shutdown_complete) = 0;
+};
+
+/// Lazily instantiate and return a default global EventEngine instance if no
+/// custom instance is provided. If a custom EventEngine is provided for every
+/// channel/server via ChannelArgs, this method should never be called, and the
+/// default instance will never be instantiated.
+std::shared_ptr<EventEngine> GetDefaultEventEngine();
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_EVENT_ENGINE_H
diff --git a/grpc/spm-core-include/grpc/event_engine/port.h b/grpc/spm-core-include/grpc/event_engine/port.h
new file mode 100644
index 0000000..c24b8f9
--- /dev/null
+++ b/grpc/spm-core-include/grpc/event_engine/port.h
@@ -0,0 +1,39 @@
+// Copyright 2021 The 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_EVENT_ENGINE_PORT_H
+#define GRPC_EVENT_ENGINE_PORT_H
+
+#include <grpc/support/port_platform.h>
+
+// Platform-specific sockaddr includes
+#ifdef GRPC_UV
+#include <uv.h>
+#elif defined(GPR_ANDROID) || defined(GPR_LINUX) || defined(GPR_APPLE) ||   \
+    defined(GPR_FREEBSD) || defined(GPR_OPENBSD) || defined(GPR_SOLARIS) || \
+    defined(GPR_AIX) || defined(GPR_NACL) || defined(GPR_FUCHSIA) ||        \
+    defined(GRPC_POSIX_SOCKET)
+#define GRPC_EVENT_ENGINE_POSIX
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#elif defined(GPR_WINDOWS)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+// must be included after the above
+#include <mswsock.h>
+#else
+#error UNKNOWN PLATFORM
+#endif
+
+#endif  // GRPC_EVENT_ENGINE_PORT_H
diff --git a/grpc/spm-core-include/grpc/event_engine/slice_allocator.h b/grpc/spm-core-include/grpc/event_engine/slice_allocator.h
new file mode 100644
index 0000000..4370cd5
--- /dev/null
+++ b/grpc/spm-core-include/grpc/event_engine/slice_allocator.h
@@ -0,0 +1,81 @@
+// Copyright 2021 The 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_EVENT_ENGINE_SLICE_ALLOCATOR_H
+#define GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include <functional>
+
+#include "absl/status/status.h"
+
+// forward-declaring an internal struct, not used publicly.
+struct grpc_resource_quota;
+struct grpc_resource_user;
+
+namespace grpc_event_engine {
+namespace experimental {
+
+// TODO(nnoble): forward declared here, needs definition.
+class SliceBuffer;
+
+class SliceAllocator {
+ public:
+  // gRPC-internal constructor
+  explicit SliceAllocator(grpc_resource_user* user);
+  // Not copyable
+  SliceAllocator(SliceAllocator& other) = delete;
+  SliceAllocator& operator=(const SliceAllocator& other) = delete;
+  // Moveable
+  SliceAllocator(SliceAllocator&& other) = default;
+  SliceAllocator& operator=(SliceAllocator&& other) = default;
+  ~SliceAllocator();
+
+  using AllocateCallback =
+      std::function<void(absl::Status, SliceBuffer* buffer)>;
+  // TODO(hork): explain what happens under resource exhaustion.
+  /// Requests \a size bytes from gRPC, and populates \a dest with the allocated
+  /// slices. Ownership of the \a SliceBuffer is not transferred.
+  absl::Status Allocate(size_t size, SliceBuffer* dest,
+                        SliceAllocator::AllocateCallback cb);
+
+ private:
+  grpc_resource_user* resource_user_;
+};
+
+class SliceAllocatorFactory {
+ public:
+  // gRPC-internal constructor
+  explicit SliceAllocatorFactory(grpc_resource_quota* quota);
+  // Not copyable
+  SliceAllocatorFactory(SliceAllocatorFactory& other) = delete;
+  SliceAllocatorFactory& operator=(const SliceAllocatorFactory& other) = delete;
+  // Moveable
+  SliceAllocatorFactory(SliceAllocatorFactory&& other) = default;
+  SliceAllocatorFactory& operator=(SliceAllocatorFactory&& other) = default;
+  ~SliceAllocatorFactory();
+
+  /// On Endpoint creation, call \a CreateSliceAllocator with the name of the
+  /// endpoint peer (a URI string, most likely). Note: \a peer_name must outlive
+  /// the Endpoint.
+  SliceAllocator CreateSliceAllocator(absl::string_view peer_name);
+
+ private:
+  grpc_resource_quota* resource_quota_;
+};
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
+
+#endif  // GRPC_EVENT_ENGINE_SLICE_ALLOCATOR_H
diff --git a/grpc/spm-core-include/grpc/grpc.h b/grpc/spm-core-include/grpc/grpc.h
index 09bb106..f4408e1 100644
--- a/grpc/spm-core-include/grpc/grpc.h
+++ b/grpc/spm-core-include/grpc/grpc.h
@@ -411,10 +411,20 @@
                                                    grpc_completion_queue* cq,
                                                    void* reserved);
 
+// There might be more methods added later, so users should take care to memset
+// this to 0 before using it.
+typedef struct {
+  void (*on_serving_status_update)(void* user_data, const char* uri,
+                                   grpc_status_code code,
+                                   const char* error_message);
+  void* user_data;
+} grpc_server_xds_status_notifier;
+
 typedef struct grpc_server_config_fetcher grpc_server_config_fetcher;
 
 /** EXPERIMENTAL.  Creates an xDS config fetcher. */
-GRPCAPI grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create();
+GRPCAPI grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create(
+    grpc_server_xds_status_notifier notifier, const grpc_channel_args* args);
 
 /** EXPERIMENTAL.  Destroys a config fetcher. */
 GRPCAPI void grpc_server_config_fetcher_destroy(
@@ -495,6 +505,10 @@
 GRPCAPI void grpc_resource_quota_set_max_threads(
     grpc_resource_quota* resource_quota, int new_max_threads);
 
+/** EXPERIMENTAL.  Dumps xDS configs as a serialized ClientConfig proto.
+    The full name of the proto is envoy.service.status.v3.ClientConfig. */
+GRPCAPI grpc_slice grpc_dump_xds_configs();
+
 /** Fetch a vtable for a grpc_channel_arg that points to a grpc_resource_quota
  */
 GRPCAPI const grpc_arg_pointer_vtable* grpc_resource_quota_arg_vtable(void);
diff --git a/grpc/spm-core-include/grpc/grpc_security.h b/grpc/spm-core-include/grpc/grpc_security.h
index c1d7295..b5dafe1 100644
--- a/grpc/spm-core-include/grpc/grpc_security.h
+++ b/grpc/spm-core-include/grpc/grpc_security.h
@@ -856,8 +856,8 @@
 
 /**
  * Sets the options of whether to request and verify client certs. This should
- * be called only on the server side. It returns 1 on success and 0 on failure.
- * It is used for experimental purpose for now and subject to change.
+ * be called only on the server side. It is used for experimental purpose for
+ * now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_set_cert_request_type(
     grpc_tls_credentials_options* options,
@@ -868,8 +868,7 @@
  * hostname check, etc. This should be called only on the client side. If
  * |server_verification_option| is not GRPC_TLS_SERVER_VERIFICATION, use of a
  * custom authorization check (grpc_tls_server_authorization_check_config) is
- * mandatory. It returns 1 on success and 0 on failure. It is used for
- * experimental purpose for now and subject to change.
+ * mandatory. It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_set_server_verification_option(
     grpc_tls_credentials_options* options,
@@ -878,7 +877,6 @@
 /**
  * Sets the credential provider in the options.
  * The |options| will implicitly take a new ref to the |provider|.
- * It returns 1 on success and 0 on failure.
  * It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_set_certificate_provider(
@@ -887,8 +885,14 @@
 
 /**
  * If set, gRPC stack will keep watching the root certificates with
- * name |root_cert_name|. It returns 1 on success and 0 on failure. It is used
- * for experimental purpose for now and subject to change.
+ * name |root_cert_name|.
+ * If this is not set on the client side, we will use the root certificates
+ * stored in the default system location, since client side must provide root
+ * certificates in TLS.
+ * If this is not set on the server side, we will not watch any root certificate
+ * updates, and assume no root certificates needed for the server(single-side
+ * TLS). Default root certs on the server side is not supported.
+ * It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_watch_root_certs(
     grpc_tls_credentials_options* options);
@@ -903,8 +907,9 @@
 
 /**
  * If set, gRPC stack will keep watching the identity key-cert pairs
- * with name |identity_cert_name|. It returns 1 on success and 0 on failure. It
- * is used for experimental purpose for now and subject to change.
+ * with name |identity_cert_name|.
+ * This is required on the server side, and optional on the client side.
+ * It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_watch_identity_key_cert_pairs(
     grpc_tls_credentials_options* options);
@@ -920,8 +925,8 @@
 /**
  * Sets the configuration for a custom authorization check performed at the end
  * of the handshake. The |options| will implicitly take a new ref to the
- * |config|. It returns 1 on success and 0 on failure. It is used for
- * experimental purpose for now and subject to change.
+ * |config|.
+ * It is used for experimental purpose for now and subject to change.
  */
 GRPCAPI void grpc_tls_credentials_options_set_server_authorization_check_config(
     grpc_tls_credentials_options* options,
diff --git a/grpc/spm-core-include/grpc/grpc_security_constants.h b/grpc/spm-core-include/grpc/grpc_security_constants.h
index a62f767..4d7f078 100644
--- a/grpc/spm-core-include/grpc/grpc_security_constants.h
+++ b/grpc/spm-core-include/grpc/grpc_security_constants.h
@@ -29,10 +29,24 @@
 #define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
 #define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
 #define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert"
+// Please note that internally, we just faithfully pass whatever value we got by
+// calling SSL_get_peer_cert_chain() in OpenSSL/BoringSSL. This will mean in
+// OpenSSL, the following conditions might apply:
+// 1. On the client side, this property returns the full certificate chain. On
+// the server side, this property will return the certificate chain without the
+// leaf certificate. Application can use GRPC_X509_PEM_CERT_PROPERTY_NAME to
+// get the peer leaf certificate.
+// 2. If the session is resumed, this property could be empty for OpenSSL (but
+// not for BoringSSL).
+// For more, please refer to the official OpenSSL manual:
+// https://www.openssl.org/docs/man1.1.0/man3/SSL_get_peer_cert_chain.html.
 #define GRPC_X509_PEM_CERT_CHAIN_PROPERTY_NAME "x509_pem_cert_chain"
 #define GRPC_SSL_SESSION_REUSED_PROPERTY "ssl_session_reused"
 #define GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME "security_level"
+#define GRPC_PEER_DNS_PROPERTY_NAME "peer_dns"
 #define GRPC_PEER_SPIFFE_ID_PROPERTY_NAME "peer_spiffe_id"
+#define GRPC_PEER_EMAIL_PROPERTY_NAME "peer_email"
+#define GRPC_PEER_IP_PROPERTY_NAME "peer_ip"
 
 /** Environment variable that points to the default SSL roots file. This file
    must be a PEM encoded file with all the roots such as the one that can be
diff --git a/grpc/spm-core-include/grpc/impl/codegen/grpc_types.h b/grpc/spm-core-include/grpc/impl/codegen/grpc_types.h
index d67a9e9..9cf6d83 100644
--- a/grpc/spm-core-include/grpc/impl/codegen/grpc_types.h
+++ b/grpc/spm-core-include/grpc/impl/codegen/grpc_types.h
@@ -353,6 +353,17 @@
 /* Timeout in milliseconds to use for calls to the grpclb load balancer.
    If 0 or unset, the balancer calls will have no deadline. */
 #define GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS "grpc.grpclb_call_timeout_ms"
+/* Specifies the xDS bootstrap config as a JSON string.
+   FOR TESTING PURPOSES ONLY -- DO NOT USE IN PRODUCTION.
+   This option allows controlling the bootstrap configuration on a
+   per-channel basis, which is useful in tests.  However, this results
+   in having a separate xDS client instance per channel rather than
+   using the global instance, which is not the intended way to use xDS.
+   Currently, this will (a) add unnecessary load on the xDS server and
+   (b) break use of CSDS, and there may be additional side effects in
+   the future. */
+#define GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG \
+  "grpc.TEST_ONLY_DO_NOT_USE_IN_PROD.xds_bootstrap_config"
 /* Timeout in milliseconds to wait for the serverlist from the grpclb load
    balancer before using fallback backend addresses from the resolver.
    If 0, enter fallback mode immediately. Default value is 10000. */
diff --git a/grpc/spm-core-include/grpc/impl/codegen/port_platform.h b/grpc/spm-core-include/grpc/impl/codegen/port_platform.h
index c1bada1..387639b 100644
--- a/grpc/spm-core-include/grpc/impl/codegen/port_platform.h
+++ b/grpc/spm-core-include/grpc/impl/codegen/port_platform.h
@@ -39,6 +39,11 @@
 #endif
 #endif  // GPR_ABSEIL_SYNC
 
+/*
+ * Defines GRPC_ERROR_IS_ABSEIL_STATUS to use absl::Status for grpc_error_handle
+ */
+// #define GRPC_ERROR_IS_ABSEIL_STATUS 1
+
 /* Get windows.h included everywhere (we need it) */
 #if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
 #ifndef WIN32_LEAN_AND_MEAN
@@ -366,6 +371,7 @@
 #define GPR_ARCH_32 1
 #endif /* _LP64 */
 #elif defined(__Fuchsia__)
+#define GRPC_ARES 0
 #define GPR_FUCHSIA 1
 #define GPR_ARCH_64 1
 #define GPR_PLATFORM_STRING "fuchsia"
@@ -387,6 +393,7 @@
 #define GPR_POSIX_TIME 1
 #define GPR_HAS_PTHREAD_H 1
 #define GPR_GETPID_IN_UNISTD_H 1
+#define GRPC_ROOT_PEM_PATH "/config/ssl/cert.pem"
 #else
 #error "Could not auto-detect platform"
 #endif
diff --git a/grpc/spm-core-include/grpc/module.modulemap b/grpc/spm-core-include/grpc/module.modulemap
index 06c1e97..40606e5 100644
--- a/grpc/spm-core-include/grpc/module.modulemap
+++ b/grpc/spm-core-include/grpc/module.modulemap
@@ -2,6 +2,15 @@
 framework module grpc {
   umbrella header "grpc.h"
 
+header "byte_buffer.h"
+  header "byte_buffer_reader.h"
+  header "census.h"
+  header "compression.h"
+  header "fork.h"
+  header "grpc.h"
+  header "grpc_posix.h"
+  header "grpc_security.h"
+  header "grpc_security_constants.h"
   header "impl/codegen/atm.h"
   header "impl/codegen/byte_buffer.h"
   header "impl/codegen/byte_buffer_reader.h"
@@ -19,6 +28,10 @@
   header "impl/codegen/sync.h"
   header "impl/codegen/sync_abseil.h"
   header "impl/codegen/sync_generic.h"
+  header "load_reporting.h"
+  header "slice.h"
+  header "slice_buffer.h"
+  header "status.h"
   header "support/alloc.h"
   header "support/atm.h"
   header "support/cpu.h"
@@ -31,22 +44,9 @@
   header "support/sync_generic.h"
   header "support/thd_id.h"
   header "support/time.h"
-  header "byte_buffer.h"
-  header "byte_buffer_reader.h"
-  header "census.h"
-  header "compression.h"
-  header "fork.h"
-  header "grpc.h"
-  header "grpc_posix.h"
-  header "grpc_security.h"
-  header "grpc_security_constants.h"
-  header "load_reporting.h"
-  header "slice.h"
-  header "slice_buffer.h"
-  header "status.h"
   header "support/workaround_list.h"
 
-  textual header "impl/codegen/atm_gcc_atomic.h"
+textual header "impl/codegen/atm_gcc_atomic.h"
   textual header "impl/codegen/atm_gcc_sync.h"
   textual header "impl/codegen/atm_windows.h"
   textual header "impl/codegen/sync_custom.h"
diff --git a/grpc/spm-cpp-include/grpcpp/alarm.h b/grpc/spm-cpp-include/grpcpp/alarm.h
index 1405590..6723e13 100644
--- a/grpc/spm-cpp-include/grpcpp/alarm.h
+++ b/grpc/spm-cpp-include/grpcpp/alarm.h
@@ -56,6 +56,10 @@
   /// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
   /// an event with tag \a tag will be added to \a cq. If the alarm expired, the
   /// event's success bit will be true, false otherwise (ie, upon cancellation).
+  //
+  // USAGE NOTE: This is frequently used to inject arbitrary tags into \a cq by
+  // setting an immediate deadline. Such usage allows synchronizing an external
+  // event with an application's \a grpc::CompletionQueue::Next loop.
   template <typename T>
   void Set(::grpc::CompletionQueue* cq, const T& deadline, void* tag) {
     SetInternal(cq, ::grpc::TimePoint<T>(deadline).raw_time(), tag);
diff --git a/grpc/spm-cpp-include/grpcpp/channel.h b/grpc/spm-cpp-include/grpcpp/channel.h
index 5e67c64..65cc46d 100644
--- a/grpc/spm-cpp-include/grpcpp/channel.h
+++ b/grpc/spm-cpp-include/grpcpp/channel.h
@@ -114,7 +114,7 @@
   // with this channel (if any). It is set on the first call to CallbackCQ().
   // It is _not owned_ by the channel; ownership belongs with its internal
   // shutdown callback tag (invoked when the CQ is fully shutdown).
-  ::grpc::CompletionQueue* callback_cq_ = nullptr;
+  std::atomic<CompletionQueue*> callback_cq_{nullptr};
 
   std::vector<
       std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>>
diff --git a/grpc/spm-cpp-include/grpcpp/ext/admin_services.h b/grpc/spm-cpp-include/grpcpp/ext/admin_services.h
new file mode 100644
index 0000000..898a87e
--- /dev/null
+++ b/grpc/spm-cpp-include/grpcpp/ext/admin_services.h
@@ -0,0 +1,33 @@
+//
+//
+// Copyright 2021 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 GRPCPP_EXT_ADMIN_SERVICES_H
+#define GRPCPP_EXT_ADMIN_SERVICES_H
+
+#include <grpcpp/server_builder.h>
+
+namespace grpc {
+
+// Registers admin services to the given ServerBuilder. This function will add
+// admin services based on build time dependencies, for example, it only adds
+// CSDS service if xDS is enabled in this binary.
+void AddAdminServices(grpc::ServerBuilder* builder);
+
+}  // namespace grpc
+
+#endif  // GRPCPP_EXT_ADMIN_SERVICES_H
diff --git a/grpc/spm-cpp-include/grpcpp/generic/generic_stub.h b/grpc/spm-cpp-include/grpcpp/generic/generic_stub.h
index e4576af..e9564c3 100644
--- a/grpc/spm-cpp-include/grpcpp/generic/generic_stub.h
+++ b/grpc/spm-cpp-include/grpcpp/generic/generic_stub.h
@@ -22,6 +22,7 @@
 #include <functional>
 
 #include <grpcpp/client_context.h>
+#include <grpcpp/impl/codegen/stub_options.h>
 #include <grpcpp/impl/rpc_method.h>
 #include <grpcpp/support/async_stream.h>
 #include <grpcpp/support/async_unary_call.h>
@@ -53,7 +54,8 @@
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
   PrepareCall(ClientContext* context, const std::string& method,
               ::grpc::CompletionQueue* cq) {
-    return CallInternal(channel_.get(), context, method, cq, false, nullptr);
+    return CallInternal(channel_.get(), context, method, /*options=*/{}, cq,
+                        false, nullptr);
   }
 
   /// Setup a unary call to a named method \a method using \a context, and don't
@@ -67,6 +69,7 @@
         internal::ClientAsyncResponseReaderHelper::Create<ResponseType>(
             channel_.get(), cq,
             grpc::internal::RpcMethod(method.c_str(),
+                                      /*suffix_for_stats=*/nullptr,
                                       grpc::internal::RpcMethod::NORMAL_RPC),
             context, request));
   }
@@ -80,7 +83,8 @@
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> Call(
       ClientContext* context, const std::string& method,
       ::grpc::CompletionQueue* cq, void* tag) {
-    return CallInternal(channel_.get(), context, method, cq, true, tag);
+    return CallInternal(channel_.get(), context, method, /*options=*/{}, cq,
+                        true, tag);
   }
 
 #ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
@@ -89,7 +93,7 @@
   void UnaryCall(ClientContext* context, const std::string& method,
                  const RequestType* request, ResponseType* response,
                  std::function<void(grpc::Status)> on_completion) {
-    UnaryCallInternal(context, method, request, response,
+    UnaryCallInternal(context, method, /*options=*/{}, request, response,
                       std::move(on_completion));
   }
 
@@ -100,7 +104,8 @@
   void PrepareUnaryCall(ClientContext* context, const std::string& method,
                         const RequestType* request, ResponseType* response,
                         ClientUnaryReactor* reactor) {
-    PrepareUnaryCallInternal(context, method, request, response, reactor);
+    PrepareUnaryCallInternal(context, method, /*options=*/{}, request, response,
+                             reactor);
   }
 
   /// Setup a call to a named method \a method using \a context and tied to
@@ -109,7 +114,7 @@
   void PrepareBidiStreamingCall(
       ClientContext* context, const std::string& method,
       ClientBidiReactor<RequestType, ResponseType>* reactor) {
-    PrepareBidiStreamingCallInternal(context, method, reactor);
+    PrepareBidiStreamingCallInternal(context, method, /*options=*/{}, reactor);
   }
 #endif
 
@@ -123,9 +128,10 @@
     /// Setup and start a unary call to a named method \a method using
     /// \a context and specifying the \a request and \a response buffers.
     void UnaryCall(ClientContext* context, const std::string& method,
-                   const RequestType* request, ResponseType* response,
+                   StubOptions options, const RequestType* request,
+                   ResponseType* response,
                    std::function<void(grpc::Status)> on_completion) {
-      stub_->UnaryCallInternal(context, method, request, response,
+      stub_->UnaryCallInternal(context, method, options, request, response,
                                std::move(on_completion));
     }
 
@@ -134,19 +140,20 @@
     /// Like any other reactor-based RPC, it will not be activated until
     /// StartCall is invoked on its reactor.
     void PrepareUnaryCall(ClientContext* context, const std::string& method,
-                          const RequestType* request, ResponseType* response,
-                          ClientUnaryReactor* reactor) {
-      stub_->PrepareUnaryCallInternal(context, method, request, response,
-                                      reactor);
+                          StubOptions options, const RequestType* request,
+                          ResponseType* response, ClientUnaryReactor* reactor) {
+      stub_->PrepareUnaryCallInternal(context, method, options, request,
+                                      response, reactor);
     }
 
     /// Setup a call to a named method \a method using \a context and tied to
     /// \a reactor . Like any other bidi streaming RPC, it will not be activated
     /// until StartCall is invoked on its reactor.
     void PrepareBidiStreamingCall(
-        ClientContext* context, const std::string& method,
+        ClientContext* context, const std::string& method, StubOptions options,
         ClientBidiReactor<RequestType, ResponseType>* reactor) {
-      stub_->PrepareBidiStreamingCallInternal(context, method, reactor);
+      stub_->PrepareBidiStreamingCallInternal(context, method, options,
+                                              reactor);
     }
 
    private:
@@ -162,48 +169,50 @@
   std::shared_ptr<grpc::ChannelInterface> channel_;
 
   void UnaryCallInternal(ClientContext* context, const std::string& method,
-                         const RequestType* request, ResponseType* response,
+                         StubOptions options, const RequestType* request,
+                         ResponseType* response,
                          std::function<void(grpc::Status)> on_completion) {
     internal::CallbackUnaryCall(
         channel_.get(),
-        grpc::internal::RpcMethod(method.c_str(),
+        grpc::internal::RpcMethod(method.c_str(), options.suffix_for_stats(),
                                   grpc::internal::RpcMethod::NORMAL_RPC),
         context, request, response, std::move(on_completion));
   }
 
   void PrepareUnaryCallInternal(ClientContext* context,
-                                const std::string& method,
+                                const std::string& method, StubOptions options,
                                 const RequestType* request,
                                 ResponseType* response,
                                 ClientUnaryReactor* reactor) {
     internal::ClientCallbackUnaryFactory::Create<RequestType, ResponseType>(
         channel_.get(),
-        grpc::internal::RpcMethod(method.c_str(),
+        grpc::internal::RpcMethod(method.c_str(), options.suffix_for_stats(),
                                   grpc::internal::RpcMethod::NORMAL_RPC),
         context, request, response, reactor);
   }
 
   void PrepareBidiStreamingCallInternal(
-      ClientContext* context, const std::string& method,
+      ClientContext* context, const std::string& method, StubOptions options,
       ClientBidiReactor<RequestType, ResponseType>* reactor) {
     internal::ClientCallbackReaderWriterFactory<RequestType, ResponseType>::
         Create(channel_.get(),
                grpc::internal::RpcMethod(
-                   method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
+                   method.c_str(), options.suffix_for_stats(),
+                   grpc::internal::RpcMethod::BIDI_STREAMING),
                context, reactor);
   }
 
   std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
   CallInternal(grpc::ChannelInterface* channel, ClientContext* context,
-               const std::string& method, ::grpc::CompletionQueue* cq,
-               bool start, void* tag) {
+               const std::string& method, StubOptions options,
+               ::grpc::CompletionQueue* cq, bool start, void* tag) {
     return std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>(
         internal::ClientAsyncReaderWriterFactory<RequestType, ResponseType>::
-            Create(
-                channel, cq,
-                grpc::internal::RpcMethod(
-                    method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
-                context, start, tag));
+            Create(channel, cq,
+                   grpc::internal::RpcMethod(
+                       method.c_str(), options.suffix_for_stats(),
+                       grpc::internal::RpcMethod::BIDI_STREAMING),
+                   context, start, tag));
   }
 };
 
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/async_unary_call.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/async_unary_call.h
index 7541fa3..7cb7cc6 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/async_unary_call.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/async_unary_call.h
@@ -250,7 +250,7 @@
     initial_metadata_read_ = true;
   }
 
-  /// See \a ClientAysncResponseReaderInterface::Finish for semantics.
+  /// See \a ClientAsyncResponseReaderInterface::Finish for semantics.
   ///
   /// Side effect:
   ///   - the \a ClientContext associated with this call is updated with
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/byte_buffer.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/byte_buffer.h
index 4347745..2c015f2 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/byte_buffer.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/byte_buffer.h
@@ -41,8 +41,7 @@
 template <class RequestType, class ResponseType>
 class CallbackServerStreamingHandler;
 template <class RequestType>
-void* UnaryDeserializeHelper(grpc_call*, grpc_byte_buffer*, ::grpc::Status*,
-                             RequestType*);
+void* UnaryDeserializeHelper(grpc_byte_buffer*, ::grpc::Status*, RequestType*);
 template <class ServiceType, class RequestType, class ResponseType>
 class ServerStreamingHandler;
 template <::grpc::StatusCode code>
@@ -164,7 +163,7 @@
   friend class internal::CallOpRecvMessage;
   friend class internal::CallOpGenericRecvMessage;
   template <class RequestType>
-  friend void* internal::UnaryDeserializeHelper(grpc_call*, grpc_byte_buffer*,
+  friend void* internal::UnaryDeserializeHelper(grpc_byte_buffer*,
                                                 ::grpc::Status*, RequestType*);
   template <class ServiceType, class RequestType, class ResponseType>
   friend class internal::ServerStreamingHandler;
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/call_op_set.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/call_op_set.h
index 370d519..7fde1ed 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/call_op_set.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/call_op_set.h
@@ -878,6 +878,9 @@
         interceptor_methods_(InterceptorBatchMethodsImpl()) {}
 
   CallOpSet& operator=(const CallOpSet& other) {
+    if (&other == this) {
+      return *this;
+    }
     core_cq_tag_ = this;
     return_tag_ = this;
     call_ = other.call_;
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/client_callback.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/client_callback.h
index 77bc885..ba80290 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/client_callback.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/client_callback.h
@@ -27,6 +27,7 @@
 #include <grpcpp/impl/codegen/config.h>
 #include <grpcpp/impl/codegen/core_codegen_interface.h>
 #include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/sync.h>
 
 namespace grpc {
 class Channel;
@@ -110,6 +111,8 @@
 // Base class for public API classes.
 class ClientReactor {
  public:
+  virtual ~ClientReactor() = default;
+
   /// Called by the library when all operations associated with this RPC have
   /// completed and all Holds have been removed. OnDone provides the RPC status
   /// outcome for both successful and failed RPCs. If it is never called on an
@@ -211,16 +214,19 @@
 // activated by calling StartCall, possibly after initiating StartRead,
 // StartWrite, or AddHold operations on the streaming object. Note that none of
 // the classes are pure; all reactions have a default empty reaction so that the
-// user class only needs to override those classes that it cares about.
+// user class only needs to override those reactions that it cares about.
 // The reactor must be passed to the stub invocation before any of the below
-// operations can be called.
+// operations can be called and its reactions will be invoked by the library in
+// response to the completion of various operations. Reactions must not include
+// blocking operations (such as blocking I/O, starting synchronous RPCs, or
+// waiting on condition variables). Reactions may be invoked concurrently,
+// except that OnDone is called after all others (assuming proper API usage).
+// The reactor may not be deleted until OnDone is called.
 
 /// \a ClientBidiReactor is the interface for a bidirectional streaming RPC.
 template <class Request, class Response>
 class ClientBidiReactor : public internal::ClientReactor {
  public:
-  virtual ~ClientBidiReactor() {}
-
   /// Activate the RPC and initiate any reads or writes that have been Start'ed
   /// before this call. All streaming RPCs issued by the client MUST have
   /// StartCall invoked on them (even if they are canceled) as this call is the
@@ -357,8 +363,6 @@
 template <class Response>
 class ClientReadReactor : public internal::ClientReactor {
  public:
-  virtual ~ClientReadReactor() {}
-
   void StartCall() { reader_->StartCall(); }
   void StartRead(Response* resp) { reader_->Read(resp); }
 
@@ -384,8 +388,6 @@
 template <class Request>
 class ClientWriteReactor : public internal::ClientReactor {
  public:
-  virtual ~ClientWriteReactor() {}
-
   void StartCall() { writer_->StartCall(); }
   void StartWrite(const Request* req) {
     StartWrite(req, ::grpc::WriteOptions());
@@ -430,8 +432,6 @@
 /// initiation API among all the reactor flavors.
 class ClientUnaryReactor : public internal::ClientReactor {
  public:
-  virtual ~ClientUnaryReactor() {}
-
   void StartCall() { call_->StartCall(); }
   void OnDone(const ::grpc::Status& /*s*/) override {}
   virtual void OnReadInitialMetadataDone(bool /*ok*/) {}
@@ -473,7 +473,7 @@
   // there are no tests catching the compiler warning.
   static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
 
-  void StartCall() override {
+  void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
     // This call initiates two batches, plus any backlog, each with a callback
     // 1. Send initial metadata (unless corked) + recv initial metadata
     // 2. Any read backlog
@@ -522,7 +522,8 @@
     call_.PerformOps(&read_ops_);
   }
 
-  void Write(const Request* msg, ::grpc::WriteOptions options) override {
+  void Write(const Request* msg, ::grpc::WriteOptions options)
+      ABSL_LOCKS_EXCLUDED(start_mu_) override {
     if (options.is_last_message()) {
       options.set_buffer_hint();
       write_ops_.ClientSendClose();
@@ -545,7 +546,7 @@
     }
     call_.PerformOps(&write_ops_);
   }
-  void WritesDone() override {
+  void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
     writes_done_ops_.ClientSendClose();
     writes_done_tag_.Set(
         call_.call(),
@@ -686,7 +687,7 @@
     bool writes_done_ops = false;
     bool read_ops = false;
   };
-  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;
+  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
 
   // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
   std::atomic<intptr_t> callbacks_outstanding_{3};
@@ -844,7 +845,7 @@
   struct StartCallBacklog {
     bool read_ops = false;
   };
-  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;
+  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
 
   // Minimum of 2 callbacks to pre-register for start and finish
   std::atomic<intptr_t> callbacks_outstanding_{2};
@@ -885,7 +886,7 @@
   // there are no tests catching the compiler warning.
   static void operator delete(void*, void*) { GPR_CODEGEN_ASSERT(false); }
 
-  void StartCall() override {
+  void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override {
     // This call initiates two batches, plus any backlog, each with a callback
     // 1. Send initial metadata (unless corked) + recv initial metadata
     // 2. Any backlog
@@ -917,7 +918,8 @@
     this->MaybeFinish(/*from_reaction=*/false);
   }
 
-  void Write(const Request* msg, ::grpc::WriteOptions options) override {
+  void Write(const Request* msg, ::grpc::WriteOptions options)
+      ABSL_LOCKS_EXCLUDED(start_mu_) override {
     if (GPR_UNLIKELY(options.is_last_message())) {
       options.set_buffer_hint();
       write_ops_.ClientSendClose();
@@ -942,7 +944,7 @@
     call_.PerformOps(&write_ops_);
   }
 
-  void WritesDone() override {
+  void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override {
     writes_done_ops_.ClientSendClose();
     writes_done_tag_.Set(
         call_.call(),
@@ -1071,7 +1073,7 @@
     bool write_ops = false;
     bool writes_done_ops = false;
   };
-  StartCallBacklog backlog_ /* GUARDED_BY(start_mu_) */;
+  StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
 
   // Minimum of 3 callbacks to pre-register for start ops, StartCall, and finish
   std::atomic<intptr_t> callbacks_outstanding_{3};
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/client_context.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/client_context.h
index acf1d85..952a7ba 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/client_context.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/client_context.h
@@ -464,12 +464,13 @@
                 const std::shared_ptr<::grpc::Channel>& channel);
 
   grpc::experimental::ClientRpcInfo* set_client_rpc_info(
-      const char* method, grpc::internal::RpcMethod::RpcType type,
-      grpc::ChannelInterface* channel,
+      const char* method, const char* suffix_for_stats,
+      grpc::internal::RpcMethod::RpcType type, grpc::ChannelInterface* channel,
       const std::vector<std::unique_ptr<
           grpc::experimental::ClientInterceptorFactoryInterface>>& creators,
       size_t interceptor_pos) {
-    rpc_info_ = grpc::experimental::ClientRpcInfo(this, type, method, channel);
+    rpc_info_ = grpc::experimental::ClientRpcInfo(this, type, method,
+                                                  suffix_for_stats, channel);
     rpc_info_.RegisterInterceptors(creators, interceptor_pos);
     return &rpc_info_;
   }
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/client_interceptor.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/client_interceptor.h
index 78be1f7..ec78074 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/client_interceptor.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/client_interceptor.h
@@ -87,6 +87,10 @@
   /// Return the fully-specified method name
   const char* method() const { return method_; }
 
+  /// Return an identifying suffix for the client stub, or nullptr if one wasn't
+  /// specified.
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
+
   /// Return a pointer to the channel on which the RPC is being sent
   ChannelInterface* channel() { return channel_; }
 
@@ -116,10 +120,12 @@
 
   // Constructor will only be called from ClientContext
   ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type,
-                const char* method, grpc::ChannelInterface* channel)
+                const char* method, const char* suffix_for_stats,
+                grpc::ChannelInterface* channel)
       : ctx_(ctx),
         type_(static_cast<Type>(type)),
         method_(method),
+        suffix_for_stats_(suffix_for_stats),
         channel_(channel) {}
 
   // Move assignment should only be used by ClientContext
@@ -162,6 +168,7 @@
   // TODO(yashykt): make type_ const once move-assignment is deleted
   Type type_{Type::UNKNOWN};
   const char* method_ = nullptr;
+  const char* suffix_for_stats_ = nullptr;
   grpc::ChannelInterface* channel_ = nullptr;
   std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
   bool hijacked_ = false;
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/completion_queue.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/completion_queue.h
index f6589f0..d23e0e2 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/completion_queue.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/completion_queue.h
@@ -409,6 +409,9 @@
     return true;
   }
 
+  static CompletionQueue* CallbackAlternativeCQ();
+  static void ReleaseCallbackAlternativeCQ(CompletionQueue* cq);
+
   grpc_completion_queue* cq_;  // owned
 
   gpr_atm avalanches_in_flight_;
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/interceptor_common.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/interceptor_common.h
index 520d981..b9a6ede 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/interceptor_common.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/interceptor_common.h
@@ -223,18 +223,11 @@
   bool InterceptorsListEmpty() {
     auto* client_rpc_info = call_->client_rpc_info();
     if (client_rpc_info != nullptr) {
-      if (client_rpc_info->interceptors_.empty()) {
-        return true;
-      } else {
-        return false;
-      }
+      return client_rpc_info->interceptors_.empty();
     }
 
     auto* server_rpc_info = call_->server_rpc_info();
-    if (server_rpc_info == nullptr || server_rpc_info->interceptors_.empty()) {
-      return true;
-    }
-    return false;
+    return server_rpc_info == nullptr || server_rpc_info->interceptors_.empty();
   }
 
   // This should be used only by subclasses of CallOpSetInterface. SetCall and
@@ -419,11 +412,7 @@
  public:
   bool QueryInterceptionHookPoint(
       experimental::InterceptionHookPoints type) override {
-    if (type == experimental::InterceptionHookPoints::PRE_SEND_CANCEL) {
-      return true;
-    } else {
-      return false;
-    }
+    return type == experimental::InterceptionHookPoints::PRE_SEND_CANCEL;
   }
 
   void Proceed() override {
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/method_handler.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/method_handler.h
index 963423d..fb093f5 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/method_handler.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/method_handler.h
@@ -77,8 +77,8 @@
 /// A helper function with reduced templating to do deserializing.
 
 template <class RequestType>
-void* UnaryDeserializeHelper(grpc_call* call, grpc_byte_buffer* req,
-                             ::grpc::Status* status, RequestType* request) {
+void* UnaryDeserializeHelper(grpc_byte_buffer* req, ::grpc::Status* status,
+                             RequestType* request) {
   ::grpc::ByteBuffer buf;
   buf.set_buffer(req);
   *status = ::grpc::SerializationTraits<RequestType>::Deserialize(
@@ -123,7 +123,7 @@
     auto* request =
         new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
             call, sizeof(RequestType))) RequestType;
-    return UnaryDeserializeHelper(call, req, status,
+    return UnaryDeserializeHelper(req, status,
                                   static_cast<BaseRequestType*>(request));
   }
 
@@ -357,9 +357,12 @@
 template <::grpc::StatusCode code>
 class ErrorMethodHandler : public ::grpc::internal::MethodHandler {
  public:
+  explicit ErrorMethodHandler(const std::string& message) : message_(message) {}
+
   template <class T>
-  static void FillOps(::grpc::ServerContextBase* context, T* ops) {
-    ::grpc::Status status(code, "");
+  static void FillOps(::grpc::ServerContextBase* context,
+                      const std::string& message, T* ops) {
+    ::grpc::Status status(code, message);
     if (!context->sent_initial_metadata_) {
       ops->SendInitialMetadata(&context->initial_metadata_,
                                context->initial_metadata_flags());
@@ -375,7 +378,7 @@
     ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
                                 ::grpc::internal::CallOpServerSendStatus>
         ops;
-    FillOps(param.server_context, &ops);
+    FillOps(param.server_context, message_, &ops);
     param.call->PerformOps(&ops);
     param.call->cq()->Pluck(&ops);
   }
@@ -388,6 +391,9 @@
     }
     return nullptr;
   }
+
+ private:
+  const std::string message_;
 };
 
 typedef ErrorMethodHandler<::grpc::StatusCode::UNIMPLEMENTED>
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/rpc_method.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/rpc_method.h
index 394a29b..388784e 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/rpc_method.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/rpc_method.h
@@ -36,21 +36,40 @@
   };
 
   RpcMethod(const char* name, RpcType type)
-      : name_(name), method_type_(type), channel_tag_(nullptr) {}
+      : name_(name),
+        suffix_for_stats_(nullptr),
+        method_type_(type),
+        channel_tag_(nullptr) {}
+
+  RpcMethod(const char* name, const char* suffix_for_stats, RpcType type)
+      : name_(name),
+        suffix_for_stats_(suffix_for_stats),
+        method_type_(type),
+        channel_tag_(nullptr) {}
 
   RpcMethod(const char* name, RpcType type,
             const std::shared_ptr<ChannelInterface>& channel)
       : name_(name),
+        suffix_for_stats_(nullptr),
+        method_type_(type),
+        channel_tag_(channel->RegisterMethod(name)) {}
+
+  RpcMethod(const char* name, const char* suffix_for_stats, RpcType type,
+            const std::shared_ptr<ChannelInterface>& channel)
+      : name_(name),
+        suffix_for_stats_(suffix_for_stats),
         method_type_(type),
         channel_tag_(channel->RegisterMethod(name)) {}
 
   const char* name() const { return name_; }
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
   RpcType method_type() const { return method_type_; }
   void SetMethodType(RpcType type) { method_type_ = type; }
   void* channel_tag() const { return channel_tag_; }
 
  private:
   const char* const name_;
+  const char* const suffix_for_stats_;
   RpcType method_type_;
   void* const channel_tag_;
 };
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/security/auth_context.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/security/auth_context.h
index 728be37..cea6dbe 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/security/auth_context.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/security/auth_context.h
@@ -42,7 +42,7 @@
   AuthPropertyIterator operator++(int);
   bool operator==(const AuthPropertyIterator& rhs) const;
   bool operator!=(const AuthPropertyIterator& rhs) const;
-  const AuthProperty operator*();
+  AuthProperty operator*();
 
  protected:
   AuthPropertyIterator();
@@ -86,7 +86,7 @@
 
   /// Mutation functions: should only be used by an AuthMetadataProcessor.
   virtual void AddProperty(const std::string& key, const string_ref& value) = 0;
-  virtual bool SetPeerIdentityPropertyName(const string& name) = 0;
+  virtual bool SetPeerIdentityPropertyName(const std::string& name) = 0;
 };
 
 }  // namespace grpc
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/server_callback.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/server_callback.h
index 9dda984..3ccabdb 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/server_callback.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/server_callback.h
@@ -29,6 +29,7 @@
 #include <grpcpp/impl/codegen/core_codegen_interface.h>
 #include <grpcpp/impl/codegen/message_allocator.h>
 #include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/sync.h>
 
 namespace grpc {
 
@@ -256,7 +257,12 @@
 // by the user, returned as the output parameter of the method handler for a
 // callback method. Note that none of the classes are pure; all reactions have a
 // default empty reaction so that the user class only needs to override those
-// classes that it cares about.
+// reactions that it cares about. The reaction methods will be invoked by the
+// library in response to the completion of various operations. Reactions must
+// not include blocking operations (such as blocking I/O, starting synchronous
+// RPCs, or waiting on condition variables). Reactions may be invoked
+// concurrently, except that OnDone is called after all others (assuming proper
+// API usage). The reactor may not be deleted until OnDone is called.
 
 /// \a ServerBidiReactor is the interface for a bidirectional streaming RPC.
 template <class Request, class Response>
@@ -273,7 +279,7 @@
   /// Send any initial metadata stored in the RPC context. If not invoked,
   /// any initial metadata will be passed along with the first Write or the
   /// Finish (if there are no writes).
-  void StartSendInitialMetadata() {
+  void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -291,7 +297,7 @@
   ///
   /// \param[out] req Where to eventually store the read message. Valid when
   ///                 the library calls OnReadDone
-  void StartRead(Request* req) {
+  void StartRead(Request* req) ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -320,7 +326,8 @@
   ///                 ownership but the caller must ensure that the message is
   ///                 not deleted or modified until OnWriteDone is called.
   /// \param[in] options The WriteOptions to use for writing this message
-  void StartWrite(const Response* resp, ::grpc::WriteOptions options) {
+  void StartWrite(const Response* resp, ::grpc::WriteOptions options)
+      ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -349,7 +356,7 @@
   /// \param[in] options The WriteOptions to use for writing this message
   /// \param[in] s The status outcome of this RPC
   void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options,
-                           ::grpc::Status s) {
+                           ::grpc::Status s) ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -384,7 +391,7 @@
   /// cancelled.
   ///
   /// \param[in] s The status outcome of this RPC
-  void Finish(::grpc::Status s) {
+  void Finish(::grpc::Status s) ABSL_LOCKS_EXCLUDED(stream_mu_) {
     ServerCallbackReaderWriter<Request, Response>* stream =
         stream_.load(std::memory_order_acquire);
     if (stream == nullptr) {
@@ -476,7 +483,7 @@
     ::grpc::WriteOptions write_options_wanted;
     ::grpc::Status status_wanted;
   };
-  PreBindBacklog backlog_ /* GUARDED_BY(stream_mu_) */;
+  PreBindBacklog backlog_ ABSL_GUARDED_BY(stream_mu_);
 };
 
 /// \a ServerReadReactor is the interface for a client-streaming RPC.
@@ -487,7 +494,7 @@
   ~ServerReadReactor() override = default;
 
   /// The following operation initiations are exactly like ServerBidiReactor.
-  void StartSendInitialMetadata() {
+  void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(reader_mu_) {
     ServerCallbackReader<Request>* reader =
         reader_.load(std::memory_order_acquire);
     if (reader == nullptr) {
@@ -500,7 +507,7 @@
     }
     reader->SendInitialMetadata();
   }
-  void StartRead(Request* req) {
+  void StartRead(Request* req) ABSL_LOCKS_EXCLUDED(reader_mu_) {
     ServerCallbackReader<Request>* reader =
         reader_.load(std::memory_order_acquire);
     if (reader == nullptr) {
@@ -513,7 +520,7 @@
     }
     reader->Read(req);
   }
-  void Finish(::grpc::Status s) {
+  void Finish(::grpc::Status s) ABSL_LOCKS_EXCLUDED(reader_mu_) {
     ServerCallbackReader<Request>* reader =
         reader_.load(std::memory_order_acquire);
     if (reader == nullptr) {
@@ -539,7 +546,8 @@
 
   // May be overridden by internal implementation details. This is not a public
   // customization point.
-  virtual void InternalBindReader(ServerCallbackReader<Request>* reader) {
+  virtual void InternalBindReader(ServerCallbackReader<Request>* reader)
+      ABSL_LOCKS_EXCLUDED(reader_mu_) {
     grpc::internal::MutexLock l(&reader_mu_);
 
     if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
@@ -563,7 +571,7 @@
     Request* read_wanted = nullptr;
     ::grpc::Status status_wanted;
   };
-  PreBindBacklog backlog_ /* GUARDED_BY(reader_mu_) */;
+  PreBindBacklog backlog_ ABSL_GUARDED_BY(reader_mu_);
 };
 
 /// \a ServerWriteReactor is the interface for a server-streaming RPC.
@@ -574,7 +582,7 @@
   ~ServerWriteReactor() override = default;
 
   /// The following operation initiations are exactly like ServerBidiReactor.
-  void StartSendInitialMetadata() {
+  void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(writer_mu_) {
     ServerCallbackWriter<Response>* writer =
         writer_.load(std::memory_order_acquire);
     if (writer == nullptr) {
@@ -590,7 +598,8 @@
   void StartWrite(const Response* resp) {
     StartWrite(resp, ::grpc::WriteOptions());
   }
-  void StartWrite(const Response* resp, ::grpc::WriteOptions options) {
+  void StartWrite(const Response* resp, ::grpc::WriteOptions options)
+      ABSL_LOCKS_EXCLUDED(writer_mu_) {
     ServerCallbackWriter<Response>* writer =
         writer_.load(std::memory_order_acquire);
     if (writer == nullptr) {
@@ -605,7 +614,7 @@
     writer->Write(resp, options);
   }
   void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options,
-                           ::grpc::Status s) {
+                           ::grpc::Status s) ABSL_LOCKS_EXCLUDED(writer_mu_) {
     ServerCallbackWriter<Response>* writer =
         writer_.load(std::memory_order_acquire);
     if (writer == nullptr) {
@@ -624,7 +633,7 @@
   void StartWriteLast(const Response* resp, ::grpc::WriteOptions options) {
     StartWrite(resp, options.set_last_message());
   }
-  void Finish(::grpc::Status s) {
+  void Finish(::grpc::Status s) ABSL_LOCKS_EXCLUDED(writer_mu_) {
     ServerCallbackWriter<Response>* writer =
         writer_.load(std::memory_order_acquire);
     if (writer == nullptr) {
@@ -649,7 +658,8 @@
   friend class ServerCallbackWriter<Response>;
   // May be overridden by internal implementation details. This is not a public
   // customization point.
-  virtual void InternalBindWriter(ServerCallbackWriter<Response>* writer) {
+  virtual void InternalBindWriter(ServerCallbackWriter<Response>* writer)
+      ABSL_LOCKS_EXCLUDED(writer_mu_) {
     grpc::internal::MutexLock l(&writer_mu_);
 
     if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
@@ -682,7 +692,7 @@
     ::grpc::WriteOptions write_options_wanted;
     ::grpc::Status status_wanted;
   };
-  PreBindBacklog backlog_ /* GUARDED_BY(writer_mu_) */;
+  PreBindBacklog backlog_ ABSL_GUARDED_BY(writer_mu_);
 };
 
 class ServerUnaryReactor : public internal::ServerReactor {
@@ -691,7 +701,7 @@
   ~ServerUnaryReactor() override = default;
 
   /// StartSendInitialMetadata is exactly like ServerBidiReactor.
-  void StartSendInitialMetadata() {
+  void StartSendInitialMetadata() ABSL_LOCKS_EXCLUDED(call_mu_) {
     ServerCallbackUnary* call = call_.load(std::memory_order_acquire);
     if (call == nullptr) {
       grpc::internal::MutexLock l(&call_mu_);
@@ -706,7 +716,7 @@
   /// Finish is similar to ServerBidiReactor except for one detail.
   /// If the status is non-OK, any message will not be sent. Instead,
   /// the client will only receive the status and any trailing metadata.
-  void Finish(::grpc::Status s) {
+  void Finish(::grpc::Status s) ABSL_LOCKS_EXCLUDED(call_mu_) {
     ServerCallbackUnary* call = call_.load(std::memory_order_acquire);
     if (call == nullptr) {
       grpc::internal::MutexLock l(&call_mu_);
@@ -729,7 +739,8 @@
   friend class ServerCallbackUnary;
   // May be overridden by internal implementation details. This is not a public
   // customization point.
-  virtual void InternalBindCall(ServerCallbackUnary* call) {
+  virtual void InternalBindCall(ServerCallbackUnary* call)
+      ABSL_LOCKS_EXCLUDED(call_mu_) {
     grpc::internal::MutexLock l(&call_mu_);
 
     if (GPR_UNLIKELY(backlog_.send_initial_metadata_wanted)) {
@@ -749,7 +760,7 @@
     bool finish_wanted = false;
     ::grpc::Status status_wanted;
   };
-  PreBindBacklog backlog_ /* GUARDED_BY(call_mu_) */;
+  PreBindBacklog backlog_ ABSL_GUARDED_BY(call_mu_);
 };
 
 namespace internal {
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/server_callback_handlers.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/server_callback_handlers.h
index 4815cb4..76e655a 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/server_callback_handlers.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/server_callback_handlers.h
@@ -210,6 +210,9 @@
       grpc_call* call = call_.call();
       auto call_requester = std::move(call_requester_);
       allocator_state_->Release();
+      if (ctx_->context_allocator() != nullptr) {
+        ctx_->context_allocator()->Release(ctx_);
+      }
       this->~ServerCallbackUnaryImpl();  // explicitly call destructor
       ::grpc::g_core_codegen_interface->grpc_call_unref(call);
       call_requester();
@@ -402,6 +405,9 @@
       reactor_.load(std::memory_order_relaxed)->OnDone();
       grpc_call* call = call_.call();
       auto call_requester = std::move(call_requester_);
+      if (ctx_->context_allocator() != nullptr) {
+        ctx_->context_allocator()->Release(ctx_);
+      }
       this->~ServerCallbackReaderImpl();  // explicitly call destructor
       ::grpc::g_core_codegen_interface->grpc_call_unref(call);
       call_requester();
@@ -616,7 +622,11 @@
       // DefaultReactor (which is unary).
       this->MaybeDone(/*inlineable_ondone=*/false);
     }
-    ~ServerCallbackWriterImpl() { req_->~RequestType(); }
+    ~ServerCallbackWriterImpl() {
+      if (req_ != nullptr) {
+        req_->~RequestType();
+      }
+    }
 
     const RequestType* request() { return req_; }
 
@@ -624,6 +634,9 @@
       reactor_.load(std::memory_order_relaxed)->OnDone();
       grpc_call* call = call_.call();
       auto call_requester = std::move(call_requester_);
+      if (ctx_->context_allocator() != nullptr) {
+        ctx_->context_allocator()->Release(ctx_);
+      }
       this->~ServerCallbackWriterImpl();  // explicitly call destructor
       ::grpc::g_core_codegen_interface->grpc_call_unref(call);
       call_requester();
@@ -835,6 +848,9 @@
       reactor_.load(std::memory_order_relaxed)->OnDone();
       grpc_call* call = call_.call();
       auto call_requester = std::move(call_requester_);
+      if (ctx_->context_allocator() != nullptr) {
+        ctx_->context_allocator()->Release(ctx_);
+      }
       this->~ServerCallbackReaderWriterImpl();  // explicitly call destructor
       ::grpc::g_core_codegen_interface->grpc_call_unref(call);
       call_requester();
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/server_context.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/server_context.h
index 5a62873..cbbd229 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/server_context.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/server_context.h
@@ -100,6 +100,7 @@
 class GenericServerContext;
 class Server;
 class ServerInterface;
+class ContextAllocator;
 
 // TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
 namespace experimental {
@@ -340,6 +341,12 @@
   ServerContextBase();
   ServerContextBase(gpr_timespec deadline, grpc_metadata_array* arr);
 
+  void set_context_allocator(ContextAllocator* context_allocator) {
+    context_allocator_ = context_allocator;
+  }
+
+  ContextAllocator* context_allocator() const { return context_allocator_; }
+
  private:
   friend class ::grpc::testing::InteropServerContextInspector;
   friend class ::grpc::testing::ServerContextTestSpouse;
@@ -463,6 +470,7 @@
 
   ::grpc::experimental::ServerRpcInfo* rpc_info_ = nullptr;
   ::grpc::experimental::RpcAllocatorState* message_allocator_state_ = nullptr;
+  ContextAllocator* context_allocator_ = nullptr;
 
   class Reactor : public ::grpc::ServerUnaryReactor {
    public:
@@ -590,12 +598,14 @@
   using ServerContextBase::compression_algorithm;
   using ServerContextBase::compression_level;
   using ServerContextBase::compression_level_set;
+  using ServerContextBase::context_allocator;
   using ServerContextBase::deadline;
   using ServerContextBase::IsCancelled;
   using ServerContextBase::peer;
   using ServerContextBase::raw_deadline;
   using ServerContextBase::set_compression_algorithm;
   using ServerContextBase::set_compression_level;
+  using ServerContextBase::set_context_allocator;
   using ServerContextBase::SetLoadReportingCosts;
   using ServerContextBase::TryCancel;
 
@@ -612,6 +622,37 @@
   CallbackServerContext& operator=(const CallbackServerContext&) = delete;
 };
 
+/// A CallbackServerContext allows users to use the contents of the
+/// CallbackServerContext or GenericCallbackServerContext structure for the
+/// callback API.
+/// The library will invoke the allocator any time a new call is initiated.
+/// and call the Release method after the server OnDone.
+class ContextAllocator {
+ public:
+  virtual ~ContextAllocator() {}
+
+  virtual CallbackServerContext* NewCallbackServerContext() { return nullptr; }
+
+#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
+  virtual experimental::GenericCallbackServerContext*
+  NewGenericCallbackServerContext() {
+    return nullptr;
+  }
+#else
+  virtual GenericCallbackServerContext* NewGenericCallbackServerContext() {
+    return nullptr;
+  }
+#endif
+
+  virtual void Release(CallbackServerContext*) {}
+
+#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
+  virtual void Release(experimental::GenericCallbackServerContext*) {}
+#else
+  virtual void Release(GenericCallbackServerContext*) {}
+#endif
+};
+
 }  // namespace grpc
 
 static_assert(
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/server_interface.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/server_interface.h
index c4398f4..a44ab1f 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/server_interface.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/server_interface.h
@@ -147,6 +147,8 @@
     /// May not be abstract since this is a post-1.0 API addition
     virtual void RegisterCallbackGenericService(
         experimental::CallbackGenericService* /*service*/) {}
+    virtual void RegisterContextAllocator(
+        std::unique_ptr<ContextAllocator> context_allocator) {}
   };
 
   /// NOTE: The function experimental_registration() is not stable public API.
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/string_ref.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/string_ref.h
index 153f371..4543e42 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/string_ref.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/string_ref.h
@@ -51,6 +51,7 @@
   string_ref() : data_(nullptr), length_(0) {}
   string_ref(const string_ref& other)
       : data_(other.data_), length_(other.length_) {}
+  // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
   string_ref& operator=(const string_ref& rhs) {
     data_ = rhs.data_;
     length_ = rhs.length_;
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/stub_options.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/stub_options.h
index a56695a..30509c2 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/stub_options.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/stub_options.h
@@ -22,7 +22,20 @@
 namespace grpc {
 
 /// Useful interface for generated stubs
-class StubOptions {};
+class StubOptions {
+ public:
+  StubOptions() = default;
+  explicit StubOptions(const char* suffix_for_stats)
+      : suffix_for_stats_(suffix_for_stats) {}
+
+  void set_suffix_for_stats(const char* suffix_for_stats) {
+    suffix_for_stats_ = suffix_for_stats;
+  }
+  const char* suffix_for_stats() const { return suffix_for_stats_; }
+
+ private:
+  const char* suffix_for_stats_ = nullptr;
+};
 
 }  // namespace grpc
 
diff --git a/grpc/spm-cpp-include/grpcpp/impl/codegen/sync.h b/grpc/spm-cpp-include/grpcpp/impl/codegen/sync.h
index 146f182..0c4effe 100644
--- a/grpc/spm-cpp-include/grpcpp/impl/codegen/sync.h
+++ b/grpc/spm-cpp-include/grpcpp/impl/codegen/sync.h
@@ -32,6 +32,8 @@
 
 #include <grpcpp/impl/codegen/core_codegen_interface.h>
 
+#include "absl/synchronization/mutex.h"
+
 // The core library is not accessible in C++ codegen headers, and vice versa.
 // Thus, we need to have duplicate headers with similar functionality.
 // Make sure any change to this file is also reflected in
@@ -44,7 +46,16 @@
 namespace grpc {
 namespace internal {
 
-class Mutex {
+#ifdef GRPCPP_ABSEIL_SYNC
+
+using Mutex = absl::Mutex;
+using MutexLock = absl::MutexLock;
+using ReleasableMutexLock = absl::ReleasableMutexLock;
+using CondVar = absl::CondVar;
+
+#else
+
+class ABSL_LOCKABLE Mutex {
  public:
   Mutex() { g_core_codegen_interface->gpr_mu_init(&mu_); }
   ~Mutex() { g_core_codegen_interface->gpr_mu_destroy(&mu_); }
@@ -52,8 +63,12 @@
   Mutex(const Mutex&) = delete;
   Mutex& operator=(const Mutex&) = delete;
 
-  gpr_mu* get() { return &mu_; }
-  const gpr_mu* get() const { return &mu_; }
+  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
+    g_core_codegen_interface->gpr_mu_lock(&mu_);
+  }
+  void Unlock() ABSL_UNLOCK_FUNCTION() {
+    g_core_codegen_interface->gpr_mu_unlock(&mu_);
+  }
 
  private:
   union {
@@ -63,55 +78,45 @@
     pthread_mutex_t do_not_use_pth_;
 #endif
   };
+
+  friend class CondVar;
 };
 
-// MutexLock is a std::
-class MutexLock {
+class ABSL_SCOPED_LOCKABLE MutexLock {
  public:
-  explicit MutexLock(Mutex* mu) : mu_(mu->get()) {
-    g_core_codegen_interface->gpr_mu_lock(mu_);
+  explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
+    mu_->Lock();
   }
-  explicit MutexLock(gpr_mu* mu) : mu_(mu) {
-    g_core_codegen_interface->gpr_mu_lock(mu_);
-  }
-  ~MutexLock() { g_core_codegen_interface->gpr_mu_unlock(mu_); }
+  ~MutexLock() ABSL_UNLOCK_FUNCTION() { mu_->Unlock(); }
 
   MutexLock(const MutexLock&) = delete;
   MutexLock& operator=(const MutexLock&) = delete;
 
  private:
-  gpr_mu* const mu_;
+  Mutex* const mu_;
 };
 
-class ReleasableMutexLock {
+class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
  public:
-  explicit ReleasableMutexLock(Mutex* mu) : mu_(mu->get()) {
-    g_core_codegen_interface->gpr_mu_lock(mu_);
+  explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu_->Lock();
   }
-  explicit ReleasableMutexLock(gpr_mu* mu) : mu_(mu) {
-    g_core_codegen_interface->gpr_mu_lock(mu_);
-  }
-  ~ReleasableMutexLock() {
-    if (!released_) g_core_codegen_interface->gpr_mu_unlock(mu_);
+  ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
+    if (!released_) mu_->Unlock();
   }
 
   ReleasableMutexLock(const ReleasableMutexLock&) = delete;
   ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
 
-  void Lock() {
-    GPR_DEBUG_ASSERT(released_);
-    g_core_codegen_interface->gpr_mu_lock(mu_);
-    released_ = false;
-  }
-
-  void Unlock() {
+  void Release() ABSL_UNLOCK_FUNCTION() {
     GPR_DEBUG_ASSERT(!released_);
     released_ = true;
-    g_core_codegen_interface->gpr_mu_unlock(mu_);
+    mu_->Unlock();
   }
 
  private:
-  gpr_mu* const mu_;
+  Mutex* const mu_;
   bool released_ = false;
 };
 
@@ -124,27 +129,27 @@
   CondVar& operator=(const CondVar&) = delete;
 
   void Signal() { g_core_codegen_interface->gpr_cv_signal(&cv_); }
-  void Broadcast() { g_core_codegen_interface->gpr_cv_broadcast(&cv_); }
+  void SignalAll() { g_core_codegen_interface->gpr_cv_broadcast(&cv_); }
 
-  int Wait(Mutex* mu) {
-    return Wait(mu,
-                g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
-  }
-  int Wait(Mutex* mu, const gpr_timespec& deadline) {
-    return g_core_codegen_interface->gpr_cv_wait(&cv_, mu->get(), deadline);
-  }
-
-  template <typename Predicate>
-  void WaitUntil(Mutex* mu, Predicate pred) {
-    while (!pred()) {
-      Wait(mu, g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
-    }
+  void Wait(Mutex* mu) {
+    g_core_codegen_interface->gpr_cv_wait(
+        &cv_, &mu->mu_,
+        g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
   }
 
  private:
   gpr_cv cv_;
 };
 
+#endif  // GRPCPP_ABSEIL_SYNC
+
+template <typename Predicate>
+static void WaitUntil(CondVar* cv, Mutex* mu, Predicate pred) {
+  while (!pred()) {
+    cv->Wait(mu);
+  }
+}
+
 }  // namespace internal
 }  // namespace grpc
 
diff --git a/grpc/spm-cpp-include/grpcpp/security/credentials.h b/grpc/spm-cpp-include/grpcpp/security/credentials.h
index 98b5d9a..1b1f994 100644
--- a/grpc/spm-cpp-include/grpcpp/security/credentials.h
+++ b/grpc/spm-cpp-include/grpcpp/security/credentials.h
@@ -277,6 +277,12 @@
 std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
     std::unique_ptr<MetadataCredentialsPlugin> plugin);
 
+/// Builds External Account credentials.
+/// json_string is the JSON string containing the credentials options.
+/// scopes contains the scopes to be binded with the credentials.
+std::shared_ptr<CallCredentials> ExternalAccountCredentials(
+    const grpc::string& json_string, const std::vector<grpc::string>& scopes);
+
 namespace experimental {
 
 /// Options for creating STS Oauth Token Exchange credentials following the IETF
@@ -307,12 +313,6 @@
 std::shared_ptr<CallCredentials> StsCredentials(
     const StsCredentialsOptions& options);
 
-/// Builds External Account credentials.
-/// json_string is the JSON string containing the credentials options.
-/// scopes contains the scopes to be binded with the credentials.
-std::shared_ptr<CallCredentials> ExternalAccountCredentials(
-    const grpc::string& json_string, const std::vector<grpc::string>& scopes);
-
 std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
     std::unique_ptr<MetadataCredentialsPlugin> plugin,
     grpc_security_level min_security_level);
diff --git a/grpc/spm-cpp-include/grpcpp/security/server_credentials.h b/grpc/spm-cpp-include/grpcpp/security/server_credentials.h
index ad7c0e7..0ce46a8 100644
--- a/grpc/spm-cpp-include/grpcpp/security/server_credentials.h
+++ b/grpc/spm-cpp-include/grpcpp/security/server_credentials.h
@@ -67,9 +67,10 @@
 }  // namespace experimental
 
 /// Wrapper around \a grpc_server_credentials, a way to authenticate a server.
-class ServerCredentials {
+class ServerCredentials : private grpc::GrpcLibraryCodegen {
  public:
-  virtual ~ServerCredentials();
+  ServerCredentials();
+  ~ServerCredentials() override;
 
   /// This method is not thread-safe and has to be called before the server is
   /// started. The last call to this function wins.
diff --git a/grpc/spm-cpp-include/grpcpp/security/tls_credentials_options.h b/grpc/spm-cpp-include/grpcpp/security/tls_credentials_options.h
index 6abdcaa..da2b595 100644
--- a/grpc/spm-cpp-include/grpcpp/security/tls_credentials_options.h
+++ b/grpc/spm-cpp-include/grpcpp/security/tls_credentials_options.h
@@ -155,13 +155,21 @@
   //
   // @param certificate_provider the provider which fetches TLS credentials that
   // will be used in the TLS handshake
-  explicit TlsCredentialsOptions(
-      std::shared_ptr<CertificateProviderInterface> certificate_provider);
+  TlsCredentialsOptions();
   // ---- Setters for member fields ----
+  // Sets the certificate provider used to store root certs and identity certs.
+  void set_certificate_provider(
+      std::shared_ptr<CertificateProviderInterface> certificate_provider);
   // Watches the updates of root certificates with name |root_cert_name|.
-  // If used in TLS credentials, it should always be set unless the root
-  // certificates are not needed(e.g. in the one-side TLS scenario, the server
-  // is not required to verify the client).
+  // If used in TLS credentials, setting this field is optional for both the
+  // client side and the server side.
+  // If this is not set on the client side, we will use the root certificates
+  // stored in the default system location, since client side must provide root
+  // certificates in TLS(no matter single-side TLS or mutual TLS).
+  // If this is not set on the server side, we will not watch any root
+  // certificate updates, and assume no root certificates needed for the server
+  // (in the one-side TLS scenario, the server is not required to provide root
+  // certs). We don't support default root certs on server side.
   void watch_root_certs();
   // Sets the name of root certificates being watched, if |watch_root_certs| is
   // called. If not set, an empty string will be used as the name.
@@ -169,9 +177,9 @@
   // @param root_cert_name the name of root certs being set.
   void set_root_cert_name(const std::string& root_cert_name);
   // Watches the updates of identity key-cert pairs with name
-  // |identity_cert_name|. If used in TLS credentials, it should always be set
-  // unless the identity certificates are not needed(e.g. in the one-side TLS
-  // scenario, the client is not required to provide certs).
+  // |identity_cert_name|. If used in TLS credentials, it is required to be set
+  // on the server side, and optional for the client side(in the one-side
+  // TLS scenario, the client is not required to provide identity certs).
   void watch_identity_key_cert_pairs();
   // Sets the name of identity key-cert pairs being watched, if
   // |watch_identity_key_cert_pairs| is called. If not set, an empty string will
@@ -192,13 +200,13 @@
 };
 
 // Contains configurable options on the client side.
+// Client side doesn't need to always use certificate provider. When the
+// certificate provider is not set, we will use the root certificates stored
+// in the system default locations, and assume client won't provide any
+// identity certificates(single side TLS).
 // It is used for experimental purposes for now and it is subject to change.
 class TlsChannelCredentialsOptions final : public TlsCredentialsOptions {
  public:
-  explicit TlsChannelCredentialsOptions(
-      std::shared_ptr<CertificateProviderInterface> certificate_provider)
-      : TlsCredentialsOptions(std::move(certificate_provider)) {}
-
   // Sets the option to verify the server.
   // The default is GRPC_TLS_SERVER_VERIFICATION.
   void set_server_verification_option(
@@ -215,9 +223,13 @@
 // It is used for experimental purposes for now and it is subject to change.
 class TlsServerCredentialsOptions final : public TlsCredentialsOptions {
  public:
+  // Server side is required to use a provider, because server always needs to
+  // use identity certs.
   explicit TlsServerCredentialsOptions(
       std::shared_ptr<CertificateProviderInterface> certificate_provider)
-      : TlsCredentialsOptions(std::move(certificate_provider)) {}
+      : TlsCredentialsOptions() {
+    set_certificate_provider(certificate_provider);
+  }
 
   // Sets option to request the certificates from the client.
   // The default is GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE.
diff --git a/grpc/spm-cpp-include/grpcpp/server.h b/grpc/spm-cpp-include/grpcpp/server.h
index 5dc73a1..a69e64b 100644
--- a/grpc/spm-cpp-include/grpcpp/server.h
+++ b/grpc/spm-cpp-include/grpcpp/server.h
@@ -58,13 +58,13 @@
 /// \a Server instances.
 class Server : public ServerInterface, private GrpcLibraryCodegen {
  public:
-  ~Server() override;
+  ~Server() ABSL_LOCKS_EXCLUDED(mu_) override;
 
   /// Block until the server shuts down.
   ///
   /// \warning The server must be either shutting down or some other thread must
   /// call \a Shutdown for this function to ever return.
-  void Wait() override;
+  void Wait() ABSL_LOCKS_EXCLUDED(mu_) override;
 
   /// Global callbacks are a set of hooks that are called when server
   /// events occur.  \a SetGlobalCallbacks method is used to register
@@ -203,6 +203,8 @@
     health_check_service_ = std::move(service);
   }
 
+  ContextAllocator* context_allocator() { return context_allocator_.get(); }
+
   /// NOTE: This method is not part of the public API for this class.
   bool health_check_service_disabled() const {
     return health_check_service_disabled_;
@@ -240,6 +242,12 @@
   /// ownership of theservice. The service must exist for the lifetime of the
   /// Server instance.
   void RegisterCallbackGenericService(CallbackGenericService* service) override;
+
+  void RegisterContextAllocator(
+      std::unique_ptr<ContextAllocator> context_allocator) {
+    context_allocator_ = std::move(context_allocator);
+  }
+
 #else
   /// NOTE: class experimental_registration_type is not part of the public API
   /// of this class
@@ -254,6 +262,11 @@
       server_->RegisterCallbackGenericService(service);
     }
 
+    void RegisterContextAllocator(
+        std::unique_ptr<ContextAllocator> context_allocator) override {
+      server_->context_allocator_ = std::move(context_allocator);
+    }
+
    private:
     Server* server_;
   };
@@ -273,13 +286,14 @@
   void PerformOpsOnCall(internal::CallOpSetInterface* ops,
                         internal::Call* call) override;
 
-  void ShutdownInternal(gpr_timespec deadline) override;
+  void ShutdownInternal(gpr_timespec deadline)
+      ABSL_LOCKS_EXCLUDED(mu_) override;
 
   int max_receive_message_size() const override {
     return max_receive_message_size_;
   }
 
-  CompletionQueue* CallbackCQ() override;
+  CompletionQueue* CallbackCQ() ABSL_LOCKS_EXCLUDED(mu_) override;
 
   ServerInitializer* initializer();
 
@@ -287,8 +301,8 @@
   // the ref count are the running state of the server (take a ref at start and
   // drop it at shutdown) and each running callback RPC.
   void Ref();
-  void UnrefWithPossibleNotify() /* LOCKS_EXCLUDED(mu_) */;
-  void UnrefAndWaitLocked() /* EXCLUSIVE_LOCKS_REQUIRED(mu_) */;
+  void UnrefWithPossibleNotify() ABSL_LOCKS_EXCLUDED(mu_);
+  void UnrefAndWaitLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   std::vector<std::shared_ptr<internal::ExternalConnectionAcceptorImpl>>
       acceptors_;
@@ -322,10 +336,11 @@
   // Server status
   internal::Mutex mu_;
   bool started_;
-  bool shutdown_;
-  bool shutdown_notified_;  // Was notify called on the shutdown_cv_
+  bool shutdown_ ABSL_GUARDED_BY(mu_);
+  bool shutdown_notified_
+      ABSL_GUARDED_BY(mu_);  // Was notify called on the shutdown_cv_
   internal::CondVar shutdown_done_cv_;
-  bool shutdown_done_ = false;
+  bool shutdown_done_ ABSL_GUARDED_BY(mu_) = false;
   std::atomic_int shutdown_refs_outstanding_{1};
 
   internal::CondVar shutdown_cv_;
@@ -342,6 +357,8 @@
 
   std::unique_ptr<ServerInitializer> server_initializer_;
 
+  std::unique_ptr<ContextAllocator> context_allocator_;
+
   std::unique_ptr<HealthCheckServiceInterface> health_check_service_;
   bool health_check_service_disabled_;
 
@@ -363,7 +380,7 @@
   // with this server (if any). It is set on the first call to CallbackCQ().
   // It is _not owned_ by the server; ownership belongs with its internal
   // shutdown callback tag (invoked when the CQ is fully shutdown).
-  CompletionQueue* callback_cq_ /* GUARDED_BY(mu_) */ = nullptr;
+  std::atomic<CompletionQueue*> callback_cq_{nullptr};
 
   // List of CQs passed in by user that must be Shutdown only after Server is
   // Shutdown.  Even though this is only used with NDEBUG, instantiate it in all
diff --git a/grpc/spm-cpp-include/grpcpp/server_builder.h b/grpc/spm-cpp-include/grpcpp/server_builder.h
index cb75d87..00e82a1 100644
--- a/grpc/spm-cpp-include/grpcpp/server_builder.h
+++ b/grpc/spm-cpp-include/grpcpp/server_builder.h
@@ -269,6 +269,11 @@
       builder_->interceptor_creators_ = std::move(interceptor_creators);
     }
 
+    /// Set the allocator for creating and releasing callback server context.
+    /// Takes the owndership of the allocator.
+    ServerBuilder& SetContextAllocator(
+        std::unique_ptr<grpc::ContextAllocator> context_allocator);
+
 #ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
     /// Register a generic service that uses the callback API.
     /// Matches requests with any :authority
@@ -352,6 +357,9 @@
     server_config_fetcher_ = server_config_fetcher;
   }
 
+  /// Experimental API, subject to change.
+  virtual ChannelArguments BuildChannelArgs();
+
  private:
   friend class ::grpc::testing::ServerBuilderPluginTest;
 
@@ -389,6 +397,7 @@
   std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>> plugins_;
   grpc_resource_quota* resource_quota_;
   grpc::AsyncGenericService* generic_service_{nullptr};
+  std::unique_ptr<ContextAllocator> context_allocator_;
 #ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
   grpc::CallbackGenericService* callback_generic_service_{nullptr};
 #else
diff --git a/grpc/spm-cpp-include/grpcpp/support/channel_arguments.h b/grpc/spm-cpp-include/grpcpp/support/channel_arguments.h
index 41a8ad3..a9514bc 100644
--- a/grpc/spm-cpp-include/grpcpp/support/channel_arguments.h
+++ b/grpc/spm-cpp-include/grpcpp/support/channel_arguments.h
@@ -98,14 +98,18 @@
   /// Primarily meant for use in unit tests.
   void SetServiceConfigJSON(const std::string& service_config_json);
 
-  // Generic channel argument setters. Only for advanced use cases.
+  // Generic channel argument setter. Only for advanced use cases.
   /// Set an integer argument \a value under \a key.
   void SetInt(const std::string& key, int value);
 
   // Generic channel argument setter. Only for advanced use cases.
-  /// Set a pointer argument \a value under \a key. Owership is not transferred.
+  /// Set a pointer argument \a value under \a key. Ownership is not
+  /// transferred.
   void SetPointer(const std::string& key, void* value);
 
+  /// Set a pointer argument \a value under \a key, transferring ownership of
+  /// \a value to the \a ChannelArguments object. The \a vtable::Delete function
+  /// is responsible for \a value cleanup/destruction when called.
   void SetPointerWithVtable(const std::string& key, void* value,
                             const grpc_arg_pointer_vtable* vtable);
 
diff --git a/grpc/spm-cpp-include/grpcpp/support/error_details.h b/grpc/spm-cpp-include/grpcpp/support/error_details.h
index 15b917f..72305e8 100644
--- a/grpc/spm-cpp-include/grpcpp/support/error_details.h
+++ b/grpc/spm-cpp-include/grpcpp/support/error_details.h
@@ -21,12 +21,6 @@
 
 #include <grpcpp/support/status.h>
 
-namespace google {
-namespace rpc {
-class Status;
-}  // namespace rpc
-}  // namespace google
-
 namespace grpc {
 
 /// Map a \a grpc::Status to a \a google::rpc::Status.
@@ -34,14 +28,48 @@
 /// On success, returns status with OK.
 /// Returns status with \a INVALID_ARGUMENT, if failed to deserialize.
 /// Returns status with \a FAILED_PRECONDITION, if \a to is nullptr.
-grpc::Status ExtractErrorDetails(const grpc::Status& from,
-                                 ::google::rpc::Status* to);
+///
+/// \note
+/// This function is a template to avoid a build dep on \a status.proto.
+/// However, this function still requires that \tparam T is of type
+/// \a google::rpc::Status, which is defined at
+/// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto
+template <typename T>
+grpc::Status ExtractErrorDetails(const grpc::Status& from, T* to) {
+  if (to == nullptr) {
+    return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "");
+  }
+  if (!to->ParseFromString(from.error_details())) {
+    return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "");
+  }
+  return grpc::Status::OK;
+}
+inline grpc::Status ExtractErrorDetails(const grpc::Status&, std::nullptr_t) {
+  return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "");
+}
 
 /// Map \a google::rpc::Status to a \a grpc::Status.
 /// Returns OK on success.
 /// Returns status with \a FAILED_PRECONDITION if \a to is nullptr.
-grpc::Status SetErrorDetails(const ::google::rpc::Status& from,
-                             grpc::Status* to);
+///
+/// \note
+/// This function is a template to avoid a build dep on \a status.proto.
+/// However, this function still requires that \tparam T is of type
+/// \a google::rpc::Status, which is defined at
+/// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto
+template <typename T>
+grpc::Status SetErrorDetails(const T& from, grpc::Status* to) {
+  if (to == nullptr) {
+    return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "");
+  }
+  grpc::StatusCode code = grpc::StatusCode::UNKNOWN;
+  if (from.code() >= grpc::StatusCode::OK &&
+      from.code() <= grpc::StatusCode::UNAUTHENTICATED) {
+    code = static_cast<grpc::StatusCode>(from.code());
+  }
+  *to = grpc::Status(code, from.message(), from.SerializeAsString());
+  return grpc::Status::OK;
+}
 
 }  // namespace grpc
 
diff --git a/grpc/spm-cpp-include/grpcpp/test/mock_stream.h b/grpc/spm-cpp-include/grpcpp/test/mock_stream.h
index e33595d..deffad3 100644
--- a/grpc/spm-cpp-include/grpcpp/test/mock_stream.h
+++ b/grpc/spm-cpp-include/grpcpp/test/mock_stream.h
@@ -90,6 +90,8 @@
  public:
   MockClientAsyncResponseReader() = default;
 
+  /// ClientAsyncResponseReaderInterface
+  MOCK_METHOD0_T(StartCall, void());
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD3_T(Finish, void(R*, Status*, void*));
 };
@@ -100,6 +102,7 @@
   MockClientAsyncReader() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
@@ -113,11 +116,13 @@
   MockClientAsyncWriter() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
   /// AsyncWriterInterface
   MOCK_METHOD2_T(Write, void(const W&, void*));
+  MOCK_METHOD3_T(Write, void(const W&, ::grpc::WriteOptions, void*));
 
   /// ClientAsyncWriterInterface
   MOCK_METHOD1_T(WritesDone, void(void*));
@@ -130,11 +135,13 @@
   MockClientAsyncReaderWriter() = default;
 
   /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(StartCall, void(void*));
   MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
   MOCK_METHOD2_T(Finish, void(Status*, void*));
 
   /// AsyncWriterInterface
   MOCK_METHOD2_T(Write, void(const W&, void*));
+  MOCK_METHOD3_T(Write, void(const W&, ::grpc::WriteOptions, void*));
 
   /// AsyncReaderInterface
   MOCK_METHOD2_T(Read, void(R*, void*));
diff --git a/grpc/spm-cpp-include/grpcpp/xds_server_builder.h b/grpc/spm-cpp-include/grpcpp/xds_server_builder.h
index 1ed9e83..076c377 100644
--- a/grpc/spm-cpp-include/grpcpp/xds_server_builder.h
+++ b/grpc/spm-cpp-include/grpcpp/xds_server_builder.h
@@ -26,15 +26,52 @@
 namespace grpc {
 namespace experimental {
 
+class XdsServerServingStatusNotifierInterface {
+ public:
+  virtual ~XdsServerServingStatusNotifierInterface() = default;
+
+  // \a uri contains the listening target associated with the notification. Note
+  // that a single target provided to XdsServerBuilder can get resolved to
+  // multiple listening addresses.
+  // The callback is invoked each time there is an update to the serving status.
+  // The API does not provide any guarantees around duplicate updates.
+  // Status::OK signifies that the server is serving, while a non-OK status
+  // signifies that the server is not serving.
+  virtual void OnServingStatusUpdate(std::string uri, grpc::Status status) = 0;
+};
+
 class XdsServerBuilder : public ::grpc::ServerBuilder {
  public:
-  std::unique_ptr<Server> BuildAndStart() override {
-    grpc_server_config_fetcher* fetcher =
-        grpc_server_config_fetcher_xds_create();
-    if (fetcher == nullptr) return nullptr;
-    set_fetcher(fetcher);
-    return ServerBuilder::BuildAndStart();
+  // It is the responsibility of the application to make sure that \a notifier
+  // outlasts the life of the server. Notifications will start being made
+  // asynchronously once `BuildAndStart()` has been called. Note that it is
+  // possible for notifications to be made before `BuildAndStart()` returns.
+  void set_status_notifier(XdsServerServingStatusNotifierInterface* notifier) {
+    notifier_ = notifier;
   }
+
+ private:
+  // Called at the beginning of BuildAndStart().
+  ChannelArguments BuildChannelArgs() override {
+    ChannelArguments args = ServerBuilder::BuildChannelArgs();
+    grpc_channel_args c_channel_args = args.c_channel_args();
+    grpc_server_config_fetcher* fetcher = grpc_server_config_fetcher_xds_create(
+        {OnServingStatusUpdate, notifier_}, &c_channel_args);
+    if (fetcher != nullptr) set_fetcher(fetcher);
+    return args;
+  }
+
+  static void OnServingStatusUpdate(void* user_data, const char* uri,
+                                    grpc_status_code code,
+                                    const char* error_message) {
+    if (user_data == nullptr) return;
+    XdsServerServingStatusNotifierInterface* notifier =
+        static_cast<XdsServerServingStatusNotifierInterface*>(user_data);
+    notifier->OnServingStatusUpdate(
+        uri, grpc::Status(static_cast<StatusCode>(code), error_message));
+  }
+
+  XdsServerServingStatusNotifierInterface* notifier_ = nullptr;
 };
 
 }  // namespace experimental
diff --git a/grpc/src/abseil-cpp/preprocessed_builds.yaml b/grpc/src/abseil-cpp/preprocessed_builds.yaml
index 257efad..6c73dd3 100644
--- a/grpc/src/abseil-cpp/preprocessed_builds.yaml
+++ b/grpc/src/abseil-cpp/preprocessed_builds.yaml
@@ -63,14 +63,6 @@
   - third_party/abseil-cpp/absl/base/internal/scheduling_mode.h
   name: absl/base:base_internal
   src: []
-- cmake_target: absl::bits
-  deps:
-  - absl/base:config
-  - absl/base:core_headers
-  headers:
-  - third_party/abseil-cpp/absl/base/internal/bits.h
-  name: absl/base:bits
-  src: []
 - cmake_target: absl::config
   deps: []
   headers:
@@ -103,6 +95,7 @@
   src: []
 - cmake_target: absl::endian
   deps:
+  - absl/base:base
   - absl/base:config
   - absl/base:core_headers
   headers:
@@ -215,6 +208,24 @@
   name: absl/base:throw_delegate
   src:
   - third_party/abseil-cpp/absl/base/internal/throw_delegate.cc
+- cmake_target: absl::cleanup
+  deps:
+  - absl/base:config
+  - absl/base:core_headers
+  - absl/cleanup:cleanup_internal
+  headers:
+  - third_party/abseil-cpp/absl/cleanup/cleanup.h
+  name: absl/cleanup:cleanup
+  src: []
+- cmake_target: absl::cleanup_internal
+  deps:
+  - absl/base:base_internal
+  - absl/base:core_headers
+  - absl/utility:utility
+  headers:
+  - third_party/abseil-cpp/absl/cleanup/internal/cleanup.h
+  name: absl/cleanup:cleanup_internal
+  src: []
 - cmake_target: absl::btree
   deps:
   - absl/base:core_headers
@@ -425,7 +436,6 @@
   src: []
 - cmake_target: absl::raw_hash_set
   deps:
-  - absl/base:bits
   - absl/base:config
   - absl/base:core_headers
   - absl/base:endian
@@ -439,6 +449,7 @@
   - absl/container:layout
   - absl/memory:memory
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/utility:utility
   headers:
   - third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
@@ -619,6 +630,7 @@
   - absl/utility:utility
   headers:
   - third_party/abseil-cpp/absl/flags/internal/flag.h
+  - third_party/abseil-cpp/absl/flags/internal/sequence_lock.h
   name: absl/flags:flag_internal
   src:
   - third_party/abseil-cpp/absl/flags/internal/flag.cc
@@ -766,10 +778,12 @@
   - third_party/abseil-cpp/absl/hash/internal/city.cc
 - cmake_target: absl::hash
   deps:
+  - absl/base:config
   - absl/base:core_headers
   - absl/base:endian
   - absl/container:fixed_array
   - absl/hash:city
+  - absl/hash:wyhash
   - absl/meta:type_traits
   - absl/numeric:int128
   - absl/strings:strings
@@ -782,6 +796,16 @@
   name: absl/hash:hash
   src:
   - third_party/abseil-cpp/absl/hash/internal/hash.cc
+- cmake_target: absl::wyhash
+  deps:
+  - absl/base:config
+  - absl/base:endian
+  - absl/numeric:int128
+  headers:
+  - third_party/abseil-cpp/absl/hash/internal/wyhash.h
+  name: absl/hash:wyhash
+  src:
+  - third_party/abseil-cpp/absl/hash/internal/wyhash.cc
 - cmake_target: absl::memory
   deps:
   - absl/base:core_headers
@@ -797,18 +821,34 @@
   - third_party/abseil-cpp/absl/meta/type_traits.h
   name: absl/meta:type_traits
   src: []
-- cmake_target: absl::int128
+- cmake_target: absl::bits
   deps:
-  - absl/base:bits
   - absl/base:config
   - absl/base:core_headers
   headers:
+  - third_party/abseil-cpp/absl/numeric/bits.h
+  - third_party/abseil-cpp/absl/numeric/internal/bits.h
+  name: absl/numeric:bits
+  src: []
+- cmake_target: absl::int128
+  deps:
+  - absl/base:config
+  - absl/base:core_headers
+  - absl/numeric:bits
+  headers:
   - third_party/abseil-cpp/absl/numeric/int128.h
   - third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc
   - third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc
   name: absl/numeric:int128
   src:
   - third_party/abseil-cpp/absl/numeric/int128.cc
+- cmake_target: absl::numeric_representation
+  deps:
+  - absl/base:config
+  headers:
+  - third_party/abseil-cpp/absl/numeric/internal/representation.h
+  name: absl/numeric:representation
+  src: []
 - cmake_target: absl::random_internal_distribution_caller
   deps:
   - absl/base:config
@@ -828,15 +868,15 @@
   src: []
 - cmake_target: absl::random_internal_fastmath
   deps:
-  - absl/base:bits
+  - absl/numeric:bits
   headers:
   - third_party/abseil-cpp/absl/random/internal/fastmath.h
   name: absl/random/internal:fastmath
   src: []
 - cmake_target: absl::random_internal_generate_real
   deps:
-  - absl/base:bits
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/random/internal:fastmath
   - absl/random/internal:traits
   headers:
@@ -888,6 +928,7 @@
   deps:
   - absl/base:config
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/numeric:int128
   - absl/random/internal:fastmath
   - absl/random/internal:iostream_state_saver
@@ -934,6 +975,7 @@
   - third_party/abseil-cpp/absl/random/internal/randen.cc
 - cmake_target: absl::random_internal_randen_engine
   deps:
+  - absl/base:endian
   - absl/meta:type_traits
   - absl/random/internal:iostream_state_saver
   - absl/random/internal:randen
@@ -1014,8 +1056,8 @@
   src: []
 - cmake_target: absl::random_internal_wide_multiply
   deps:
-  - absl/base:bits
   - absl/base:config
+  - absl/numeric:bits
   - absl/numeric:int128
   - absl/random/internal:traits
   headers:
@@ -1040,6 +1082,7 @@
   - absl/base:config
   - absl/base:core_headers
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/random/internal:distribution_caller
   - absl/random/internal:fast_uniform_bits
   - absl/random/internal:fastmath
@@ -1158,13 +1201,25 @@
 - cmake_target: absl::cord
   deps:
   - absl/base:base_internal
+  - absl/base:config
+  - absl/base:core_headers
+  - absl/base:endian
+  - absl/base:raw_logging_internal
+  - absl/base:throw_delegate
   - absl/container:compressed_tuple
+  - absl/container:inlined_vector
+  - absl/container:layout
   - absl/meta:type_traits
   - absl/strings:strings
   headers:
   - third_party/abseil-cpp/absl/strings/internal/cord_internal.h
+  - third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h
+  - third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h
+  - third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h
   name: absl/strings:cord_internal
-  src: []
+  src:
+  - third_party/abseil-cpp/absl/strings/internal/cord_internal.cc
+  - third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc
 - cmake_target: absl::strings_internal
   deps:
   - absl/base:config
@@ -1192,12 +1247,13 @@
   src: []
 - cmake_target: absl::str_format_internal
   deps:
-  - absl/base:bits
   - absl/base:config
   - absl/base:core_headers
   - absl/functional:function_ref
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/numeric:int128
+  - absl/numeric:representation
   - absl/strings:strings
   - absl/types:optional
   - absl/types:span
@@ -1220,7 +1276,6 @@
 - cmake_target: absl::strings
   deps:
   - absl/base:base
-  - absl/base:bits
   - absl/base:config
   - absl/base:core_headers
   - absl/base:endian
@@ -1228,6 +1283,7 @@
   - absl/base:throw_delegate
   - absl/memory:memory
   - absl/meta:type_traits
+  - absl/numeric:bits
   - absl/numeric:int128
   - absl/strings:internal
   headers:
@@ -1240,6 +1296,7 @@
   - third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h
   - third_party/abseil-cpp/absl/strings/internal/str_join_internal.h
   - third_party/abseil-cpp/absl/strings/internal/str_split_internal.h
+  - third_party/abseil-cpp/absl/strings/internal/string_constant.h
   - third_party/abseil-cpp/absl/strings/match.h
   - third_party/abseil-cpp/absl/strings/numbers.h
   - third_party/abseil-cpp/absl/strings/str_cat.h
@@ -1305,7 +1362,7 @@
   - third_party/abseil-cpp/absl/synchronization/barrier.h
   - third_party/abseil-cpp/absl/synchronization/blocking_counter.h
   - third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h
-  - third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc
+  - third_party/abseil-cpp/absl/synchronization/internal/futex.h
   - third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h
   - third_party/abseil-cpp/absl/synchronization/internal/waiter.h
   - third_party/abseil-cpp/absl/synchronization/mutex.h
diff --git a/grpc/src/boringssl/boringssl_prefix_symbols.h b/grpc/src/boringssl/boringssl_prefix_symbols.h
index 85fa0e5..1991903 100644
--- a/grpc/src/boringssl/boringssl_prefix_symbols.h
+++ b/grpc/src/boringssl/boringssl_prefix_symbols.h
@@ -1,4 +1,4 @@
-// generated by generate_boringssl_prefix_header.sh on BoringSSL commit: 29c6e0e27268f5a43e039cd2ed4e849d6b736fc1
+// generated by generate_boringssl_prefix_header.sh on BoringSSL commit: 688fc5cf5428868679d2ae1072cad81055752068
 
 // Copyright (c) 2018, Google Inc.
 //
@@ -142,6 +142,7 @@
 #define SSL_CTX_set1_chain BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_chain)
 #define SSL_CTX_set1_curves BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_curves)
 #define SSL_CTX_set1_curves_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_curves_list)
+#define SSL_CTX_set1_ech_server_config_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_ech_server_config_list)
 #define SSL_CTX_set1_param BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_param)
 #define SSL_CTX_set1_sigalgs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_sigalgs)
 #define SSL_CTX_set1_sigalgs_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set1_sigalgs_list)
@@ -168,7 +169,6 @@
 #define SSL_CTX_set_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_ex_data)
 #define SSL_CTX_set_false_start_allowed_without_alpn BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_false_start_allowed_without_alpn)
 #define SSL_CTX_set_grease_enabled BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_grease_enabled)
-#define SSL_CTX_set_ignore_tls13_downgrade BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_ignore_tls13_downgrade)
 #define SSL_CTX_set_info_callback BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_info_callback)
 #define SSL_CTX_set_keylog_callback BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_keylog_callback)
 #define SSL_CTX_set_max_cert_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_set_max_cert_list)
@@ -230,6 +230,10 @@
 #define SSL_CTX_use_certificate_chain_file BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_use_certificate_chain_file)
 #define SSL_CTX_use_certificate_file BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_use_certificate_file)
 #define SSL_CTX_use_psk_identity_hint BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_CTX_use_psk_identity_hint)
+#define SSL_ECH_SERVER_CONFIG_LIST_add BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_ECH_SERVER_CONFIG_LIST_add)
+#define SSL_ECH_SERVER_CONFIG_LIST_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_ECH_SERVER_CONFIG_LIST_free)
+#define SSL_ECH_SERVER_CONFIG_LIST_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_ECH_SERVER_CONFIG_LIST_new)
+#define SSL_ECH_SERVER_CONFIG_LIST_up_ref BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_ECH_SERVER_CONFIG_LIST_up_ref)
 #define SSL_SESSION_copy_without_early_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_SESSION_copy_without_early_data)
 #define SSL_SESSION_early_data_capable BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_SESSION_early_data_capable)
 #define SSL_SESSION_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_SESSION_free)
@@ -393,7 +397,6 @@
 #define SSL_is_init_finished BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_init_finished)
 #define SSL_is_server BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_server)
 #define SSL_is_signature_algorithm_rsa_pss BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_signature_algorithm_rsa_pss)
-#define SSL_is_tls13_downgrade BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_tls13_downgrade)
 #define SSL_is_token_binding_negotiated BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_is_token_binding_negotiated)
 #define SSL_key_update BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_key_update)
 #define SSL_library_init BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_library_init)
@@ -415,9 +418,12 @@
 #define SSL_read BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_read)
 #define SSL_renegotiate BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_renegotiate)
 #define SSL_renegotiate_pending BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_renegotiate_pending)
+#define SSL_request_handshake_hints BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_request_handshake_hints)
 #define SSL_reset_early_data_reject BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_reset_early_data_reject)
 #define SSL_select_next_proto BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_select_next_proto)
 #define SSL_send_fatal_alert BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_send_fatal_alert)
+#define SSL_serialize_capabilities BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_serialize_capabilities)
+#define SSL_serialize_handshake_hints BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_serialize_handshake_hints)
 #define SSL_session_reused BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_session_reused)
 #define SSL_set0_chain BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set0_chain)
 #define SSL_set0_client_CAs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set0_client_CAs)
@@ -444,10 +450,11 @@
 #define SSL_set_connect_state BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_connect_state)
 #define SSL_set_custom_verify BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_custom_verify)
 #define SSL_set_early_data_enabled BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_early_data_enabled)
+#define SSL_set_enable_ech_grease BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_enable_ech_grease)
 #define SSL_set_enforce_rsa_key_usage BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_enforce_rsa_key_usage)
 #define SSL_set_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_ex_data)
 #define SSL_set_fd BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_fd)
-#define SSL_set_ignore_tls13_downgrade BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_ignore_tls13_downgrade)
+#define SSL_set_handshake_hints BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_handshake_hints)
 #define SSL_set_info_callback BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_info_callback)
 #define SSL_set_jdk11_workaround BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_jdk11_workaround)
 #define SSL_set_max_cert_list BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_max_cert_list)
@@ -467,6 +474,7 @@
 #define SSL_set_quic_early_data_context BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_quic_early_data_context)
 #define SSL_set_quic_method BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_quic_method)
 #define SSL_set_quic_transport_params BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_quic_transport_params)
+#define SSL_set_quic_use_legacy_codepoint BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_quic_use_legacy_codepoint)
 #define SSL_set_quiet_shutdown BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_quiet_shutdown)
 #define SSL_set_read_ahead BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_read_ahead)
 #define SSL_set_renegotiate_mode BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, SSL_set_renegotiate_mode)
@@ -640,7 +648,6 @@
 #define ASN1_OBJECT_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_OBJECT_free)
 #define ASN1_OBJECT_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_OBJECT_it)
 #define ASN1_OBJECT_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_OBJECT_new)
-#define ASN1_OCTET_STRING_NDEF_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_OCTET_STRING_NDEF_it)
 #define ASN1_OCTET_STRING_cmp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_OCTET_STRING_cmp)
 #define ASN1_OCTET_STRING_dup BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_OCTET_STRING_dup)
 #define ASN1_OCTET_STRING_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_OCTET_STRING_free)
@@ -735,7 +742,6 @@
 #define ASN1_item_i2d BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_item_i2d)
 #define ASN1_item_i2d_bio BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_item_i2d_bio)
 #define ASN1_item_i2d_fp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_item_i2d_fp)
-#define ASN1_item_ndef_i2d BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_item_ndef_i2d)
 #define ASN1_item_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_item_new)
 #define ASN1_item_pack BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_item_pack)
 #define ASN1_item_sign BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_item_sign)
@@ -746,13 +752,11 @@
 #define ASN1_mbstring_ncopy BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_mbstring_ncopy)
 #define ASN1_object_size BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_object_size)
 #define ASN1_primitive_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_primitive_free)
-#define ASN1_primitive_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_primitive_new)
 #define ASN1_put_eoc BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_put_eoc)
 #define ASN1_put_object BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_put_object)
 #define ASN1_tag2bit BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_tag2bit)
 #define ASN1_tag2str BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_tag2str)
 #define ASN1_template_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_template_free)
-#define ASN1_template_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ASN1_template_new)
 #define AUTHORITY_INFO_ACCESS_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, AUTHORITY_INFO_ACCESS_free)
 #define AUTHORITY_INFO_ACCESS_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, AUTHORITY_INFO_ACCESS_it)
 #define AUTHORITY_INFO_ACCESS_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, AUTHORITY_INFO_ACCESS_new)
@@ -861,6 +865,10 @@
 #define BIO_write BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BIO_write)
 #define BIO_write_all BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BIO_write_all)
 #define BIO_write_filename BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BIO_write_filename)
+#define BLAKE2B256 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BLAKE2B256)
+#define BLAKE2B256_Final BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BLAKE2B256_Final)
+#define BLAKE2B256_Init BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BLAKE2B256_Init)
+#define BLAKE2B256_Update BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BLAKE2B256_Update)
 #define BN_BLINDING_convert BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BN_BLINDING_convert)
 #define BN_BLINDING_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BN_BLINDING_free)
 #define BN_BLINDING_invalidate BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BN_BLINDING_invalidate)
@@ -1068,7 +1076,9 @@
 #define CBS_get_u8 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_get_u8)
 #define CBS_get_u8_length_prefixed BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_get_u8_length_prefixed)
 #define CBS_init BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_init)
+#define CBS_is_unsigned_asn1_integer BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_is_unsigned_asn1_integer)
 #define CBS_is_valid_asn1_bitstring BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_is_valid_asn1_bitstring)
+#define CBS_is_valid_asn1_integer BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_is_valid_asn1_integer)
 #define CBS_len BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_len)
 #define CBS_mem_equal BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_mem_equal)
 #define CBS_peek_asn1_tag BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CBS_peek_asn1_tag)
@@ -1128,6 +1138,7 @@
 #define CRYPTO_cleanup_all_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CRYPTO_cleanup_all_ex_data)
 #define CRYPTO_ctr128_encrypt BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CRYPTO_ctr128_encrypt)
 #define CRYPTO_ctr128_encrypt_ctr32 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CRYPTO_ctr128_encrypt_ctr32)
+#define CRYPTO_fork_detect_ignore_madv_wipeonfork_for_testing BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CRYPTO_fork_detect_ignore_madv_wipeonfork_for_testing)
 #define CRYPTO_free_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CRYPTO_free_ex_data)
 #define CRYPTO_gcm128_aad BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CRYPTO_gcm128_aad)
 #define CRYPTO_gcm128_decrypt BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, CRYPTO_gcm128_decrypt)
@@ -1196,6 +1207,8 @@
 #define DH_check BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_check)
 #define DH_check_pub_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_check_pub_key)
 #define DH_compute_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_compute_key)
+#define DH_compute_key_hashed BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_compute_key_hashed)
+#define DH_compute_key_padded BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_compute_key_padded)
 #define DH_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_free)
 #define DH_generate_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_generate_key)
 #define DH_generate_parameters_ex BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_generate_parameters_ex)
@@ -1206,15 +1219,13 @@
 #define DH_get0_priv_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_get0_priv_key)
 #define DH_get0_pub_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_get0_pub_key)
 #define DH_get0_q BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_get0_q)
-#define DH_get_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_get_ex_data)
-#define DH_get_ex_new_index BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_get_ex_new_index)
+#define DH_get_rfc7919_2048 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_get_rfc7919_2048)
 #define DH_marshal_parameters BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_marshal_parameters)
 #define DH_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_new)
 #define DH_num_bits BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_num_bits)
 #define DH_parse_parameters BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_parse_parameters)
 #define DH_set0_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_set0_key)
 #define DH_set0_pqg BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_set0_pqg)
-#define DH_set_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_set_ex_data)
 #define DH_set_length BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_set_length)
 #define DH_size BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_size)
 #define DH_up_ref BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_up_ref)
@@ -1284,6 +1295,7 @@
 #define ECDSA_do_sign BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_do_sign)
 #define ECDSA_do_verify BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_do_verify)
 #define ECDSA_sign BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_sign)
+#define ECDSA_sign_with_nonce_and_leak_private_key_for_testing BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_sign_with_nonce_and_leak_private_key_for_testing)
 #define ECDSA_size BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_size)
 #define ECDSA_verify BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ECDSA_verify)
 #define EC_GFp_mont_method BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GFp_mont_method)
@@ -1295,6 +1307,7 @@
 #define EC_GROUP_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_free)
 #define EC_GROUP_get0_generator BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get0_generator)
 #define EC_GROUP_get0_order BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get0_order)
+#define EC_GROUP_get_asn1_flag BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get_asn1_flag)
 #define EC_GROUP_get_cofactor BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get_cofactor)
 #define EC_GROUP_get_curve_GFp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get_curve_GFp)
 #define EC_GROUP_get_curve_name BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_GROUP_get_curve_name)
@@ -1348,6 +1361,7 @@
 #define EC_POINT_dbl BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_dbl)
 #define EC_POINT_dup BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_dup)
 #define EC_POINT_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_free)
+#define EC_POINT_get_affine_coordinates BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_get_affine_coordinates)
 #define EC_POINT_get_affine_coordinates_GFp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_get_affine_coordinates_GFp)
 #define EC_POINT_invert BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_invert)
 #define EC_POINT_is_at_infinity BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_is_at_infinity)
@@ -1357,6 +1371,7 @@
 #define EC_POINT_oct2point BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_oct2point)
 #define EC_POINT_point2cbb BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_point2cbb)
 #define EC_POINT_point2oct BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_point2oct)
+#define EC_POINT_set_affine_coordinates BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_set_affine_coordinates)
 #define EC_POINT_set_affine_coordinates_GFp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_set_affine_coordinates_GFp)
 #define EC_POINT_set_compressed_coordinates_GFp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_set_compressed_coordinates_GFp)
 #define EC_POINT_set_to_infinity BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EC_POINT_set_to_infinity)
@@ -1498,6 +1513,8 @@
 #define EVP_EncryptUpdate BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_EncryptUpdate)
 #define EVP_HPKE_CTX_cleanup BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_cleanup)
 #define EVP_HPKE_CTX_export BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_export)
+#define EVP_HPKE_CTX_get_aead_id BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_get_aead_id)
+#define EVP_HPKE_CTX_get_kdf_id BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_get_kdf_id)
 #define EVP_HPKE_CTX_init BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_init)
 #define EVP_HPKE_CTX_max_overhead BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_max_overhead)
 #define EVP_HPKE_CTX_open BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_open)
@@ -1508,6 +1525,8 @@
 #define EVP_HPKE_CTX_setup_psk_r_x25519 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_setup_psk_r_x25519)
 #define EVP_HPKE_CTX_setup_psk_s_x25519 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_setup_psk_s_x25519)
 #define EVP_HPKE_CTX_setup_psk_s_x25519_for_test BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_CTX_setup_psk_s_x25519_for_test)
+#define EVP_HPKE_get_aead BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_get_aead)
+#define EVP_HPKE_get_hkdf_md BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_HPKE_get_hkdf_md)
 #define EVP_MD_CTX_block_size BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_MD_CTX_block_size)
 #define EVP_MD_CTX_cleanup BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_MD_CTX_cleanup)
 #define EVP_MD_CTX_copy BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_MD_CTX_copy)
@@ -1622,7 +1641,6 @@
 #define EVP_add_digest BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_add_digest)
 #define EVP_aead_aes_128_cbc_sha1_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_cbc_sha1_tls)
 #define EVP_aead_aes_128_cbc_sha1_tls_implicit_iv BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_cbc_sha1_tls_implicit_iv)
-#define EVP_aead_aes_128_cbc_sha256_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_cbc_sha256_tls)
 #define EVP_aead_aes_128_ccm_bluetooth BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_ccm_bluetooth)
 #define EVP_aead_aes_128_ccm_bluetooth_8 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_ccm_bluetooth_8)
 #define EVP_aead_aes_128_ctr_hmac_sha256 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_128_ctr_hmac_sha256)
@@ -1634,8 +1652,6 @@
 #define EVP_aead_aes_192_gcm BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_192_gcm)
 #define EVP_aead_aes_256_cbc_sha1_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_cbc_sha1_tls)
 #define EVP_aead_aes_256_cbc_sha1_tls_implicit_iv BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_cbc_sha1_tls_implicit_iv)
-#define EVP_aead_aes_256_cbc_sha256_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_cbc_sha256_tls)
-#define EVP_aead_aes_256_cbc_sha384_tls BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_cbc_sha384_tls)
 #define EVP_aead_aes_256_ctr_hmac_sha256 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_ctr_hmac_sha256)
 #define EVP_aead_aes_256_gcm BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_gcm)
 #define EVP_aead_aes_256_gcm_randnonce BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aead_aes_256_gcm_randnonce)
@@ -1662,6 +1678,7 @@
 #define EVP_aes_256_ecb BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aes_256_ecb)
 #define EVP_aes_256_gcm BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aes_256_gcm)
 #define EVP_aes_256_ofb BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_aes_256_ofb)
+#define EVP_blake2b256 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_blake2b256)
 #define EVP_cleanup BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_cleanup)
 #define EVP_des_cbc BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_des_cbc)
 #define EVP_des_ecb BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_des_ecb)
@@ -1690,6 +1707,7 @@
 #define EVP_rc2_cbc BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_rc2_cbc)
 #define EVP_rc4 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_rc4)
 #define EVP_sha1 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha1)
+#define EVP_sha1_final_with_secret_suffix BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha1_final_with_secret_suffix)
 #define EVP_sha224 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha224)
 #define EVP_sha256 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha256)
 #define EVP_sha384 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EVP_sha384)
@@ -1704,6 +1722,7 @@
 #define EXTENDED_KEY_USAGE_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, EXTENDED_KEY_USAGE_new)
 #define FIPS_mode BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, FIPS_mode)
 #define FIPS_mode_set BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, FIPS_mode_set)
+#define FIPS_read_counter BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, FIPS_read_counter)
 #define GENERAL_NAMES_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, GENERAL_NAMES_free)
 #define GENERAL_NAMES_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, GENERAL_NAMES_it)
 #define GENERAL_NAMES_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, GENERAL_NAMES_new)
@@ -1987,6 +2006,7 @@
 #define PROXY_POLICY_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, PROXY_POLICY_free)
 #define PROXY_POLICY_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, PROXY_POLICY_it)
 #define PROXY_POLICY_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, PROXY_POLICY_new)
+#define RAND_OpenSSL BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, RAND_OpenSSL)
 #define RAND_SSLeay BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, RAND_SSLeay)
 #define RAND_add BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, RAND_add)
 #define RAND_bytes BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, RAND_bytes)
@@ -2187,7 +2207,6 @@
 #define X509_ALGOR_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ALGOR_new)
 #define X509_ALGOR_set0 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ALGOR_set0)
 #define X509_ALGOR_set_md BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ALGOR_set_md)
-#define X509_ATTRIBUTE_SET_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ATTRIBUTE_SET_it)
 #define X509_ATTRIBUTE_count BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ATTRIBUTE_count)
 #define X509_ATTRIBUTE_create BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ATTRIBUTE_create)
 #define X509_ATTRIBUTE_create_by_NID BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_ATTRIBUTE_create_by_NID)
@@ -2207,10 +2226,8 @@
 #define X509_CERT_AUX_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CERT_AUX_new)
 #define X509_CERT_AUX_print BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CERT_AUX_print)
 #define X509_CINF_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_free)
-#define X509_CINF_get_signature BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_get_signature)
 #define X509_CINF_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_it)
 #define X509_CINF_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_new)
-#define X509_CINF_set_modified BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CINF_set_modified)
 #define X509_CRL_INFO_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CRL_INFO_free)
 #define X509_CRL_INFO_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CRL_INFO_it)
 #define X509_CRL_INFO_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_CRL_INFO_new)
@@ -2339,6 +2356,7 @@
 #define X509_PUBKEY_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_free)
 #define X509_PUBKEY_get BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_get)
 #define X509_PUBKEY_get0_param BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_get0_param)
+#define X509_PUBKEY_get0_public_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_get0_public_key)
 #define X509_PUBKEY_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_it)
 #define X509_PUBKEY_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_new)
 #define X509_PUBKEY_set BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_PUBKEY_set)
@@ -2375,7 +2393,6 @@
 #define X509_REQ_get_attr_by_NID BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_attr_by_NID)
 #define X509_REQ_get_attr_by_OBJ BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_attr_by_OBJ)
 #define X509_REQ_get_attr_count BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_attr_count)
-#define X509_REQ_get_extension_nids BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_extension_nids)
 #define X509_REQ_get_extensions BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_extensions)
 #define X509_REQ_get_pubkey BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_pubkey)
 #define X509_REQ_get_signature_nid BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_get_signature_nid)
@@ -2386,13 +2403,11 @@
 #define X509_REQ_print BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_print)
 #define X509_REQ_print_ex BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_print_ex)
 #define X509_REQ_print_fp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_print_fp)
-#define X509_REQ_set_extension_nids BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_set_extension_nids)
 #define X509_REQ_set_pubkey BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_set_pubkey)
 #define X509_REQ_set_subject_name BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_set_subject_name)
 #define X509_REQ_set_version BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_set_version)
 #define X509_REQ_sign BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_sign)
 #define X509_REQ_sign_ctx BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_sign_ctx)
-#define X509_REQ_to_X509 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_to_X509)
 #define X509_REQ_verify BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REQ_verify)
 #define X509_REVOKED_add1_ext_i2d BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REVOKED_add1_ext_i2d)
 #define X509_REVOKED_add_ext BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_REVOKED_add_ext)
@@ -2580,7 +2595,6 @@
 #define X509_get1_email BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get1_email)
 #define X509_get1_ocsp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get1_ocsp)
 #define X509_get_X509_PUBKEY BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_X509_PUBKEY)
-#define X509_get_cert_info BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_cert_info)
 #define X509_get_default_cert_area BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_default_cert_area)
 #define X509_get_default_cert_dir BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_default_cert_dir)
 #define X509_get_default_cert_dir_env BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_get_default_cert_dir_env)
@@ -2611,7 +2625,6 @@
 #define X509_getm_notBefore BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_getm_notBefore)
 #define X509_gmtime_adj BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_gmtime_adj)
 #define X509_issuer_and_serial_cmp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_issuer_and_serial_cmp)
-#define X509_issuer_and_serial_hash BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_issuer_and_serial_hash)
 #define X509_issuer_name_cmp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_issuer_name_cmp)
 #define X509_issuer_name_hash BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_issuer_name_hash)
 #define X509_issuer_name_hash_old BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_issuer_name_hash_old)
@@ -2643,6 +2656,8 @@
 #define X509_reject_clear BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_reject_clear)
 #define X509_set1_notAfter BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_set1_notAfter)
 #define X509_set1_notBefore BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_set1_notBefore)
+#define X509_set1_signature_algo BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_set1_signature_algo)
+#define X509_set1_signature_value BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_set1_signature_value)
 #define X509_set_ex_data BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_set_ex_data)
 #define X509_set_issuer_name BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_set_issuer_name)
 #define X509_set_notAfter BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_set_notAfter)
@@ -2766,8 +2781,6 @@
 #define asn1_enc_init BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_enc_init)
 #define asn1_enc_restore BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_enc_restore)
 #define asn1_enc_save BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_enc_save)
-#define asn1_ex_c2i BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_ex_c2i)
-#define asn1_ex_i2c BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_ex_i2c)
 #define asn1_generalizedtime_to_tm BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_generalizedtime_to_tm)
 #define asn1_get_choice_selector BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_get_choice_selector)
 #define asn1_get_field_ptr BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_get_field_ptr)
@@ -2775,6 +2788,7 @@
 #define asn1_refcount_dec_and_test_zero BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_refcount_dec_and_test_zero)
 #define asn1_refcount_set_one BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_refcount_set_one)
 #define asn1_set_choice_selector BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_set_choice_selector)
+#define asn1_type_value_as_pointer BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_type_value_as_pointer)
 #define asn1_utctime_to_tm BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, asn1_utctime_to_tm)
 #define beeu_mod_inverse_vartime BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, beeu_mod_inverse_vartime)
 #define bio_clear_socket_error BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bio_clear_socket_error)
@@ -2838,6 +2852,7 @@
 #define bn_scatter5 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_scatter5)
 #define bn_select_words BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_select_words)
 #define bn_set_minimal_width BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_set_minimal_width)
+#define bn_set_static_words BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_set_static_words)
 #define bn_set_words BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_set_words)
 #define bn_sqr8x_internal BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_sqr8x_internal)
 #define bn_sqr_comba4 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_sqr_comba4)
@@ -3074,6 +3089,7 @@
 #define ec_set_to_safe_point BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ec_set_to_safe_point)
 #define ec_simple_scalar_inv0_montgomery BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ec_simple_scalar_inv0_montgomery)
 #define ec_simple_scalar_to_montgomery_inv_vartime BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ec_simple_scalar_to_montgomery_inv_vartime)
+#define ecdsa_sign_with_nonce_for_known_answer_test BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ecdsa_sign_with_nonce_for_known_answer_test)
 #define ecp_nistz256_avx2_select_w7 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ecp_nistz256_avx2_select_w7)
 #define ecp_nistz256_mul_mont BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ecp_nistz256_mul_mont)
 #define ecp_nistz256_neg BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, ecp_nistz256_neg)
@@ -3215,6 +3231,7 @@
 #define i2d_X509_CRL_INFO BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_CRL_INFO)
 #define i2d_X509_CRL_bio BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_CRL_bio)
 #define i2d_X509_CRL_fp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_CRL_fp)
+#define i2d_X509_CRL_tbs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_CRL_tbs)
 #define i2d_X509_EXTENSION BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_EXTENSION)
 #define i2d_X509_EXTENSIONS BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_EXTENSIONS)
 #define i2d_X509_NAME BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_NAME)
@@ -3229,6 +3246,7 @@
 #define i2d_X509_VAL BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_VAL)
 #define i2d_X509_bio BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_bio)
 #define i2d_X509_fp BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_fp)
+#define i2d_X509_tbs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_X509_tbs)
 #define i2d_re_X509_CRL_tbs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_re_X509_CRL_tbs)
 #define i2d_re_X509_REQ_tbs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_re_X509_REQ_tbs)
 #define i2d_re_X509_tbs BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, i2d_re_X509_tbs)
@@ -3291,6 +3309,7 @@
 #define policy_node_cmp_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, policy_node_cmp_new)
 #define policy_node_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, policy_node_free)
 #define policy_node_match BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, policy_node_match)
+#define poly_Rq_mul BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, poly_Rq_mul)
 #define rand_fork_unsafe_buffering_enabled BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, rand_fork_unsafe_buffering_enabled)
 #define rsa_asn1_meth BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, rsa_asn1_meth)
 #define rsa_check_public_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, rsa_check_public_key)
diff --git a/grpc/src/compiler/config_protobuf.h b/grpc/src/compiler/config_protobuf.h
index 06d5073..4b27c8e 100644
--- a/grpc/src/compiler/config_protobuf.h
+++ b/grpc/src/compiler/config_protobuf.h
@@ -49,4 +49,14 @@
   ::google::protobuf::compiler::ParseGeneratorParameter
 #endif
 
+#ifndef GRPC_CUSTOM_CSHARP_GETCLASSNAME
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#define GRPC_CUSTOM_CSHARP_GETCLASSNAME \
+  ::google::protobuf::compiler::csharp::GetClassName
+#define GRPC_CUSTOM_CSHARP_GETFILENAMESPACE \
+  ::google::protobuf::compiler::csharp::GetFileNamespace
+#define GRPC_CUSTOM_CSHARP_GETREFLECTIONCLASSNAME \
+  ::google::protobuf::compiler::csharp::GetReflectionClassName
+#endif
+
 #endif  // SRC_COMPILER_CONFIG_PROTOBUF_H
diff --git a/grpc/src/compiler/cpp_generator.cc b/grpc/src/compiler/cpp_generator.cc
index 1e0490a..c8dff73 100644
--- a/grpc/src/compiler/cpp_generator.cc
+++ b/grpc/src/compiler/cpp_generator.cc
@@ -633,12 +633,12 @@
     printer->Print(*vars,
                    "#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL\n"
                    "virtual void $Method$(::grpc::ClientContext* context, "
-                   "$Request$* request, "
+                   "const $Request$* request, "
                    "::grpc::ClientReadReactor< $Response$>* "
                    "reactor) = 0;\n"
                    "#else\n"
                    "virtual void $Method$(::grpc::ClientContext* context, "
-                   "$Request$* request, "
+                   "const $Request$* request, "
                    "::grpc::experimental::ClientReadReactor< $Response$>* "
                    "reactor) = 0;\n"
                    "#endif\n");
@@ -730,12 +730,12 @@
     printer->Print(*vars,
                    "#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL\n"
                    "void $Method$(::grpc::ClientContext* context, "
-                   "$Request$* request, "
+                   "const $Request$* request, "
                    "::grpc::ClientReadReactor< $Response$>* "
                    "reactor) override;\n"
                    "#else\n"
                    "void $Method$(::grpc::ClientContext* context, "
-                   "$Request$* request, "
+                   "const $Request$* request, "
                    "::grpc::experimental::ClientReadReactor< $Response$>* "
                    "reactor) override;\n"
                    "#endif\n");
@@ -762,7 +762,7 @@
   printer->Indent();
   printer->Print("friend class Stub;\n");
   printer->Print("explicit experimental_async(Stub* stub): stub_(stub) { }\n");
-  // include a function with a dummy use of stub_ to avoid an unused
+  // include a function with a phony use of stub_ to avoid an unused
   // private member warning for service with no methods
   printer->Print("Stub* stub() { return stub_; }\n");
   printer->Print("Stub* stub_;\n");
@@ -1557,7 +1557,8 @@
   printer->Indent();
   printer->Print(
       "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& "
-      "channel);\n");
+      "channel, const ::grpc::StubOptions& options = "
+      "::grpc::StubOptions());\n");
   for (int i = 0; i < service->method_count(); ++i) {
     PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
   }
@@ -2005,7 +2006,7 @@
         *vars,
         "void $ns$$Service$::Stub::experimental_async::$Method$(::grpc::"
         "ClientContext* context, "
-        "$Request$* request, "
+        "const $Request$* request, "
         "::grpc::experimental::ClientReadReactor< $Response$>* reactor) {\n");
     printer->Print(*vars,
                    "  ::grpc::internal::ClientCallbackReaderFactory< "
@@ -2163,12 +2164,13 @@
                  "const ::grpc::StubOptions& options) {\n"
                  "  (void)options;\n"
                  "  std::unique_ptr< $ns$$Service$::Stub> stub(new "
-                 "$ns$$Service$::Stub(channel));\n"
+                 "$ns$$Service$::Stub(channel, options));\n"
                  "  return stub;\n"
                  "}\n\n");
   printer->Print(*vars,
                  "$ns$$Service$::Stub::Stub(const std::shared_ptr< "
-                 "::grpc::ChannelInterface>& channel)\n");
+                 "::grpc::ChannelInterface>& channel, const "
+                 "::grpc::StubOptions& options)\n");
   printer->Indent();
   printer->Print(": channel_(channel)");
   for (int i = 0; i < service->method_count(); ++i) {
@@ -2187,12 +2189,13 @@
     } else {
       (*vars)["StreamingType"] = "BIDI_STREAMING";
     }
-    printer->Print(*vars,
-                   ", rpcmethod_$Method$_("
-                   "$prefix$$Service$_method_names[$Idx$], "
-                   "::grpc::internal::RpcMethod::$StreamingType$, "
-                   "channel"
-                   ")\n");
+    printer->Print(
+        *vars,
+        ", rpcmethod_$Method$_("
+        "$prefix$$Service$_method_names[$Idx$], options.suffix_for_stats(),"
+        "::grpc::internal::RpcMethod::$StreamingType$, "
+        "channel"
+        ")\n");
   }
   printer->Print("{}\n\n");
   printer->Outdent();
diff --git a/grpc/src/compiler/csharp_generator.cc b/grpc/src/compiler/csharp_generator.cc
index 3ec554b..c7677c5 100644
--- a/grpc/src/compiler/csharp_generator.cc
+++ b/grpc/src/compiler/csharp_generator.cc
@@ -25,23 +25,13 @@
 #include "src/compiler/csharp_generator.h"
 #include "src/compiler/csharp_generator_helpers.h"
 
-using google::protobuf::compiler::csharp::GetClassName;
-using google::protobuf::compiler::csharp::GetFileNamespace;
-using google::protobuf::compiler::csharp::GetReflectionClassName;
 using grpc::protobuf::Descriptor;
 using grpc::protobuf::FileDescriptor;
 using grpc::protobuf::MethodDescriptor;
 using grpc::protobuf::ServiceDescriptor;
 using grpc::protobuf::io::Printer;
 using grpc::protobuf::io::StringOutputStream;
-using grpc_generator::GetMethodType;
-using grpc_generator::MethodType;
-using grpc_generator::METHODTYPE_BIDI_STREAMING;
-using grpc_generator::METHODTYPE_CLIENT_STREAMING;
-using grpc_generator::METHODTYPE_NO_STREAMING;
-using grpc_generator::METHODTYPE_SERVER_STREAMING;
 using grpc_generator::StringReplace;
-using std::map;
 using std::vector;
 
 namespace grpc_csharp_generator {
@@ -184,34 +174,36 @@
   return service->name() + "Base";
 }
 
-std::string GetCSharpMethodType(MethodType method_type) {
-  switch (method_type) {
-    case METHODTYPE_NO_STREAMING:
-      return "grpc::MethodType.Unary";
-    case METHODTYPE_CLIENT_STREAMING:
-      return "grpc::MethodType.ClientStreaming";
-    case METHODTYPE_SERVER_STREAMING:
-      return "grpc::MethodType.ServerStreaming";
-    case METHODTYPE_BIDI_STREAMING:
+std::string GetCSharpMethodType(const MethodDescriptor* method) {
+  if (method->client_streaming()) {
+    if (method->server_streaming()) {
       return "grpc::MethodType.DuplexStreaming";
+    } else {
+      return "grpc::MethodType.ClientStreaming";
+    }
+  } else {
+    if (method->server_streaming()) {
+      return "grpc::MethodType.ServerStreaming";
+    } else {
+      return "grpc::MethodType.Unary";
+    }
   }
-  GOOGLE_LOG(FATAL) << "Can't get here.";
-  return "";
 }
 
-std::string GetCSharpServerMethodType(MethodType method_type) {
-  switch (method_type) {
-    case METHODTYPE_NO_STREAMING:
-      return "grpc::UnaryServerMethod";
-    case METHODTYPE_CLIENT_STREAMING:
-      return "grpc::ClientStreamingServerMethod";
-    case METHODTYPE_SERVER_STREAMING:
-      return "grpc::ServerStreamingServerMethod";
-    case METHODTYPE_BIDI_STREAMING:
+std::string GetCSharpServerMethodType(const MethodDescriptor* method) {
+  if (method->client_streaming()) {
+    if (method->server_streaming()) {
       return "grpc::DuplexStreamingServerMethod";
+    } else {
+      return "grpc::ClientStreamingServerMethod";
+    }
+  } else {
+    if (method->server_streaming()) {
+      return "grpc::ServerStreamingServerMethod";
+    } else {
+      return "grpc::UnaryServerMethod";
+    }
   }
-  GOOGLE_LOG(FATAL) << "Can't get here.";
-  return "";
 }
 
 std::string GetServiceNameFieldName() { return "__ServiceName"; }
@@ -233,7 +225,7 @@
   if (invocation_param) {
     return "request, ";
   }
-  return GetClassName(method->input_type()) + " request, ";
+  return GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) + " request, ";
 }
 
 std::string GetAccessLevel(bool internal_access) {
@@ -241,65 +233,50 @@
 }
 
 std::string GetMethodReturnTypeClient(const MethodDescriptor* method) {
-  switch (GetMethodType(method)) {
-    case METHODTYPE_NO_STREAMING:
-      return "grpc::AsyncUnaryCall<" + GetClassName(method->output_type()) +
-             ">";
-    case METHODTYPE_CLIENT_STREAMING:
-      return "grpc::AsyncClientStreamingCall<" +
-             GetClassName(method->input_type()) + ", " +
-             GetClassName(method->output_type()) + ">";
-    case METHODTYPE_SERVER_STREAMING:
-      return "grpc::AsyncServerStreamingCall<" +
-             GetClassName(method->output_type()) + ">";
-    case METHODTYPE_BIDI_STREAMING:
+  if (method->client_streaming()) {
+    if (method->server_streaming()) {
       return "grpc::AsyncDuplexStreamingCall<" +
-             GetClassName(method->input_type()) + ", " +
-             GetClassName(method->output_type()) + ">";
+             GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) + ", " +
+             GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
+    } else {
+      return "grpc::AsyncClientStreamingCall<" +
+             GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) + ", " +
+             GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
+    }
+  } else {
+    if (method->server_streaming()) {
+      return "grpc::AsyncServerStreamingCall<" +
+             GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
+    } else {
+      return "grpc::AsyncUnaryCall<" +
+             GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
+    }
   }
-  GOOGLE_LOG(FATAL) << "Can't get here.";
-  return "";
 }
 
 std::string GetMethodRequestParamServer(const MethodDescriptor* method) {
-  switch (GetMethodType(method)) {
-    case METHODTYPE_NO_STREAMING:
-    case METHODTYPE_SERVER_STREAMING:
-      return GetClassName(method->input_type()) + " request";
-    case METHODTYPE_CLIENT_STREAMING:
-    case METHODTYPE_BIDI_STREAMING:
-      return "grpc::IAsyncStreamReader<" + GetClassName(method->input_type()) +
-             "> requestStream";
+  if (method->client_streaming()) {
+    return "grpc::IAsyncStreamReader<" +
+           GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) +
+           "> requestStream";
   }
-  GOOGLE_LOG(FATAL) << "Can't get here.";
-  return "";
+  return GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()) + " request";
 }
 
 std::string GetMethodReturnTypeServer(const MethodDescriptor* method) {
-  switch (GetMethodType(method)) {
-    case METHODTYPE_NO_STREAMING:
-    case METHODTYPE_CLIENT_STREAMING:
-      return "global::System.Threading.Tasks.Task<" +
-             GetClassName(method->output_type()) + ">";
-    case METHODTYPE_SERVER_STREAMING:
-    case METHODTYPE_BIDI_STREAMING:
-      return "global::System.Threading.Tasks.Task";
+  if (method->server_streaming()) {
+    return "global::System.Threading.Tasks.Task";
   }
-  GOOGLE_LOG(FATAL) << "Can't get here.";
-  return "";
+  return "global::System.Threading.Tasks.Task<" +
+         GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) + ">";
 }
 
 std::string GetMethodResponseStreamMaybe(const MethodDescriptor* method) {
-  switch (GetMethodType(method)) {
-    case METHODTYPE_NO_STREAMING:
-    case METHODTYPE_CLIENT_STREAMING:
-      return "";
-    case METHODTYPE_SERVER_STREAMING:
-    case METHODTYPE_BIDI_STREAMING:
-      return ", grpc::IServerStreamWriter<" +
-             GetClassName(method->output_type()) + "> responseStream";
+  if (method->server_streaming()) {
+    return ", grpc::IServerStreamWriter<" +
+           GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()) +
+           "> responseStream";
   }
-  GOOGLE_LOG(FATAL) << "Can't get here.";
   return "";
 }
 
@@ -396,7 +373,7 @@
         "grpc::Marshallers.Create(__Helper_SerializeMessage, "
         "context => __Helper_DeserializeMessage(context, $type$.Parser));\n",
         "fieldname", GetMarshallerFieldName(message), "type",
-        GetClassName(message));
+        GRPC_CUSTOM_CSHARP_GETCLASSNAME(message));
   }
   out->Print("\n");
 }
@@ -406,12 +383,11 @@
       "static readonly grpc::Method<$request$, $response$> $fieldname$ = new "
       "grpc::Method<$request$, $response$>(\n",
       "fieldname", GetMethodFieldName(method), "request",
-      GetClassName(method->input_type()), "response",
-      GetClassName(method->output_type()));
+      GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()), "response",
+      GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()));
   out->Indent();
   out->Indent();
-  out->Print("$methodtype$,\n", "methodtype",
-             GetCSharpMethodType(GetMethodType(method)));
+  out->Print("$methodtype$,\n", "methodtype", GetCSharpMethodType(method));
   out->Print("$servicenamefield$,\n", "servicenamefield",
              GetServiceNameFieldName());
   out->Print("\"$methodname$\",\n", "methodname", method->name());
@@ -434,8 +410,9 @@
       "Descriptor\n");
   out->Print("{\n");
   out->Print("  get { return $umbrella$.Descriptor.Services[$index$]; }\n",
-             "umbrella", GetReflectionClassName(service->file()), "index",
-             index.str());
+             "umbrella",
+             GRPC_CUSTOM_CSHARP_GETREFLECTIONCLASSNAME(service->file()),
+             "index", index.str());
   out->Print("}\n");
   out->Print("\n");
 }
@@ -526,9 +503,7 @@
 
   for (int i = 0; i < service->method_count(); i++) {
     const MethodDescriptor* method = service->method(i);
-    MethodType method_type = GetMethodType(method);
-
-    if (method_type == METHODTYPE_NO_STREAMING) {
+    if (!method->client_streaming() && !method->server_streaming()) {
       // unary calls have an extra synchronous stub method
       GenerateDocCommentClientMethod(out, method, true, false);
       out->Print(
@@ -539,8 +514,8 @@
           "cancellationToken = "
           "default(global::System.Threading.CancellationToken))\n",
           "methodname", method->name(), "request",
-          GetClassName(method->input_type()), "response",
-          GetClassName(method->output_type()));
+          GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()), "response",
+          GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()));
       out->Print("{\n");
       out->Indent();
       out->Print(
@@ -557,8 +532,8 @@
           "public virtual $response$ $methodname$($request$ request, "
           "grpc::CallOptions options)\n",
           "methodname", method->name(), "request",
-          GetClassName(method->input_type()), "response",
-          GetClassName(method->output_type()));
+          GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()), "response",
+          GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()));
       out->Print("{\n");
       out->Indent();
       out->Print(
@@ -570,7 +545,7 @@
     }
 
     std::string method_name = method->name();
-    if (method_type == METHODTYPE_NO_STREAMING) {
+    if (!method->client_streaming() && !method->server_streaming()) {
       method_name += "Async";  // prevent name clash with synchronous method.
     }
     GenerateDocCommentClientMethod(out, method, false, false);
@@ -607,33 +582,30 @@
         GetMethodReturnTypeClient(method));
     out->Print("{\n");
     out->Indent();
-    switch (GetMethodType(method)) {
-      case METHODTYPE_NO_STREAMING:
-        out->Print(
-            "return CallInvoker.AsyncUnaryCall($methodfield$, null, options, "
-            "request);\n",
-            "methodfield", GetMethodFieldName(method));
-        break;
-      case METHODTYPE_CLIENT_STREAMING:
-        out->Print(
-            "return CallInvoker.AsyncClientStreamingCall($methodfield$, null, "
-            "options);\n",
-            "methodfield", GetMethodFieldName(method));
-        break;
-      case METHODTYPE_SERVER_STREAMING:
-        out->Print(
-            "return CallInvoker.AsyncServerStreamingCall($methodfield$, null, "
-            "options, request);\n",
-            "methodfield", GetMethodFieldName(method));
-        break;
-      case METHODTYPE_BIDI_STREAMING:
-        out->Print(
-            "return CallInvoker.AsyncDuplexStreamingCall($methodfield$, null, "
-            "options);\n",
-            "methodfield", GetMethodFieldName(method));
-        break;
-      default:
-        GOOGLE_LOG(FATAL) << "Can't get here.";
+    if (!method->client_streaming() && !method->server_streaming()) {
+      // Non-Streaming
+      out->Print(
+          "return CallInvoker.AsyncUnaryCall($methodfield$, null, options, "
+          "request);\n",
+          "methodfield", GetMethodFieldName(method));
+    } else if (method->client_streaming() && !method->server_streaming()) {
+      // Client Streaming Only
+      out->Print(
+          "return CallInvoker.AsyncClientStreamingCall($methodfield$, null, "
+          "options);\n",
+          "methodfield", GetMethodFieldName(method));
+    } else if (!method->client_streaming() && method->server_streaming()) {
+      // Server Streaming Only
+      out->Print(
+          "return CallInvoker.AsyncServerStreamingCall($methodfield$, null, "
+          "options, request);\n",
+          "methodfield", GetMethodFieldName(method));
+    } else {
+      // Bi-Directional Streaming
+      out->Print(
+          "return CallInvoker.AsyncDuplexStreamingCall($methodfield$, null, "
+          "options);\n",
+          "methodfield", GetMethodFieldName(method));
     }
     out->Outdent();
     out->Print("}\n");
@@ -722,9 +694,10 @@
         "new $servermethodtype$<$inputtype$, $outputtype$>("
         "serviceImpl.$methodname$));\n",
         "methodfield", GetMethodFieldName(method), "servermethodtype",
-        GetCSharpServerMethodType(GetMethodType(method)), "inputtype",
-        GetClassName(method->input_type()), "outputtype",
-        GetClassName(method->output_type()), "methodname", method->name());
+        GetCSharpServerMethodType(method), "inputtype",
+        GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->input_type()), "outputtype",
+        GRPC_CUSTOM_CSHARP_GETCLASSNAME(method->output_type()), "methodname",
+        method->name());
   }
 
   out->Outdent();
@@ -805,7 +778,7 @@
     out.Print("using grpc = global::Grpc.Core;\n");
     out.Print("\n");
 
-    std::string file_namespace = GetFileNamespace(file);
+    std::string file_namespace = GRPC_CUSTOM_CSHARP_GETFILENAMESPACE(file);
     if (file_namespace != "") {
       out.Print("namespace $namespace$ {\n", "namespace", file_namespace);
       out.Indent();
diff --git a/grpc/src/compiler/csharp_generator.h b/grpc/src/compiler/csharp_generator.h
index 1596840..494c479 100644
--- a/grpc/src/compiler/csharp_generator.h
+++ b/grpc/src/compiler/csharp_generator.h
@@ -21,8 +21,6 @@
 
 #include "src/compiler/config.h"
 
-#include <google/protobuf/compiler/csharp/csharp_names.h>
-
 namespace grpc_csharp_generator {
 
 std::string GetServices(const grpc::protobuf::FileDescriptor* file,
diff --git a/grpc/src/compiler/php_generator.cc b/grpc/src/compiler/php_generator.cc
index b2a26e5..28bbebd 100644
--- a/grpc/src/compiler/php_generator.cc
+++ b/grpc/src/compiler/php_generator.cc
@@ -131,34 +131,177 @@
   out->Print("}\n\n");
 }
 
+void PrintServerMethod(const MethodDescriptor* method, Printer* out) {
+  map<std::string, std::string> vars;
+  const Descriptor* input_type = method->input_type();
+  const Descriptor* output_type = method->output_type();
+  vars["service_name"] = method->service()->full_name();
+  vars["method_name"] = method->name();
+  vars["input_type_id"] =
+      MessageIdentifierName(GeneratedClassName(input_type), input_type->file());
+  vars["output_type_id"] = MessageIdentifierName(
+      GeneratedClassName(output_type), output_type->file());
+
+  out->Print("/**\n");
+  out->Print(GetPHPComments(method, " *").c_str());
+
+  const char* method_template;
+  if (method->client_streaming() && method->server_streaming()) {
+    method_template =
+        " * @param \\Grpc\\ServerCallReader $$reader read client request data "
+        "of \\$input_type_id$\n"
+        " * @param \\Grpc\\ServerCallWriter $$writer write response data of "
+        "\\$output_type_id$\n"
+        " * @param \\Grpc\\ServerContext $$context server request context\n"
+        " * @return void\n"
+        " */\n"
+        "public function $method_name$(\n"
+        "    \\Grpc\\ServerCallReader $$reader,\n"
+        "    \\Grpc\\ServerCallWriter $$writer,\n"
+        "    \\Grpc\\ServerContext $$context\n"
+        "): void {\n"
+        "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
+        "    $$writer->finish();\n"
+        "}\n\n";
+  } else if (method->client_streaming()) {
+    method_template =
+        " * @param \\Grpc\\ServerCallReader $$reader read client request data "
+        "of \\$input_type_id$\n"
+        " * @param \\Grpc\\ServerContext $$context server request context\n"
+        " * @return \\$output_type_id$ for response data, null if if error "
+        "occured\n"
+        " *     initial metadata (if any) and status (if not ok) should be set "
+        "to $$context\n"
+        " */\n"
+        "public function $method_name$(\n"
+        "    \\Grpc\\ServerCallReader $$reader,\n"
+        "    \\Grpc\\ServerContext $$context\n"
+        "): ?\\$output_type_id$ {\n"
+        "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
+        "    return null;\n"
+        "}\n\n";
+  } else if (method->server_streaming()) {
+    method_template =
+        " * @param \\$input_type_id$ $$request client request\n"
+        " * @param \\Grpc\\ServerCallWriter $$writer write response data of "
+        "\\$output_type_id$\n"
+        " * @param \\Grpc\\ServerContext $$context server request context\n"
+        " * @return void\n"
+        " */\n"
+        "public function $method_name$(\n"
+        "    \\$input_type_id$ $$request,\n"
+        "    \\Grpc\\ServerCallWriter $$writer,\n"
+        "    \\Grpc\\ServerContext $$context\n"
+        "): void {\n"
+        "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
+        "    $$writer->finish();\n"
+        "}\n\n";
+  } else {
+    method_template =
+        " * @param \\$input_type_id$ $$request client request\n"
+        " * @param \\Grpc\\ServerContext $$context server request context\n"
+        " * @return \\$output_type_id$ for response data, null if if error "
+        "occured\n"
+        " *     initial metadata (if any) and status (if not ok) should be set "
+        "to $$context\n"
+        " */\n"
+        "public function $method_name$(\n"
+        "    \\$input_type_id$ $$request,\n"
+        "    \\Grpc\\ServerContext $$context\n"
+        "): ?\\$output_type_id$ {\n"
+        "    $$context->setStatus(\\Grpc\\Status::unimplemented());\n"
+        "    return null;\n"
+        "}\n\n";
+  }
+  out->Print(vars, method_template);
+}
+
+void PrintServerMethodDescriptors(const ServiceDescriptor* service,
+                                  Printer* out) {
+  map<std::string, std::string> vars;
+  vars["service_name"] = service->full_name();
+
+  out->Print(
+      "/**\n"
+      " * Get the method descriptors of the service for server registration\n"
+      " *\n"
+      " * @return array of \\Grpc\\MethodDescriptor for the service methods\n"
+      " */\n"
+      "public final function getMethodDescriptors(): array\n{\n");
+  out->Indent();
+  out->Indent();
+  out->Print("return [\n");
+  out->Indent();
+  out->Indent();
+  for (int i = 0; i < service->method_count(); i++) {
+    auto method = service->method(i);
+    auto input_type = method->input_type();
+    vars["method_name"] = method->name();
+    vars["input_type_id"] = MessageIdentifierName(
+        GeneratedClassName(input_type), input_type->file());
+    if (method->client_streaming() && method->server_streaming()) {
+      vars["call_type"] = "BIDI_STREAMING_CALL";
+    } else if (method->client_streaming()) {
+      vars["call_type"] = "CLIENT_STREAMING_CALL";
+    } else if (method->server_streaming()) {
+      vars["call_type"] = "SERVER_STREAMING_CALL";
+    } else {
+      vars["call_type"] = "UNARY_CALL";
+    }
+    out->Print(
+        vars,
+        "'/$service_name$/$method_name$' => new \\Grpc\\MethodDescriptor(\n"
+        "    $$this,\n"
+        "    '$method_name$',\n"
+        "    '\\$input_type_id$',\n"
+        "    \\Grpc\\MethodDescriptor::$call_type$\n"
+        "),\n");
+  }
+  out->Outdent();
+  out->Outdent();
+  out->Print("];\n");
+  out->Outdent();
+  out->Outdent();
+  out->Print("}\n\n");
+}
+
 // Prints out the service descriptor object
 void PrintService(const ServiceDescriptor* service,
-                  const std::string& class_suffix, Printer* out) {
+                  const std::string& class_suffix, bool is_server,
+                  Printer* out) {
   map<std::string, std::string> vars;
   out->Print("/**\n");
   out->Print(GetPHPComments(service, " *").c_str());
   out->Print(" */\n");
-  vars["name"] = GetPHPServiceClassname(service, class_suffix);
-  out->Print(vars, "class $name$ extends \\Grpc\\BaseStub {\n\n");
+  vars["name"] = GetPHPServiceClassname(service, class_suffix, is_server);
+  vars["extends"] = is_server ? "" : "extends \\Grpc\\BaseStub ";
+  out->Print(vars, "class $name$ $extends${\n\n");
   out->Indent();
   out->Indent();
-  out->Print(
-      "/**\n * @param string $$hostname hostname\n"
-      " * @param array $$opts channel options\n"
-      " * @param \\Grpc\\Channel $$channel (optional) re-use channel "
-      "object\n */\n"
-      "public function __construct($$hostname, $$opts, "
-      "$$channel = null) {\n");
-  out->Indent();
-  out->Indent();
-  out->Print("parent::__construct($$hostname, $$opts, $$channel);\n");
-  out->Outdent();
-  out->Outdent();
-  out->Print("}\n\n");
+  if (!is_server) {
+    out->Print(
+        "/**\n * @param string $$hostname hostname\n"
+        " * @param array $$opts channel options\n"
+        " * @param \\Grpc\\Channel $$channel (optional) re-use channel object\n"
+        " */\n"
+        "public function __construct($$hostname, $$opts, "
+        "$$channel = null) {\n");
+    out->Indent();
+    out->Indent();
+    out->Print("parent::__construct($$hostname, $$opts, $$channel);\n");
+    out->Outdent();
+    out->Outdent();
+    out->Print("}\n\n");
+  }
   for (int i = 0; i < service->method_count(); i++) {
-    std::string method_name =
-        grpc_generator::LowercaseFirstLetter(service->method(i)->name());
-    PrintMethod(service->method(i), out);
+    if (is_server) {
+      PrintServerMethod(service->method(i), out);
+    } else {
+      PrintMethod(service->method(i), out);
+    }
+  }
+  if (is_server) {
+    PrintServerMethodDescriptors(service, out);
   }
   out->Outdent();
   out->Outdent();
@@ -168,7 +311,7 @@
 
 std::string GenerateFile(const FileDescriptor* file,
                          const ServiceDescriptor* service,
-                         const std::string& class_suffix) {
+                         const std::string& class_suffix, bool is_server) {
   std::string output;
   {
     StringOutputStream output_stream(&output);
@@ -188,7 +331,7 @@
     vars["package"] = php_namespace;
     out.Print(vars, "namespace $package$;\n\n");
 
-    PrintService(service, class_suffix, &out);
+    PrintService(service, class_suffix, is_server, &out);
   }
   return output;
 }
diff --git a/grpc/src/compiler/php_generator.h b/grpc/src/compiler/php_generator.h
index aa6d20c..f775c8f 100644
--- a/grpc/src/compiler/php_generator.h
+++ b/grpc/src/compiler/php_generator.h
@@ -25,7 +25,8 @@
 
 std::string GenerateFile(const grpc::protobuf::FileDescriptor* file,
                          const grpc::protobuf::ServiceDescriptor* service,
-                         const std::string& class_suffix);
+                         const std::string& class_suffix,
+                         bool is_server = false);
 
 }  // namespace grpc_php_generator
 
diff --git a/grpc/src/compiler/php_generator_helpers.h b/grpc/src/compiler/php_generator_helpers.h
index 24560e4..a4617df 100644
--- a/grpc/src/compiler/php_generator_helpers.h
+++ b/grpc/src/compiler/php_generator_helpers.h
@@ -28,8 +28,10 @@
 
 inline std::string GetPHPServiceClassname(
     const grpc::protobuf::ServiceDescriptor* service,
-    const std::string& class_suffix) {
-  return service->name() + (class_suffix == "" ? "Client" : class_suffix);
+    const std::string& class_suffix, bool is_server) {
+  return service->name() +
+         (class_suffix == "" ? (is_server ? "" : "Client") : class_suffix) +
+         (is_server ? "Stub" : "");
 }
 
 // ReplaceAll replaces all instances of search with replace in s.
@@ -46,7 +48,7 @@
 inline std::string GetPHPServiceFilename(
     const grpc::protobuf::FileDescriptor* file,
     const grpc::protobuf::ServiceDescriptor* service,
-    const std::string& class_suffix) {
+    const std::string& class_suffix, bool is_server) {
   std::ostringstream oss;
   if (file->options().has_php_namespace()) {
     oss << ReplaceAll(file->options().php_namespace(), "\\", "/");
@@ -58,8 +60,8 @@
           << grpc_generator::CapitalizeFirstLetter(tokens[i]);
     }
   }
-  return oss.str() + "/" + GetPHPServiceClassname(service, class_suffix) +
-         ".php";
+  return oss.str() + "/" +
+         GetPHPServiceClassname(service, class_suffix, is_server) + ".php";
 }
 
 // Get leading or trailing comments in a string. Comment lines start with "// ".
diff --git a/grpc/src/compiler/php_plugin.cc b/grpc/src/compiler/php_plugin.cc
index c1be387..7d4e4ce 100644
--- a/grpc/src/compiler/php_plugin.cc
+++ b/grpc/src/compiler/php_plugin.cc
@@ -48,10 +48,13 @@
     std::vector<std::pair<std::string, std::string> > options;
     ParseGeneratorParameter(parameter, &options);
 
+    bool generate_server = false;
     std::string class_suffix;
     for (size_t i = 0; i < options.size(); ++i) {
       if (options[i].first == "class_suffix") {
         class_suffix = options[i].second;
+      } else if (options[i].first == "generate_server") {
+        generate_server = true;
       } else {
         *error = "unsupported options: " + options[i].first;
         return false;
@@ -59,20 +62,32 @@
     }
 
     for (int i = 0; i < file->service_count(); i++) {
-      std::string code = GenerateFile(file, file->service(i), class_suffix);
-
-      // Get output file name
-      std::string file_name =
-          GetPHPServiceFilename(file, file->service(i), class_suffix);
-
-      std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
-          context->Open(file_name));
-      grpc::protobuf::io::CodedOutputStream coded_out(output.get());
-      coded_out.WriteRaw(code.data(), code.size());
+      GenerateService(file, file->service(i), class_suffix, false, context);
+      if (generate_server) {
+        GenerateService(file, file->service(i), class_suffix, true, context);
+      }
     }
 
     return true;
   }
+
+ private:
+  void GenerateService(
+      const grpc::protobuf::FileDescriptor* file,
+      const grpc::protobuf::ServiceDescriptor* service,
+      const std::string& class_suffix, bool is_server,
+      grpc::protobuf::compiler::GeneratorContext* context) const {
+    std::string code = GenerateFile(file, service, class_suffix, is_server);
+
+    // Get output file name
+    std::string file_name =
+        GetPHPServiceFilename(file, service, class_suffix, is_server);
+
+    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
+        context->Open(file_name));
+    grpc::protobuf::io::CodedOutputStream coded_out(output.get());
+    coded_out.WriteRaw(code.data(), code.size());
+  }
 };
 
 int main(int argc, char* argv[]) {
diff --git a/grpc/src/compiler/ruby_generator.cc b/grpc/src/compiler/ruby_generator.cc
index 2b86b70..2fae610 100644
--- a/grpc/src/compiler/ruby_generator.cc
+++ b/grpc/src/compiler/ruby_generator.cc
@@ -80,7 +80,7 @@
   // Write the indented class body.
   out->Indent();
   out->Print("\n");
-  out->Print("include GRPC::GenericService\n");
+  out->Print("include ::GRPC::GenericService\n");
   out->Print("\n");
   out->Print("self.marshal_class_method = :encode\n");
   out->Print("self.unmarshal_class_method = :decode\n");
diff --git a/grpc/src/core/ext/filters/client_channel/backup_poller.cc b/grpc/src/core/ext/filters/client_channel/backup_poller.cc
index 1b77089..ad7f892 100644
--- a/grpc/src/core/ext/filters/client_channel/backup_poller.cc
+++ b/grpc/src/core/ext/filters/client_channel/backup_poller.cc
@@ -89,7 +89,7 @@
   }
 }
 
-static void done_poller(void* arg, grpc_error* /*error*/) {
+static void done_poller(void* arg, grpc_error_handle /*error*/) {
   backup_poller_shutdown_unref(static_cast<backup_poller*>(arg));
 }
 
@@ -112,7 +112,7 @@
   }
 }
 
-static void run_poller(void* arg, grpc_error* error) {
+static void run_poller(void* arg, grpc_error_handle error) {
   backup_poller* p = static_cast<backup_poller*>(arg);
   if (error != GRPC_ERROR_NONE) {
     if (error != GRPC_ERROR_CANCELLED) {
@@ -127,7 +127,7 @@
     backup_poller_shutdown_unref(p);
     return;
   }
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_pollset_work(p->pollset, nullptr, grpc_core::ExecCtx::Get()->Now());
   gpr_mu_unlock(p->pollset_mu);
   GRPC_LOG_IF_ERROR("Run client channel backup poller", err);
diff --git a/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc b/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc
index 4ebb976..e5ec5c5 100644
--- a/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc
+++ b/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc
@@ -1,28 +1,23 @@
-/*
- *
- * Copyright 2015 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.
- *
- */
+//
+// Copyright 2015 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>
 
 #include "src/core/lib/surface/channel.h"
 
-#include <inttypes.h>
-
-#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
@@ -32,195 +27,205 @@
 
 grpc_connectivity_state grpc_channel_check_connectivity_state(
     grpc_channel* channel, int try_to_connect) {
-  /* forward through to the underlying client channel */
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  grpc_connectivity_state state;
   GRPC_API_TRACE(
       "grpc_channel_check_connectivity_state(channel=%p, try_to_connect=%d)", 2,
       (channel, try_to_connect));
-  if (GPR_LIKELY(client_channel_elem->filter == &grpc_client_channel_filter)) {
-    state = grpc_client_channel_check_connectivity_state(client_channel_elem,
-                                                         try_to_connect);
-
-    return state;
+  // Forward through to the underlying client channel.
+  grpc_core::ClientChannel* client_channel =
+      grpc_core::ClientChannel::GetFromChannel(channel);
+  if (GPR_UNLIKELY(client_channel == nullptr)) {
+    gpr_log(GPR_ERROR,
+            "grpc_channel_check_connectivity_state called on something that is "
+            "not a client channel");
+    return GRPC_CHANNEL_SHUTDOWN;
   }
-  gpr_log(GPR_ERROR,
-          "grpc_channel_check_connectivity_state called on something that is "
-          "not a client channel, but '%s'",
-          client_channel_elem->filter->name);
-
-  return GRPC_CHANNEL_SHUTDOWN;
-}
-
-typedef enum {
-  WAITING,
-  READY_TO_CALL_BACK,
-  CALLING_BACK_AND_FINISHED,
-} callback_phase;
-
-namespace {
-struct state_watcher {
-  gpr_mu mu;
-  callback_phase phase;
-  grpc_closure on_complete;
-  grpc_closure on_timeout;
-  grpc_closure watcher_timer_init;
-  grpc_timer alarm;
-  grpc_connectivity_state state;
-  grpc_completion_queue* cq;
-  grpc_cq_completion completion_storage;
-  grpc_channel* channel;
-  grpc_error* error;
-  void* tag;
-};
-}  // namespace
-
-static void delete_state_watcher(state_watcher* w) {
-  grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-      grpc_channel_get_channel_stack(w->channel));
-  if (client_channel_elem->filter == &grpc_client_channel_filter) {
-    GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_channel_connectivity");
-  } else {
-    abort();
-  }
-  gpr_mu_destroy(&w->mu);
-  gpr_free(w);
-}
-
-static void finished_completion(void* pw, grpc_cq_completion* /*ignored*/) {
-  bool should_delete = false;
-  state_watcher* w = static_cast<state_watcher*>(pw);
-  gpr_mu_lock(&w->mu);
-  switch (w->phase) {
-    case WAITING:
-    case READY_TO_CALL_BACK:
-      GPR_UNREACHABLE_CODE(return );
-    case CALLING_BACK_AND_FINISHED:
-      should_delete = true;
-      break;
-  }
-  gpr_mu_unlock(&w->mu);
-
-  if (should_delete) {
-    delete_state_watcher(w);
-  }
-}
-
-static void partly_done(state_watcher* w, bool due_to_completion,
-                        grpc_error* error) {
-  bool end_op = false;
-  void* end_op_tag = nullptr;
-  grpc_error* end_op_error = nullptr;
-  grpc_completion_queue* end_op_cq = nullptr;
-  grpc_cq_completion* end_op_completion_storage = nullptr;
-
-  if (due_to_completion) {
-    grpc_timer_cancel(&w->alarm);
-  } else {
-    grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-        grpc_channel_get_channel_stack(w->channel));
-    grpc_client_channel_watch_connectivity_state(
-        client_channel_elem,
-        grpc_polling_entity_create_from_pollset(grpc_cq_pollset(w->cq)),
-        nullptr, &w->on_complete, nullptr);
-  }
-
-  gpr_mu_lock(&w->mu);
-
-  if (due_to_completion) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures)) {
-      GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error));
-    }
-    GRPC_ERROR_UNREF(error);
-    error = GRPC_ERROR_NONE;
-  } else {
-    if (error == GRPC_ERROR_NONE) {
-      error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "Timed out waiting for connection state change");
-    } else if (error == GRPC_ERROR_CANCELLED) {
-      error = GRPC_ERROR_NONE;
-    }
-  }
-  switch (w->phase) {
-    case WAITING:
-      GRPC_ERROR_REF(error);
-      w->error = error;
-      w->phase = READY_TO_CALL_BACK;
-      break;
-    case READY_TO_CALL_BACK:
-      if (error != GRPC_ERROR_NONE) {
-        GPR_ASSERT(!due_to_completion);
-        GRPC_ERROR_UNREF(w->error);
-        GRPC_ERROR_REF(error);
-        w->error = error;
-      }
-      w->phase = CALLING_BACK_AND_FINISHED;
-      end_op = true;
-      end_op_cq = w->cq;
-      end_op_tag = w->tag;
-      end_op_error = w->error;
-      end_op_completion_storage = &w->completion_storage;
-      break;
-    case CALLING_BACK_AND_FINISHED:
-      GPR_UNREACHABLE_CODE(return );
-      break;
-  }
-  gpr_mu_unlock(&w->mu);
-
-  if (end_op) {
-    grpc_cq_end_op(end_op_cq, end_op_tag, end_op_error, finished_completion, w,
-                   end_op_completion_storage);
-  }
-
-  GRPC_ERROR_UNREF(error);
-}
-
-static void watch_complete(void* pw, grpc_error* error) {
-  partly_done(static_cast<state_watcher*>(pw), true, GRPC_ERROR_REF(error));
-}
-
-static void timeout_complete(void* pw, grpc_error* error) {
-  partly_done(static_cast<state_watcher*>(pw), false, GRPC_ERROR_REF(error));
+  return client_channel->CheckConnectivityState(try_to_connect);
 }
 
 int grpc_channel_num_external_connectivity_watchers(grpc_channel* channel) {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
-  return grpc_client_channel_num_external_connectivity_watchers(
-      client_channel_elem);
-}
-
-typedef struct watcher_timer_init_arg {
-  state_watcher* w;
-  gpr_timespec deadline;
-} watcher_timer_init_arg;
-
-static void watcher_timer_init(void* arg, grpc_error* /*error_ignored*/) {
-  watcher_timer_init_arg* wa = static_cast<watcher_timer_init_arg*>(arg);
-
-  grpc_timer_init(&wa->w->alarm, grpc_timespec_to_millis_round_up(wa->deadline),
-                  &wa->w->on_timeout);
-  gpr_free(wa);
+  grpc_core::ClientChannel* client_channel =
+      grpc_core::ClientChannel::GetFromChannel(channel);
+  if (client_channel == nullptr) {
+    gpr_log(GPR_ERROR,
+            "grpc_channel_num_external_connectivity_watchers called on "
+            "something that is not a client channel");
+    return 0;
+  }
+  return client_channel->NumExternalConnectivityWatchers();
 }
 
 int grpc_channel_support_connectivity_watcher(grpc_channel* channel) {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
-  return client_channel_elem->filter != &grpc_client_channel_filter ? 0 : 1;
+  return grpc_core::ClientChannel::GetFromChannel(channel) != nullptr;
 }
 
+namespace grpc_core {
+namespace {
+
+class StateWatcher {
+ public:
+  StateWatcher(grpc_channel* channel, grpc_completion_queue* cq, void* tag,
+               grpc_connectivity_state last_observed_state,
+               gpr_timespec deadline)
+      : channel_(channel), cq_(cq), tag_(tag), state_(last_observed_state) {
+    GPR_ASSERT(grpc_cq_begin_op(cq, tag));
+    GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
+    GRPC_CLOSURE_INIT(&on_complete_, WatchComplete, this, nullptr);
+    GRPC_CLOSURE_INIT(&on_timeout_, TimeoutComplete, this, nullptr);
+    auto* watcher_timer_init_state = new WatcherTimerInitState(
+        this, grpc_timespec_to_millis_round_up(deadline));
+    ClientChannel* client_channel = ClientChannel::GetFromChannel(channel);
+    GPR_ASSERT(client_channel != nullptr);
+    client_channel->AddExternalConnectivityWatcher(
+        grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &state_,
+        &on_complete_, watcher_timer_init_state->closure());
+  }
+
+  ~StateWatcher() {
+    GRPC_CHANNEL_INTERNAL_UNREF(channel_, "watch_channel_connectivity");
+  }
+
+ private:
+  // A fire-and-forget object used to delay starting the timer until the
+  // ClientChannel actually starts the watch.
+  class WatcherTimerInitState {
+   public:
+    WatcherTimerInitState(StateWatcher* state_watcher, grpc_millis deadline)
+        : state_watcher_(state_watcher), deadline_(deadline) {
+      GRPC_CLOSURE_INIT(&closure_, WatcherTimerInit, this, nullptr);
+    }
+
+    grpc_closure* closure() { return &closure_; }
+
+   private:
+    static void WatcherTimerInit(void* arg, grpc_error_handle /*error*/) {
+      auto* self = static_cast<WatcherTimerInitState*>(arg);
+      grpc_timer_init(&self->state_watcher_->timer_, self->deadline_,
+                      &self->state_watcher_->on_timeout_);
+      delete self;
+    }
+
+    StateWatcher* state_watcher_;
+    grpc_millis deadline_;
+    grpc_closure closure_;
+  };
+
+  enum CallbackPhase { kWaiting, kReadyToCallBack, kCallingBackAndFinished };
+
+  // Called when the completion is returned to the CQ.
+  static void FinishedCompletion(void* arg, grpc_cq_completion* /*ignored*/) {
+    auto* self = static_cast<StateWatcher*>(arg);
+    bool should_delete = false;
+    {
+      MutexLock lock(&self->mu_);
+      switch (self->phase_) {
+        case kWaiting:
+        case kReadyToCallBack:
+          GPR_UNREACHABLE_CODE(return );
+        case kCallingBackAndFinished:
+          should_delete = true;
+      }
+    }
+    if (should_delete) delete self;
+  }
+
+  void PartlyDone(bool due_to_completion, grpc_error_handle error) {
+    bool end_op = false;
+    void* end_op_tag = nullptr;
+    grpc_error_handle end_op_error = GRPC_ERROR_NONE;
+    grpc_completion_queue* end_op_cq = nullptr;
+    grpc_cq_completion* end_op_completion_storage = nullptr;
+    if (due_to_completion) {
+      grpc_timer_cancel(&timer_);
+    } else {
+      grpc_core::ClientChannel* client_channel =
+          grpc_core::ClientChannel::GetFromChannel(channel_);
+      GPR_ASSERT(client_channel != nullptr);
+      client_channel->CancelExternalConnectivityWatcher(&on_complete_);
+    }
+    {
+      MutexLock lock(&mu_);
+      if (due_to_completion) {
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures)) {
+          GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error));
+        }
+        GRPC_ERROR_UNREF(error);
+        error = GRPC_ERROR_NONE;
+      } else {
+        if (error == GRPC_ERROR_NONE) {
+          error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+              "Timed out waiting for connection state change");
+        } else if (error == GRPC_ERROR_CANCELLED) {
+          error = GRPC_ERROR_NONE;
+        }
+      }
+      switch (phase_) {
+        case kWaiting:
+          GRPC_ERROR_REF(error);
+          error_ = error;
+          phase_ = kReadyToCallBack;
+          break;
+        case kReadyToCallBack:
+          if (error != GRPC_ERROR_NONE) {
+            GPR_ASSERT(!due_to_completion);
+            GRPC_ERROR_UNREF(error_);
+            GRPC_ERROR_REF(error);
+            error_ = error;
+          }
+          phase_ = kCallingBackAndFinished;
+          end_op = true;
+          end_op_cq = cq_;
+          end_op_tag = tag_;
+          end_op_error = error_;
+          end_op_completion_storage = &completion_storage_;
+          break;
+        case kCallingBackAndFinished:
+          GPR_UNREACHABLE_CODE(return );
+      }
+    }
+    if (end_op) {
+      grpc_cq_end_op(end_op_cq, end_op_tag, end_op_error, FinishedCompletion,
+                     this, end_op_completion_storage);
+    }
+    GRPC_ERROR_UNREF(error);
+  }
+
+  static void WatchComplete(void* arg, grpc_error_handle error) {
+    auto* self = static_cast<StateWatcher*>(arg);
+    self->PartlyDone(/*due_to_completion=*/true, GRPC_ERROR_REF(error));
+  }
+
+  static void TimeoutComplete(void* arg, grpc_error_handle error) {
+    auto* self = static_cast<StateWatcher*>(arg);
+    self->PartlyDone(/*due_to_completion=*/false, GRPC_ERROR_REF(error));
+  }
+
+  grpc_channel* channel_;
+  grpc_completion_queue* cq_;
+  void* tag_;
+
+  grpc_connectivity_state state_;
+
+  grpc_cq_completion completion_storage_;
+
+  grpc_closure on_complete_;
+  grpc_timer timer_;
+  grpc_closure on_timeout_;
+
+  Mutex mu_;
+  CallbackPhase phase_ ABSL_GUARDED_BY(mu_) = kWaiting;
+  grpc_error_handle error_ ABSL_GUARDED_BY(mu_) = GRPC_ERROR_NONE;
+};
+
+}  // namespace
+}  // namespace grpc_core
+
 void grpc_channel_watch_connectivity_state(
     grpc_channel* channel, grpc_connectivity_state last_observed_state,
     gpr_timespec deadline, grpc_completion_queue* cq, void* tag) {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  state_watcher* w = static_cast<state_watcher*>(gpr_malloc(sizeof(*w)));
-
   GRPC_API_TRACE(
       "grpc_channel_watch_connectivity_state("
       "channel=%p, last_observed_state=%d, "
@@ -230,35 +235,5 @@
       7,
       (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec,
        (int)deadline.clock_type, cq, tag));
-
-  GPR_ASSERT(grpc_cq_begin_op(cq, tag));
-
-  gpr_mu_init(&w->mu);
-  GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w,
-                    grpc_schedule_on_exec_ctx);
-  GRPC_CLOSURE_INIT(&w->on_timeout, timeout_complete, w,
-                    grpc_schedule_on_exec_ctx);
-  w->phase = WAITING;
-  w->state = last_observed_state;
-  w->cq = cq;
-  w->tag = tag;
-  w->channel = channel;
-  w->error = nullptr;
-
-  watcher_timer_init_arg* wa = static_cast<watcher_timer_init_arg*>(
-      gpr_malloc(sizeof(watcher_timer_init_arg)));
-  wa->w = w;
-  wa->deadline = deadline;
-  GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa,
-                    grpc_schedule_on_exec_ctx);
-
-  if (client_channel_elem->filter == &grpc_client_channel_filter) {
-    GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
-    grpc_client_channel_watch_connectivity_state(
-        client_channel_elem,
-        grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &w->state,
-        &w->on_complete, &w->watcher_timer_init);
-  } else {
-    abort();
-  }
+  new grpc_core::StateWatcher(channel, cq, tag, last_observed_state, deadline);
 }
diff --git a/grpc/src/core/ext/filters/client_channel/client_channel.cc b/grpc/src/core/ext/filters/client_channel/client_channel.cc
index 048cd20..3bbec5e 100644
--- a/grpc/src/core/ext/filters/client_channel/client_channel.cc
+++ b/grpc/src/core/ext/filters/client_channel/client_channel.cc
@@ -51,7 +51,7 @@
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
-#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/retry_filter.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
 #include "src/core/ext/filters/client_channel/service_config_call_data.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
@@ -61,7 +61,6 @@
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/polling_entity.h"
@@ -81,335 +80,23 @@
 // Client channel filter
 //
 
-// By default, we buffer 256 KiB per RPC for retries.
-// TODO(roth): Do we have any data to suggest a better value?
-#define DEFAULT_PER_RPC_RETRY_BUFFER_SIZE (256 << 10)
-
-// This value was picked arbitrarily.  It can be changed if there is
-// any even moderately compelling reason to do so.
-#define RETRY_BACKOFF_JITTER 0.2
-
-// Max number of batches that can be pending on a call at any given
-// time.  This includes one batch for each of the following ops:
-//   recv_initial_metadata
-//   send_initial_metadata
-//   recv_message
-//   send_message
-//   recv_trailing_metadata
-//   send_trailing_metadata
-#define MAX_PENDING_BATCHES 6
-
-// Channel arg containing a pointer to the ChannelData object.
-#define GRPC_ARG_CLIENT_CHANNEL_DATA "grpc.internal.client_channel_data"
-
-// Channel arg containing a pointer to the RetryThrottleData object.
-#define GRPC_ARG_RETRY_THROTTLE_DATA "grpc.internal.retry_throttle_data"
-
 namespace grpc_core {
 
 using internal::ClientChannelGlobalParsedConfig;
 using internal::ClientChannelMethodParsedConfig;
 using internal::ClientChannelServiceConfigParser;
-using internal::ServerRetryThrottleData;
 
 TraceFlag grpc_client_channel_call_trace(false, "client_channel_call");
 TraceFlag grpc_client_channel_routing_trace(false, "client_channel_routing");
 
-namespace {
-
 //
-// ChannelData definition
+// ClientChannel::CallData definition
 //
 
-class LoadBalancedCall;
-
-class ChannelData {
+class ClientChannel::CallData {
  public:
-  struct ResolverQueuedCall {
-    grpc_call_element* elem;
-    ResolverQueuedCall* next = nullptr;
-  };
-  struct LbQueuedCall {
-    LoadBalancedCall* lb_call;
-    LbQueuedCall* next = nullptr;
-  };
-
-  static grpc_error* Init(grpc_channel_element* elem,
-                          grpc_channel_element_args* args);
-  static void Destroy(grpc_channel_element* elem);
-  static void StartTransportOp(grpc_channel_element* elem,
-                               grpc_transport_op* op);
-  static void GetChannelInfo(grpc_channel_element* elem,
-                             const grpc_channel_info* info);
-
-  bool deadline_checking_enabled() const { return deadline_checking_enabled_; }
-  bool enable_retries() const { return enable_retries_; }
-  size_t per_rpc_retry_buffer_size() const {
-    return per_rpc_retry_buffer_size_;
-  }
-  grpc_channel_stack* owning_stack() const { return owning_stack_; }
-
-  // Note: Does NOT return a new ref.
-  grpc_error* disconnect_error() const {
-    return disconnect_error_.Load(MemoryOrder::ACQUIRE);
-  }
-
-  Mutex* resolution_mu() const { return &resolution_mu_; }
-  // These methods all require holding resolution_mu_.
-  void AddResolverQueuedCall(ResolverQueuedCall* call,
-                             grpc_polling_entity* pollent);
-  void RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
-                                grpc_polling_entity* pollent);
-  bool received_service_config_data() const {
-    return received_service_config_data_;
-  }
-  grpc_error* resolver_transient_failure_error() const {
-    return resolver_transient_failure_error_;
-  }
-  RefCountedPtr<ServiceConfig> service_config() const {
-    return service_config_;
-  }
-  ConfigSelector* config_selector() const { return config_selector_.get(); }
-  RefCountedPtr<DynamicFilters> dynamic_filters() const {
-    return dynamic_filters_;
-  }
-
-  Mutex* data_plane_mu() const { return &data_plane_mu_; }
-  // These methods all require holding data_plane_mu_.
-  LoadBalancingPolicy::SubchannelPicker* picker() const {
-    return picker_.get();
-  }
-  void AddLbQueuedCall(LbQueuedCall* call, grpc_polling_entity* pollent);
-  void RemoveLbQueuedCall(LbQueuedCall* to_remove,
-                          grpc_polling_entity* pollent);
-  RefCountedPtr<ConnectedSubchannel> GetConnectedSubchannelInDataPlane(
-      SubchannelInterface* subchannel) const;
-
-  WorkSerializer* work_serializer() const { return work_serializer_.get(); }
-
-  grpc_connectivity_state CheckConnectivityState(bool try_to_connect);
-
-  void AddExternalConnectivityWatcher(grpc_polling_entity pollent,
-                                      grpc_connectivity_state* state,
-                                      grpc_closure* on_complete,
-                                      grpc_closure* watcher_timer_init) {
-    new ExternalConnectivityWatcher(this, pollent, state, on_complete,
-                                    watcher_timer_init);
-  }
-
-  void RemoveExternalConnectivityWatcher(grpc_closure* on_complete,
-                                         bool cancel) {
-    ExternalConnectivityWatcher::RemoveWatcherFromExternalWatchersMap(
-        this, on_complete, cancel);
-  }
-
-  int NumExternalConnectivityWatchers() const {
-    MutexLock lock(&external_watchers_mu_);
-    return static_cast<int>(external_watchers_.size());
-  }
-
-  void AddConnectivityWatcher(
-      grpc_connectivity_state initial_state,
-      OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher);
-  void RemoveConnectivityWatcher(
-      AsyncConnectivityStateWatcherInterface* watcher);
-
- private:
-  class SubchannelWrapper;
-  class ClientChannelControlHelper;
-  class ConnectivityWatcherAdder;
-  class ConnectivityWatcherRemover;
-
-  // Represents a pending connectivity callback from an external caller
-  // via grpc_client_channel_watch_connectivity_state().
-  class ExternalConnectivityWatcher : public ConnectivityStateWatcherInterface {
-   public:
-    ExternalConnectivityWatcher(ChannelData* chand, grpc_polling_entity pollent,
-                                grpc_connectivity_state* state,
-                                grpc_closure* on_complete,
-                                grpc_closure* watcher_timer_init);
-
-    ~ExternalConnectivityWatcher() override;
-
-    // Removes the watcher from the external_watchers_ map.
-    static void RemoveWatcherFromExternalWatchersMap(ChannelData* chand,
-                                                     grpc_closure* on_complete,
-                                                     bool cancel);
-
-    void Notify(grpc_connectivity_state state,
-                const absl::Status& /* status */) override;
-
-    void Cancel();
-
-   private:
-    // Adds the watcher to state_tracker_. Consumes the ref that is passed to it
-    // from Start().
-    void AddWatcherLocked();
-    void RemoveWatcherLocked();
-
-    ChannelData* chand_;
-    grpc_polling_entity pollent_;
-    grpc_connectivity_state initial_state_;
-    grpc_connectivity_state* state_;
-    grpc_closure* on_complete_;
-    grpc_closure* watcher_timer_init_;
-    Atomic<bool> done_{false};
-  };
-
-  class ResolverResultHandler : public Resolver::ResultHandler {
-   public:
-    explicit ResolverResultHandler(ChannelData* chand) : chand_(chand) {
-      GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ResolverResultHandler");
-    }
-
-    ~ResolverResultHandler() override {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
-        gpr_log(GPR_INFO, "chand=%p: resolver shutdown complete", chand_);
-      }
-      GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "ResolverResultHandler");
-    }
-
-    void ReturnResult(Resolver::Result result) override {
-      chand_->OnResolverResultChangedLocked(std::move(result));
-    }
-
-    void ReturnError(grpc_error* error) override {
-      chand_->OnResolverErrorLocked(error);
-    }
-
-   private:
-    ChannelData* chand_;
-  };
-
-  ChannelData(grpc_channel_element_args* args, grpc_error** error);
-  ~ChannelData();
-
-  // Note: All methods with "Locked" suffix must be invoked from within
-  // work_serializer_.
-
-  void OnResolverResultChangedLocked(Resolver::Result result);
-  void OnResolverErrorLocked(grpc_error* error);
-
-  void CreateOrUpdateLbPolicyLocked(
-      RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
-      Resolver::Result result);
-  OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
-      const grpc_channel_args& args);
-
-  void UpdateStateAndPickerLocked(
-      grpc_connectivity_state state, const absl::Status& status,
-      const char* reason,
-      std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker);
-
-  void UpdateServiceConfigInControlPlaneLocked(
-      RefCountedPtr<ServiceConfig> service_config,
-      RefCountedPtr<ConfigSelector> config_selector,
-      const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
-      const char* lb_policy_name);
-
-  void UpdateServiceConfigInDataPlaneLocked();
-
-  void CreateResolverLocked();
-  void DestroyResolverAndLbPolicyLocked();
-
-  grpc_error* DoPingLocked(grpc_transport_op* op);
-
-  void StartTransportOpLocked(grpc_transport_op* op);
-
-  void TryToConnectLocked();
-
-  //
-  // Fields set at construction and never modified.
-  //
-  const bool deadline_checking_enabled_;
-  const bool enable_retries_;
-  const size_t per_rpc_retry_buffer_size_;
-  grpc_channel_stack* owning_stack_;
-  ClientChannelFactory* client_channel_factory_;
-  const grpc_channel_args* channel_args_;
-  RefCountedPtr<ServiceConfig> default_service_config_;
-  std::string server_name_;
-  UniquePtr<char> target_uri_;
-  channelz::ChannelNode* channelz_node_;
-
-  //
-  // Fields related to name resolution.  Guarded by resolution_mu_.
-  //
-  mutable Mutex resolution_mu_;
-  // Linked list of calls queued waiting for resolver result.
-  ResolverQueuedCall* resolver_queued_calls_ = nullptr;
-  // Data from service config.
-  grpc_error* resolver_transient_failure_error_ = GRPC_ERROR_NONE;
-  bool received_service_config_data_ = false;
-  RefCountedPtr<ServiceConfig> service_config_;
-  RefCountedPtr<ConfigSelector> config_selector_;
-  RefCountedPtr<DynamicFilters> dynamic_filters_;
-
-  //
-  // Fields used in the data plane.  Guarded by data_plane_mu_.
-  //
-  mutable Mutex data_plane_mu_;
-  std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker_;
-  // Linked list of calls queued waiting for LB pick.
-  LbQueuedCall* lb_queued_calls_ = nullptr;
-
-  //
-  // Fields used in the control plane.  Guarded by work_serializer.
-  //
-  std::shared_ptr<WorkSerializer> work_serializer_;
-  grpc_pollset_set* interested_parties_;
-  ConnectivityStateTracker state_tracker_;
-  OrphanablePtr<Resolver> resolver_;
-  bool previous_resolution_contained_addresses_ = false;
-  RefCountedPtr<ServiceConfig> saved_service_config_;
-  RefCountedPtr<ConfigSelector> saved_config_selector_;
-  absl::optional<std::string> health_check_service_name_;
-  OrphanablePtr<LoadBalancingPolicy> lb_policy_;
-  RefCountedPtr<SubchannelPoolInterface> subchannel_pool_;
-  // The number of SubchannelWrapper instances referencing a given Subchannel.
-  std::map<Subchannel*, int> subchannel_refcount_map_;
-  // The set of SubchannelWrappers that currently exist.
-  // No need to hold a ref, since the map is updated in the control-plane
-  // work_serializer when the SubchannelWrappers are created and destroyed.
-  std::set<SubchannelWrapper*> subchannel_wrappers_;
-  // Pending ConnectedSubchannel updates for each SubchannelWrapper.
-  // Updates are queued here in the control plane work_serializer and then
-  // applied in the data plane mutex when the picker is updated.
-  std::map<RefCountedPtr<SubchannelWrapper>, RefCountedPtr<ConnectedSubchannel>>
-      pending_subchannel_updates_;
-  int keepalive_time_ = -1;
-
-  //
-  // Fields accessed from both data plane mutex and control plane
-  // work_serializer.
-  //
-  Atomic<grpc_error*> disconnect_error_;
-
-  //
-  // Fields guarded by a mutex, since they need to be accessed
-  // synchronously via get_channel_info().
-  //
-  gpr_mu info_mu_;
-  UniquePtr<char> info_lb_policy_name_;
-  UniquePtr<char> info_service_config_json_;
-
-  //
-  // Fields guarded by a mutex, since they need to be accessed
-  // synchronously via grpc_channel_num_external_connectivity_watchers().
-  //
-  mutable Mutex external_watchers_mu_;
-  std::map<grpc_closure*, RefCountedPtr<ExternalConnectivityWatcher>>
-      external_watchers_;
-};
-
-//
-// CallData definition
-//
-
-class CallData {
- public:
-  static grpc_error* Init(grpc_call_element* elem,
-                          const grpc_call_element_args* args);
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args);
   static void Destroy(grpc_call_element* elem,
                       const grpc_call_final_info* final_info,
                       grpc_closure* then_schedule_closure);
@@ -418,22 +105,23 @@
   static void SetPollent(grpc_call_element* elem, grpc_polling_entity* pollent);
 
   // Invoked by channel for queued calls when name resolution is completed.
-  static void CheckResolution(void* arg, grpc_error* error);
+  static void CheckResolution(void* arg, grpc_error_handle error);
   // Helper function for applying the service config to a call while
-  // holding ChannelData::resolution_mu_.
+  // holding ClientChannel::resolution_mu_.
   // Returns true if the service config has been applied to the call, in which
   // case the caller must invoke ResolutionDone() or AsyncResolutionDone()
   // with the returned error.
-  bool CheckResolutionLocked(grpc_call_element* elem, grpc_error** error);
+  bool CheckResolutionLocked(grpc_call_element* elem, grpc_error_handle* error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::resolution_mu_);
   // Schedules a callback to continue processing the call once
   // resolution is complete.  The callback will not run until after this
   // method returns.
-  void AsyncResolutionDone(grpc_call_element* elem, grpc_error* error);
+  void AsyncResolutionDone(grpc_call_element* elem, grpc_error_handle error);
 
  private:
   class ResolverQueuedCallCanceller;
 
-  CallData(grpc_call_element* elem, const ChannelData& chand,
+  CallData(grpc_call_element* elem, const ClientChannel& chand,
            const grpc_call_element_args& args);
   ~CallData();
 
@@ -441,7 +129,8 @@
   static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
   void PendingBatchesAdd(grpc_call_element* elem,
                          grpc_transport_stream_op_batch* batch);
-  static void FailPendingBatchInCallCombiner(void* arg, grpc_error* error);
+  static void FailPendingBatchInCallCombiner(void* arg,
+                                             grpc_error_handle error);
   // A predicate type and some useful implementations for PendingBatchesFail().
   typedef bool (*YieldCallCombinerPredicate)(
       const CallCombinerClosureList& closures);
@@ -459,9 +148,10 @@
   // If yield_call_combiner_predicate returns true, assumes responsibility for
   // yielding the call combiner.
   void PendingBatchesFail(
-      grpc_call_element* elem, grpc_error* error,
+      grpc_call_element* elem, grpc_error_handle error,
       YieldCallCombinerPredicate yield_call_combiner_predicate);
-  static void ResumePendingBatchInCallCombiner(void* arg, grpc_error* ignored);
+  static void ResumePendingBatchInCallCombiner(void* arg,
+                                               grpc_error_handle ignored);
   // Resumes all pending batches on lb_call_.
   void PendingBatchesResume(grpc_call_element* elem);
 
@@ -469,20 +159,23 @@
   // that the resolver has returned results to the channel.
   // If an error is returned, the error indicates the status with which
   // the call should be failed.
-  grpc_error* ApplyServiceConfigToCallLocked(
-      grpc_call_element* elem, grpc_metadata_batch* initial_metadata);
+  grpc_error_handle ApplyServiceConfigToCallLocked(
+      grpc_call_element* elem, grpc_metadata_batch* initial_metadata)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::resolution_mu_);
   // Invoked when the resolver result is applied to the caller, on both
   // success or failure.
-  static void ResolutionDone(void* arg, grpc_error* error);
+  static void ResolutionDone(void* arg, grpc_error_handle error);
   // Removes the call (if present) from the channel's list of calls queued
   // for name resolution.
-  void MaybeRemoveCallFromResolverQueuedCallsLocked(grpc_call_element* elem);
+  void MaybeRemoveCallFromResolverQueuedCallsLocked(grpc_call_element* elem)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::resolution_mu_);
   // Adds the call (if not already present) to the channel's list of
   // calls queued for name resolution.
-  void MaybeAddCallToResolverQueuedCallsLocked(grpc_call_element* elem);
+  void MaybeAddCallToResolverQueuedCallsLocked(grpc_call_element* elem)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::resolution_mu_);
 
   static void RecvInitialMetadataReadyForConfigSelectorCommitCallback(
-      void* arg, grpc_error* error);
+      void* arg, grpc_error_handle error);
   void InjectRecvInitialMetadataReadyForConfigSelectorCommitCallback(
       grpc_transport_stream_op_batch* batch);
 
@@ -508,11 +201,15 @@
 
   grpc_closure pick_closure_;
 
-  // Accessed while holding ChannelData::resolution_mu_.
-  bool service_config_applied_ = false;
-  bool queued_pending_resolver_result_ = false;
-  ChannelData::ResolverQueuedCall resolver_queued_call_;
-  ResolverQueuedCallCanceller* resolver_call_canceller_ = nullptr;
+  // Accessed while holding ClientChannel::resolution_mu_.
+  bool service_config_applied_ ABSL_GUARDED_BY(&ClientChannel::resolution_mu_) =
+      false;
+  bool queued_pending_resolver_result_
+      ABSL_GUARDED_BY(&ClientChannel::resolution_mu_) = false;
+  ClientChannel::ResolverQueuedCall resolver_queued_call_
+      ABSL_GUARDED_BY(&ClientChannel::resolution_mu_);
+  ResolverQueuedCallCanceller* resolver_call_canceller_
+      ABSL_GUARDED_BY(&ClientChannel::resolution_mu_) = nullptr;
 
   std::function<void()> on_call_committed_;
 
@@ -530,611 +227,105 @@
   grpc_transport_stream_op_batch* pending_batches_[MAX_PENDING_BATCHES] = {};
 
   // Set when we get a cancel_stream op.
-  grpc_error* cancel_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_error_ = GRPC_ERROR_NONE;
 };
 
 //
-// RetryingCall definition
+// Filter vtable
 //
 
-class RetryingCall {
- public:
-  RetryingCall(
-      ChannelData* chand, const grpc_call_element_args& args,
-      grpc_polling_entity* pollent,
-      RefCountedPtr<ServerRetryThrottleData> retry_throttle_data,
-      const ClientChannelMethodParsedConfig::RetryPolicy* retry_policy);
-  ~RetryingCall();
-
-  void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
-
-  RefCountedPtr<SubchannelCall> subchannel_call() const;
-
- private:
-  // State used for starting a retryable batch on a subchannel call.
-  // This provides its own grpc_transport_stream_op_batch and other data
-  // structures needed to populate the ops in the batch.
-  // We allocate one struct on the arena for each attempt at starting a
-  // batch on a given subchannel call.
-  struct SubchannelCallBatchData {
-    // Creates a SubchannelCallBatchData object on the call's arena with the
-    // specified refcount.  If set_on_complete is true, the batch's
-    // on_complete callback will be set to point to on_complete();
-    // otherwise, the batch's on_complete callback will be null.
-    static SubchannelCallBatchData* Create(RetryingCall* call, int refcount,
-                                           bool set_on_complete);
-
-    void Unref() {
-      if (gpr_unref(&refs)) Destroy();
-    }
-
-    SubchannelCallBatchData(RetryingCall* call, int refcount,
-                            bool set_on_complete);
-    // All dtor code must be added in `Destroy()`. This is because we may
-    // call closures in `SubchannelCallBatchData` after they are unrefed by
-    // `Unref()`, and msan would complain about accessing this class
-    // after calling dtor. As a result we cannot call the `dtor` in `Unref()`.
-    // TODO(soheil): We should try to call the dtor in `Unref()`.
-    ~SubchannelCallBatchData() { Destroy(); }
-    void Destroy();
-
-    gpr_refcount refs;
-    grpc_call_element* elem;
-    RetryingCall* call;
-    RefCountedPtr<LoadBalancedCall> lb_call;
-    // The batch to use in the subchannel call.
-    // Its payload field points to SubchannelCallRetryState::batch_payload.
-    grpc_transport_stream_op_batch batch;
-    // For intercepting on_complete.
-    grpc_closure on_complete;
-  };
-
-  // Retry state associated with a subchannel call.
-  // Stored in the parent_data of the subchannel call object.
-  struct SubchannelCallRetryState {
-    explicit SubchannelCallRetryState(grpc_call_context_element* context)
-        : batch_payload(context),
-          started_send_initial_metadata(false),
-          completed_send_initial_metadata(false),
-          started_send_trailing_metadata(false),
-          completed_send_trailing_metadata(false),
-          started_recv_initial_metadata(false),
-          completed_recv_initial_metadata(false),
-          started_recv_trailing_metadata(false),
-          completed_recv_trailing_metadata(false),
-          retry_dispatched(false) {}
-
-    // SubchannelCallBatchData.batch.payload points to this.
-    grpc_transport_stream_op_batch_payload batch_payload;
-    // For send_initial_metadata.
-    // Note that we need to make a copy of the initial metadata for each
-    // subchannel call instead of just referring to the copy in call_data,
-    // because filters in the subchannel stack will probably add entries,
-    // so we need to start in a pristine state for each attempt of the call.
-    grpc_linked_mdelem* send_initial_metadata_storage;
-    grpc_metadata_batch send_initial_metadata;
-    // For send_message.
-    // TODO(roth): Restructure this to eliminate use of ManualConstructor.
-    ManualConstructor<ByteStreamCache::CachingByteStream> send_message;
-    // For send_trailing_metadata.
-    grpc_linked_mdelem* send_trailing_metadata_storage;
-    grpc_metadata_batch send_trailing_metadata;
-    // For intercepting recv_initial_metadata.
-    grpc_metadata_batch recv_initial_metadata;
-    grpc_closure recv_initial_metadata_ready;
-    bool trailing_metadata_available = false;
-    // For intercepting recv_message.
-    grpc_closure recv_message_ready;
-    OrphanablePtr<ByteStream> recv_message;
-    // For intercepting recv_trailing_metadata.
-    grpc_metadata_batch recv_trailing_metadata;
-    grpc_transport_stream_stats collect_stats;
-    grpc_closure recv_trailing_metadata_ready;
-    // These fields indicate which ops have been started and completed on
-    // this subchannel call.
-    size_t started_send_message_count = 0;
-    size_t completed_send_message_count = 0;
-    size_t started_recv_message_count = 0;
-    size_t completed_recv_message_count = 0;
-    bool started_send_initial_metadata : 1;
-    bool completed_send_initial_metadata : 1;
-    bool started_send_trailing_metadata : 1;
-    bool completed_send_trailing_metadata : 1;
-    bool started_recv_initial_metadata : 1;
-    bool completed_recv_initial_metadata : 1;
-    bool started_recv_trailing_metadata : 1;
-    bool completed_recv_trailing_metadata : 1;
-    // State for callback processing.
-    SubchannelCallBatchData* recv_initial_metadata_ready_deferred_batch =
-        nullptr;
-    grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
-    SubchannelCallBatchData* recv_message_ready_deferred_batch = nullptr;
-    grpc_error* recv_message_error = GRPC_ERROR_NONE;
-    SubchannelCallBatchData* recv_trailing_metadata_internal_batch = nullptr;
-    // NOTE: Do not move this next to the metadata bitfields above. That would
-    //       save space but will also result in a data race because compiler
-    //       will generate a 2 byte store which overwrites the meta-data
-    //       fields upon setting this field.
-    bool retry_dispatched : 1;
-  };
-
-  // Pending batches stored in call data.
-  struct PendingBatch {
-    // The pending batch.  If nullptr, this slot is empty.
-    grpc_transport_stream_op_batch* batch = nullptr;
-    // Indicates whether payload for send ops has been cached in CallData.
-    bool send_ops_cached = false;
-  };
-
-  // Caches data for send ops so that it can be retried later, if not
-  // already cached.
-  void MaybeCacheSendOpsForBatch(PendingBatch* pending);
-  void FreeCachedSendInitialMetadata();
-  // Frees cached send_message at index idx.
-  void FreeCachedSendMessage(size_t idx);
-  void FreeCachedSendTrailingMetadata();
-  // Frees cached send ops that have already been completed after
-  // committing the call.
-  void FreeCachedSendOpDataAfterCommit(SubchannelCallRetryState* retry_state);
-  // Frees cached send ops that were completed by the completed batch in
-  // batch_data.  Used when batches are completed after the call is committed.
-  void FreeCachedSendOpDataForCompletedBatch(
-      SubchannelCallBatchData* batch_data,
-      SubchannelCallRetryState* retry_state);
-
-  // Returns the index into pending_batches_ to be used for batch.
-  static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
-  void PendingBatchesAdd(grpc_transport_stream_op_batch* batch);
-  void PendingBatchClear(PendingBatch* pending);
-  void MaybeClearPendingBatch(PendingBatch* pending);
-  static void FailPendingBatchInCallCombiner(void* arg, grpc_error* error);
-  // A predicate type and some useful implementations for PendingBatchesFail().
-  typedef bool (*YieldCallCombinerPredicate)(
-      const CallCombinerClosureList& closures);
-  static bool YieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
-    return true;
-  }
-  static bool NoYieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
-    return false;
-  }
-  static bool YieldCallCombinerIfPendingBatchesFound(
-      const CallCombinerClosureList& closures) {
-    return closures.size() > 0;
-  }
-  // Fails all pending batches.
-  // If yield_call_combiner_predicate returns true, assumes responsibility for
-  // yielding the call combiner.
-  void PendingBatchesFail(
-      grpc_error* error,
-      YieldCallCombinerPredicate yield_call_combiner_predicate);
-  static void ResumePendingBatchInCallCombiner(void* arg, grpc_error* ignored);
-  // Resumes all pending batches on lb_call_.
-  void PendingBatchesResume();
-  // Returns a pointer to the first pending batch for which predicate(batch)
-  // returns true, or null if not found.
-  template <typename Predicate>
-  PendingBatch* PendingBatchFind(const char* log_message, Predicate predicate);
-
-  // Commits the call so that no further retry attempts will be performed.
-  void RetryCommit(SubchannelCallRetryState* retry_state);
-  // Starts a retry after appropriate back-off.
-  void DoRetry(SubchannelCallRetryState* retry_state,
-               grpc_millis server_pushback_ms);
-  // Returns true if the call is being retried.
-  bool MaybeRetry(SubchannelCallBatchData* batch_data, grpc_status_code status,
-                  grpc_mdelem* server_pushback_md);
-
-  // Invokes recv_initial_metadata_ready for a subchannel batch.
-  static void InvokeRecvInitialMetadataCallback(void* arg, grpc_error* error);
-  // Intercepts recv_initial_metadata_ready callback for retries.
-  // Commits the call and returns the initial metadata up the stack.
-  static void RecvInitialMetadataReady(void* arg, grpc_error* error);
-
-  // Invokes recv_message_ready for a subchannel batch.
-  static void InvokeRecvMessageCallback(void* arg, grpc_error* error);
-  // Intercepts recv_message_ready callback for retries.
-  // Commits the call and returns the message up the stack.
-  static void RecvMessageReady(void* arg, grpc_error* error);
-
-  // Sets *status and *server_pushback_md based on md_batch and error.
-  // Only sets *server_pushback_md if server_pushback_md != nullptr.
-  void GetCallStatus(grpc_metadata_batch* md_batch, grpc_error* error,
-                     grpc_status_code* status,
-                     grpc_mdelem** server_pushback_md);
-  // Adds recv_trailing_metadata_ready closure to closures.
-  void AddClosureForRecvTrailingMetadataReady(
-      SubchannelCallBatchData* batch_data, grpc_error* error,
-      CallCombinerClosureList* closures);
-  // Adds any necessary closures for deferred recv_initial_metadata and
-  // recv_message callbacks to closures.
-  static void AddClosuresForDeferredRecvCallbacks(
-      SubchannelCallBatchData* batch_data,
-      SubchannelCallRetryState* retry_state, CallCombinerClosureList* closures);
-  // Returns true if any op in the batch was not yet started.
-  // Only looks at send ops, since recv ops are always started immediately.
-  bool PendingBatchIsUnstarted(PendingBatch* pending,
-                               SubchannelCallRetryState* retry_state);
-  // For any pending batch containing an op that has not yet been started,
-  // adds the pending batch's completion closures to closures.
-  void AddClosuresToFailUnstartedPendingBatches(
-      SubchannelCallRetryState* retry_state, grpc_error* error,
-      CallCombinerClosureList* closures);
-  // Runs necessary closures upon completion of a call attempt.
-  void RunClosuresForCompletedCall(SubchannelCallBatchData* batch_data,
-                                   grpc_error* error);
-  // Intercepts recv_trailing_metadata_ready callback for retries.
-  // Commits the call and returns the trailing metadata up the stack.
-  static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
-
-  // Adds the on_complete closure for the pending batch completed in
-  // batch_data to closures.
-  void AddClosuresForCompletedPendingBatch(SubchannelCallBatchData* batch_data,
-                                           grpc_error* error,
-                                           CallCombinerClosureList* closures);
-
-  // If there are any cached ops to replay or pending ops to start on the
-  // subchannel call, adds a closure to closures to invoke
-  // StartRetriableSubchannelBatches().
-  void AddClosuresForReplayOrPendingSendOps(
-      SubchannelCallBatchData* batch_data,
-      SubchannelCallRetryState* retry_state, CallCombinerClosureList* closures);
-
-  // Callback used to intercept on_complete from subchannel calls.
-  // Called only when retries are enabled.
-  static void OnComplete(void* arg, grpc_error* error);
-
-  static void StartBatchInCallCombiner(void* arg, grpc_error* ignored);
-  // Adds a closure to closures that will execute batch in the call combiner.
-  void AddClosureForSubchannelBatch(grpc_transport_stream_op_batch* batch,
-                                    CallCombinerClosureList* closures);
-  // Adds retriable send_initial_metadata op to batch_data.
-  void AddRetriableSendInitialMetadataOp(SubchannelCallRetryState* retry_state,
-                                         SubchannelCallBatchData* batch_data);
-  // Adds retriable send_message op to batch_data.
-  void AddRetriableSendMessageOp(SubchannelCallRetryState* retry_state,
-                                 SubchannelCallBatchData* batch_data);
-  // Adds retriable send_trailing_metadata op to batch_data.
-  void AddRetriableSendTrailingMetadataOp(SubchannelCallRetryState* retry_state,
-                                          SubchannelCallBatchData* batch_data);
-  // Adds retriable recv_initial_metadata op to batch_data.
-  void AddRetriableRecvInitialMetadataOp(SubchannelCallRetryState* retry_state,
-                                         SubchannelCallBatchData* batch_data);
-  // Adds retriable recv_message op to batch_data.
-  void AddRetriableRecvMessageOp(SubchannelCallRetryState* retry_state,
-                                 SubchannelCallBatchData* batch_data);
-  // Adds retriable recv_trailing_metadata op to batch_data.
-  void AddRetriableRecvTrailingMetadataOp(SubchannelCallRetryState* retry_state,
-                                          SubchannelCallBatchData* batch_data);
-  // Helper function used to start a recv_trailing_metadata batch.  This
-  // is used in the case where a recv_initial_metadata or recv_message
-  // op fails in a way that we know the call is over but when the application
-  // has not yet started its own recv_trailing_metadata op.
-  void StartInternalRecvTrailingMetadata();
-  // If there are any cached send ops that need to be replayed on the
-  // current subchannel call, creates and returns a new subchannel batch
-  // to replay those ops.  Otherwise, returns nullptr.
-  SubchannelCallBatchData* MaybeCreateSubchannelBatchForReplay(
-      SubchannelCallRetryState* retry_state);
-  // Adds subchannel batches for pending batches to closures.
-  void AddSubchannelBatchesForPendingBatches(
-      SubchannelCallRetryState* retry_state, CallCombinerClosureList* closures);
-  // Constructs and starts whatever subchannel batches are needed on the
-  // subchannel call.
-  static void StartRetriableSubchannelBatches(void* arg, grpc_error* ignored);
-
-  static void CreateLbCall(void* arg, grpc_error* error);
-
-  ChannelData* chand_;
-  grpc_polling_entity* pollent_;
-  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
-  const ClientChannelMethodParsedConfig::RetryPolicy* retry_policy_ = nullptr;
-  BackOff retry_backoff_;
-
-  grpc_slice path_;  // Request path.
-  gpr_cycle_counter call_start_time_;
-  grpc_millis deadline_;
-  Arena* arena_;
-  grpc_call_stack* owning_call_;
-  CallCombiner* call_combiner_;
-  grpc_call_context_element* call_context_;
-
-  grpc_closure retry_closure_;
-
-  RefCountedPtr<LoadBalancedCall> lb_call_;
-
-  // Batches are added to this list when received from above.
-  // They are removed when we are done handling the batch (i.e., when
-  // either we have invoked all of the batch's callbacks or we have
-  // passed the batch down to the LB call and are not intercepting any of
-  // its callbacks).
-  // TODO(roth): Now that the retry code is split out into its own call
-  // object, revamp this to work in a cleaner way, since we no longer need
-  // for batches to ever wait for name resolution or LB picks.
-  PendingBatch pending_batches_[MAX_PENDING_BATCHES];
-  bool pending_send_initial_metadata_ : 1;
-  bool pending_send_message_ : 1;
-  bool pending_send_trailing_metadata_ : 1;
-
-  // Set when we get a cancel_stream op.
-  grpc_error* cancel_error_ = GRPC_ERROR_NONE;
-
-  // Retry state.
-  bool enable_retries_ : 1;
-  bool retry_committed_ : 1;
-  bool last_attempt_got_server_pushback_ : 1;
-  int num_attempts_completed_ = 0;
-  size_t bytes_buffered_for_retry_ = 0;
-  grpc_timer retry_timer_;
-
-  // The number of pending retriable subchannel batches containing send ops.
-  // We hold a ref to the call stack while this is non-zero, since replay
-  // batches may not complete until after all callbacks have been returned
-  // to the surface, and we need to make sure that the call is not destroyed
-  // until all of these batches have completed.
-  // Note that we actually only need to track replay batches, but it's
-  // easier to track all batches with send ops.
-  int num_pending_retriable_subchannel_send_batches_ = 0;
-
-  // Cached data for retrying send ops.
-  // send_initial_metadata
-  bool seen_send_initial_metadata_ = false;
-  grpc_linked_mdelem* send_initial_metadata_storage_ = nullptr;
-  grpc_metadata_batch send_initial_metadata_;
-  uint32_t send_initial_metadata_flags_;
-  gpr_atm* peer_string_;
-  // send_message
-  // When we get a send_message op, we replace the original byte stream
-  // with a CachingByteStream that caches the slices to a local buffer for
-  // use in retries.
-  // Note: We inline the cache for the first 3 send_message ops and use
-  // dynamic allocation after that.  This number was essentially picked
-  // at random; it could be changed in the future to tune performance.
-  absl::InlinedVector<ByteStreamCache*, 3> send_messages_;
-  // send_trailing_metadata
-  bool seen_send_trailing_metadata_ = false;
-  grpc_linked_mdelem* send_trailing_metadata_storage_ = nullptr;
-  grpc_metadata_batch send_trailing_metadata_;
-};
-
-//
-// LoadBalancedCall definition
-//
-
-// This object is ref-counted, but it cannot inherit from RefCounted<>,
-// because it is allocated on the arena and can't free its memory when
-// its refcount goes to zero.  So instead, it manually implements the
-// same API as RefCounted<>, so that it can be used with RefCountedPtr<>.
-class LoadBalancedCall {
- public:
-  static RefCountedPtr<LoadBalancedCall> Create(
-      ChannelData* chand, const grpc_call_element_args& args,
-      grpc_polling_entity* pollent, size_t parent_data_size);
-
-  LoadBalancedCall(ChannelData* chand, const grpc_call_element_args& args,
-                   grpc_polling_entity* pollent);
-  ~LoadBalancedCall();
-
-  // Interface of RefCounted<>.
-  RefCountedPtr<LoadBalancedCall> Ref() GRPC_MUST_USE_RESULT;
-  RefCountedPtr<LoadBalancedCall> Ref(const DebugLocation& location,
-                                      const char* reason) GRPC_MUST_USE_RESULT;
-  // When refcount drops to 0, destroys itself and the associated call stack,
-  // but does NOT free the memory because it's in the call arena.
-  void Unref();
-  void Unref(const DebugLocation& location, const char* reason);
-
-  void* GetParentData();
-
-  void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
-
-  // Invoked by channel for queued LB picks when the picker is updated.
-  static void PickSubchannel(void* arg, grpc_error* error);
-  // Helper function for performing an LB pick while holding the data plane
-  // mutex.  Returns true if the pick is complete, in which case the caller
-  // must invoke PickDone() or AsyncPickDone() with the returned error.
-  bool PickSubchannelLocked(grpc_error** error);
-  // Schedules a callback to process the completed pick.  The callback
-  // will not run until after this method returns.
-  void AsyncPickDone(grpc_error* error);
-
-  RefCountedPtr<SubchannelCall> subchannel_call() const {
-    return subchannel_call_;
-  }
-
- private:
-  // Allow RefCountedPtr<> to access IncrementRefCount().
-  template <typename T>
-  friend class ::grpc_core::RefCountedPtr;
-
-  class LbQueuedCallCanceller;
-  class Metadata;
-  class LbCallState;
-
-  // Interface of RefCounted<>.
-  void IncrementRefCount();
-  void IncrementRefCount(const DebugLocation& location, const char* reason);
-
-  // Returns the index into pending_batches_ to be used for batch.
-  static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
-  void PendingBatchesAdd(grpc_transport_stream_op_batch* batch);
-  static void FailPendingBatchInCallCombiner(void* arg, grpc_error* error);
-  // A predicate type and some useful implementations for PendingBatchesFail().
-  typedef bool (*YieldCallCombinerPredicate)(
-      const CallCombinerClosureList& closures);
-  static bool YieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
-    return true;
-  }
-  static bool NoYieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
-    return false;
-  }
-  static bool YieldCallCombinerIfPendingBatchesFound(
-      const CallCombinerClosureList& closures) {
-    return closures.size() > 0;
-  }
-  // Fails all pending batches.
-  // If yield_call_combiner_predicate returns true, assumes responsibility for
-  // yielding the call combiner.
-  void PendingBatchesFail(
-      grpc_error* error,
-      YieldCallCombinerPredicate yield_call_combiner_predicate);
-  static void ResumePendingBatchInCallCombiner(void* arg, grpc_error* ignored);
-  // Resumes all pending batches on subchannel_call_.
-  void PendingBatchesResume();
-
-  static void RecvTrailingMetadataReadyForLoadBalancingPolicy(
-      void* arg, grpc_error* error);
-  void InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
-      grpc_transport_stream_op_batch* batch);
-
-  void CreateSubchannelCall();
-  // Invoked when a pick is completed, on both success or failure.
-  static void PickDone(void* arg, grpc_error* error);
-  // Removes the call from the channel's list of queued picks if present.
-  void MaybeRemoveCallFromLbQueuedCallsLocked();
-  // Adds the call to the channel's list of queued picks if not already present.
-  void MaybeAddCallToLbQueuedCallsLocked();
-
-  RefCount refs_;
-
-  ChannelData* chand_;
-
-  // TODO(roth): Instead of duplicating these fields in every filter
-  // that uses any one of them, we should store them in the call
-  // context.  This will save per-call memory overhead.
-  grpc_slice path_;  // Request path.
-  gpr_cycle_counter call_start_time_;
-  grpc_millis deadline_;
-  Arena* arena_;
-  grpc_call_stack* owning_call_;
-  CallCombiner* call_combiner_;
-  grpc_call_context_element* call_context_;
-
-  // Set when we get a cancel_stream op.
-  grpc_error* cancel_error_ = GRPC_ERROR_NONE;
-
-  grpc_polling_entity* pollent_ = nullptr;
-
-  grpc_closure pick_closure_;
-
-  // Accessed while holding ChannelData::data_plane_mu_.
-  ChannelData::LbQueuedCall queued_call_;
-  bool queued_pending_lb_pick_ = false;
-  const LoadBalancingPolicy::BackendMetricData* backend_metric_data_ = nullptr;
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
-  std::function<void(grpc_error*, LoadBalancingPolicy::MetadataInterface*,
-                     LoadBalancingPolicy::CallState*)>
-      lb_recv_trailing_metadata_ready_;
-  LbQueuedCallCanceller* lb_call_canceller_ = nullptr;
-
-  RefCountedPtr<SubchannelCall> subchannel_call_;
-
-  // For intercepting recv_trailing_metadata_ready for the LB policy.
-  grpc_metadata_batch* recv_trailing_metadata_ = nullptr;
-  grpc_closure recv_trailing_metadata_ready_;
-  grpc_closure* original_recv_trailing_metadata_ready_ = nullptr;
-
-  // Batches are added to this list when received from above.
-  // They are removed when we are done handling the batch (i.e., when
-  // either we have invoked all of the batch's callbacks or we have
-  // passed the batch down to the subchannel call and are not
-  // intercepting any of its callbacks).
-  grpc_transport_stream_op_batch* pending_batches_[MAX_PENDING_BATCHES] = {};
+const grpc_channel_filter ClientChannel::kFilterVtable = {
+    ClientChannel::CallData::StartTransportStreamOpBatch,
+    ClientChannel::StartTransportOp,
+    sizeof(ClientChannel::CallData),
+    ClientChannel::CallData::Init,
+    ClientChannel::CallData::SetPollent,
+    ClientChannel::CallData::Destroy,
+    sizeof(ClientChannel),
+    ClientChannel::Init,
+    ClientChannel::Destroy,
+    ClientChannel::GetChannelInfo,
+    "client-channel",
 };
 
 //
 // dynamic termination filter
 //
 
-// Channel arg pointer vtable for GRPC_ARG_CLIENT_CHANNEL_DATA.
-void* ChannelDataArgCopy(void* p) { return p; }
-void ChannelDataArgDestroy(void* p) {}
-int ChannelDataArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
-const grpc_arg_pointer_vtable kChannelDataArgPointerVtable = {
-    ChannelDataArgCopy, ChannelDataArgDestroy, ChannelDataArgCmp};
+namespace {
 
-// Channel arg pointer vtable for GRPC_ARG_RETRY_THROTTLE_DATA.
-void* RetryThrottleDataArgCopy(void* p) {
-  auto* retry_throttle_data = static_cast<ServerRetryThrottleData*>(p);
-  retry_throttle_data->Ref().release();
+// Channel arg pointer vtable for GRPC_ARG_CLIENT_CHANNEL.
+void* ClientChannelArgCopy(void* p) { return p; }
+void ClientChannelArgDestroy(void* /*p*/) {}
+int ClientChannelArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
+const grpc_arg_pointer_vtable kClientChannelArgPointerVtable = {
+    ClientChannelArgCopy, ClientChannelArgDestroy, ClientChannelArgCmp};
+
+// Channel arg pointer vtable for GRPC_ARG_SERVICE_CONFIG_OBJ.
+void* ServiceConfigObjArgCopy(void* p) {
+  auto* service_config = static_cast<ServiceConfig*>(p);
+  service_config->Ref().release();
   return p;
 }
-void RetryThrottleDataArgDestroy(void* p) {
-  auto* retry_throttle_data = static_cast<ServerRetryThrottleData*>(p);
-  retry_throttle_data->Unref();
+void ServiceConfigObjArgDestroy(void* p) {
+  auto* service_config = static_cast<ServiceConfig*>(p);
+  service_config->Unref();
 }
-int RetryThrottleDataArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
-const grpc_arg_pointer_vtable kRetryThrottleDataArgPointerVtable = {
-    RetryThrottleDataArgCopy, RetryThrottleDataArgDestroy,
-    RetryThrottleDataArgCmp};
+int ServiceConfigObjArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
+const grpc_arg_pointer_vtable kServiceConfigObjArgPointerVtable = {
+    ServiceConfigObjArgCopy, ServiceConfigObjArgDestroy,
+    ServiceConfigObjArgCmp};
 
-class DynamicTerminationFilterChannelData {
+class DynamicTerminationFilter {
  public:
-  static grpc_error* Init(grpc_channel_element* elem,
-                          grpc_channel_element_args* args);
+  class CallData;
+
+  static const grpc_channel_filter kFilterVtable;
+
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args) {
+    GPR_ASSERT(args->is_last);
+    GPR_ASSERT(elem->filter == &kFilterVtable);
+    new (elem->channel_data) DynamicTerminationFilter(args->channel_args);
+    return GRPC_ERROR_NONE;
+  }
 
   static void Destroy(grpc_channel_element* elem) {
-    auto* chand =
-        static_cast<DynamicTerminationFilterChannelData*>(elem->channel_data);
-    chand->~DynamicTerminationFilterChannelData();
+    auto* chand = static_cast<DynamicTerminationFilter*>(elem->channel_data);
+    chand->~DynamicTerminationFilter();
   }
 
   // Will never be called.
-  static void StartTransportOp(grpc_channel_element* elem,
-                               grpc_transport_op* op) {}
-  static void GetChannelInfo(grpc_channel_element* elem,
-                             const grpc_channel_info* info) {}
-
-  ChannelData* chand() const { return chand_; }
-  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data() const {
-    return retry_throttle_data_;
-  }
+  static void StartTransportOp(grpc_channel_element* /*elem*/,
+                               grpc_transport_op* /*op*/) {}
+  static void GetChannelInfo(grpc_channel_element* /*elem*/,
+                             const grpc_channel_info* /*info*/) {}
 
  private:
-  static RefCountedPtr<ServerRetryThrottleData> GetRetryThrottleDataFromArgs(
-      const grpc_channel_args* args) {
-    auto* retry_throttle_data =
-        grpc_channel_args_find_pointer<ServerRetryThrottleData>(
-            args, GRPC_ARG_RETRY_THROTTLE_DATA);
-    if (retry_throttle_data == nullptr) return nullptr;
-    return retry_throttle_data->Ref();
-  }
+  explicit DynamicTerminationFilter(const grpc_channel_args* args)
+      : chand_(grpc_channel_args_find_pointer<ClientChannel>(
+            args, GRPC_ARG_CLIENT_CHANNEL)) {}
 
-  explicit DynamicTerminationFilterChannelData(const grpc_channel_args* args)
-      : chand_(grpc_channel_args_find_pointer<ChannelData>(
-            args, GRPC_ARG_CLIENT_CHANNEL_DATA)),
-        retry_throttle_data_(GetRetryThrottleDataFromArgs(args)) {}
-
-  ChannelData* chand_;
-  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
+  ClientChannel* chand_;
 };
 
-class DynamicTerminationFilterCallData {
+class DynamicTerminationFilter::CallData {
  public:
-  static grpc_error* Init(grpc_call_element* elem,
-                          const grpc_call_element_args* args) {
-    new (elem->call_data) DynamicTerminationFilterCallData(*args);
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args) {
+    new (elem->call_data) CallData(*args);
     return GRPC_ERROR_NONE;
   }
 
   static void Destroy(grpc_call_element* elem,
-                      const grpc_call_final_info* final_info,
+                      const grpc_call_final_info* /*final_info*/,
                       grpc_closure* then_schedule_closure) {
-    auto* calld =
-        static_cast<DynamicTerminationFilterCallData*>(elem->call_data);
-    auto* chand =
-        static_cast<DynamicTerminationFilterChannelData*>(elem->channel_data);
+    auto* calld = static_cast<CallData*>(elem->call_data);
     RefCountedPtr<SubchannelCall> subchannel_call;
-    if (chand->chand()->enable_retries()) {
-      if (GPR_LIKELY(calld->retrying_call_ != nullptr)) {
-        subchannel_call = calld->retrying_call_->subchannel_call();
-        calld->retrying_call_->~RetryingCall();
-      }
-    } else {
-      if (GPR_LIKELY(calld->lb_call_ != nullptr)) {
-        subchannel_call = calld->lb_call_->subchannel_call();
-      }
+    if (GPR_LIKELY(calld->lb_call_ != nullptr)) {
+      subchannel_call = calld->lb_call_->subchannel_call();
     }
-    calld->~DynamicTerminationFilterCallData();
+    calld->~CallData();
     if (GPR_LIKELY(subchannel_call != nullptr)) {
       subchannel_call->SetAfterCallStackDestroy(then_schedule_closure);
     } else {
@@ -1145,60 +336,31 @@
 
   static void StartTransportStreamOpBatch(
       grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
-    auto* calld =
-        static_cast<DynamicTerminationFilterCallData*>(elem->call_data);
-    auto* chand =
-        static_cast<DynamicTerminationFilterChannelData*>(elem->channel_data);
-    if (chand->chand()->enable_retries()) {
-      calld->retrying_call_->StartTransportStreamOpBatch(batch);
-    } else {
-      calld->lb_call_->StartTransportStreamOpBatch(batch);
-    }
+    auto* calld = static_cast<CallData*>(elem->call_data);
+    calld->lb_call_->StartTransportStreamOpBatch(batch);
   }
 
   static void SetPollent(grpc_call_element* elem,
                          grpc_polling_entity* pollent) {
-    auto* calld =
-        static_cast<DynamicTerminationFilterCallData*>(elem->call_data);
-    auto* chand =
-        static_cast<DynamicTerminationFilterChannelData*>(elem->channel_data);
-    ChannelData* client_channel = chand->chand();
+    auto* calld = static_cast<CallData*>(elem->call_data);
+    auto* chand = static_cast<DynamicTerminationFilter*>(elem->channel_data);
+    ClientChannel* client_channel = chand->chand_;
     grpc_call_element_args args = {
         calld->owning_call_,     nullptr,
         calld->call_context_,    calld->path_,
         calld->call_start_time_, calld->deadline_,
         calld->arena_,           calld->call_combiner_};
-    if (client_channel->enable_retries()) {
-      // Get retry settings from service config.
-      auto* svc_cfg_call_data = static_cast<ServiceConfigCallData*>(
-          calld->call_context_[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value);
-      GPR_ASSERT(svc_cfg_call_data != nullptr);
-      auto* method_config = static_cast<const ClientChannelMethodParsedConfig*>(
-          svc_cfg_call_data->GetMethodParsedConfig(
-              ClientChannelServiceConfigParser::ParserIndex()));
-      // Create retrying call.
-      calld->retrying_call_ = calld->arena_->New<RetryingCall>(
-          client_channel, args, pollent, chand->retry_throttle_data(),
-          method_config == nullptr ? nullptr : method_config->retry_policy());
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
-        gpr_log(
-            GPR_INFO,
-            "chand=%p dymamic_termination_calld=%p: create retrying_call=%p",
-            client_channel, calld, calld->retrying_call_);
-      }
-    } else {
-      calld->lb_call_ =
-          LoadBalancedCall::Create(client_channel, args, pollent, 0);
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
-        gpr_log(GPR_INFO,
-                "chand=%p dynamic_termination_calld=%p: create lb_call=%p",
-                chand, client_channel, calld->lb_call_.get());
-      }
+    calld->lb_call_ =
+        client_channel->CreateLoadBalancedCall(args, pollent, nullptr);
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p dynamic_termination_calld=%p: create lb_call=%p", chand,
+              client_channel, calld->lb_call_.get());
     }
   }
 
  private:
-  explicit DynamicTerminationFilterCallData(const grpc_call_element_args& args)
+  explicit CallData(const grpc_call_element_args& args)
       : path_(grpc_slice_ref_internal(args.path)),
         call_start_time_(args.start_time),
         deadline_(args.deadline),
@@ -1207,7 +369,7 @@
         call_combiner_(args.call_combiner),
         call_context_(args.context) {}
 
-  ~DynamicTerminationFilterCallData() { grpc_slice_unref_internal(path_); }
+  ~CallData() { grpc_slice_unref_internal(path_); }
 
   grpc_slice path_;  // Request path.
   gpr_cycle_counter call_start_time_;
@@ -1217,35 +379,58 @@
   CallCombiner* call_combiner_;
   grpc_call_context_element* call_context_;
 
-  RetryingCall* retrying_call_ = nullptr;
-  RefCountedPtr<LoadBalancedCall> lb_call_;
+  RefCountedPtr<ClientChannel::LoadBalancedCall> lb_call_;
 };
 
-const grpc_channel_filter kDynamicTerminationFilterVtable = {
-    DynamicTerminationFilterCallData::StartTransportStreamOpBatch,
-    DynamicTerminationFilterChannelData::StartTransportOp,
-    sizeof(DynamicTerminationFilterCallData),
-    DynamicTerminationFilterCallData::Init,
-    DynamicTerminationFilterCallData::SetPollent,
-    DynamicTerminationFilterCallData::Destroy,
-    sizeof(DynamicTerminationFilterChannelData),
-    DynamicTerminationFilterChannelData::Init,
-    DynamicTerminationFilterChannelData::Destroy,
-    DynamicTerminationFilterChannelData::GetChannelInfo,
+const grpc_channel_filter DynamicTerminationFilter::kFilterVtable = {
+    DynamicTerminationFilter::CallData::StartTransportStreamOpBatch,
+    DynamicTerminationFilter::StartTransportOp,
+    sizeof(DynamicTerminationFilter::CallData),
+    DynamicTerminationFilter::CallData::Init,
+    DynamicTerminationFilter::CallData::SetPollent,
+    DynamicTerminationFilter::CallData::Destroy,
+    sizeof(DynamicTerminationFilter),
+    DynamicTerminationFilter::Init,
+    DynamicTerminationFilter::Destroy,
+    DynamicTerminationFilter::GetChannelInfo,
     "dynamic_filter_termination",
 };
 
-grpc_error* DynamicTerminationFilterChannelData::Init(
-    grpc_channel_element* elem, grpc_channel_element_args* args) {
-  GPR_ASSERT(args->is_last);
-  GPR_ASSERT(elem->filter == &kDynamicTerminationFilterVtable);
-  new (elem->channel_data)
-      DynamicTerminationFilterChannelData(args->channel_args);
-  return GRPC_ERROR_NONE;
-}
+}  // namespace
 
 //
-// ChannelData::SubchannelWrapper
+// ClientChannel::ResolverResultHandler
+//
+
+class ClientChannel::ResolverResultHandler : public Resolver::ResultHandler {
+ public:
+  explicit ResolverResultHandler(ClientChannel* chand) : chand_(chand) {
+    GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ResolverResultHandler");
+  }
+
+  ~ResolverResultHandler() override {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
+      gpr_log(GPR_INFO, "chand=%p: resolver shutdown complete", chand_);
+    }
+    GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "ResolverResultHandler");
+  }
+
+  void ReturnResult(Resolver::Result result) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+    chand_->OnResolverResultChangedLocked(std::move(result));
+  }
+
+  void ReturnError(grpc_error_handle error) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+    chand_->OnResolverErrorLocked(error);
+  }
+
+ private:
+  ClientChannel* chand_;
+};
+
+//
+// ClientChannel::SubchannelWrapper
 //
 
 // This class is a wrapper for Subchannel that hides details of the
@@ -1256,29 +441,30 @@
 // underlying subchannel is shared between channels, this wrapper will only
 // be used within one channel, so it will always be synchronized by the
 // control plane work_serializer.
-class ChannelData::SubchannelWrapper : public SubchannelInterface {
+class ClientChannel::SubchannelWrapper : public SubchannelInterface {
  public:
-  SubchannelWrapper(ChannelData* chand, Subchannel* subchannel,
+  SubchannelWrapper(ClientChannel* chand, RefCountedPtr<Subchannel> subchannel,
                     absl::optional<std::string> health_check_service_name)
       : SubchannelInterface(
             GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)
                 ? "SubchannelWrapper"
                 : nullptr),
         chand_(chand),
-        subchannel_(subchannel),
+        subchannel_(std::move(subchannel)),
         health_check_service_name_(std::move(health_check_service_name)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO,
               "chand=%p: creating subchannel wrapper %p for subchannel %p",
-              chand, this, subchannel_);
+              chand, this, subchannel_.get());
     }
     GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "SubchannelWrapper");
     auto* subchannel_node = subchannel_->channelz_node();
     if (subchannel_node != nullptr) {
-      auto it = chand_->subchannel_refcount_map_.find(subchannel_);
+      auto it = chand_->subchannel_refcount_map_.find(subchannel_.get());
       if (it == chand_->subchannel_refcount_map_.end()) {
         chand_->channelz_node_->AddChildSubchannel(subchannel_node->uuid());
-        it = chand_->subchannel_refcount_map_.emplace(subchannel_, 0).first;
+        it = chand_->subchannel_refcount_map_.emplace(subchannel_.get(), 0)
+                 .first;
       }
       ++it->second;
     }
@@ -1289,12 +475,12 @@
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO,
               "chand=%p: destroying subchannel wrapper %p for subchannel %p",
-              chand_, this, subchannel_);
+              chand_, this, subchannel_.get());
     }
     chand_->subchannel_wrappers_.erase(this);
     auto* subchannel_node = subchannel_->channelz_node();
     if (subchannel_node != nullptr) {
-      auto it = chand_->subchannel_refcount_map_.find(subchannel_);
+      auto it = chand_->subchannel_refcount_map_.find(subchannel_.get());
       GPR_ASSERT(it != chand_->subchannel_refcount_map_.end());
       --it->second;
       if (it->second == 0) {
@@ -1302,11 +488,11 @@
         chand_->subchannel_refcount_map_.erase(it);
       }
     }
-    GRPC_SUBCHANNEL_UNREF(subchannel_, "unref from LB");
     GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "SubchannelWrapper");
   }
 
-  grpc_connectivity_state CheckConnectivityState() override {
+  grpc_connectivity_state CheckConnectivityState() override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     RefCountedPtr<ConnectedSubchannel> connected_subchannel;
     grpc_connectivity_state connectivity_state =
         subchannel_->CheckConnectivityState(health_check_service_name_,
@@ -1385,16 +571,19 @@
   }
 
   // Caller must be holding the control-plane work_serializer.
-  ConnectedSubchannel* connected_subchannel() const {
+  ConnectedSubchannel* connected_subchannel() const
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::work_serializer_) {
     return connected_subchannel_.get();
   }
 
   // Caller must be holding the data-plane mutex.
-  ConnectedSubchannel* connected_subchannel_in_data_plane() const {
+  ConnectedSubchannel* connected_subchannel_in_data_plane() const
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_) {
     return connected_subchannel_in_data_plane_.get();
   }
   void set_connected_subchannel_in_data_plane(
-      RefCountedPtr<ConnectedSubchannel> connected_subchannel) {
+      RefCountedPtr<ConnectedSubchannel> connected_subchannel)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_) {
     connected_subchannel_in_data_plane_ = std::move(connected_subchannel);
   }
 
@@ -1427,7 +616,10 @@
     ~WatcherWrapper() override {
       auto* parent = parent_.release();  // ref owned by lambda
       parent->chand_->work_serializer_->Run(
-          [parent]() { parent->Unref(DEBUG_LOCATION, "WatcherWrapper"); },
+          [parent]()
+              ABSL_EXCLUSIVE_LOCKS_REQUIRED(parent_->chand_->work_serializer_) {
+                parent->Unref(DEBUG_LOCATION, "WatcherWrapper");
+              },
           DEBUG_LOCATION);
     }
 
@@ -1436,14 +628,15 @@
         gpr_log(GPR_INFO,
                 "chand=%p: connectivity change for subchannel wrapper %p "
                 "subchannel %p; hopping into work_serializer",
-                parent_->chand_, parent_.get(), parent_->subchannel_);
+                parent_->chand_, parent_.get(), parent_->subchannel_.get());
       }
       Ref().release();  // ref owned by lambda
       parent_->chand_->work_serializer_->Run(
-          [this]() {
-            ApplyUpdateInControlPlaneWorkSerializer();
-            Unref();
-          },
+          [this]()
+              ABSL_EXCLUSIVE_LOCKS_REQUIRED(parent_->chand_->work_serializer_) {
+                ApplyUpdateInControlPlaneWorkSerializer();
+                Unref();
+              },
           DEBUG_LOCATION);
     }
 
@@ -1464,13 +657,14 @@
     grpc_connectivity_state last_seen_state() const { return last_seen_state_; }
 
    private:
-    void ApplyUpdateInControlPlaneWorkSerializer() {
+    void ApplyUpdateInControlPlaneWorkSerializer()
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(parent_->chand_->work_serializer_) {
       if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
         gpr_log(GPR_INFO,
                 "chand=%p: processing connectivity change in work serializer "
                 "for subchannel wrapper %p subchannel %p "
                 "watcher=%p",
-                parent_->chand_, parent_.get(), parent_->subchannel_,
+                parent_->chand_, parent_.get(), parent_->subchannel_.get(),
                 watcher_.get());
       }
       ConnectivityStateChange state_change = PopConnectivityStateChange();
@@ -1518,7 +712,8 @@
   };
 
   void MaybeUpdateConnectedSubchannel(
-      RefCountedPtr<ConnectedSubchannel> connected_subchannel) {
+      RefCountedPtr<ConnectedSubchannel> connected_subchannel)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::work_serializer_) {
     // Update the connected subchannel only if the channel is not shutting
     // down.  This is because once the channel is shutting down, we
     // ignore picker updates from the LB policy, which means that
@@ -1526,7 +721,7 @@
     // in chand_->pending_subchannel_updates_.  So we don't want to add
     // entries there that will never be processed, since that would
     // leave dangling refs to the channel and prevent its destruction.
-    grpc_error* disconnect_error = chand_->disconnect_error();
+    grpc_error_handle disconnect_error = chand_->disconnect_error();
     if (disconnect_error != GRPC_ERROR_NONE) return;
     // Not shutting down, so do the update.
     if (connected_subchannel_ != connected_subchannel) {
@@ -1538,8 +733,8 @@
     }
   }
 
-  ChannelData* chand_;
-  Subchannel* subchannel_;
+  ClientChannel* chand_;
+  RefCountedPtr<Subchannel> subchannel_;
   absl::optional<std::string> health_check_service_name_;
   // Maps from the address of the watcher passed to us by the LB policy
   // to the address of the WrapperWatcher that we passed to the underlying
@@ -1548,17 +743,19 @@
   // corresponding WrapperWatcher to cancel on the underlying subchannel.
   std::map<ConnectivityStateWatcherInterface*, WatcherWrapper*> watcher_map_;
   // To be accessed only in the control plane work_serializer.
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
+  RefCountedPtr<ConnectedSubchannel> connected_subchannel_
+      ABSL_GUARDED_BY(&ClientChannel::work_serializer_);
   // To be accessed only in the data plane mutex.
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel_in_data_plane_;
+  RefCountedPtr<ConnectedSubchannel> connected_subchannel_in_data_plane_
+      ABSL_GUARDED_BY(&ClientChannel::data_plane_mu_);
 };
 
 //
-// ChannelData::ExternalConnectivityWatcher
+// ClientChannel::ExternalConnectivityWatcher
 //
 
-ChannelData::ExternalConnectivityWatcher::ExternalConnectivityWatcher(
-    ChannelData* chand, grpc_polling_entity pollent,
+ClientChannel::ExternalConnectivityWatcher::ExternalConnectivityWatcher(
+    ClientChannel* chand, grpc_polling_entity pollent,
     grpc_connectivity_state* state, grpc_closure* on_complete,
     grpc_closure* watcher_timer_init)
     : chand_(chand),
@@ -1580,22 +777,22 @@
   }
   // Pass the ref from creating the object to Start().
   chand_->work_serializer_->Run(
-      [this]() {
+      [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
         // The ref is passed to AddWatcherLocked().
         AddWatcherLocked();
       },
       DEBUG_LOCATION);
 }
 
-ChannelData::ExternalConnectivityWatcher::~ExternalConnectivityWatcher() {
+ClientChannel::ExternalConnectivityWatcher::~ExternalConnectivityWatcher() {
   grpc_polling_entity_del_from_pollset_set(&pollent_,
                                            chand_->interested_parties_);
   GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_,
                            "ExternalConnectivityWatcher");
 }
 
-void ChannelData::ExternalConnectivityWatcher::
-    RemoveWatcherFromExternalWatchersMap(ChannelData* chand,
+void ClientChannel::ExternalConnectivityWatcher::
+    RemoveWatcherFromExternalWatchersMap(ClientChannel* chand,
                                          grpc_closure* on_complete,
                                          bool cancel) {
   RefCountedPtr<ExternalConnectivityWatcher> watcher;
@@ -1612,7 +809,7 @@
   if (watcher != nullptr && cancel) watcher->Cancel();
 }
 
-void ChannelData::ExternalConnectivityWatcher::Notify(
+void ClientChannel::ExternalConnectivityWatcher::Notify(
     grpc_connectivity_state state, const absl::Status& /* status */) {
   bool done = false;
   if (!done_.CompareExchangeStrong(&done, true, MemoryOrder::RELAXED,
@@ -1620,7 +817,8 @@
     return;  // Already done.
   }
   // Remove external watcher.
-  chand_->RemoveExternalConnectivityWatcher(on_complete_, /*cancel=*/false);
+  ExternalConnectivityWatcher::RemoveWatcherFromExternalWatchersMap(
+      chand_, on_complete_, /*cancel=*/false);
   // Report new state to the user.
   *state_ = state;
   ExecCtx::Run(DEBUG_LOCATION, on_complete_, GRPC_ERROR_NONE);
@@ -1628,12 +826,15 @@
   // Not needed in state SHUTDOWN, because the tracker will
   // automatically remove all watchers in that case.
   if (state != GRPC_CHANNEL_SHUTDOWN) {
-    chand_->work_serializer_->Run([this]() { RemoveWatcherLocked(); },
-                                  DEBUG_LOCATION);
+    chand_->work_serializer_->Run(
+        [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+          RemoveWatcherLocked();
+        },
+        DEBUG_LOCATION);
   }
 }
 
-void ChannelData::ExternalConnectivityWatcher::Cancel() {
+void ClientChannel::ExternalConnectivityWatcher::Cancel() {
   bool done = false;
   if (!done_.CompareExchangeStrong(&done, true, MemoryOrder::RELAXED,
                                    MemoryOrder::RELAXED)) {
@@ -1641,84 +842,95 @@
   }
   ExecCtx::Run(DEBUG_LOCATION, on_complete_, GRPC_ERROR_CANCELLED);
   // Hop back into the work_serializer to clean up.
-  chand_->work_serializer_->Run([this]() { RemoveWatcherLocked(); },
-                                DEBUG_LOCATION);
+  chand_->work_serializer_->Run(
+      [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+        RemoveWatcherLocked();
+      },
+      DEBUG_LOCATION);
 }
 
-void ChannelData::ExternalConnectivityWatcher::AddWatcherLocked() {
+void ClientChannel::ExternalConnectivityWatcher::AddWatcherLocked() {
   Closure::Run(DEBUG_LOCATION, watcher_timer_init_, GRPC_ERROR_NONE);
   // Add new watcher. Pass the ref of the object from creation to OrphanablePtr.
   chand_->state_tracker_.AddWatcher(
       initial_state_, OrphanablePtr<ConnectivityStateWatcherInterface>(this));
 }
 
-void ChannelData::ExternalConnectivityWatcher::RemoveWatcherLocked() {
+void ClientChannel::ExternalConnectivityWatcher::RemoveWatcherLocked() {
   chand_->state_tracker_.RemoveWatcher(this);
 }
 
 //
-// ChannelData::ConnectivityWatcherAdder
+// ClientChannel::ConnectivityWatcherAdder
 //
 
-class ChannelData::ConnectivityWatcherAdder {
+class ClientChannel::ConnectivityWatcherAdder {
  public:
   ConnectivityWatcherAdder(
-      ChannelData* chand, grpc_connectivity_state initial_state,
+      ClientChannel* chand, grpc_connectivity_state initial_state,
       OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher)
       : chand_(chand),
         initial_state_(initial_state),
         watcher_(std::move(watcher)) {
     GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ConnectivityWatcherAdder");
-    chand_->work_serializer_->Run([this]() { AddWatcherLocked(); },
-                                  DEBUG_LOCATION);
+    chand_->work_serializer_->Run(
+        [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+          AddWatcherLocked();
+        },
+        DEBUG_LOCATION);
   }
 
  private:
-  void AddWatcherLocked() {
+  void AddWatcherLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     chand_->state_tracker_.AddWatcher(initial_state_, std::move(watcher_));
     GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "ConnectivityWatcherAdder");
     delete this;
   }
 
-  ChannelData* chand_;
+  ClientChannel* chand_;
   grpc_connectivity_state initial_state_;
   OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher_;
 };
 
 //
-// ChannelData::ConnectivityWatcherRemover
+// ClientChannel::ConnectivityWatcherRemover
 //
 
-class ChannelData::ConnectivityWatcherRemover {
+class ClientChannel::ConnectivityWatcherRemover {
  public:
-  ConnectivityWatcherRemover(ChannelData* chand,
+  ConnectivityWatcherRemover(ClientChannel* chand,
                              AsyncConnectivityStateWatcherInterface* watcher)
       : chand_(chand), watcher_(watcher) {
     GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ConnectivityWatcherRemover");
-    chand_->work_serializer_->Run([this]() { RemoveWatcherLocked(); },
-                                  DEBUG_LOCATION);
+    chand_->work_serializer_->Run(
+        [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
+          RemoveWatcherLocked();
+        },
+        DEBUG_LOCATION);
   }
 
  private:
-  void RemoveWatcherLocked() {
+  void RemoveWatcherLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     chand_->state_tracker_.RemoveWatcher(watcher_);
     GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_,
                              "ConnectivityWatcherRemover");
     delete this;
   }
 
-  ChannelData* chand_;
+  ClientChannel* chand_;
   AsyncConnectivityStateWatcherInterface* watcher_;
 };
 
 //
-// ChannelData::ClientChannelControlHelper
+// ClientChannel::ClientChannelControlHelper
 //
 
-class ChannelData::ClientChannelControlHelper
+class ClientChannel::ClientChannelControlHelper
     : public LoadBalancingPolicy::ChannelControlHelper {
  public:
-  explicit ClientChannelControlHelper(ChannelData* chand) : chand_(chand) {
+  explicit ClientChannelControlHelper(ClientChannel* chand) : chand_(chand) {
     GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ClientChannelControlHelper");
   }
 
@@ -1728,11 +940,12 @@
   }
 
   RefCountedPtr<SubchannelInterface> CreateSubchannel(
-      ServerAddress address, const grpc_channel_args& args) override {
+      ServerAddress address, const grpc_channel_args& args) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     if (chand_->resolver_ == nullptr) return nullptr;  // Shutting down.
     // Determine health check service name.
-    bool inhibit_health_checking = grpc_channel_arg_get_bool(
-        grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false);
+    bool inhibit_health_checking = grpc_channel_args_find_bool(
+        &args, GRPC_ARG_INHIBIT_HEALTH_CHECKING, false);
     absl::optional<std::string> health_check_service_name;
     if (!inhibit_health_checking) {
       health_check_service_name = chand_->health_check_service_name_;
@@ -1758,7 +971,7 @@
         args_to_add.data(), args_to_add.size());
     gpr_free(args_to_add[0].value.string);
     // Create subchannel.
-    Subchannel* subchannel =
+    RefCountedPtr<Subchannel> subchannel =
         chand_->client_channel_factory_->CreateSubchannel(new_args);
     grpc_channel_args_destroy(new_args);
     if (subchannel == nullptr) return nullptr;
@@ -1766,14 +979,15 @@
     subchannel->ThrottleKeepaliveTime(chand_->keepalive_time_);
     // Create and return wrapper for the subchannel.
     return MakeRefCounted<SubchannelWrapper>(
-        chand_, subchannel, std::move(health_check_service_name));
+        chand_, std::move(subchannel), std::move(health_check_service_name));
   }
 
   void UpdateState(
       grpc_connectivity_state state, const absl::Status& status,
-      std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker) override {
+      std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     if (chand_->resolver_ == nullptr) return;  // Shutting down.
-    grpc_error* disconnect_error = chand_->disconnect_error();
+    grpc_error_handle disconnect_error = chand_->disconnect_error();
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       const char* extra = disconnect_error == GRPC_ERROR_NONE
                               ? ""
@@ -1789,7 +1003,8 @@
     }
   }
 
-  void RequestReresolution() override {
+  void RequestReresolution() override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     if (chand_->resolver_ == nullptr) return;  // Shutting down.
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO, "chand=%p: started name re-resolving", chand_);
@@ -1797,8 +1012,8 @@
     chand_->resolver_->RequestReresolutionLocked();
   }
 
-  void AddTraceEvent(TraceSeverity severity,
-                     absl::string_view message) override {
+  void AddTraceEvent(TraceSeverity severity, absl::string_view message) override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_) {
     if (chand_->resolver_ == nullptr) return;  // Shutting down.
     if (chand_->channelz_node_ != nullptr) {
       chand_->channelz_node_->AddTraceEvent(
@@ -1815,42 +1030,44 @@
     return channelz::ChannelTrace::Error;
   }
 
-  ChannelData* chand_;
+  ClientChannel* chand_;
 };
 
 //
-// ChannelData implementation
+// ClientChannel implementation
 //
 
-grpc_error* ChannelData::Init(grpc_channel_element* elem,
-                              grpc_channel_element_args* args) {
+ClientChannel* ClientChannel::GetFromChannel(grpc_channel* channel) {
+  grpc_channel_element* elem =
+      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
+  if (elem->filter != &kFilterVtable) return nullptr;
+  return static_cast<ClientChannel*>(elem->channel_data);
+}
+
+grpc_error_handle ClientChannel::Init(grpc_channel_element* elem,
+                                      grpc_channel_element_args* args) {
   GPR_ASSERT(args->is_last);
-  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
-  grpc_error* error = GRPC_ERROR_NONE;
-  new (elem->channel_data) ChannelData(args, &error);
+  GPR_ASSERT(elem->filter == &kFilterVtable);
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  new (elem->channel_data) ClientChannel(args, &error);
   return error;
 }
 
-void ChannelData::Destroy(grpc_channel_element* elem) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
-  chand->~ChannelData();
+void ClientChannel::Destroy(grpc_channel_element* elem) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
+  chand->~ClientChannel();
 }
 
+namespace {
+
 bool GetEnableRetries(const grpc_channel_args* args) {
-  return grpc_channel_arg_get_bool(
-      grpc_channel_args_find(args, GRPC_ARG_ENABLE_RETRIES), true);
-}
-
-size_t GetMaxPerRpcRetryBufferSize(const grpc_channel_args* args) {
-  return static_cast<size_t>(grpc_channel_arg_get_integer(
-      grpc_channel_args_find(args, GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE),
-      {DEFAULT_PER_RPC_RETRY_BUFFER_SIZE, 0, INT_MAX}));
+  return grpc_channel_args_find_bool(args, GRPC_ARG_ENABLE_RETRIES, false);
 }
 
 RefCountedPtr<SubchannelPoolInterface> GetSubchannelPool(
     const grpc_channel_args* args) {
-  const bool use_local_subchannel_pool = grpc_channel_arg_get_bool(
-      grpc_channel_args_find(args, GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL), false);
+  const bool use_local_subchannel_pool = grpc_channel_args_find_bool(
+      args, GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, false);
   if (use_local_subchannel_pool) {
     return MakeRefCounted<LocalSubchannelPool>();
   }
@@ -1858,26 +1075,23 @@
 }
 
 channelz::ChannelNode* GetChannelzNode(const grpc_channel_args* args) {
-  const grpc_arg* arg =
-      grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
-  if (arg != nullptr && arg->type == GRPC_ARG_POINTER) {
-    return static_cast<channelz::ChannelNode*>(arg->value.pointer.p);
-  }
-  return nullptr;
+  return grpc_channel_args_find_pointer<channelz::ChannelNode>(
+      args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
 }
 
-ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
+}  // namespace
+
+ClientChannel::ClientChannel(grpc_channel_element_args* args,
+                             grpc_error_handle* error)
     : deadline_checking_enabled_(
           grpc_deadline_checking_enabled(args->channel_args)),
       enable_retries_(GetEnableRetries(args->channel_args)),
-      per_rpc_retry_buffer_size_(
-          GetMaxPerRpcRetryBufferSize(args->channel_args)),
       owning_stack_(args->channel_stack),
       client_channel_factory_(
           ClientChannelFactory::GetFromChannelArgs(args->channel_args)),
       channelz_node_(GetChannelzNode(args->channel_args)),
-      work_serializer_(std::make_shared<WorkSerializer>()),
       interested_parties_(grpc_pollset_set_create()),
+      work_serializer_(std::make_shared<WorkSerializer>()),
       state_tracker_("client_channel", GRPC_CHANNEL_IDLE),
       subchannel_pool_(GetSubchannelPool(args->channel_args)),
       disconnect_error_(GRPC_ERROR_NONE) {
@@ -1885,8 +1099,6 @@
     gpr_log(GPR_INFO, "chand=%p: creating client_channel for channel stack %p",
             this, owning_stack_);
   }
-  // Initialize data members.
-  gpr_mu_init(&info_mu_);
   // Start backup polling.
   grpc_client_channel_start_backup_polling(interested_parties_);
   // Check client channel factory.
@@ -1896,8 +1108,8 @@
     return;
   }
   // Get server name to resolve, using proxy mapper if needed.
-  const char* server_uri = grpc_channel_arg_get_string(
-      grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI));
+  const char* server_uri =
+      grpc_channel_args_find_string(args->channel_args, GRPC_ARG_SERVER_URI);
   if (server_uri == nullptr) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "server URI channel arg missing or wrong type in client channel "
@@ -1906,8 +1118,8 @@
   }
   // Get default service config.  If none is specified via the client API,
   // we use an empty config.
-  const char* service_config_json = grpc_channel_arg_get_string(
-      grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG));
+  const char* service_config_json = grpc_channel_args_find_string(
+      args->channel_args, GRPC_ARG_SERVICE_CONFIG);
   if (service_config_json == nullptr) service_config_json = "{}";
   *error = GRPC_ERROR_NONE;
   default_service_config_ =
@@ -1944,7 +1156,7 @@
   *error = GRPC_ERROR_NONE;
 }
 
-ChannelData::~ChannelData() {
+ClientChannel::~ClientChannel() {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p: destroying channel", this);
   }
@@ -1955,9 +1167,18 @@
   grpc_client_channel_stop_backup_polling(interested_parties_);
   grpc_pollset_set_destroy(interested_parties_);
   GRPC_ERROR_UNREF(disconnect_error_.Load(MemoryOrder::RELAXED));
-  gpr_mu_destroy(&info_mu_);
 }
 
+RefCountedPtr<ClientChannel::LoadBalancedCall>
+ClientChannel::CreateLoadBalancedCall(
+    const grpc_call_element_args& args, grpc_polling_entity* pollent,
+    grpc_closure* on_call_destruction_complete) {
+  return args.arena->New<LoadBalancedCall>(this, args, pollent,
+                                           on_call_destruction_complete);
+}
+
+namespace {
+
 RefCountedPtr<LoadBalancingPolicy::Config> ChooseLbPolicy(
     const Resolver::Result& resolver_result,
     const internal::ClientChannelGlobalParsedConfig* parsed_service_config) {
@@ -1971,9 +1192,8 @@
   if (!parsed_service_config->parsed_deprecated_lb_policy().empty()) {
     policy_name = parsed_service_config->parsed_deprecated_lb_policy().c_str();
   } else {
-    const grpc_arg* channel_arg =
-        grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME);
-    policy_name = grpc_channel_arg_get_string(channel_arg);
+    policy_name = grpc_channel_args_find_string(resolver_result.args,
+                                                GRPC_ARG_LB_POLICY_NAME);
   }
   // Use pick_first if nothing was specified and we didn't select grpclb
   // above.
@@ -1982,7 +1202,7 @@
   Json config_json = Json::Array{Json::Object{
       {policy_name, Json::Object{}},
   }};
-  grpc_error* parse_error = GRPC_ERROR_NONE;
+  grpc_error_handle parse_error = GRPC_ERROR_NONE;
   auto lb_policy_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
       config_json, &parse_error);
   // The policy name came from one of three places:
@@ -2002,7 +1222,9 @@
   return lb_policy_config;
 }
 
-void ChannelData::OnResolverResultChangedLocked(Resolver::Result result) {
+}  // namespace
+
+void ClientChannel::OnResolverResultChangedLocked(Resolver::Result result) {
   // Handle race conditions.
   if (resolver_ == nullptr) return;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
@@ -2025,21 +1247,19 @@
     trace_strings.push_back("Address list became non-empty");
   }
   previous_resolution_contained_addresses_ = !result.addresses.empty();
-  // The result of grpc_error_string() is owned by the error itself.
-  // We're storing that string in trace_strings, so we need to make sure
-  // that the error lives until we're done with the string.
-  grpc_error* service_config_error =
-      GRPC_ERROR_REF(result.service_config_error);
-  if (service_config_error != GRPC_ERROR_NONE) {
-    trace_strings.push_back(grpc_error_string(service_config_error));
+  std::string service_config_error_string_storage;
+  if (result.service_config_error != GRPC_ERROR_NONE) {
+    service_config_error_string_storage =
+        grpc_error_std_string(result.service_config_error);
+    trace_strings.push_back(service_config_error_string_storage.c_str());
   }
   // Choose the service config.
   RefCountedPtr<ServiceConfig> service_config;
   RefCountedPtr<ConfigSelector> config_selector;
-  if (service_config_error != GRPC_ERROR_NONE) {
+  if (result.service_config_error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO, "chand=%p: resolver returned service config error: %s",
-              this, grpc_error_string(service_config_error));
+              this, grpc_error_std_string(result.service_config_error).c_str());
     }
     // If the service config was invalid, then fallback to the
     // previously returned service config.
@@ -2056,7 +1276,7 @@
       // We received an invalid service config and we don't have a
       // previous service config to fall back to.  Put the channel into
       // TRANSIENT_FAILURE.
-      OnResolverErrorLocked(GRPC_ERROR_REF(service_config_error));
+      OnResolverErrorLocked(GRPC_ERROR_REF(result.service_config_error));
       trace_strings.push_back("no valid service config");
     }
   } else if (result.service_config == nullptr) {
@@ -2121,24 +1341,24 @@
                                     grpc_slice_from_cpp_string(message));
     }
   }
-  GRPC_ERROR_UNREF(service_config_error);
 }
 
-void ChannelData::OnResolverErrorLocked(grpc_error* error) {
+void ClientChannel::OnResolverErrorLocked(grpc_error_handle error) {
   if (resolver_ == nullptr) {
     GRPC_ERROR_UNREF(error);
     return;
   }
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p: resolver transient failure: %s", this,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   // If we already have an LB policy from a previous resolution
   // result, then we continue to let it set the connectivity state.
   // Otherwise, we go into TRANSIENT_FAILURE.
   if (lb_policy_ == nullptr) {
-    grpc_error* state_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-        "Resolver transient failure", &error, 1);
+    grpc_error_handle state_error =
+        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+            "Resolver transient failure", &error, 1);
     {
       MutexLock lock(&resolution_mu_);
       // Update resolver transient failure.
@@ -2149,7 +1369,7 @@
            call = call->next) {
         grpc_call_element* elem = call->elem;
         CallData* calld = static_cast<CallData*>(elem->call_data);
-        grpc_error* error = GRPC_ERROR_NONE;
+        grpc_error_handle error = GRPC_ERROR_NONE;
         if (calld->CheckResolutionLocked(elem, &error)) {
           calld->AsyncResolutionDone(elem, error);
         }
@@ -2165,7 +1385,7 @@
   GRPC_ERROR_UNREF(error);
 }
 
-void ChannelData::CreateOrUpdateLbPolicyLocked(
+void ClientChannel::CreateOrUpdateLbPolicyLocked(
     RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
     Resolver::Result result) {
   // Construct update.
@@ -2191,7 +1411,7 @@
 }
 
 // Creates a new LB policy.
-OrphanablePtr<LoadBalancingPolicy> ChannelData::CreateLbPolicyLocked(
+OrphanablePtr<LoadBalancingPolicy> ClientChannel::CreateLbPolicyLocked(
     const grpc_channel_args& args) {
   LoadBalancingPolicy::Args lb_policy_args;
   lb_policy_args.work_serializer = work_serializer_;
@@ -2210,8 +1430,8 @@
   return lb_policy;
 }
 
-void ChannelData::AddResolverQueuedCall(ResolverQueuedCall* call,
-                                        grpc_polling_entity* pollent) {
+void ClientChannel::AddResolverQueuedCall(ResolverQueuedCall* call,
+                                          grpc_polling_entity* pollent) {
   // Add call to queued calls list.
   call->next = resolver_queued_calls_;
   resolver_queued_calls_ = call;
@@ -2220,8 +1440,8 @@
   grpc_polling_entity_add_to_pollset_set(pollent, interested_parties_);
 }
 
-void ChannelData::RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
-                                           grpc_polling_entity* pollent) {
+void ClientChannel::RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
+                                             grpc_polling_entity* pollent) {
   // Remove call's pollent from channel's interested_parties.
   grpc_polling_entity_del_from_pollset_set(pollent, interested_parties_);
   // Remove from queued calls list.
@@ -2234,7 +1454,7 @@
   }
 }
 
-void ChannelData::UpdateServiceConfigInControlPlaneLocked(
+void ClientChannel::UpdateServiceConfigInControlPlaneLocked(
     RefCountedPtr<ServiceConfig> service_config,
     RefCountedPtr<ConfigSelector> config_selector,
     const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
@@ -2274,7 +1494,7 @@
   }
 }
 
-void ChannelData::UpdateServiceConfigInDataPlaneLocked() {
+void ClientChannel::UpdateServiceConfigInDataPlaneLocked() {
   // Grab ref to service config.
   RefCountedPtr<ServiceConfig> service_config = saved_service_config_;
   // Grab ref to config selector.  Use default if resolver didn't supply one.
@@ -2287,34 +1507,25 @@
     config_selector =
         MakeRefCounted<DefaultConfigSelector>(saved_service_config_);
   }
-  // Get retry throttle data from service config.
-  const internal::ClientChannelGlobalParsedConfig* parsed_service_config =
-      static_cast<const internal::ClientChannelGlobalParsedConfig*>(
-          saved_service_config_->GetGlobalParsedConfig(
-              internal::ClientChannelServiceConfigParser::ParserIndex()));
-  absl::optional<internal::ClientChannelGlobalParsedConfig::RetryThrottling>
-      retry_throttle_config = parsed_service_config->retry_throttling();
-  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data;
-  if (retry_throttle_config.has_value()) {
-    retry_throttle_data = internal::ServerRetryThrottleMap::GetDataForServer(
-        server_name_, retry_throttle_config.value().max_milli_tokens,
-        retry_throttle_config.value().milli_token_ratio);
-  }
-  // Construct per-LB filter stack.
+  // Construct dynamic filter stack.
   std::vector<const grpc_channel_filter*> filters =
       config_selector->GetFilters();
-  filters.push_back(&kDynamicTerminationFilterVtable);
-  absl::InlinedVector<grpc_arg, 2> args_to_add;
-  args_to_add.push_back(grpc_channel_arg_pointer_create(
-      const_cast<char*>(GRPC_ARG_CLIENT_CHANNEL_DATA), this,
-      &kChannelDataArgPointerVtable));
-  if (retry_throttle_data != nullptr) {
-    args_to_add.push_back(grpc_channel_arg_pointer_create(
-        const_cast<char*>(GRPC_ARG_RETRY_THROTTLE_DATA),
-        retry_throttle_data.get(), &kRetryThrottleDataArgPointerVtable));
+  if (enable_retries_) {
+    filters.push_back(&kRetryFilterVtable);
+  } else {
+    filters.push_back(&DynamicTerminationFilter::kFilterVtable);
   }
+  absl::InlinedVector<grpc_arg, 2> args_to_add = {
+      grpc_channel_arg_pointer_create(
+          const_cast<char*>(GRPC_ARG_CLIENT_CHANNEL), this,
+          &kClientChannelArgPointerVtable),
+      grpc_channel_arg_pointer_create(
+          const_cast<char*>(GRPC_ARG_SERVICE_CONFIG_OBJ), service_config.get(),
+          &kServiceConfigObjArgPointerVtable),
+  };
   grpc_channel_args* new_args = grpc_channel_args_copy_and_add(
       channel_args_, args_to_add.data(), args_to_add.size());
+  new_args = config_selector->ModifyChannelArgs(new_args);
   RefCountedPtr<DynamicFilters> dynamic_filters =
       DynamicFilters::Create(new_args, std::move(filters));
   GPR_ASSERT(dynamic_filters != nullptr);
@@ -2339,7 +1550,7 @@
          call = call->next) {
       grpc_call_element* elem = call->elem;
       CallData* calld = static_cast<CallData*>(elem->call_data);
-      grpc_error* error = GRPC_ERROR_NONE;
+      grpc_error_handle error = GRPC_ERROR_NONE;
       if (calld->CheckResolutionLocked(elem, &error)) {
         calld->AsyncResolutionDone(elem, error);
       }
@@ -2349,7 +1560,7 @@
   // of scope.
 }
 
-void ChannelData::CreateResolverLocked() {
+void ClientChannel::CreateResolverLocked() {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p: starting name resolution", this);
   }
@@ -2368,7 +1579,7 @@
   }
 }
 
-void ChannelData::DestroyResolverAndLbPolicyLocked() {
+void ClientChannel::DestroyResolverAndLbPolicyLocked() {
   if (resolver_ != nullptr) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO, "chand=%p: shutting down resolver=%p", this,
@@ -2387,14 +1598,27 @@
   }
 }
 
-void ChannelData::UpdateStateAndPickerLocked(
+void ClientChannel::UpdateStateAndPickerLocked(
     grpc_connectivity_state state, const absl::Status& status,
     const char* reason,
     std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker) {
-  // Clean the control plane when entering IDLE.
+  // Special case for IDLE and SHUTDOWN states.
   if (picker == nullptr || state == GRPC_CHANNEL_SHUTDOWN) {
     saved_service_config_.reset();
     saved_config_selector_.reset();
+    // Acquire resolution lock to update config selector and associated state.
+    // To minimize lock contention, we wait to unref these objects until
+    // after we release the lock.
+    RefCountedPtr<ServiceConfig> service_config_to_unref;
+    RefCountedPtr<ConfigSelector> config_selector_to_unref;
+    RefCountedPtr<DynamicFilters> dynamic_filters_to_unref;
+    {
+      MutexLock lock(&resolution_mu_);
+      received_service_config_data_ = false;
+      service_config_to_unref = std::move(service_config_);
+      config_selector_to_unref = std::move(config_selector_);
+      dynamic_filters_to_unref = std::move(dynamic_filters_);
+    }
   }
   // Update connectivity state.
   state_tracker_.SetState(state, status, reason);
@@ -2414,13 +1638,7 @@
   // the refs until after we release the lock, and then unref them at
   // that point.  This includes the following:
   // - refs to subchannel wrappers in the keys of pending_subchannel_updates_
-  // - ref stored in service_config_
-  // - ref stored in config_selector_
-  // - ref stored in dynamic_filters_
   // - ownership of the existing picker in picker_
-  RefCountedPtr<ServiceConfig> service_config_to_unref;
-  RefCountedPtr<ConfigSelector> config_selector_to_unref;
-  RefCountedPtr<DynamicFilters> dynamic_filters_to_unref;
   {
     MutexLock lock(&data_plane_mu_);
     // Handle subchannel updates.
@@ -2439,18 +1657,10 @@
     // Swap out the picker.
     // Note: Original value will be destroyed after the lock is released.
     picker_.swap(picker);
-    // Clean the data plane if the updated picker is nullptr.
-    if (picker_ == nullptr || state == GRPC_CHANNEL_SHUTDOWN) {
-      received_service_config_data_ = false;
-      // Note: We save the objects to unref until after the lock is released.
-      service_config_to_unref = std::move(service_config_);
-      config_selector_to_unref = std::move(config_selector_);
-      dynamic_filters_to_unref = std::move(dynamic_filters_);
-    }
     // Re-process queued picks.
     for (LbQueuedCall* call = lb_queued_calls_; call != nullptr;
          call = call->next) {
-      grpc_error* error = GRPC_ERROR_NONE;
+      grpc_error_handle error = GRPC_ERROR_NONE;
       if (call->lb_call->PickSubchannelLocked(&error)) {
         call->lb_call->AsyncPickDone(error);
       }
@@ -2461,12 +1671,15 @@
   pending_subchannel_updates_.clear();
 }
 
-grpc_error* ChannelData::DoPingLocked(grpc_transport_op* op) {
+grpc_error_handle ClientChannel::DoPingLocked(grpc_transport_op* op) {
   if (state_tracker_.state() != GRPC_CHANNEL_READY) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("channel not connected");
   }
-  LoadBalancingPolicy::PickResult result =
-      picker_->Pick(LoadBalancingPolicy::PickArgs());
+  LoadBalancingPolicy::PickResult result;
+  {
+    MutexLock lock(&data_plane_mu_);
+    result = picker_->Pick(LoadBalancingPolicy::PickArgs());
+  }
   ConnectedSubchannel* connected_subchannel = nullptr;
   if (result.subchannel != nullptr) {
     SubchannelWrapper* subchannel =
@@ -2484,7 +1697,7 @@
   return result.error;
 }
 
-void ChannelData::StartTransportOpLocked(grpc_transport_op* op) {
+void ClientChannel::StartTransportOpLocked(grpc_transport_op* op) {
   // Connectivity watch.
   if (op->start_connectivity_watch != nullptr) {
     state_tracker_.AddWatcher(op->start_connectivity_watch_state,
@@ -2495,7 +1708,7 @@
   }
   // Ping.
   if (op->send_ping.on_initiate != nullptr || op->send_ping.on_ack != nullptr) {
-    grpc_error* error = DoPingLocked(op);
+    grpc_error_handle error = DoPingLocked(op);
     if (error != GRPC_ERROR_NONE) {
       ExecCtx::Run(DEBUG_LOCATION, op->send_ping.on_initiate,
                    GRPC_ERROR_REF(error));
@@ -2515,7 +1728,7 @@
   if (op->disconnect_with_error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p: disconnect_with_error: %s", this,
-              grpc_error_string(op->disconnect_with_error));
+              grpc_error_std_string(op->disconnect_with_error).c_str());
     }
     DestroyResolverAndLbPolicyLocked();
     intptr_t value;
@@ -2543,9 +1756,9 @@
   ExecCtx::Run(DEBUG_LOCATION, op->on_consumed, GRPC_ERROR_NONE);
 }
 
-void ChannelData::StartTransportOp(grpc_channel_element* elem,
-                                   grpc_transport_op* op) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::StartTransportOp(grpc_channel_element* elem,
+                                     grpc_transport_op* op) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   GPR_ASSERT(op->set_accept_stream == false);
   // Handle bind_pollset.
   if (op->bind_pollset != nullptr) {
@@ -2554,12 +1767,15 @@
   // Pop into control plane work_serializer for remaining ops.
   GRPC_CHANNEL_STACK_REF(chand->owning_stack_, "start_transport_op");
   chand->work_serializer_->Run(
-      [chand, op]() { chand->StartTransportOpLocked(op); }, DEBUG_LOCATION);
+      [chand, op]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand->work_serializer_) {
+        chand->StartTransportOpLocked(op);
+      },
+      DEBUG_LOCATION);
 }
 
-void ChannelData::GetChannelInfo(grpc_channel_element* elem,
-                                 const grpc_channel_info* info) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::GetChannelInfo(grpc_channel_element* elem,
+                                   const grpc_channel_info* info) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   MutexLock lock(&chand->info_mu_);
   if (info->lb_policy_name != nullptr) {
     *info->lb_policy_name = gpr_strdup(chand->info_lb_policy_name_.get());
@@ -2570,8 +1786,8 @@
   }
 }
 
-void ChannelData::AddLbQueuedCall(LbQueuedCall* call,
-                                  grpc_polling_entity* pollent) {
+void ClientChannel::AddLbQueuedCall(LbQueuedCall* call,
+                                    grpc_polling_entity* pollent) {
   // Add call to queued picks list.
   call->next = lb_queued_calls_;
   lb_queued_calls_ = call;
@@ -2580,8 +1796,8 @@
   grpc_polling_entity_add_to_pollset_set(pollent, interested_parties_);
 }
 
-void ChannelData::RemoveLbQueuedCall(LbQueuedCall* to_remove,
-                                     grpc_polling_entity* pollent) {
+void ClientChannel::RemoveLbQueuedCall(LbQueuedCall* to_remove,
+                                       grpc_polling_entity* pollent) {
   // Remove call's pollent from channel's interested_parties.
   grpc_polling_entity_del_from_pollset_set(pollent, interested_parties_);
   // Remove from queued picks list.
@@ -2595,7 +1811,7 @@
 }
 
 RefCountedPtr<ConnectedSubchannel>
-ChannelData::GetConnectedSubchannelInDataPlane(
+ClientChannel::GetConnectedSubchannelInDataPlane(
     SubchannelInterface* subchannel) const {
   SubchannelWrapper* subchannel_wrapper =
       static_cast<SubchannelWrapper*>(subchannel);
@@ -2605,7 +1821,7 @@
   return connected_subchannel->Ref();
 }
 
-void ChannelData::TryToConnectLocked() {
+void ClientChannel::TryToConnectLocked() {
   if (lb_policy_ != nullptr) {
     lb_policy_->ExitIdleLocked();
   } else if (resolver_ == nullptr) {
@@ -2614,23 +1830,29 @@
   GRPC_CHANNEL_STACK_UNREF(owning_stack_, "TryToConnect");
 }
 
-grpc_connectivity_state ChannelData::CheckConnectivityState(
+grpc_connectivity_state ClientChannel::CheckConnectivityState(
     bool try_to_connect) {
-  grpc_connectivity_state out = state_tracker_.state();
+  // state_tracker_ is guarded by work_serializer_, which we're not
+  // holding here.  But the one method of state_tracker_ that *is*
+  // thread-safe to call without external synchronization is the state()
+  // method, so we can disable thread-safety analysis for this one read.
+  grpc_connectivity_state out = ABSL_TS_UNCHECKED_READ(state_tracker_).state();
   if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
     GRPC_CHANNEL_STACK_REF(owning_stack_, "TryToConnect");
-    work_serializer_->Run([this]() { TryToConnectLocked(); }, DEBUG_LOCATION);
+    work_serializer_->Run([this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(
+                              work_serializer_) { TryToConnectLocked(); },
+                          DEBUG_LOCATION);
   }
   return out;
 }
 
-void ChannelData::AddConnectivityWatcher(
+void ClientChannel::AddConnectivityWatcher(
     grpc_connectivity_state initial_state,
     OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher) {
   new ConnectivityWatcherAdder(this, initial_state, std::move(watcher));
 }
 
-void ChannelData::RemoveConnectivityWatcher(
+void ClientChannel::RemoveConnectivityWatcher(
     AsyncConnectivityStateWatcherInterface* watcher) {
   new ConnectivityWatcherRemover(this, watcher);
 }
@@ -2639,10 +1861,11 @@
 // CallData implementation
 //
 
-CallData::CallData(grpc_call_element* elem, const ChannelData& chand,
-                   const grpc_call_element_args& args)
+ClientChannel::CallData::CallData(grpc_call_element* elem,
+                                  const ClientChannel& chand,
+                                  const grpc_call_element_args& args)
     : deadline_state_(elem, args,
-                      GPR_LIKELY(chand.deadline_checking_enabled())
+                      GPR_LIKELY(chand.deadline_checking_enabled_)
                           ? args.deadline
                           : GRPC_MILLIS_INF_FUTURE),
       path_(grpc_slice_ref_internal(args.path)),
@@ -2651,9 +1874,13 @@
       arena_(args.arena),
       owning_call_(args.call_stack),
       call_combiner_(args.call_combiner),
-      call_context_(args.context) {}
+      call_context_(args.context) {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: created call", &chand, this);
+  }
+}
 
-CallData::~CallData() {
+ClientChannel::CallData::~CallData() {
   grpc_slice_unref_internal(path_);
   GRPC_ERROR_UNREF(cancel_error_);
   // Make sure there are no remaining pending batches.
@@ -2662,16 +1889,16 @@
   }
 }
 
-grpc_error* CallData::Init(grpc_call_element* elem,
-                           const grpc_call_element_args* args) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+grpc_error_handle ClientChannel::CallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   new (elem->call_data) CallData(elem, *chand, *args);
   return GRPC_ERROR_NONE;
 }
 
-void CallData::Destroy(grpc_call_element* elem,
-                       const grpc_call_final_info* /*final_info*/,
-                       grpc_closure* then_schedule_closure) {
+void ClientChannel::CallData::Destroy(
+    grpc_call_element* elem, const grpc_call_final_info* /*final_info*/,
+    grpc_closure* then_schedule_closure) {
   CallData* calld = static_cast<CallData*>(elem->call_data);
   RefCountedPtr<DynamicFilters::Call> dynamic_call =
       std::move(calld->dynamic_call_);
@@ -2684,12 +1911,12 @@
   }
 }
 
-void CallData::StartTransportStreamOpBatch(
+void ClientChannel::CallData::StartTransportStreamOpBatch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
   GPR_TIMER_SCOPE("cc_start_transport_stream_op_batch", 0);
   CallData* calld = static_cast<CallData*>(elem->call_data);
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
-  if (GPR_LIKELY(chand->deadline_checking_enabled())) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
+  if (GPR_LIKELY(chand->deadline_checking_enabled_)) {
     grpc_deadline_state_client_start_transport_stream_op_batch(elem, batch);
   }
   // Intercept recv_initial_metadata for config selector on-committed callback.
@@ -2700,7 +1927,8 @@
   if (GPR_UNLIKELY(calld->cancel_error_ != GRPC_ERROR_NONE)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p calld=%p: failing batch with error: %s",
-              chand, calld, grpc_error_string(calld->cancel_error_));
+              chand, calld,
+              grpc_error_std_string(calld->cancel_error_).c_str());
     }
     // Note: This will release the call combiner.
     grpc_transport_stream_op_batch_finish_with_failure(
@@ -2719,7 +1947,7 @@
         GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p calld=%p: recording cancel_error=%s", chand,
-              calld, grpc_error_string(calld->cancel_error_));
+              calld, grpc_error_std_string(calld->cancel_error_).c_str());
     }
     // If we do not have a dynamic call (i.e., name resolution has not
     // yet completed), fail all pending batches.  Otherwise, send the
@@ -2773,8 +2001,8 @@
   }
 }
 
-void CallData::SetPollent(grpc_call_element* elem,
-                          grpc_polling_entity* pollent) {
+void ClientChannel::CallData::SetPollent(grpc_call_element* elem,
+                                         grpc_polling_entity* pollent) {
   CallData* calld = static_cast<CallData*>(elem->call_data);
   calld->pollent_ = pollent;
 }
@@ -2783,9 +2011,11 @@
 // pending_batches management
 //
 
-size_t CallData::GetBatchIndex(grpc_transport_stream_op_batch* batch) {
+size_t ClientChannel::CallData::GetBatchIndex(
+    grpc_transport_stream_op_batch* batch) {
   // Note: It is important the send_initial_metadata be the first entry
-  // here, since the code in pick_subchannel_locked() assumes it will be.
+  // here, since the code in ApplyServiceConfigToCallLocked() and
+  // CheckResolutionLocked() assumes it will be.
   if (batch->send_initial_metadata) return 0;
   if (batch->send_message) return 1;
   if (batch->send_trailing_metadata) return 2;
@@ -2796,9 +2026,9 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void CallData::PendingBatchesAdd(grpc_call_element* elem,
-                                 grpc_transport_stream_op_batch* batch) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::CallData::PendingBatchesAdd(
+    grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   const size_t idx = GetBatchIndex(batch);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
     gpr_log(GPR_INFO,
@@ -2811,7 +2041,8 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void CallData::FailPendingBatchInCallCombiner(void* arg, grpc_error* error) {
+void ClientChannel::CallData::FailPendingBatchInCallCombiner(
+    void* arg, grpc_error_handle error) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   CallData* calld = static_cast<CallData*>(batch->handler_private.extra_arg);
@@ -2821,8 +2052,8 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void CallData::PendingBatchesFail(
-    grpc_call_element* elem, grpc_error* error,
+void ClientChannel::CallData::PendingBatchesFail(
+    grpc_call_element* elem, grpc_error_handle error,
     YieldCallCombinerPredicate yield_call_combiner_predicate) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
@@ -2832,7 +2063,8 @@
     }
     gpr_log(GPR_INFO,
             "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
-            elem->channel_data, this, num_batches, grpc_error_string(error));
+            elem->channel_data, this, num_batches,
+            grpc_error_std_string(error).c_str());
   }
   CallCombinerClosureList closures;
   for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
@@ -2856,8 +2088,8 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void CallData::ResumePendingBatchInCallCombiner(void* arg,
-                                                grpc_error* /*ignored*/) {
+void ClientChannel::CallData::ResumePendingBatchInCallCombiner(
+    void* arg, grpc_error_handle /*ignored*/) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   auto* elem =
@@ -2868,8 +2100,8 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void CallData::PendingBatchesResume(grpc_call_element* elem) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::CallData::PendingBatchesResume(grpc_call_element* elem) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   // Retries not enabled; send down batches as-is.
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
     size_t num_batches = 0;
@@ -2903,7 +2135,7 @@
 
 // A class to handle the call combiner cancellation callback for a
 // queued pick.
-class CallData::ResolverQueuedCallCanceller {
+class ClientChannel::CallData::ResolverQueuedCallCanceller {
  public:
   explicit ResolverQueuedCallCanceller(grpc_call_element* elem) : elem_(elem) {
     auto* calld = static_cast<CallData*>(elem->call_data);
@@ -2914,17 +2146,17 @@
   }
 
  private:
-  static void CancelLocked(void* arg, grpc_error* error) {
+  static void CancelLocked(void* arg, grpc_error_handle error) {
     auto* self = static_cast<ResolverQueuedCallCanceller*>(arg);
-    auto* chand = static_cast<ChannelData*>(self->elem_->channel_data);
+    auto* chand = static_cast<ClientChannel*>(self->elem_->channel_data);
     auto* calld = static_cast<CallData*>(self->elem_->call_data);
     {
-      MutexLock lock(chand->resolution_mu());
+      MutexLock lock(&chand->resolution_mu_);
       if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
         gpr_log(GPR_INFO,
                 "chand=%p calld=%p: cancelling resolver queued pick: "
                 "error=%s self=%p calld->resolver_pick_canceller=%p",
-                chand, calld, grpc_error_string(error), self,
+                chand, calld, grpc_error_std_string(error).c_str(), self,
                 calld->resolver_call_canceller_);
       }
       if (calld->resolver_call_canceller_ == self && error != GRPC_ERROR_NONE) {
@@ -2943,10 +2175,10 @@
   grpc_closure closure_;
 };
 
-void CallData::MaybeRemoveCallFromResolverQueuedCallsLocked(
+void ClientChannel::CallData::MaybeRemoveCallFromResolverQueuedCallsLocked(
     grpc_call_element* elem) {
   if (!queued_pending_resolver_result_) return;
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
+  auto* chand = static_cast<ClientChannel*>(elem->channel_data);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO,
             "chand=%p calld=%p: removing from resolver queued picks list",
@@ -2958,10 +2190,10 @@
   resolver_call_canceller_ = nullptr;
 }
 
-void CallData::MaybeAddCallToResolverQueuedCallsLocked(
+void ClientChannel::CallData::MaybeAddCallToResolverQueuedCallsLocked(
     grpc_call_element* elem) {
   if (queued_pending_resolver_result_) return;
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
+  auto* chand = static_cast<ClientChannel*>(elem->channel_data);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p calld=%p: adding to resolver queued picks list",
             chand, this);
@@ -2973,14 +2205,14 @@
   resolver_call_canceller_ = new ResolverQueuedCallCanceller(elem);
 }
 
-grpc_error* CallData::ApplyServiceConfigToCallLocked(
+grpc_error_handle ClientChannel::CallData::ApplyServiceConfigToCallLocked(
     grpc_call_element* elem, grpc_metadata_batch* initial_metadata) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p calld=%p: applying service config to call",
             chand, this);
   }
-  ConfigSelector* config_selector = chand->config_selector();
+  ConfigSelector* config_selector = chand->config_selector_.get();
   if (config_selector != nullptr) {
     // Use the ConfigSelector to determine the config for the call.
     ConfigSelector::CallConfig call_config =
@@ -3002,7 +2234,7 @@
     if (method_params != nullptr) {
       // If the deadline from the service config is shorter than the one
       // from the client API, reset the deadline timer.
-      if (chand->deadline_checking_enabled() && method_params->timeout() != 0) {
+      if (chand->deadline_checking_enabled_ && method_params->timeout() != 0) {
         const grpc_millis per_method_deadline =
             grpc_cycle_counter_to_millis_round_up(call_start_time_) +
             method_params->timeout();
@@ -3027,13 +2259,14 @@
       }
     }
     // Set the dynamic filter stack.
-    dynamic_filters_ = chand->dynamic_filters();
+    dynamic_filters_ = chand->dynamic_filters_;
   }
   return GRPC_ERROR_NONE;
 }
 
-void CallData::RecvInitialMetadataReadyForConfigSelectorCommitCallback(
-    void* arg, grpc_error* error) {
+void ClientChannel::CallData::
+    RecvInitialMetadataReadyForConfigSelectorCommitCallback(
+        void* arg, grpc_error_handle error) {
   auto* self = static_cast<CallData*>(arg);
   if (self->on_call_committed_ != nullptr) {
     self->on_call_committed_();
@@ -3046,8 +2279,9 @@
 
 // TODO(roth): Consider not intercepting this callback unless we
 // actually need to, if this causes a performance problem.
-void CallData::InjectRecvInitialMetadataReadyForConfigSelectorCommitCallback(
-    grpc_transport_stream_op_batch* batch) {
+void ClientChannel::CallData::
+    InjectRecvInitialMetadataReadyForConfigSelectorCommitCallback(
+        grpc_transport_stream_op_batch* batch) {
   original_recv_initial_metadata_ready_ =
       batch->payload->recv_initial_metadata.recv_initial_metadata_ready;
   GRPC_CLOSURE_INIT(&recv_initial_metadata_ready_,
@@ -3057,20 +2291,22 @@
       &recv_initial_metadata_ready_;
 }
 
-void CallData::AsyncResolutionDone(grpc_call_element* elem, grpc_error* error) {
+void ClientChannel::CallData::AsyncResolutionDone(grpc_call_element* elem,
+                                                  grpc_error_handle error) {
   GRPC_CLOSURE_INIT(&pick_closure_, ResolutionDone, elem, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &pick_closure_, error);
 }
 
-void CallData::ResolutionDone(void* arg, grpc_error* error) {
+void ClientChannel::CallData::ResolutionDone(void* arg,
+                                             grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO,
               "chand=%p calld=%p: error applying config to call: error=%s",
-              chand, calld, grpc_error_string(error));
+              chand, calld, grpc_error_std_string(error).c_str());
     }
     calld->PendingBatchesFail(elem, GRPC_ERROR_REF(error), YieldCallCombiner);
     return;
@@ -3078,13 +2314,14 @@
   calld->CreateDynamicCall(elem);
 }
 
-void CallData::CheckResolution(void* arg, grpc_error* error) {
+void ClientChannel::CallData::CheckResolution(void* arg,
+                                              grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   bool resolution_complete;
   {
-    MutexLock lock(chand->resolution_mu());
+    MutexLock lock(&chand->resolution_mu_);
     resolution_complete = calld->CheckResolutionLocked(elem, &error);
   }
   if (resolution_complete) {
@@ -3093,27 +2330,28 @@
   }
 }
 
-bool CallData::CheckResolutionLocked(grpc_call_element* elem,
-                                     grpc_error** error) {
-  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
+bool ClientChannel::CallData::CheckResolutionLocked(grpc_call_element* elem,
+                                                    grpc_error_handle* error) {
+  ClientChannel* chand = static_cast<ClientChannel*>(elem->channel_data);
   // If we're still in IDLE, we need to start resolving.
   if (GPR_UNLIKELY(chand->CheckConnectivityState(false) == GRPC_CHANNEL_IDLE)) {
     // Bounce into the control plane work serializer to start resolving,
     // in case we are still in IDLE state.  Since we are holding on to the
     // resolution mutex here, we offload it on the ExecCtx so that we don't
     // deadlock with ourselves.
-    GRPC_CHANNEL_STACK_REF(chand->owning_stack(), "CheckResolutionLocked");
+    GRPC_CHANNEL_STACK_REF(chand->owning_stack_, "CheckResolutionLocked");
     ExecCtx::Run(
         DEBUG_LOCATION,
         GRPC_CLOSURE_CREATE(
-            [](void* arg, grpc_error* /*error*/) {
-              auto* chand = static_cast<ChannelData*>(arg);
-              chand->work_serializer()->Run(
-                  [chand]() {
-                    chand->CheckConnectivityState(/*try_to_connect=*/true);
-                    GRPC_CHANNEL_STACK_UNREF(chand->owning_stack(),
-                                             "CheckResolutionLocked");
-                  },
+            [](void* arg, grpc_error_handle /*error*/) {
+              auto* chand = static_cast<ClientChannel*>(arg);
+              chand->work_serializer_->Run(
+                  [chand]()
+                      ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand->work_serializer_) {
+                        chand->CheckConnectivityState(/*try_to_connect=*/true);
+                        GRPC_CHANNEL_STACK_UNREF(chand->owning_stack_,
+                                                 "CheckResolutionLocked");
+                      },
                   DEBUG_LOCATION);
             },
             chand, nullptr),
@@ -3128,10 +2366,10 @@
       send_initial_metadata.send_initial_metadata_flags;
   // If we don't yet have a resolver result, we need to queue the call
   // until we get one.
-  if (GPR_UNLIKELY(!chand->received_service_config_data())) {
+  if (GPR_UNLIKELY(!chand->received_service_config_data_)) {
     // If the resolver returned transient failure before returning the
     // first service config, fail any non-wait_for_ready calls.
-    grpc_error* resolver_error = chand->resolver_transient_failure_error();
+    grpc_error_handle resolver_error = chand->resolver_transient_failure_error_;
     if (resolver_error != GRPC_ERROR_NONE &&
         (send_initial_metadata_flags & GRPC_INITIAL_METADATA_WAIT_FOR_READY) ==
             0) {
@@ -3154,8 +2392,8 @@
   return true;
 }
 
-void CallData::CreateDynamicCall(grpc_call_element* elem) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
+void ClientChannel::CallData::CreateDynamicCall(grpc_call_element* elem) {
+  auto* chand = static_cast<ClientChannel*>(elem->channel_data);
   DynamicFilters::Call::Args args = {std::move(dynamic_filters_),
                                      pollent_,
                                      path_,
@@ -3164,14 +2402,20 @@
                                      arena_,
                                      call_context_,
                                      call_combiner_};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   DynamicFilters* channel_stack = args.channel_stack.get();
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
+    gpr_log(
+        GPR_INFO,
+        "chand=%p calld=%p: creating dynamic call stack on channel_stack=%p",
+        chand, this, channel_stack);
+  }
   dynamic_call_ = channel_stack->CreateCall(std::move(args), &error);
   if (error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO,
               "chand=%p calld=%p: failed to create dynamic call: error=%s",
-              chand, this, grpc_error_string(error));
+              chand, this, grpc_error_std_string(error).c_str());
     }
     PendingBatchesFail(elem, error, YieldCallCombiner);
     return;
@@ -3180,1613 +2424,10 @@
 }
 
 //
-// RetryingCall implementation
+// ClientChannel::LoadBalancedCall::Metadata
 //
 
-// Retry support:
-//
-// In order to support retries, we act as a proxy for stream op batches.
-// When we get a batch from the surface, we add it to our list of pending
-// batches, and we then use those batches to construct separate "child"
-// batches to be started on the subchannel call.  When the child batches
-// return, we then decide which pending batches have been completed and
-// schedule their callbacks accordingly.  If a subchannel call fails and
-// we want to retry it, we do a new pick and start again, constructing
-// new "child" batches for the new subchannel call.
-//
-// Note that retries are committed when receiving data from the server
-// (except for Trailers-Only responses).  However, there may be many
-// send ops started before receiving any data, so we may have already
-// completed some number of send ops (and returned the completions up to
-// the surface) by the time we realize that we need to retry.  To deal
-// with this, we cache data for send ops, so that we can replay them on a
-// different subchannel call even after we have completed the original
-// batches.
-//
-// There are two sets of data to maintain:
-// - In call_data (in the parent channel), we maintain a list of pending
-//   ops and cached data for send ops.
-// - In the subchannel call, we maintain state to indicate what ops have
-//   already been sent down to that call.
-//
-// When constructing the "child" batches, we compare those two sets of
-// data to see which batches need to be sent to the subchannel call.
-
-// TODO(roth): In subsequent PRs:
-// - add support for transparent retries (including initial metadata)
-// - figure out how to record stats in census for retries
-//   (census filter is on top of this one)
-// - add census stats for retries
-
-RetryingCall::RetryingCall(
-    ChannelData* chand, const grpc_call_element_args& args,
-    grpc_polling_entity* pollent,
-    RefCountedPtr<ServerRetryThrottleData> retry_throttle_data,
-    const ClientChannelMethodParsedConfig::RetryPolicy* retry_policy)
-    : chand_(chand),
-      pollent_(pollent),
-      retry_throttle_data_(std::move(retry_throttle_data)),
-      retry_policy_(retry_policy),
-      retry_backoff_(
-          BackOff::Options()
-              .set_initial_backoff(
-                  retry_policy_ == nullptr ? 0 : retry_policy_->initial_backoff)
-              .set_multiplier(retry_policy_ == nullptr
-                                  ? 0
-                                  : retry_policy_->backoff_multiplier)
-              .set_jitter(RETRY_BACKOFF_JITTER)
-              .set_max_backoff(
-                  retry_policy_ == nullptr ? 0 : retry_policy_->max_backoff)),
-      path_(grpc_slice_ref_internal(args.path)),
-      call_start_time_(args.start_time),
-      deadline_(args.deadline),
-      arena_(args.arena),
-      owning_call_(args.call_stack),
-      call_combiner_(args.call_combiner),
-      call_context_(args.context),
-      pending_send_initial_metadata_(false),
-      pending_send_message_(false),
-      pending_send_trailing_metadata_(false),
-      enable_retries_(true),
-      retry_committed_(false),
-      last_attempt_got_server_pushback_(false) {}
-
-RetryingCall::~RetryingCall() {
-  grpc_slice_unref_internal(path_);
-  GRPC_ERROR_UNREF(cancel_error_);
-  // Make sure there are no remaining pending batches.
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    GPR_ASSERT(pending_batches_[i].batch == nullptr);
-  }
-}
-
-void RetryingCall::StartTransportStreamOpBatch(
-    grpc_transport_stream_op_batch* batch) {
-  // If we've previously been cancelled, immediately fail any new batches.
-  if (GPR_UNLIKELY(cancel_error_ != GRPC_ERROR_NONE)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: failing batch with error: %s", chand_,
-              this, grpc_error_string(cancel_error_));
-    }
-    // Note: This will release the call combiner.
-    grpc_transport_stream_op_batch_finish_with_failure(
-        batch, GRPC_ERROR_REF(cancel_error_), call_combiner_);
-    return;
-  }
-  // Handle cancellation.
-  if (GPR_UNLIKELY(batch->cancel_stream)) {
-    // Stash a copy of cancel_error in our call data, so that we can use
-    // it for subsequent operations.  This ensures that if the call is
-    // cancelled before any batches are passed down (e.g., if the deadline
-    // is in the past when the call starts), we can return the right
-    // error to the caller when the first batch does get passed down.
-    GRPC_ERROR_UNREF(cancel_error_);
-    cancel_error_ = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: recording cancel_error=%s",
-              chand_, this, grpc_error_string(cancel_error_));
-    }
-    // If we do not have an LB call (i.e., a pick has not yet been started),
-    // fail all pending batches.  Otherwise, send the cancellation down to the
-    // LB call.
-    if (lb_call_ == nullptr) {
-      // TODO(roth): If there is a pending retry callback, do we need to
-      // cancel it here?
-      PendingBatchesFail(GRPC_ERROR_REF(cancel_error_), NoYieldCallCombiner);
-      // Note: This will release the call combiner.
-      grpc_transport_stream_op_batch_finish_with_failure(
-          batch, GRPC_ERROR_REF(cancel_error_), call_combiner_);
-    } else {
-      // Note: This will release the call combiner.
-      lb_call_->StartTransportStreamOpBatch(batch);
-    }
-    return;
-  }
-  // Add the batch to the pending list.
-  PendingBatchesAdd(batch);
-  // Create LB call if needed.
-  // TODO(roth): If we get a new batch from the surface after the
-  // initial retry attempt has failed, while the retry timer is pending,
-  // we should queue the batch and not try to send it immediately.
-  if (lb_call_ == nullptr) {
-    // We do not yet have an LB call, so create one.
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: creating LB call", chand_,
-              this);
-    }
-    CreateLbCall(this, GRPC_ERROR_NONE);
-    return;
-  }
-  // Send batches to LB call.
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO, "chand=%p retrying_call=%p: starting batch on lb_call=%p",
-            chand_, this, lb_call_.get());
-  }
-  PendingBatchesResume();
-}
-
-RefCountedPtr<SubchannelCall> RetryingCall::subchannel_call() const {
-  if (lb_call_ == nullptr) return nullptr;
-  return lb_call_->subchannel_call();
-}
-
-//
-// send op data caching
-//
-
-void RetryingCall::MaybeCacheSendOpsForBatch(PendingBatch* pending) {
-  if (pending->send_ops_cached) return;
-  pending->send_ops_cached = true;
-  grpc_transport_stream_op_batch* batch = pending->batch;
-  // Save a copy of metadata for send_initial_metadata ops.
-  if (batch->send_initial_metadata) {
-    seen_send_initial_metadata_ = true;
-    GPR_ASSERT(send_initial_metadata_storage_ == nullptr);
-    grpc_metadata_batch* send_initial_metadata =
-        batch->payload->send_initial_metadata.send_initial_metadata;
-    send_initial_metadata_storage_ =
-        static_cast<grpc_linked_mdelem*>(arena_->Alloc(
-            sizeof(grpc_linked_mdelem) * send_initial_metadata->list.count));
-    grpc_metadata_batch_copy(send_initial_metadata, &send_initial_metadata_,
-                             send_initial_metadata_storage_);
-    send_initial_metadata_flags_ =
-        batch->payload->send_initial_metadata.send_initial_metadata_flags;
-    peer_string_ = batch->payload->send_initial_metadata.peer_string;
-  }
-  // Set up cache for send_message ops.
-  if (batch->send_message) {
-    ByteStreamCache* cache = arena_->New<ByteStreamCache>(
-        std::move(batch->payload->send_message.send_message));
-    send_messages_.push_back(cache);
-  }
-  // Save metadata batch for send_trailing_metadata ops.
-  if (batch->send_trailing_metadata) {
-    seen_send_trailing_metadata_ = true;
-    GPR_ASSERT(send_trailing_metadata_storage_ == nullptr);
-    grpc_metadata_batch* send_trailing_metadata =
-        batch->payload->send_trailing_metadata.send_trailing_metadata;
-    send_trailing_metadata_storage_ =
-        static_cast<grpc_linked_mdelem*>(arena_->Alloc(
-            sizeof(grpc_linked_mdelem) * send_trailing_metadata->list.count));
-    grpc_metadata_batch_copy(send_trailing_metadata, &send_trailing_metadata_,
-                             send_trailing_metadata_storage_);
-  }
-}
-
-void RetryingCall::FreeCachedSendInitialMetadata() {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: destroying send_initial_metadata",
-            chand_, this);
-  }
-  grpc_metadata_batch_destroy(&send_initial_metadata_);
-}
-
-void RetryingCall::FreeCachedSendMessage(size_t idx) {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: destroying send_messages[%" PRIuPTR "]",
-            chand_, this, idx);
-  }
-  send_messages_[idx]->Destroy();
-}
-
-void RetryingCall::FreeCachedSendTrailingMetadata() {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand_=%p retrying_call=%p: destroying send_trailing_metadata",
-            chand_, this);
-  }
-  grpc_metadata_batch_destroy(&send_trailing_metadata_);
-}
-
-void RetryingCall::FreeCachedSendOpDataAfterCommit(
-    SubchannelCallRetryState* retry_state) {
-  if (retry_state->completed_send_initial_metadata) {
-    FreeCachedSendInitialMetadata();
-  }
-  for (size_t i = 0; i < retry_state->completed_send_message_count; ++i) {
-    FreeCachedSendMessage(i);
-  }
-  if (retry_state->completed_send_trailing_metadata) {
-    FreeCachedSendTrailingMetadata();
-  }
-}
-
-void RetryingCall::FreeCachedSendOpDataForCompletedBatch(
-    SubchannelCallBatchData* batch_data,
-    SubchannelCallRetryState* retry_state) {
-  if (batch_data->batch.send_initial_metadata) {
-    FreeCachedSendInitialMetadata();
-  }
-  if (batch_data->batch.send_message) {
-    FreeCachedSendMessage(retry_state->completed_send_message_count - 1);
-  }
-  if (batch_data->batch.send_trailing_metadata) {
-    FreeCachedSendTrailingMetadata();
-  }
-}
-
-//
-// pending_batches management
-//
-
-size_t RetryingCall::GetBatchIndex(grpc_transport_stream_op_batch* batch) {
-  // Note: It is important the send_initial_metadata be the first entry
-  // here, since the code in pick_subchannel_locked() assumes it will be.
-  if (batch->send_initial_metadata) return 0;
-  if (batch->send_message) return 1;
-  if (batch->send_trailing_metadata) return 2;
-  if (batch->recv_initial_metadata) return 3;
-  if (batch->recv_message) return 4;
-  if (batch->recv_trailing_metadata) return 5;
-  GPR_UNREACHABLE_CODE(return (size_t)-1);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void RetryingCall::PendingBatchesAdd(grpc_transport_stream_op_batch* batch) {
-  const size_t idx = GetBatchIndex(batch);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(
-        GPR_INFO,
-        "chand_=%p retrying_call=%p: adding pending batch at index %" PRIuPTR,
-        chand_, this, idx);
-  }
-  PendingBatch* pending = &pending_batches_[idx];
-  GPR_ASSERT(pending->batch == nullptr);
-  pending->batch = batch;
-  pending->send_ops_cached = false;
-  if (enable_retries_) {
-    // Update state in calld about pending batches.
-    // Also check if the batch takes us over the retry buffer limit.
-    // Note: We don't check the size of trailing metadata here, because
-    // gRPC clients do not send trailing metadata.
-    if (batch->send_initial_metadata) {
-      pending_send_initial_metadata_ = true;
-      bytes_buffered_for_retry_ += grpc_metadata_batch_size(
-          batch->payload->send_initial_metadata.send_initial_metadata);
-    }
-    if (batch->send_message) {
-      pending_send_message_ = true;
-      bytes_buffered_for_retry_ +=
-          batch->payload->send_message.send_message->length();
-    }
-    if (batch->send_trailing_metadata) {
-      pending_send_trailing_metadata_ = true;
-    }
-    if (GPR_UNLIKELY(bytes_buffered_for_retry_ >
-                     chand_->per_rpc_retry_buffer_size())) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(GPR_INFO,
-                "chand=%p retrying_call=%p: exceeded retry buffer size, "
-                "committing",
-                chand_, this);
-      }
-      SubchannelCallRetryState* retry_state =
-          lb_call_ == nullptr ? nullptr
-                              : static_cast<SubchannelCallRetryState*>(
-                                    lb_call_->GetParentData());
-      RetryCommit(retry_state);
-      // If we are not going to retry and have not yet started, pretend
-      // retries are disabled so that we don't bother with retry overhead.
-      if (num_attempts_completed_ == 0) {
-        if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-          gpr_log(GPR_INFO,
-                  "chand=%p retrying_call=%p: disabling retries before first "
-                  "attempt",
-                  chand_, this);
-        }
-        // TODO(roth): Treat this as a commit?
-        enable_retries_ = false;
-      }
-    }
-  }
-}
-
-void RetryingCall::PendingBatchClear(PendingBatch* pending) {
-  if (enable_retries_) {
-    if (pending->batch->send_initial_metadata) {
-      pending_send_initial_metadata_ = false;
-    }
-    if (pending->batch->send_message) {
-      pending_send_message_ = false;
-    }
-    if (pending->batch->send_trailing_metadata) {
-      pending_send_trailing_metadata_ = false;
-    }
-  }
-  pending->batch = nullptr;
-}
-
-void RetryingCall::MaybeClearPendingBatch(PendingBatch* pending) {
-  grpc_transport_stream_op_batch* batch = pending->batch;
-  // We clear the pending batch if all of its callbacks have been
-  // scheduled and reset to nullptr.
-  if (batch->on_complete == nullptr &&
-      (!batch->recv_initial_metadata ||
-       batch->payload->recv_initial_metadata.recv_initial_metadata_ready ==
-           nullptr) &&
-      (!batch->recv_message ||
-       batch->payload->recv_message.recv_message_ready == nullptr) &&
-      (!batch->recv_trailing_metadata ||
-       batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready ==
-           nullptr)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: clearing pending batch",
-              chand_, this);
-    }
-    PendingBatchClear(pending);
-  }
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void RetryingCall::FailPendingBatchInCallCombiner(void* arg,
-                                                  grpc_error* error) {
-  grpc_transport_stream_op_batch* batch =
-      static_cast<grpc_transport_stream_op_batch*>(arg);
-  RetryingCall* call =
-      static_cast<RetryingCall*>(batch->handler_private.extra_arg);
-  // Note: This will release the call combiner.
-  grpc_transport_stream_op_batch_finish_with_failure(
-      batch, GRPC_ERROR_REF(error), call->call_combiner_);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void RetryingCall::PendingBatchesFail(
-    grpc_error* error,
-    YieldCallCombinerPredicate yield_call_combiner_predicate) {
-  GPR_ASSERT(error != GRPC_ERROR_NONE);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    size_t num_batches = 0;
-    for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-      if (pending_batches_[i].batch != nullptr) ++num_batches;
-    }
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: failing %" PRIuPTR
-            " pending batches: %s",
-            chand_, this, num_batches, grpc_error_string(error));
-  }
-  CallCombinerClosureList closures;
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    grpc_transport_stream_op_batch* batch = pending->batch;
-    if (batch != nullptr) {
-      batch->handler_private.extra_arg = this;
-      GRPC_CLOSURE_INIT(&batch->handler_private.closure,
-                        FailPendingBatchInCallCombiner, batch,
-                        grpc_schedule_on_exec_ctx);
-      closures.Add(&batch->handler_private.closure, GRPC_ERROR_REF(error),
-                   "PendingBatchesFail");
-      PendingBatchClear(pending);
-    }
-  }
-  if (yield_call_combiner_predicate(closures)) {
-    closures.RunClosures(call_combiner_);
-  } else {
-    closures.RunClosuresWithoutYielding(call_combiner_);
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void RetryingCall::ResumePendingBatchInCallCombiner(void* arg,
-                                                    grpc_error* /*ignored*/) {
-  grpc_transport_stream_op_batch* batch =
-      static_cast<grpc_transport_stream_op_batch*>(arg);
-  auto* lb_call =
-      static_cast<LoadBalancedCall*>(batch->handler_private.extra_arg);
-  // Note: This will release the call combiner.
-  lb_call->StartTransportStreamOpBatch(batch);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-void RetryingCall::PendingBatchesResume() {
-  if (enable_retries_) {
-    StartRetriableSubchannelBatches(this, GRPC_ERROR_NONE);
-    return;
-  }
-  // Retries not enabled; send down batches as-is.
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    size_t num_batches = 0;
-    for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-      if (pending_batches_[i].batch != nullptr) ++num_batches;
-    }
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: starting %" PRIuPTR
-            " pending batches on lb_call=%p",
-            chand_, this, num_batches, lb_call_.get());
-  }
-  CallCombinerClosureList closures;
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    grpc_transport_stream_op_batch* batch = pending->batch;
-    if (batch != nullptr) {
-      batch->handler_private.extra_arg = lb_call_.get();
-      GRPC_CLOSURE_INIT(&batch->handler_private.closure,
-                        ResumePendingBatchInCallCombiner, batch, nullptr);
-      closures.Add(&batch->handler_private.closure, GRPC_ERROR_NONE,
-                   "PendingBatchesResume");
-      PendingBatchClear(pending);
-    }
-  }
-  // Note: This will release the call combiner.
-  closures.RunClosures(call_combiner_);
-}
-
-template <typename Predicate>
-RetryingCall::PendingBatch* RetryingCall::PendingBatchFind(
-    const char* log_message, Predicate predicate) {
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    grpc_transport_stream_op_batch* batch = pending->batch;
-    if (batch != nullptr && predicate(batch)) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(
-            GPR_INFO,
-            "chand=%p retrying_call=%p: %s pending batch at index %" PRIuPTR,
-            chand_, this, log_message, i);
-      }
-      return pending;
-    }
-  }
-  return nullptr;
-}
-
-//
-// retry code
-//
-
-void RetryingCall::RetryCommit(SubchannelCallRetryState* retry_state) {
-  if (retry_committed_) return;
-  retry_committed_ = true;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO, "chand=%p retrying_call=%p: committing retries", chand_,
-            this);
-  }
-  if (retry_state != nullptr) {
-    FreeCachedSendOpDataAfterCommit(retry_state);
-  }
-}
-
-void RetryingCall::DoRetry(SubchannelCallRetryState* retry_state,
-                           grpc_millis server_pushback_ms) {
-  GPR_ASSERT(retry_policy_ != nullptr);
-  // Reset LB call.
-  lb_call_.reset();
-  // Compute backoff delay.
-  grpc_millis next_attempt_time;
-  if (server_pushback_ms >= 0) {
-    next_attempt_time = ExecCtx::Get()->Now() + server_pushback_ms;
-    last_attempt_got_server_pushback_ = true;
-  } else {
-    if (num_attempts_completed_ == 1 || last_attempt_got_server_pushback_) {
-      last_attempt_got_server_pushback_ = false;
-    }
-    next_attempt_time = retry_backoff_.NextAttemptTime();
-  }
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: retrying failed call in %" PRId64 " ms",
-            chand_, this, next_attempt_time - ExecCtx::Get()->Now());
-  }
-  // Schedule retry after computed delay.
-  GRPC_CLOSURE_INIT(&retry_closure_, CreateLbCall, this, nullptr);
-  grpc_timer_init(&retry_timer_, next_attempt_time, &retry_closure_);
-  // Update bookkeeping.
-  if (retry_state != nullptr) retry_state->retry_dispatched = true;
-}
-
-bool RetryingCall::MaybeRetry(SubchannelCallBatchData* batch_data,
-                              grpc_status_code status,
-                              grpc_mdelem* server_pushback_md) {
-  // Get retry policy.
-  if (retry_policy_ == nullptr) return false;
-  // If we've already dispatched a retry from this call, return true.
-  // This catches the case where the batch has multiple callbacks
-  // (i.e., it includes either recv_message or recv_initial_metadata).
-  SubchannelCallRetryState* retry_state = nullptr;
-  if (batch_data != nullptr) {
-    retry_state = static_cast<SubchannelCallRetryState*>(
-        batch_data->lb_call->GetParentData());
-    if (retry_state->retry_dispatched) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(GPR_INFO, "chand=%p retrying_call=%p: retry already dispatched",
-                chand_, this);
-      }
-      return true;
-    }
-  }
-  // Check status.
-  if (GPR_LIKELY(status == GRPC_STATUS_OK)) {
-    if (retry_throttle_data_ != nullptr) {
-      retry_throttle_data_->RecordSuccess();
-    }
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: call succeeded", chand_,
-              this);
-    }
-    return false;
-  }
-  // Status is not OK.  Check whether the status is retryable.
-  if (!retry_policy_->retryable_status_codes.Contains(status)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(
-          GPR_INFO,
-          "chand=%p retrying_call=%p: status %s not configured as retryable",
-          chand_, this, grpc_status_code_to_string(status));
-    }
-    return false;
-  }
-  // Record the failure and check whether retries are throttled.
-  // Note that it's important for this check to come after the status
-  // code check above, since we should only record failures whose statuses
-  // match the configured retryable status codes, so that we don't count
-  // things like failures due to malformed requests (INVALID_ARGUMENT).
-  // Conversely, it's important for this to come before the remaining
-  // checks, so that we don't fail to record failures due to other factors.
-  if (retry_throttle_data_ != nullptr &&
-      !retry_throttle_data_->RecordFailure()) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: retries throttled", chand_,
-              this);
-    }
-    return false;
-  }
-  // Check whether the call is committed.
-  if (retry_committed_) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: retries already committed",
-              chand_, this);
-    }
-    return false;
-  }
-  // Check whether we have retries remaining.
-  ++num_attempts_completed_;
-  if (num_attempts_completed_ >= retry_policy_->max_attempts) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO, "chand=%p retrying_call=%p: exceeded %d retry attempts",
-              chand_, this, retry_policy_->max_attempts);
-    }
-    return false;
-  }
-  // If the call was cancelled from the surface, don't retry.
-  if (cancel_error_ != GRPC_ERROR_NONE) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: call cancelled from surface, not "
-              "retrying",
-              chand_, this);
-    }
-    return false;
-  }
-  // Check server push-back.
-  grpc_millis server_pushback_ms = -1;
-  if (server_pushback_md != nullptr) {
-    // If the value is "-1" or any other unparseable string, we do not retry.
-    uint32_t ms;
-    if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(*server_pushback_md), &ms)) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(
-            GPR_INFO,
-            "chand=%p retrying_call=%p: not retrying due to server push-back",
-            chand_, this);
-      }
-      return false;
-    } else {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(GPR_INFO,
-                "chand=%p retrying_call=%p: server push-back: retry in %u ms",
-                chand_, this, ms);
-      }
-      server_pushback_ms = static_cast<grpc_millis>(ms);
-    }
-  }
-  DoRetry(retry_state, server_pushback_ms);
-  return true;
-}
-
-//
-// RetryingCall::SubchannelCallBatchData
-//
-
-RetryingCall::SubchannelCallBatchData*
-RetryingCall::SubchannelCallBatchData::Create(RetryingCall* call, int refcount,
-                                              bool set_on_complete) {
-  return call->arena_->New<SubchannelCallBatchData>(call, refcount,
-                                                    set_on_complete);
-}
-
-RetryingCall::SubchannelCallBatchData::SubchannelCallBatchData(
-    RetryingCall* call, int refcount, bool set_on_complete)
-    : call(call), lb_call(call->lb_call_) {
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(lb_call->GetParentData());
-  batch.payload = &retry_state->batch_payload;
-  gpr_ref_init(&refs, refcount);
-  if (set_on_complete) {
-    GRPC_CLOSURE_INIT(&on_complete, RetryingCall::OnComplete, this,
-                      grpc_schedule_on_exec_ctx);
-    batch.on_complete = &on_complete;
-  }
-  GRPC_CALL_STACK_REF(call->owning_call_, "batch_data");
-}
-
-void RetryingCall::SubchannelCallBatchData::Destroy() {
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(lb_call->GetParentData());
-  if (batch.send_initial_metadata) {
-    grpc_metadata_batch_destroy(&retry_state->send_initial_metadata);
-  }
-  if (batch.send_trailing_metadata) {
-    grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata);
-  }
-  if (batch.recv_initial_metadata) {
-    grpc_metadata_batch_destroy(&retry_state->recv_initial_metadata);
-  }
-  if (batch.recv_trailing_metadata) {
-    grpc_metadata_batch_destroy(&retry_state->recv_trailing_metadata);
-  }
-  lb_call.reset();
-  GRPC_CALL_STACK_UNREF(call->owning_call_, "batch_data");
-}
-
-//
-// recv_initial_metadata callback handling
-//
-
-void RetryingCall::InvokeRecvInitialMetadataCallback(void* arg,
-                                                     grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  // Find pending batch.
-  PendingBatch* pending = batch_data->call->PendingBatchFind(
-      "invoking recv_initial_metadata_ready for",
-      [](grpc_transport_stream_op_batch* batch) {
-        return batch->recv_initial_metadata &&
-               batch->payload->recv_initial_metadata
-                       .recv_initial_metadata_ready != nullptr;
-      });
-  GPR_ASSERT(pending != nullptr);
-  // Return metadata.
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  grpc_metadata_batch_move(
-      &retry_state->recv_initial_metadata,
-      pending->batch->payload->recv_initial_metadata.recv_initial_metadata);
-  // Update bookkeeping.
-  // Note: Need to do this before invoking the callback, since invoking
-  // the callback will result in yielding the call combiner.
-  grpc_closure* recv_initial_metadata_ready =
-      pending->batch->payload->recv_initial_metadata
-          .recv_initial_metadata_ready;
-  pending->batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
-      nullptr;
-  batch_data->call->MaybeClearPendingBatch(pending);
-  batch_data->Unref();
-  // Invoke callback.
-  Closure::Run(DEBUG_LOCATION, recv_initial_metadata_ready,
-               GRPC_ERROR_REF(error));
-}
-
-void RetryingCall::RecvInitialMetadataReady(void* arg, grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(
-        GPR_INFO,
-        "chand=%p retrying_call=%p: got recv_initial_metadata_ready, error=%s",
-        call->chand_, call, grpc_error_string(error));
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  retry_state->completed_recv_initial_metadata = true;
-  // If a retry was already dispatched, then we're not going to use the
-  // result of this recv_initial_metadata op, so do nothing.
-  if (retry_state->retry_dispatched) {
-    GRPC_CALL_COMBINER_STOP(
-        call->call_combiner_,
-        "recv_initial_metadata_ready after retry dispatched");
-    return;
-  }
-  // If we got an error or a Trailers-Only response and have not yet gotten
-  // the recv_trailing_metadata_ready callback, then defer propagating this
-  // callback back to the surface.  We can evaluate whether to retry when
-  // recv_trailing_metadata comes back.
-  if (GPR_UNLIKELY((retry_state->trailing_metadata_available ||
-                    error != GRPC_ERROR_NONE) &&
-                   !retry_state->completed_recv_trailing_metadata)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(
-          GPR_INFO,
-          "chand=%p retrying_call=%p: deferring recv_initial_metadata_ready "
-          "(Trailers-Only)",
-          call->chand_, call);
-    }
-    retry_state->recv_initial_metadata_ready_deferred_batch = batch_data;
-    retry_state->recv_initial_metadata_error = GRPC_ERROR_REF(error);
-    if (!retry_state->started_recv_trailing_metadata) {
-      // recv_trailing_metadata not yet started by application; start it
-      // ourselves to get status.
-      call->StartInternalRecvTrailingMetadata();
-    } else {
-      GRPC_CALL_COMBINER_STOP(
-          call->call_combiner_,
-          "recv_initial_metadata_ready trailers-only or error");
-    }
-    return;
-  }
-  // Received valid initial metadata, so commit the call.
-  call->RetryCommit(retry_state);
-  // Invoke the callback to return the result to the surface.
-  // Manually invoking a callback function; it does not take ownership of error.
-  call->InvokeRecvInitialMetadataCallback(batch_data, error);
-}
-
-//
-// recv_message callback handling
-//
-
-void RetryingCall::InvokeRecvMessageCallback(void* arg, grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  // Find pending op.
-  PendingBatch* pending = call->PendingBatchFind(
-      "invoking recv_message_ready for",
-      [](grpc_transport_stream_op_batch* batch) {
-        return batch->recv_message &&
-               batch->payload->recv_message.recv_message_ready != nullptr;
-      });
-  GPR_ASSERT(pending != nullptr);
-  // Return payload.
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  *pending->batch->payload->recv_message.recv_message =
-      std::move(retry_state->recv_message);
-  // Update bookkeeping.
-  // Note: Need to do this before invoking the callback, since invoking
-  // the callback will result in yielding the call combiner.
-  grpc_closure* recv_message_ready =
-      pending->batch->payload->recv_message.recv_message_ready;
-  pending->batch->payload->recv_message.recv_message_ready = nullptr;
-  call->MaybeClearPendingBatch(pending);
-  batch_data->Unref();
-  // Invoke callback.
-  Closure::Run(DEBUG_LOCATION, recv_message_ready, GRPC_ERROR_REF(error));
-}
-
-void RetryingCall::RecvMessageReady(void* arg, grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: got recv_message_ready, error=%s",
-            call->chand_, call, grpc_error_string(error));
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  ++retry_state->completed_recv_message_count;
-  // If a retry was already dispatched, then we're not going to use the
-  // result of this recv_message op, so do nothing.
-  if (retry_state->retry_dispatched) {
-    GRPC_CALL_COMBINER_STOP(call->call_combiner_,
-                            "recv_message_ready after retry dispatched");
-    return;
-  }
-  // If we got an error or the payload was nullptr and we have not yet gotten
-  // the recv_trailing_metadata_ready callback, then defer propagating this
-  // callback back to the surface.  We can evaluate whether to retry when
-  // recv_trailing_metadata comes back.
-  if (GPR_UNLIKELY(
-          (retry_state->recv_message == nullptr || error != GRPC_ERROR_NONE) &&
-          !retry_state->completed_recv_trailing_metadata)) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(
-          GPR_INFO,
-          "chand=%p retrying_call=%p: deferring recv_message_ready (nullptr "
-          "message and recv_trailing_metadata pending)",
-          call->chand_, call);
-    }
-    retry_state->recv_message_ready_deferred_batch = batch_data;
-    retry_state->recv_message_error = GRPC_ERROR_REF(error);
-    if (!retry_state->started_recv_trailing_metadata) {
-      // recv_trailing_metadata not yet started by application; start it
-      // ourselves to get status.
-      call->StartInternalRecvTrailingMetadata();
-    } else {
-      GRPC_CALL_COMBINER_STOP(call->call_combiner_, "recv_message_ready null");
-    }
-    return;
-  }
-  // Received a valid message, so commit the call.
-  call->RetryCommit(retry_state);
-  // Invoke the callback to return the result to the surface.
-  // Manually invoking a callback function; it does not take ownership of error.
-  call->InvokeRecvMessageCallback(batch_data, error);
-}
-
-//
-// recv_trailing_metadata handling
-//
-
-void RetryingCall::GetCallStatus(grpc_metadata_batch* md_batch,
-                                 grpc_error* error, grpc_status_code* status,
-                                 grpc_mdelem** server_pushback_md) {
-  if (error != GRPC_ERROR_NONE) {
-    grpc_error_get_status(error, deadline_, status, nullptr, nullptr, nullptr);
-  } else {
-    GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
-    *status =
-        grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
-    if (server_pushback_md != nullptr &&
-        md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
-      *server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
-    }
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-void RetryingCall::AddClosureForRecvTrailingMetadataReady(
-    SubchannelCallBatchData* batch_data, grpc_error* error,
-    CallCombinerClosureList* closures) {
-  // Find pending batch.
-  PendingBatch* pending = PendingBatchFind(
-      "invoking recv_trailing_metadata for",
-      [](grpc_transport_stream_op_batch* batch) {
-        return batch->recv_trailing_metadata &&
-               batch->payload->recv_trailing_metadata
-                       .recv_trailing_metadata_ready != nullptr;
-      });
-  // If we generated the recv_trailing_metadata op internally via
-  // StartInternalRecvTrailingMetadata(), then there will be no pending batch.
-  if (pending == nullptr) {
-    GRPC_ERROR_UNREF(error);
-    return;
-  }
-  // Return metadata.
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  grpc_metadata_batch_move(
-      &retry_state->recv_trailing_metadata,
-      pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata);
-  // Add closure.
-  closures->Add(pending->batch->payload->recv_trailing_metadata
-                    .recv_trailing_metadata_ready,
-                error, "recv_trailing_metadata_ready for pending batch");
-  // Update bookkeeping.
-  pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
-      nullptr;
-  MaybeClearPendingBatch(pending);
-}
-
-void RetryingCall::AddClosuresForDeferredRecvCallbacks(
-    SubchannelCallBatchData* batch_data, SubchannelCallRetryState* retry_state,
-    CallCombinerClosureList* closures) {
-  if (batch_data->batch.recv_trailing_metadata) {
-    // Add closure for deferred recv_initial_metadata_ready.
-    if (GPR_UNLIKELY(retry_state->recv_initial_metadata_ready_deferred_batch !=
-                     nullptr)) {
-      GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready,
-                        InvokeRecvInitialMetadataCallback,
-                        retry_state->recv_initial_metadata_ready_deferred_batch,
-                        grpc_schedule_on_exec_ctx);
-      closures->Add(&retry_state->recv_initial_metadata_ready,
-                    retry_state->recv_initial_metadata_error,
-                    "resuming recv_initial_metadata_ready");
-      retry_state->recv_initial_metadata_ready_deferred_batch = nullptr;
-    }
-    // Add closure for deferred recv_message_ready.
-    if (GPR_UNLIKELY(retry_state->recv_message_ready_deferred_batch !=
-                     nullptr)) {
-      GRPC_CLOSURE_INIT(&retry_state->recv_message_ready,
-                        InvokeRecvMessageCallback,
-                        retry_state->recv_message_ready_deferred_batch,
-                        grpc_schedule_on_exec_ctx);
-      closures->Add(&retry_state->recv_message_ready,
-                    retry_state->recv_message_error,
-                    "resuming recv_message_ready");
-      retry_state->recv_message_ready_deferred_batch = nullptr;
-    }
-  }
-}
-
-bool RetryingCall::PendingBatchIsUnstarted(
-    PendingBatch* pending, SubchannelCallRetryState* retry_state) {
-  if (pending->batch == nullptr || pending->batch->on_complete == nullptr) {
-    return false;
-  }
-  if (pending->batch->send_initial_metadata &&
-      !retry_state->started_send_initial_metadata) {
-    return true;
-  }
-  if (pending->batch->send_message &&
-      retry_state->started_send_message_count < send_messages_.size()) {
-    return true;
-  }
-  if (pending->batch->send_trailing_metadata &&
-      !retry_state->started_send_trailing_metadata) {
-    return true;
-  }
-  return false;
-}
-
-void RetryingCall::AddClosuresToFailUnstartedPendingBatches(
-    SubchannelCallRetryState* retry_state, grpc_error* error,
-    CallCombinerClosureList* closures) {
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    if (PendingBatchIsUnstarted(pending, retry_state)) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-        gpr_log(GPR_INFO,
-                "chand=%p retrying_call=%p: failing unstarted pending batch at "
-                "index "
-                "%" PRIuPTR,
-                chand_, this, i);
-      }
-      closures->Add(pending->batch->on_complete, GRPC_ERROR_REF(error),
-                    "failing on_complete for pending batch");
-      pending->batch->on_complete = nullptr;
-      MaybeClearPendingBatch(pending);
-    }
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-void RetryingCall::RunClosuresForCompletedCall(
-    SubchannelCallBatchData* batch_data, grpc_error* error) {
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  // Construct list of closures to execute.
-  CallCombinerClosureList closures;
-  // First, add closure for recv_trailing_metadata_ready.
-  AddClosureForRecvTrailingMetadataReady(batch_data, GRPC_ERROR_REF(error),
-                                         &closures);
-  // If there are deferred recv_initial_metadata_ready or recv_message_ready
-  // callbacks, add them to closures.
-  AddClosuresForDeferredRecvCallbacks(batch_data, retry_state, &closures);
-  // Add closures to fail any pending batches that have not yet been started.
-  AddClosuresToFailUnstartedPendingBatches(retry_state, GRPC_ERROR_REF(error),
-                                           &closures);
-  // Don't need batch_data anymore.
-  batch_data->Unref();
-  // Schedule all of the closures identified above.
-  // Note: This will release the call combiner.
-  closures.RunClosures(call_combiner_);
-  GRPC_ERROR_UNREF(error);
-}
-
-void RetryingCall::RecvTrailingMetadataReady(void* arg, grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(
-        GPR_INFO,
-        "chand=%p retrying_call=%p: got recv_trailing_metadata_ready, error=%s",
-        call->chand_, call, grpc_error_string(error));
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  retry_state->completed_recv_trailing_metadata = true;
-  // Get the call's status and check for server pushback metadata.
-  grpc_status_code status = GRPC_STATUS_OK;
-  grpc_mdelem* server_pushback_md = nullptr;
-  grpc_metadata_batch* md_batch =
-      batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata;
-  call->GetCallStatus(md_batch, GRPC_ERROR_REF(error), &status,
-                      &server_pushback_md);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO, "chand=%p retrying_call=%p: call finished, status=%s",
-            call->chand_, call, grpc_status_code_to_string(status));
-  }
-  // Check if we should retry.
-  if (call->MaybeRetry(batch_data, status, server_pushback_md)) {
-    // Unref batch_data for deferred recv_initial_metadata_ready or
-    // recv_message_ready callbacks, if any.
-    if (retry_state->recv_initial_metadata_ready_deferred_batch != nullptr) {
-      batch_data->Unref();
-      GRPC_ERROR_UNREF(retry_state->recv_initial_metadata_error);
-    }
-    if (retry_state->recv_message_ready_deferred_batch != nullptr) {
-      batch_data->Unref();
-      GRPC_ERROR_UNREF(retry_state->recv_message_error);
-    }
-    batch_data->Unref();
-    return;
-  }
-  // Not retrying, so commit the call.
-  call->RetryCommit(retry_state);
-  // Run any necessary closures.
-  call->RunClosuresForCompletedCall(batch_data, GRPC_ERROR_REF(error));
-}
-
-//
-// on_complete callback handling
-//
-
-void RetryingCall::AddClosuresForCompletedPendingBatch(
-    SubchannelCallBatchData* batch_data, grpc_error* error,
-    CallCombinerClosureList* closures) {
-  PendingBatch* pending = PendingBatchFind(
-      "completed", [batch_data](grpc_transport_stream_op_batch* batch) {
-        // Match the pending batch with the same set of send ops as the
-        // subchannel batch we've just completed.
-        return batch->on_complete != nullptr &&
-               batch_data->batch.send_initial_metadata ==
-                   batch->send_initial_metadata &&
-               batch_data->batch.send_message == batch->send_message &&
-               batch_data->batch.send_trailing_metadata ==
-                   batch->send_trailing_metadata;
-      });
-  // If batch_data is a replay batch, then there will be no pending
-  // batch to complete.
-  if (pending == nullptr) {
-    GRPC_ERROR_UNREF(error);
-    return;
-  }
-  // Add closure.
-  closures->Add(pending->batch->on_complete, error,
-                "on_complete for pending batch");
-  pending->batch->on_complete = nullptr;
-  MaybeClearPendingBatch(pending);
-}
-
-void RetryingCall::AddClosuresForReplayOrPendingSendOps(
-    SubchannelCallBatchData* batch_data, SubchannelCallRetryState* retry_state,
-    CallCombinerClosureList* closures) {
-  bool have_pending_send_message_ops =
-      retry_state->started_send_message_count < send_messages_.size();
-  bool have_pending_send_trailing_metadata_op =
-      seen_send_trailing_metadata_ &&
-      !retry_state->started_send_trailing_metadata;
-  if (!have_pending_send_message_ops &&
-      !have_pending_send_trailing_metadata_op) {
-    for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-      PendingBatch* pending = &pending_batches_[i];
-      grpc_transport_stream_op_batch* batch = pending->batch;
-      if (batch == nullptr || pending->send_ops_cached) continue;
-      if (batch->send_message) have_pending_send_message_ops = true;
-      if (batch->send_trailing_metadata) {
-        have_pending_send_trailing_metadata_op = true;
-      }
-    }
-  }
-  if (have_pending_send_message_ops || have_pending_send_trailing_metadata_op) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: starting next batch for pending send "
-              "op(s)",
-              chand_, this);
-    }
-    GRPC_CLOSURE_INIT(&batch_data->batch.handler_private.closure,
-                      StartRetriableSubchannelBatches, this,
-                      grpc_schedule_on_exec_ctx);
-    closures->Add(&batch_data->batch.handler_private.closure, GRPC_ERROR_NONE,
-                  "starting next batch for send_* op(s)");
-  }
-}
-
-void RetryingCall::OnComplete(void* arg, grpc_error* error) {
-  SubchannelCallBatchData* batch_data =
-      static_cast<SubchannelCallBatchData*>(arg);
-  RetryingCall* call = batch_data->call;
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: got on_complete, error=%s, batch=%s",
-            call->chand_, call, grpc_error_string(error),
-            grpc_transport_stream_op_batch_string(&batch_data->batch).c_str());
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(
-          batch_data->lb_call->GetParentData());
-  // Update bookkeeping in retry_state.
-  if (batch_data->batch.send_initial_metadata) {
-    retry_state->completed_send_initial_metadata = true;
-  }
-  if (batch_data->batch.send_message) {
-    ++retry_state->completed_send_message_count;
-  }
-  if (batch_data->batch.send_trailing_metadata) {
-    retry_state->completed_send_trailing_metadata = true;
-  }
-  // If the call is committed, free cached data for send ops that we've just
-  // completed.
-  if (call->retry_committed_) {
-    call->FreeCachedSendOpDataForCompletedBatch(batch_data, retry_state);
-  }
-  // Construct list of closures to execute.
-  CallCombinerClosureList closures;
-  // If a retry was already dispatched, that means we saw
-  // recv_trailing_metadata before this, so we do nothing here.
-  // Otherwise, invoke the callback to return the result to the surface.
-  if (!retry_state->retry_dispatched) {
-    // Add closure for the completed pending batch, if any.
-    call->AddClosuresForCompletedPendingBatch(batch_data, GRPC_ERROR_REF(error),
-                                              &closures);
-    // If needed, add a callback to start any replay or pending send ops on
-    // the subchannel call.
-    if (!retry_state->completed_recv_trailing_metadata) {
-      call->AddClosuresForReplayOrPendingSendOps(batch_data, retry_state,
-                                                 &closures);
-    }
-  }
-  // Track number of pending subchannel send batches and determine if this
-  // was the last one.
-  --call->num_pending_retriable_subchannel_send_batches_;
-  const bool last_send_batch_complete =
-      call->num_pending_retriable_subchannel_send_batches_ == 0;
-  // Don't need batch_data anymore.
-  batch_data->Unref();
-  // Schedule all of the closures identified above.
-  // Note: This yeilds the call combiner.
-  closures.RunClosures(call->call_combiner_);
-  // If this was the last subchannel send batch, unref the call stack.
-  if (last_send_batch_complete) {
-    GRPC_CALL_STACK_UNREF(call->owning_call_, "subchannel_send_batches");
-  }
-}
-
-//
-// subchannel batch construction
-//
-
-void RetryingCall::StartBatchInCallCombiner(void* arg,
-                                            grpc_error* /*ignored*/) {
-  grpc_transport_stream_op_batch* batch =
-      static_cast<grpc_transport_stream_op_batch*>(arg);
-  auto* lb_call =
-      static_cast<LoadBalancedCall*>(batch->handler_private.extra_arg);
-  // Note: This will release the call combiner.
-  lb_call->StartTransportStreamOpBatch(batch);
-}
-
-void RetryingCall::AddClosureForSubchannelBatch(
-    grpc_transport_stream_op_batch* batch, CallCombinerClosureList* closures) {
-  batch->handler_private.extra_arg = lb_call_.get();
-  GRPC_CLOSURE_INIT(&batch->handler_private.closure, StartBatchInCallCombiner,
-                    batch, grpc_schedule_on_exec_ctx);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: starting subchannel batch: %s", chand_,
-            this, grpc_transport_stream_op_batch_string(batch).c_str());
-  }
-  closures->Add(&batch->handler_private.closure, GRPC_ERROR_NONE,
-                "start_subchannel_batch");
-}
-
-void RetryingCall::AddRetriableSendInitialMetadataOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  // Maps the number of retries to the corresponding metadata value slice.
-  const grpc_slice* retry_count_strings[] = {&GRPC_MDSTR_1, &GRPC_MDSTR_2,
-                                             &GRPC_MDSTR_3, &GRPC_MDSTR_4};
-  // We need to make a copy of the metadata batch for each attempt, since
-  // the filters in the subchannel stack may modify this batch, and we don't
-  // want those modifications to be passed forward to subsequent attempts.
-  //
-  // If we've already completed one or more attempts, add the
-  // grpc-retry-attempts header.
-  retry_state->send_initial_metadata_storage =
-      static_cast<grpc_linked_mdelem*>(arena_->Alloc(
-          sizeof(grpc_linked_mdelem) *
-          (send_initial_metadata_.list.count + (num_attempts_completed_ > 0))));
-  grpc_metadata_batch_copy(&send_initial_metadata_,
-                           &retry_state->send_initial_metadata,
-                           retry_state->send_initial_metadata_storage);
-  if (GPR_UNLIKELY(retry_state->send_initial_metadata.idx.named
-                       .grpc_previous_rpc_attempts != nullptr)) {
-    grpc_metadata_batch_remove(&retry_state->send_initial_metadata,
-                               GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS);
-  }
-  if (GPR_UNLIKELY(num_attempts_completed_ > 0)) {
-    grpc_mdelem retry_md = grpc_mdelem_create(
-        GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
-        *retry_count_strings[num_attempts_completed_ - 1], nullptr);
-    grpc_error* error = grpc_metadata_batch_add_tail(
-        &retry_state->send_initial_metadata,
-        &retry_state
-             ->send_initial_metadata_storage[send_initial_metadata_.list.count],
-        retry_md, GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS);
-    if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
-      gpr_log(GPR_ERROR, "error adding retry metadata: %s",
-              grpc_error_string(error));
-      GPR_ASSERT(false);
-    }
-  }
-  retry_state->started_send_initial_metadata = true;
-  batch_data->batch.send_initial_metadata = true;
-  batch_data->batch.payload->send_initial_metadata.send_initial_metadata =
-      &retry_state->send_initial_metadata;
-  batch_data->batch.payload->send_initial_metadata.send_initial_metadata_flags =
-      send_initial_metadata_flags_;
-  batch_data->batch.payload->send_initial_metadata.peer_string = peer_string_;
-}
-
-void RetryingCall::AddRetriableSendMessageOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: starting calld->send_messages[%" PRIuPTR
-            "]",
-            chand_, this, retry_state->started_send_message_count);
-  }
-  ByteStreamCache* cache =
-      send_messages_[retry_state->started_send_message_count];
-  ++retry_state->started_send_message_count;
-  retry_state->send_message.Init(cache);
-  batch_data->batch.send_message = true;
-  batch_data->batch.payload->send_message.send_message.reset(
-      retry_state->send_message.get());
-}
-
-void RetryingCall::AddRetriableSendTrailingMetadataOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  // We need to make a copy of the metadata batch for each attempt, since
-  // the filters in the subchannel stack may modify this batch, and we don't
-  // want those modifications to be passed forward to subsequent attempts.
-  retry_state->send_trailing_metadata_storage =
-      static_cast<grpc_linked_mdelem*>(arena_->Alloc(
-          sizeof(grpc_linked_mdelem) * send_trailing_metadata_.list.count));
-  grpc_metadata_batch_copy(&send_trailing_metadata_,
-                           &retry_state->send_trailing_metadata,
-                           retry_state->send_trailing_metadata_storage);
-  retry_state->started_send_trailing_metadata = true;
-  batch_data->batch.send_trailing_metadata = true;
-  batch_data->batch.payload->send_trailing_metadata.send_trailing_metadata =
-      &retry_state->send_trailing_metadata;
-}
-
-void RetryingCall::AddRetriableRecvInitialMetadataOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  retry_state->started_recv_initial_metadata = true;
-  batch_data->batch.recv_initial_metadata = true;
-  grpc_metadata_batch_init(&retry_state->recv_initial_metadata);
-  batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata =
-      &retry_state->recv_initial_metadata;
-  batch_data->batch.payload->recv_initial_metadata.trailing_metadata_available =
-      &retry_state->trailing_metadata_available;
-  GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready,
-                    RecvInitialMetadataReady, batch_data,
-                    grpc_schedule_on_exec_ctx);
-  batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata_ready =
-      &retry_state->recv_initial_metadata_ready;
-}
-
-void RetryingCall::AddRetriableRecvMessageOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  ++retry_state->started_recv_message_count;
-  batch_data->batch.recv_message = true;
-  batch_data->batch.payload->recv_message.recv_message =
-      &retry_state->recv_message;
-  GRPC_CLOSURE_INIT(&retry_state->recv_message_ready, RecvMessageReady,
-                    batch_data, grpc_schedule_on_exec_ctx);
-  batch_data->batch.payload->recv_message.recv_message_ready =
-      &retry_state->recv_message_ready;
-}
-
-void RetryingCall::AddRetriableRecvTrailingMetadataOp(
-    SubchannelCallRetryState* retry_state,
-    SubchannelCallBatchData* batch_data) {
-  retry_state->started_recv_trailing_metadata = true;
-  batch_data->batch.recv_trailing_metadata = true;
-  grpc_metadata_batch_init(&retry_state->recv_trailing_metadata);
-  batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata =
-      &retry_state->recv_trailing_metadata;
-  batch_data->batch.payload->recv_trailing_metadata.collect_stats =
-      &retry_state->collect_stats;
-  GRPC_CLOSURE_INIT(&retry_state->recv_trailing_metadata_ready,
-                    RecvTrailingMetadataReady, batch_data,
-                    grpc_schedule_on_exec_ctx);
-  batch_data->batch.payload->recv_trailing_metadata
-      .recv_trailing_metadata_ready =
-      &retry_state->recv_trailing_metadata_ready;
-}
-
-void RetryingCall::StartInternalRecvTrailingMetadata() {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(
-        GPR_INFO,
-        "chand=%p retrying_call=%p: call failed but recv_trailing_metadata not "
-        "started; starting it internally",
-        chand_, this);
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(lb_call_->GetParentData());
-  // Create batch_data with 2 refs, since this batch will be unreffed twice:
-  // once for the recv_trailing_metadata_ready callback when the subchannel
-  // batch returns, and again when we actually get a recv_trailing_metadata
-  // op from the surface.
-  SubchannelCallBatchData* batch_data =
-      SubchannelCallBatchData::Create(this, 2, false /* set_on_complete */);
-  AddRetriableRecvTrailingMetadataOp(retry_state, batch_data);
-  retry_state->recv_trailing_metadata_internal_batch = batch_data;
-  // Note: This will release the call combiner.
-  lb_call_->StartTransportStreamOpBatch(&batch_data->batch);
-}
-
-// If there are any cached send ops that need to be replayed on the
-// current subchannel call, creates and returns a new subchannel batch
-// to replay those ops.  Otherwise, returns nullptr.
-RetryingCall::SubchannelCallBatchData*
-RetryingCall::MaybeCreateSubchannelBatchForReplay(
-    SubchannelCallRetryState* retry_state) {
-  SubchannelCallBatchData* replay_batch_data = nullptr;
-  // send_initial_metadata.
-  if (seen_send_initial_metadata_ &&
-      !retry_state->started_send_initial_metadata &&
-      !pending_send_initial_metadata_) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: replaying previously completed "
-              "send_initial_metadata op",
-              chand_, this);
-    }
-    replay_batch_data =
-        SubchannelCallBatchData::Create(this, 1, true /* set_on_complete */);
-    AddRetriableSendInitialMetadataOp(retry_state, replay_batch_data);
-  }
-  // send_message.
-  // Note that we can only have one send_message op in flight at a time.
-  if (retry_state->started_send_message_count < send_messages_.size() &&
-      retry_state->started_send_message_count ==
-          retry_state->completed_send_message_count &&
-      !pending_send_message_) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: replaying previously completed "
-              "send_message op",
-              chand_, this);
-    }
-    if (replay_batch_data == nullptr) {
-      replay_batch_data =
-          SubchannelCallBatchData::Create(this, 1, true /* set_on_complete */);
-    }
-    AddRetriableSendMessageOp(retry_state, replay_batch_data);
-  }
-  // send_trailing_metadata.
-  // Note that we only add this op if we have no more send_message ops
-  // to start, since we can't send down any more send_message ops after
-  // send_trailing_metadata.
-  if (seen_send_trailing_metadata_ &&
-      retry_state->started_send_message_count == send_messages_.size() &&
-      !retry_state->started_send_trailing_metadata &&
-      !pending_send_trailing_metadata_) {
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-      gpr_log(GPR_INFO,
-              "chand=%p retrying_call=%p: replaying previously completed "
-              "send_trailing_metadata op",
-              chand_, this);
-    }
-    if (replay_batch_data == nullptr) {
-      replay_batch_data =
-          SubchannelCallBatchData::Create(this, 1, true /* set_on_complete */);
-    }
-    AddRetriableSendTrailingMetadataOp(retry_state, replay_batch_data);
-  }
-  return replay_batch_data;
-}
-
-void RetryingCall::AddSubchannelBatchesForPendingBatches(
-    SubchannelCallRetryState* retry_state, CallCombinerClosureList* closures) {
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
-    PendingBatch* pending = &pending_batches_[i];
-    grpc_transport_stream_op_batch* batch = pending->batch;
-    if (batch == nullptr) continue;
-    // Skip any batch that either (a) has already been started on this
-    // subchannel call or (b) we can't start yet because we're still
-    // replaying send ops that need to be completed first.
-    // TODO(roth): Note that if any one op in the batch can't be sent
-    // yet due to ops that we're replaying, we don't start any of the ops
-    // in the batch.  This is probably okay, but it could conceivably
-    // lead to increased latency in some cases -- e.g., we could delay
-    // starting a recv op due to it being in the same batch with a send
-    // op.  If/when we revamp the callback protocol in
-    // transport_stream_op_batch, we may be able to fix this.
-    if (batch->send_initial_metadata &&
-        retry_state->started_send_initial_metadata) {
-      continue;
-    }
-    if (batch->send_message && retry_state->completed_send_message_count <
-                                   retry_state->started_send_message_count) {
-      continue;
-    }
-    // Note that we only start send_trailing_metadata if we have no more
-    // send_message ops to start, since we can't send down any more
-    // send_message ops after send_trailing_metadata.
-    if (batch->send_trailing_metadata &&
-        (retry_state->started_send_message_count + batch->send_message <
-             send_messages_.size() ||
-         retry_state->started_send_trailing_metadata)) {
-      continue;
-    }
-    if (batch->recv_initial_metadata &&
-        retry_state->started_recv_initial_metadata) {
-      continue;
-    }
-    if (batch->recv_message && retry_state->completed_recv_message_count <
-                                   retry_state->started_recv_message_count) {
-      continue;
-    }
-    if (batch->recv_trailing_metadata &&
-        retry_state->started_recv_trailing_metadata) {
-      // If we previously completed a recv_trailing_metadata op
-      // initiated by StartInternalRecvTrailingMetadata(), use the
-      // result of that instead of trying to re-start this op.
-      if (GPR_UNLIKELY((retry_state->recv_trailing_metadata_internal_batch !=
-                        nullptr))) {
-        // If the batch completed, then trigger the completion callback
-        // directly, so that we return the previously returned results to
-        // the application.  Otherwise, just unref the internally
-        // started subchannel batch, since we'll propagate the
-        // completion when it completes.
-        if (retry_state->completed_recv_trailing_metadata) {
-          // Batches containing recv_trailing_metadata always succeed.
-          closures->Add(
-              &retry_state->recv_trailing_metadata_ready, GRPC_ERROR_NONE,
-              "re-executing recv_trailing_metadata_ready to propagate "
-              "internally triggered result");
-        } else {
-          retry_state->recv_trailing_metadata_internal_batch->Unref();
-        }
-        retry_state->recv_trailing_metadata_internal_batch = nullptr;
-      }
-      continue;
-    }
-    // If we're not retrying, just send the batch as-is.
-    // TODO(roth): This condition doesn't seem exactly right -- maybe need a
-    // notion of "draining" once we've committed and are done replaying?
-    if (retry_policy_ == nullptr || retry_committed_) {
-      AddClosureForSubchannelBatch(batch, closures);
-      PendingBatchClear(pending);
-      continue;
-    }
-    // Create batch with the right number of callbacks.
-    const bool has_send_ops = batch->send_initial_metadata ||
-                              batch->send_message ||
-                              batch->send_trailing_metadata;
-    const int num_callbacks = has_send_ops + batch->recv_initial_metadata +
-                              batch->recv_message +
-                              batch->recv_trailing_metadata;
-    SubchannelCallBatchData* batch_data = SubchannelCallBatchData::Create(
-        this, num_callbacks, has_send_ops /* set_on_complete */);
-    // Cache send ops if needed.
-    MaybeCacheSendOpsForBatch(pending);
-    // send_initial_metadata.
-    if (batch->send_initial_metadata) {
-      AddRetriableSendInitialMetadataOp(retry_state, batch_data);
-    }
-    // send_message.
-    if (batch->send_message) {
-      AddRetriableSendMessageOp(retry_state, batch_data);
-    }
-    // send_trailing_metadata.
-    if (batch->send_trailing_metadata) {
-      AddRetriableSendTrailingMetadataOp(retry_state, batch_data);
-    }
-    // recv_initial_metadata.
-    if (batch->recv_initial_metadata) {
-      // recv_flags is only used on the server side.
-      GPR_ASSERT(batch->payload->recv_initial_metadata.recv_flags == nullptr);
-      AddRetriableRecvInitialMetadataOp(retry_state, batch_data);
-    }
-    // recv_message.
-    if (batch->recv_message) {
-      AddRetriableRecvMessageOp(retry_state, batch_data);
-    }
-    // recv_trailing_metadata.
-    if (batch->recv_trailing_metadata) {
-      AddRetriableRecvTrailingMetadataOp(retry_state, batch_data);
-    }
-    AddClosureForSubchannelBatch(&batch_data->batch, closures);
-    // Track number of pending subchannel send batches.
-    // If this is the first one, take a ref to the call stack.
-    if (batch->send_initial_metadata || batch->send_message ||
-        batch->send_trailing_metadata) {
-      if (num_pending_retriable_subchannel_send_batches_ == 0) {
-        GRPC_CALL_STACK_REF(owning_call_, "subchannel_send_batches");
-      }
-      ++num_pending_retriable_subchannel_send_batches_;
-    }
-  }
-}
-
-void RetryingCall::StartRetriableSubchannelBatches(void* arg,
-                                                   grpc_error* /*ignored*/) {
-  RetryingCall* call = static_cast<RetryingCall*>(arg);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: constructing retriable batches",
-            call->chand_, call);
-  }
-  SubchannelCallRetryState* retry_state =
-      static_cast<SubchannelCallRetryState*>(call->lb_call_->GetParentData());
-  // Construct list of closures to execute, one for each pending batch.
-  CallCombinerClosureList closures;
-  // Replay previously-returned send_* ops if needed.
-  SubchannelCallBatchData* replay_batch_data =
-      call->MaybeCreateSubchannelBatchForReplay(retry_state);
-  if (replay_batch_data != nullptr) {
-    call->AddClosureForSubchannelBatch(&replay_batch_data->batch, &closures);
-    // Track number of pending subchannel send batches.
-    // If this is the first one, take a ref to the call stack.
-    if (call->num_pending_retriable_subchannel_send_batches_ == 0) {
-      GRPC_CALL_STACK_REF(call->owning_call_, "subchannel_send_batches");
-    }
-    ++call->num_pending_retriable_subchannel_send_batches_;
-  }
-  // Now add pending batches.
-  call->AddSubchannelBatchesForPendingBatches(retry_state, &closures);
-  // Start batches on subchannel call.
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
-    gpr_log(GPR_INFO,
-            "chand=%p retrying_call=%p: starting %" PRIuPTR
-            " retriable batches on lb_call=%p",
-            call->chand_, call, closures.size(), call->lb_call_.get());
-  }
-  // Note: This will yield the call combiner.
-  closures.RunClosures(call->call_combiner_);
-}
-
-void RetryingCall::CreateLbCall(void* arg, grpc_error* /*error*/) {
-  auto* call = static_cast<RetryingCall*>(arg);
-  const size_t parent_data_size =
-      call->enable_retries_ ? sizeof(SubchannelCallRetryState) : 0;
-  grpc_call_element_args args = {call->owning_call_,     nullptr,
-                                 call->call_context_,    call->path_,
-                                 call->call_start_time_, call->deadline_,
-                                 call->arena_,           call->call_combiner_};
-  call->lb_call_ = LoadBalancedCall::Create(call->chand_, args, call->pollent_,
-                                            parent_data_size);
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
-    gpr_log(GPR_INFO, "chand=%p retrying_call=%p: create lb_call=%p",
-            call->chand_, call, call->lb_call_.get());
-  }
-  if (parent_data_size > 0) {
-    new (call->lb_call_->GetParentData())
-        SubchannelCallRetryState(call->call_context_);
-  }
-  call->PendingBatchesResume();
-}
-
-//
-// LoadBalancedCall::Metadata
-//
-
-class LoadBalancedCall::Metadata
+class ClientChannel::LoadBalancedCall::Metadata
     : public LoadBalancingPolicy::MetadataInterface {
  public:
   Metadata(LoadBalancedCall* lb_call, grpc_metadata_batch* batch)
@@ -4849,10 +2490,11 @@
 };
 
 //
-// LoadBalancedCall::LbCallState
+// ClientChannel::LoadBalancedCall::LbCallState
 //
 
-class LoadBalancedCall::LbCallState : public LoadBalancingPolicy::CallState {
+class ClientChannel::LoadBalancedCall::LbCallState
+    : public LoadBalancingPolicy::CallState {
  public:
   explicit LbCallState(LoadBalancedCall* lb_call) : lb_call_(lb_call) {}
 
@@ -4888,25 +2530,12 @@
 // LoadBalancedCall
 //
 
-RefCountedPtr<LoadBalancedCall> LoadBalancedCall::Create(
-    ChannelData* chand, const grpc_call_element_args& args,
-    grpc_polling_entity* pollent, size_t parent_data_size) {
-  const size_t alloc_size =
-      parent_data_size > 0
-          ? (GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(LoadBalancedCall)) +
-             parent_data_size)
-          : sizeof(LoadBalancedCall);
-  auto* lb_call = static_cast<LoadBalancedCall*>(args.arena->Alloc(alloc_size));
-  new (lb_call) LoadBalancedCall(chand, args, pollent);
-  return lb_call;
-}
-
-LoadBalancedCall::LoadBalancedCall(ChannelData* chand,
-                                   const grpc_call_element_args& args,
-                                   grpc_polling_entity* pollent)
-    : refs_(1, GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)
-                   ? "LoadBalancedCall"
-                   : nullptr),
+ClientChannel::LoadBalancedCall::LoadBalancedCall(
+    ClientChannel* chand, const grpc_call_element_args& args,
+    grpc_polling_entity* pollent, grpc_closure* on_call_destruction_complete)
+    : RefCounted(GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)
+                     ? "LoadBalancedCall"
+                     : nullptr),
       chand_(chand),
       path_(grpc_slice_ref_internal(args.path)),
       call_start_time_(args.start_time),
@@ -4915,11 +2544,13 @@
       owning_call_(args.call_stack),
       call_combiner_(args.call_combiner),
       call_context_(args.context),
-      pollent_(pollent) {}
+      pollent_(pollent),
+      on_call_destruction_complete_(on_call_destruction_complete) {}
 
-LoadBalancedCall::~LoadBalancedCall() {
+ClientChannel::LoadBalancedCall::~LoadBalancedCall() {
   grpc_slice_unref_internal(path_);
   GRPC_ERROR_UNREF(cancel_error_);
+  GRPC_ERROR_UNREF(failure_error_);
   if (backend_metric_data_ != nullptr) {
     backend_metric_data_
         ->LoadBalancingPolicy::BackendMetricData::~BackendMetricData();
@@ -4928,47 +2559,16 @@
   for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
     GPR_ASSERT(pending_batches_[i] == nullptr);
   }
-}
-
-RefCountedPtr<LoadBalancedCall> LoadBalancedCall::Ref() {
-  IncrementRefCount();
-  return RefCountedPtr<LoadBalancedCall>(this);
-}
-
-RefCountedPtr<LoadBalancedCall> LoadBalancedCall::Ref(
-    const DebugLocation& location, const char* reason) {
-  IncrementRefCount(location, reason);
-  return RefCountedPtr<LoadBalancedCall>(this);
-}
-
-void LoadBalancedCall::Unref() {
-  if (GPR_UNLIKELY(refs_.Unref())) {
-    this->~LoadBalancedCall();
+  if (on_call_destruction_complete_ != nullptr) {
+    ExecCtx::Run(DEBUG_LOCATION, on_call_destruction_complete_,
+                 GRPC_ERROR_NONE);
   }
 }
 
-void LoadBalancedCall::Unref(const DebugLocation& location,
-                             const char* reason) {
-  if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
-    this->~LoadBalancedCall();
-  }
-}
-
-void LoadBalancedCall::IncrementRefCount() { refs_.Ref(); }
-
-void LoadBalancedCall::IncrementRefCount(const DebugLocation& location,
-                                         const char* reason) {
-  refs_.Ref(location, reason);
-}
-
-void* LoadBalancedCall::GetParentData() {
-  return reinterpret_cast<char*>(this) +
-         GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(LoadBalancedCall));
-}
-
-size_t LoadBalancedCall::GetBatchIndex(grpc_transport_stream_op_batch* batch) {
+size_t ClientChannel::LoadBalancedCall::GetBatchIndex(
+    grpc_transport_stream_op_batch* batch) {
   // Note: It is important the send_initial_metadata be the first entry
-  // here, since the code in pick_subchannel_locked() assumes it will be.
+  // here, since the code in PickSubchannelLocked() assumes it will be.
   if (batch->send_initial_metadata) return 0;
   if (batch->send_message) return 1;
   if (batch->send_trailing_metadata) return 2;
@@ -4979,7 +2579,7 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void LoadBalancedCall::PendingBatchesAdd(
+void ClientChannel::LoadBalancedCall::PendingBatchesAdd(
     grpc_transport_stream_op_batch* batch) {
   const size_t idx = GetBatchIndex(batch);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
@@ -4992,8 +2592,8 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void LoadBalancedCall::FailPendingBatchInCallCombiner(void* arg,
-                                                      grpc_error* error) {
+void ClientChannel::LoadBalancedCall::FailPendingBatchInCallCombiner(
+    void* arg, grpc_error_handle error) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   auto* self = static_cast<LoadBalancedCall*>(batch->handler_private.extra_arg);
@@ -5003,10 +2603,12 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void LoadBalancedCall::PendingBatchesFail(
-    grpc_error* error,
+void ClientChannel::LoadBalancedCall::PendingBatchesFail(
+    grpc_error_handle error,
     YieldCallCombinerPredicate yield_call_combiner_predicate) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
+  GRPC_ERROR_UNREF(failure_error_);
+  failure_error_ = error;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
     size_t num_batches = 0;
     for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
@@ -5014,7 +2616,7 @@
     }
     gpr_log(GPR_INFO,
             "chand=%p lb_call=%p: failing %" PRIuPTR " pending batches: %s",
-            chand_, this, num_batches, grpc_error_string(error));
+            chand_, this, num_batches, grpc_error_std_string(error).c_str());
   }
   CallCombinerClosureList closures;
   for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
@@ -5034,12 +2636,11 @@
   } else {
     closures.RunClosuresWithoutYielding(call_combiner_);
   }
-  GRPC_ERROR_UNREF(error);
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void LoadBalancedCall::ResumePendingBatchInCallCombiner(
-    void* arg, grpc_error* /*ignored*/) {
+void ClientChannel::LoadBalancedCall::ResumePendingBatchInCallCombiner(
+    void* arg, grpc_error_handle /*ignored*/) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   SubchannelCall* subchannel_call =
@@ -5049,7 +2650,7 @@
 }
 
 // This is called via the call combiner, so access to calld is synchronized.
-void LoadBalancedCall::PendingBatchesResume() {
+void ClientChannel::LoadBalancedCall::PendingBatchesResume() {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
     size_t num_batches = 0;
     for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
@@ -5077,7 +2678,7 @@
   closures.RunClosures(call_combiner_);
 }
 
-void LoadBalancedCall::StartTransportStreamOpBatch(
+void ClientChannel::LoadBalancedCall::StartTransportStreamOpBatch(
     grpc_transport_stream_op_batch* batch) {
   // Intercept recv_trailing_metadata_ready for LB callback.
   if (batch->recv_trailing_metadata) {
@@ -5087,7 +2688,7 @@
   if (GPR_UNLIKELY(cancel_error_ != GRPC_ERROR_NONE)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p lb_call=%p: failing batch with error: %s",
-              chand_, this, grpc_error_string(cancel_error_));
+              chand_, this, grpc_error_std_string(cancel_error_).c_str());
     }
     // Note: This will release the call combiner.
     grpc_transport_stream_op_batch_finish_with_failure(
@@ -5105,7 +2706,7 @@
     cancel_error_ = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
       gpr_log(GPR_INFO, "chand=%p lb_call=%p: recording cancel_error=%s",
-              chand_, this, grpc_error_string(cancel_error_));
+              chand_, this, grpc_error_std_string(cancel_error_).c_str());
     }
     // If we do not have a subchannel call (i.e., a pick has not yet
     // been started), fail all pending batches.  Otherwise, send the
@@ -5158,12 +2759,13 @@
   }
 }
 
-void LoadBalancedCall::RecvTrailingMetadataReadyForLoadBalancingPolicy(
-    void* arg, grpc_error* error) {
+void ClientChannel::LoadBalancedCall::
+    RecvTrailingMetadataReadyForLoadBalancingPolicy(void* arg,
+                                                    grpc_error_handle error) {
   auto* self = static_cast<LoadBalancedCall*>(arg);
   if (self->lb_recv_trailing_metadata_ready_ != nullptr) {
     // Set error if call did not succeed.
-    grpc_error* error_for_lb = GRPC_ERROR_NONE;
+    grpc_error_handle error_for_lb = GRPC_ERROR_NONE;
     if (error != GRPC_ERROR_NONE) {
       error_for_lb = error;
     } else {
@@ -5191,14 +2793,19 @@
     if (error == GRPC_ERROR_NONE) GRPC_ERROR_UNREF(error_for_lb);
   }
   // Chain to original callback.
+  if (self->failure_error_ != GRPC_ERROR_NONE) {
+    error = self->failure_error_;
+    self->failure_error_ = GRPC_ERROR_NONE;
+  } else {
+    error = GRPC_ERROR_REF(error);
+  }
   Closure::Run(DEBUG_LOCATION, self->original_recv_trailing_metadata_ready_,
-               GRPC_ERROR_REF(error));
+               error);
 }
 
-// TODO(roth): Consider not intercepting this callback unless we
-// actually need to, if this causes a performance problem.
-void LoadBalancedCall::InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
-    grpc_transport_stream_op_batch* batch) {
+void ClientChannel::LoadBalancedCall::
+    InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
+        grpc_transport_stream_op_batch* batch) {
   recv_trailing_metadata_ =
       batch->payload->recv_trailing_metadata.recv_trailing_metadata;
   original_recv_trailing_metadata_ready_ =
@@ -5210,19 +2817,23 @@
       &recv_trailing_metadata_ready_;
 }
 
-void LoadBalancedCall::CreateSubchannelCall() {
+void ClientChannel::LoadBalancedCall::CreateSubchannelCall() {
   SubchannelCall::Args call_args = {
       std::move(connected_subchannel_), pollent_, path_, call_start_time_,
       deadline_, arena_,
       // TODO(roth): When we implement hedging support, we will probably
       // need to use a separate call context for each subchannel call.
       call_context_, call_combiner_};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   subchannel_call_ = SubchannelCall::Create(std::move(call_args), &error);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO,
             "chand=%p lb_call=%p: create subchannel_call=%p: error=%s", chand_,
-            this, subchannel_call_.get(), grpc_error_string(error));
+            this, subchannel_call_.get(), grpc_error_std_string(error).c_str());
+  }
+  if (on_call_destruction_complete_ != nullptr) {
+    subchannel_call_->SetAfterCallStackDestroy(on_call_destruction_complete_);
+    on_call_destruction_complete_ = nullptr;
   }
   if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
     PendingBatchesFail(error, YieldCallCombiner);
@@ -5238,7 +2849,7 @@
 // because there may be multiple LB picks happening in parallel.
 // Instead, we will probably need to maintain a list in the CallData
 // object of pending LB picks to be cancelled when the closure runs.
-class LoadBalancedCall::LbQueuedCallCanceller {
+class ClientChannel::LoadBalancedCall::LbQueuedCallCanceller {
  public:
   explicit LbQueuedCallCanceller(RefCountedPtr<LoadBalancedCall> lb_call)
       : lb_call_(std::move(lb_call)) {
@@ -5248,17 +2859,17 @@
   }
 
  private:
-  static void CancelLocked(void* arg, grpc_error* error) {
+  static void CancelLocked(void* arg, grpc_error_handle error) {
     auto* self = static_cast<LbQueuedCallCanceller*>(arg);
     auto* lb_call = self->lb_call_.get();
     auto* chand = lb_call->chand_;
     {
-      MutexLock lock(chand->data_plane_mu());
+      MutexLock lock(&chand->data_plane_mu_);
       if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
         gpr_log(GPR_INFO,
                 "chand=%p lb_call=%p: cancelling queued pick: "
                 "error=%s self=%p calld->pick_canceller=%p",
-                chand, lb_call, grpc_error_string(error), self,
+                chand, lb_call, grpc_error_std_string(error).c_str(), self,
                 lb_call->lb_call_canceller_);
       }
       if (lb_call->lb_call_canceller_ == self && error != GRPC_ERROR_NONE) {
@@ -5277,7 +2888,7 @@
   grpc_closure closure_;
 };
 
-void LoadBalancedCall::MaybeRemoveCallFromLbQueuedCallsLocked() {
+void ClientChannel::LoadBalancedCall::MaybeRemoveCallFromLbQueuedCallsLocked() {
   if (!queued_pending_lb_pick_) return;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p lb_call=%p: removing from queued picks list",
@@ -5289,7 +2900,7 @@
   lb_call_canceller_ = nullptr;
 }
 
-void LoadBalancedCall::MaybeAddCallToLbQueuedCallsLocked() {
+void ClientChannel::LoadBalancedCall::MaybeAddCallToLbQueuedCallsLocked() {
   if (queued_pending_lb_pick_) return;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p lb_call=%p: adding to queued picks list",
@@ -5302,18 +2913,19 @@
   lb_call_canceller_ = new LbQueuedCallCanceller(Ref());
 }
 
-void LoadBalancedCall::AsyncPickDone(grpc_error* error) {
+void ClientChannel::LoadBalancedCall::AsyncPickDone(grpc_error_handle error) {
   GRPC_CLOSURE_INIT(&pick_closure_, PickDone, this, grpc_schedule_on_exec_ctx);
   ExecCtx::Run(DEBUG_LOCATION, &pick_closure_, error);
 }
 
-void LoadBalancedCall::PickDone(void* arg, grpc_error* error) {
+void ClientChannel::LoadBalancedCall::PickDone(void* arg,
+                                               grpc_error_handle error) {
   auto* self = static_cast<LoadBalancedCall*>(arg);
   if (error != GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
       gpr_log(GPR_INFO,
               "chand=%p lb_call=%p: failed to pick subchannel: error=%s",
-              self->chand_, self, grpc_error_string(error));
+              self->chand_, self, grpc_error_std_string(error).c_str());
     }
     self->PendingBatchesFail(GRPC_ERROR_REF(error), YieldCallCombiner);
     return;
@@ -5321,6 +2933,8 @@
   self->CreateSubchannelCall();
 }
 
+namespace {
+
 const char* PickResultTypeName(
     LoadBalancingPolicy::PickResult::ResultType type) {
   switch (type) {
@@ -5334,11 +2948,14 @@
   GPR_UNREACHABLE_CODE(return "UNKNOWN");
 }
 
-void LoadBalancedCall::PickSubchannel(void* arg, grpc_error* error) {
+}  // namespace
+
+void ClientChannel::LoadBalancedCall::PickSubchannel(void* arg,
+                                                     grpc_error_handle error) {
   auto* self = static_cast<LoadBalancedCall*>(arg);
   bool pick_complete;
   {
-    MutexLock lock(self->chand_->data_plane_mu());
+    MutexLock lock(&self->chand_->data_plane_mu_);
     pick_complete = self->PickSubchannelLocked(&error);
   }
   if (pick_complete) {
@@ -5347,7 +2964,8 @@
   }
 }
 
-bool LoadBalancedCall::PickSubchannelLocked(grpc_error** error) {
+bool ClientChannel::LoadBalancedCall::PickSubchannelLocked(
+    grpc_error_handle* error) {
   GPR_ASSERT(connected_subchannel_ == nullptr);
   GPR_ASSERT(subchannel_call_ == nullptr);
   // Grab initial metadata.
@@ -5364,18 +2982,18 @@
   pick_args.call_state = &lb_call_state;
   Metadata initial_metadata(this, initial_metadata_batch);
   pick_args.initial_metadata = &initial_metadata;
-  auto result = chand_->picker()->Pick(pick_args);
+  auto result = chand_->picker_->Pick(pick_args);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(
         GPR_INFO,
         "chand=%p lb_call=%p: LB pick returned %s (subchannel=%p, error=%s)",
         chand_, this, PickResultTypeName(result.type), result.subchannel.get(),
-        grpc_error_string(result.error));
+        grpc_error_std_string(result.error).c_str());
   }
   switch (result.type) {
     case LoadBalancingPolicy::PickResult::PICK_FAILED: {
       // If we're shutting down, fail all RPCs.
-      grpc_error* disconnect_error = chand_->disconnect_error();
+      grpc_error_handle disconnect_error = chand_->disconnect_error();
       if (disconnect_error != GRPC_ERROR_NONE) {
         GRPC_ERROR_UNREF(result.error);
         MaybeRemoveCallFromLbQueuedCallsLocked();
@@ -5386,7 +3004,7 @@
       // attempt's final status.
       if ((send_initial_metadata_flags &
            GRPC_INITIAL_METADATA_WAIT_FOR_READY) == 0) {
-        grpc_error* new_error =
+        grpc_error_handle new_error =
             GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                 "Failed to pick subchannel", &result.error, 1);
         GRPC_ERROR_UNREF(result.error);
@@ -5407,9 +3025,11 @@
       // Handle drops.
       if (GPR_UNLIKELY(result.subchannel == nullptr)) {
         result.error = grpc_error_set_int(
-            GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                "Call dropped by load balancing policy"),
-            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
+            grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                                   "Call dropped by load balancing policy"),
+                               GRPC_ERROR_INT_GRPC_STATUS,
+                               GRPC_STATUS_UNAVAILABLE),
+            GRPC_ERROR_INT_LB_POLICY_DROP, 1);
       } else {
         // Grab a ref to the connected subchannel while we're still
         // holding the data plane mutex.
@@ -5423,69 +3043,4 @@
   }
 }
 
-}  // namespace
 }  // namespace grpc_core
-
-/*************************************************************************
- * EXPORTED SYMBOLS
- */
-
-using grpc_core::CallData;
-using grpc_core::ChannelData;
-
-const grpc_channel_filter grpc_client_channel_filter = {
-    CallData::StartTransportStreamOpBatch,
-    ChannelData::StartTransportOp,
-    sizeof(CallData),
-    CallData::Init,
-    CallData::SetPollent,
-    CallData::Destroy,
-    sizeof(ChannelData),
-    ChannelData::Init,
-    ChannelData::Destroy,
-    ChannelData::GetChannelInfo,
-    "client-channel",
-};
-
-grpc_connectivity_state grpc_client_channel_check_connectivity_state(
-    grpc_channel_element* elem, int try_to_connect) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  return chand->CheckConnectivityState(try_to_connect);
-}
-
-int grpc_client_channel_num_external_connectivity_watchers(
-    grpc_channel_element* elem) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  return chand->NumExternalConnectivityWatchers();
-}
-
-void grpc_client_channel_watch_connectivity_state(
-    grpc_channel_element* elem, grpc_polling_entity pollent,
-    grpc_connectivity_state* state, grpc_closure* on_complete,
-    grpc_closure* watcher_timer_init) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  if (state == nullptr) {
-    // Handle cancellation.
-    GPR_ASSERT(watcher_timer_init == nullptr);
-    chand->RemoveExternalConnectivityWatcher(on_complete, /*cancel=*/true);
-    return;
-  }
-  // Handle addition.
-  return chand->AddExternalConnectivityWatcher(pollent, state, on_complete,
-                                               watcher_timer_init);
-}
-
-void grpc_client_channel_start_connectivity_watch(
-    grpc_channel_element* elem, grpc_connectivity_state initial_state,
-    grpc_core::OrphanablePtr<grpc_core::AsyncConnectivityStateWatcherInterface>
-        watcher) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  chand->AddConnectivityWatcher(initial_state, std::move(watcher));
-}
-
-void grpc_client_channel_stop_connectivity_watch(
-    grpc_channel_element* elem,
-    grpc_core::AsyncConnectivityStateWatcherInterface* watcher) {
-  auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  chand->RemoveConnectivityWatcher(watcher);
-}
diff --git a/grpc/src/core/ext/filters/client_channel/client_channel.h b/grpc/src/core/ext/filters/client_channel/client_channel.h
index 202de8a..b7dd1a1 100644
--- a/grpc/src/core/ext/filters/client_channel/client_channel.h
+++ b/grpc/src/core/ext/filters/client_channel/client_channel.h
@@ -1,78 +1,510 @@
-/*
- *
- * Copyright 2015 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.
- *
- */
+//
+// Copyright 2015 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_CLIENT_CHANNEL_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
-#include "src/core/ext/filters/client_channel/client_channel_factory.h"
-#include "src/core/ext/filters/client_channel/resolver.h"
-#include "src/core/lib/channel/channel_stack.h"
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
 
-extern grpc_core::TraceFlag grpc_client_channel_trace;
+#include "absl/status/status.h"
+#include "absl/types/optional.h"
+
+#include <grpc/support/log.h>
+
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/config_selector.h"
+#include "src/core/ext/filters/client_channel/dynamic_filters.h"
+#include "src/core/ext/filters/client_channel/lb_policy.h"
+#include "src/core/ext/filters/client_channel/resolver.h"
+#include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
+#include "src/core/lib/gprpp/sync.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/iomgr/work_serializer.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/connectivity_state.h"
+
+//
+// Client channel filter
+//
+
+// A client channel is a channel that begins disconnected, and can connect
+// to some endpoint on demand. If that endpoint disconnects, it will be
+// connected to again later.
+//
+// Calls on a disconnected client channel are queued until a connection is
+// established.
 
 // Channel arg key for server URI string.
 #define GRPC_ARG_SERVER_URI "grpc.server_uri"
 
-/* A client channel is a channel that begins disconnected, and can connect
-   to some endpoint on demand. If that endpoint disconnects, it will be
-   connected to again later.
+// Channel arg containing a pointer to the ClientChannel object.
+#define GRPC_ARG_CLIENT_CHANNEL "grpc.internal.client_channel"
 
-   Calls on a disconnected client channel are queued until a connection is
-   established. */
+// Channel arg containing a pointer to the ServiceConfig object.
+#define GRPC_ARG_SERVICE_CONFIG_OBJ "grpc.internal.service_config_obj"
 
-extern const grpc_channel_filter grpc_client_channel_filter;
+// Max number of batches that can be pending on a call at any given
+// time.  This includes one batch for each of the following ops:
+//   recv_initial_metadata
+//   send_initial_metadata
+//   recv_message
+//   send_message
+//   recv_trailing_metadata
+//   send_trailing_metadata
+#define MAX_PENDING_BATCHES 6
 
-grpc_connectivity_state grpc_client_channel_check_connectivity_state(
-    grpc_channel_element* elem, int try_to_connect);
+namespace grpc_core {
 
-int grpc_client_channel_num_external_connectivity_watchers(
-    grpc_channel_element* elem);
+class ClientChannel {
+ public:
+  static const grpc_channel_filter kFilterVtable;
 
-// Starts a one-time connectivity state watch.  When the channel's state
-// becomes different from *state, sets *state to the new state and
-// schedules on_complete.  The watcher_timer_init callback is invoked as
-// soon as the watch is actually started (i.e., after hopping into the
-// client channel combiner).  I/O will be serviced via pollent.
+  class LoadBalancedCall;
+
+  // Returns the ClientChannel object from channel, or null if channel
+  // is not a client channel.
+  static ClientChannel* GetFromChannel(grpc_channel* channel);
+
+  grpc_connectivity_state CheckConnectivityState(bool try_to_connect);
+
+  // Starts a one-time connectivity state watch.  When the channel's state
+  // becomes different from *state, sets *state to the new state and
+  // schedules on_complete.  The watcher_timer_init callback is invoked as
+  // soon as the watch is actually started (i.e., after hopping into the
+  // client channel combiner).  I/O will be serviced via pollent.
+  //
+  // This is intended to be used when starting a watch from outside of C-core
+  // via grpc_channel_watch_connectivity_state().  It should not be used
+  // by other callers.
+  void AddExternalConnectivityWatcher(grpc_polling_entity pollent,
+                                      grpc_connectivity_state* state,
+                                      grpc_closure* on_complete,
+                                      grpc_closure* watcher_timer_init) {
+    new ExternalConnectivityWatcher(this, pollent, state, on_complete,
+                                    watcher_timer_init);
+  }
+
+  // Cancels a pending external watcher previously added by
+  // AddExternalConnectivityWatcher().
+  void CancelExternalConnectivityWatcher(grpc_closure* on_complete) {
+    ExternalConnectivityWatcher::RemoveWatcherFromExternalWatchersMap(
+        this, on_complete, /*cancel=*/true);
+  }
+
+  int NumExternalConnectivityWatchers() const {
+    MutexLock lock(&external_watchers_mu_);
+    return static_cast<int>(external_watchers_.size());
+  }
+
+  // Starts and stops a connectivity watch.  The watcher will be initially
+  // notified as soon as the state changes from initial_state and then on
+  // every subsequent state change until either the watch is stopped or
+  // it is notified that the state has changed to SHUTDOWN.
+  //
+  // This is intended to be used when starting watches from code inside of
+  // C-core (e.g., for a nested control plane channel for things like xds).
+  void AddConnectivityWatcher(
+      grpc_connectivity_state initial_state,
+      OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher);
+  void RemoveConnectivityWatcher(
+      AsyncConnectivityStateWatcherInterface* watcher);
+
+  RefCountedPtr<LoadBalancedCall> CreateLoadBalancedCall(
+      const grpc_call_element_args& args, grpc_polling_entity* pollent,
+      grpc_closure* on_call_destruction_complete);
+
+ private:
+  class CallData;
+  class ResolverResultHandler;
+  class SubchannelWrapper;
+  class ClientChannelControlHelper;
+  class ConnectivityWatcherAdder;
+  class ConnectivityWatcherRemover;
+
+  // Represents a pending connectivity callback from an external caller
+  // via grpc_client_channel_watch_connectivity_state().
+  class ExternalConnectivityWatcher : public ConnectivityStateWatcherInterface {
+   public:
+    ExternalConnectivityWatcher(ClientChannel* chand,
+                                grpc_polling_entity pollent,
+                                grpc_connectivity_state* state,
+                                grpc_closure* on_complete,
+                                grpc_closure* watcher_timer_init);
+
+    ~ExternalConnectivityWatcher() override;
+
+    // Removes the watcher from the external_watchers_ map.
+    static void RemoveWatcherFromExternalWatchersMap(ClientChannel* chand,
+                                                     grpc_closure* on_complete,
+                                                     bool cancel);
+
+    void Notify(grpc_connectivity_state state,
+                const absl::Status& /* status */) override;
+
+    void Cancel();
+
+   private:
+    // Adds the watcher to state_tracker_. Consumes the ref that is passed to it
+    // from Start().
+    void AddWatcherLocked()
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_);
+    void RemoveWatcherLocked()
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(chand_->work_serializer_);
+
+    ClientChannel* chand_;
+    grpc_polling_entity pollent_;
+    grpc_connectivity_state initial_state_;
+    grpc_connectivity_state* state_;
+    grpc_closure* on_complete_;
+    grpc_closure* watcher_timer_init_;
+    Atomic<bool> done_{false};
+  };
+
+  struct ResolverQueuedCall {
+    grpc_call_element* elem;
+    ResolverQueuedCall* next = nullptr;
+  };
+  struct LbQueuedCall {
+    LoadBalancedCall* lb_call;
+    LbQueuedCall* next = nullptr;
+  };
+
+  ClientChannel(grpc_channel_element_args* args, grpc_error_handle* error);
+  ~ClientChannel();
+
+  // Filter vtable functions.
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args);
+  static void Destroy(grpc_channel_element* elem);
+  static void StartTransportOp(grpc_channel_element* elem,
+                               grpc_transport_op* op);
+  static void GetChannelInfo(grpc_channel_element* elem,
+                             const grpc_channel_info* info);
+
+  // Note: Does NOT return a new ref.
+  grpc_error_handle disconnect_error() const {
+    return disconnect_error_.Load(MemoryOrder::ACQUIRE);
+  }
+
+  // Note: All methods with "Locked" suffix must be invoked from within
+  // work_serializer_.
+
+  void OnResolverResultChangedLocked(Resolver::Result result)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+  void OnResolverErrorLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void CreateOrUpdateLbPolicyLocked(
+      RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
+      Resolver::Result result) ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+  OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
+      const grpc_channel_args& args)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void UpdateStateAndPickerLocked(
+      grpc_connectivity_state state, const absl::Status& status,
+      const char* reason,
+      std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void UpdateServiceConfigInControlPlaneLocked(
+      RefCountedPtr<ServiceConfig> service_config,
+      RefCountedPtr<ConfigSelector> config_selector,
+      const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
+      const char* lb_policy_name)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void UpdateServiceConfigInDataPlaneLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void CreateResolverLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+  void DestroyResolverAndLbPolicyLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  grpc_error_handle DoPingLocked(grpc_transport_op* op)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void StartTransportOpLocked(grpc_transport_op* op)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  void TryToConnectLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer_);
+
+  // These methods all require holding resolution_mu_.
+  void AddResolverQueuedCall(ResolverQueuedCall* call,
+                             grpc_polling_entity* pollent)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(resolution_mu_);
+  void RemoveResolverQueuedCall(ResolverQueuedCall* to_remove,
+                                grpc_polling_entity* pollent)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(resolution_mu_);
+
+  // These methods all require holding data_plane_mu_.
+  void AddLbQueuedCall(LbQueuedCall* call, grpc_polling_entity* pollent)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
+  void RemoveLbQueuedCall(LbQueuedCall* to_remove, grpc_polling_entity* pollent)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
+  RefCountedPtr<ConnectedSubchannel> GetConnectedSubchannelInDataPlane(
+      SubchannelInterface* subchannel) const
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(data_plane_mu_);
+
+  //
+  // Fields set at construction and never modified.
+  //
+  const bool deadline_checking_enabled_;
+  const bool enable_retries_;
+  grpc_channel_stack* owning_stack_;
+  ClientChannelFactory* client_channel_factory_;
+  const grpc_channel_args* channel_args_;
+  RefCountedPtr<ServiceConfig> default_service_config_;
+  std::string server_name_;
+  UniquePtr<char> target_uri_;
+  channelz::ChannelNode* channelz_node_;
+  grpc_pollset_set* interested_parties_;
+
+  //
+  // Fields related to name resolution.  Guarded by resolution_mu_.
+  //
+  mutable Mutex resolution_mu_;
+  // Linked list of calls queued waiting for resolver result.
+  ResolverQueuedCall* resolver_queued_calls_ ABSL_GUARDED_BY(resolution_mu_) =
+      nullptr;
+  // Data from service config.
+  grpc_error_handle resolver_transient_failure_error_
+      ABSL_GUARDED_BY(resolution_mu_) = GRPC_ERROR_NONE;
+  bool received_service_config_data_ ABSL_GUARDED_BY(resolution_mu_) = false;
+  RefCountedPtr<ServiceConfig> service_config_ ABSL_GUARDED_BY(resolution_mu_);
+  RefCountedPtr<ConfigSelector> config_selector_
+      ABSL_GUARDED_BY(resolution_mu_);
+  RefCountedPtr<DynamicFilters> dynamic_filters_
+      ABSL_GUARDED_BY(resolution_mu_);
+
+  //
+  // Fields used in the data plane.  Guarded by data_plane_mu_.
+  //
+  mutable Mutex data_plane_mu_;
+  std::unique_ptr<LoadBalancingPolicy::SubchannelPicker> picker_
+      ABSL_GUARDED_BY(data_plane_mu_);
+  // Linked list of calls queued waiting for LB pick.
+  LbQueuedCall* lb_queued_calls_ ABSL_GUARDED_BY(data_plane_mu_) = nullptr;
+
+  //
+  // Fields used in the control plane.  Guarded by work_serializer.
+  //
+  std::shared_ptr<WorkSerializer> work_serializer_;
+  ConnectivityStateTracker state_tracker_ ABSL_GUARDED_BY(work_serializer_);
+  OrphanablePtr<Resolver> resolver_ ABSL_GUARDED_BY(work_serializer_);
+  bool previous_resolution_contained_addresses_
+      ABSL_GUARDED_BY(work_serializer_) = false;
+  RefCountedPtr<ServiceConfig> saved_service_config_
+      ABSL_GUARDED_BY(work_serializer_);
+  RefCountedPtr<ConfigSelector> saved_config_selector_
+      ABSL_GUARDED_BY(work_serializer_);
+  absl::optional<std::string> health_check_service_name_
+      ABSL_GUARDED_BY(work_serializer_);
+  OrphanablePtr<LoadBalancingPolicy> lb_policy_
+      ABSL_GUARDED_BY(work_serializer_);
+  RefCountedPtr<SubchannelPoolInterface> subchannel_pool_
+      ABSL_GUARDED_BY(work_serializer_);
+  // The number of SubchannelWrapper instances referencing a given Subchannel.
+  std::map<Subchannel*, int> subchannel_refcount_map_
+      ABSL_GUARDED_BY(work_serializer_);
+  // The set of SubchannelWrappers that currently exist.
+  // No need to hold a ref, since the map is updated in the control-plane
+  // work_serializer when the SubchannelWrappers are created and destroyed.
+  std::set<SubchannelWrapper*> subchannel_wrappers_
+      ABSL_GUARDED_BY(work_serializer_);
+  // Pending ConnectedSubchannel updates for each SubchannelWrapper.
+  // Updates are queued here in the control plane work_serializer and then
+  // applied in the data plane mutex when the picker is updated.
+  std::map<RefCountedPtr<SubchannelWrapper>, RefCountedPtr<ConnectedSubchannel>>
+      pending_subchannel_updates_ ABSL_GUARDED_BY(work_serializer_);
+  int keepalive_time_ ABSL_GUARDED_BY(work_serializer_) = -1;
+
+  //
+  // Fields accessed from both data plane mutex and control plane
+  // work_serializer.
+  //
+  Atomic<grpc_error_handle> disconnect_error_;
+
+  //
+  // Fields guarded by a mutex, since they need to be accessed
+  // synchronously via get_channel_info().
+  //
+  Mutex info_mu_;
+  UniquePtr<char> info_lb_policy_name_ ABSL_GUARDED_BY(info_mu_);
+  UniquePtr<char> info_service_config_json_ ABSL_GUARDED_BY(info_mu_);
+
+  //
+  // Fields guarded by a mutex, since they need to be accessed
+  // synchronously via grpc_channel_num_external_connectivity_watchers().
+  //
+  mutable Mutex external_watchers_mu_;
+  std::map<grpc_closure*, RefCountedPtr<ExternalConnectivityWatcher>>
+      external_watchers_ ABSL_GUARDED_BY(external_watchers_mu_);
+};
+
 //
-// This is intended to be used when starting a watch from outside of C-core
-// via grpc_channel_watch_connectivity_state().  It should not be used
-// by other callers.
-void grpc_client_channel_watch_connectivity_state(
-    grpc_channel_element* elem, grpc_polling_entity pollent,
-    grpc_connectivity_state* state, grpc_closure* on_complete,
-    grpc_closure* watcher_timer_init);
-
-// Starts and stops a connectivity watch.  The watcher will be initially
-// notified as soon as the state changes from initial_state and then on
-// every subsequent state change until either the watch is stopped or
-// it is notified that the state has changed to SHUTDOWN.
+// ClientChannel::LoadBalancedCall
 //
-// This is intended to be used when starting watches from code inside of
-// C-core (e.g., for a nested control plane channel for things like xds).
-void grpc_client_channel_start_connectivity_watch(
-    grpc_channel_element* elem, grpc_connectivity_state initial_state,
-    grpc_core::OrphanablePtr<grpc_core::AsyncConnectivityStateWatcherInterface>
-        watcher);
-void grpc_client_channel_stop_connectivity_watch(
-    grpc_channel_element* elem,
-    grpc_core::AsyncConnectivityStateWatcherInterface* watcher);
+
+// This object is ref-counted, but it cannot inherit from RefCounted<>,
+// because it is allocated on the arena and can't free its memory when
+// its refcount goes to zero.  So instead, it manually implements the
+// same API as RefCounted<>, so that it can be used with RefCountedPtr<>.
+class ClientChannel::LoadBalancedCall
+    : public RefCounted<LoadBalancedCall, PolymorphicRefCount, kUnrefCallDtor> {
+ public:
+  // If on_call_destruction_complete is non-null, then it will be
+  // invoked once the LoadBalancedCall is completely destroyed.
+  // If it is null, then the caller is responsible for checking whether
+  // the LB call has a subchannel call and ensuring that the
+  // on_call_destruction_complete closure passed down from the surface
+  // is not invoked until after the subchannel call stack is destroyed.
+  LoadBalancedCall(ClientChannel* chand, const grpc_call_element_args& args,
+                   grpc_polling_entity* pollent,
+                   grpc_closure* on_call_destruction_complete);
+  ~LoadBalancedCall() override;
+
+  void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
+
+  // Invoked by channel for queued LB picks when the picker is updated.
+  static void PickSubchannel(void* arg, grpc_error_handle error);
+  // Helper function for performing an LB pick while holding the data plane
+  // mutex.  Returns true if the pick is complete, in which case the caller
+  // must invoke PickDone() or AsyncPickDone() with the returned error.
+  bool PickSubchannelLocked(grpc_error_handle* error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_);
+  // Schedules a callback to process the completed pick.  The callback
+  // will not run until after this method returns.
+  void AsyncPickDone(grpc_error_handle error);
+
+  RefCountedPtr<SubchannelCall> subchannel_call() const {
+    return subchannel_call_;
+  }
+
+ private:
+  class LbQueuedCallCanceller;
+  class Metadata;
+  class LbCallState;
+
+  // Returns the index into pending_batches_ to be used for batch.
+  static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
+  void PendingBatchesAdd(grpc_transport_stream_op_batch* batch);
+  static void FailPendingBatchInCallCombiner(void* arg,
+                                             grpc_error_handle error);
+  // A predicate type and some useful implementations for PendingBatchesFail().
+  typedef bool (*YieldCallCombinerPredicate)(
+      const CallCombinerClosureList& closures);
+  static bool YieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
+    return true;
+  }
+  static bool NoYieldCallCombiner(const CallCombinerClosureList& /*closures*/) {
+    return false;
+  }
+  static bool YieldCallCombinerIfPendingBatchesFound(
+      const CallCombinerClosureList& closures) {
+    return closures.size() > 0;
+  }
+  // Fails all pending batches.
+  // If yield_call_combiner_predicate returns true, assumes responsibility for
+  // yielding the call combiner.
+  void PendingBatchesFail(
+      grpc_error_handle error,
+      YieldCallCombinerPredicate yield_call_combiner_predicate);
+  static void ResumePendingBatchInCallCombiner(void* arg,
+                                               grpc_error_handle ignored);
+  // Resumes all pending batches on subchannel_call_.
+  void PendingBatchesResume();
+
+  static void RecvTrailingMetadataReadyForLoadBalancingPolicy(
+      void* arg, grpc_error_handle error);
+  void InjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
+      grpc_transport_stream_op_batch* batch);
+
+  void CreateSubchannelCall();
+  // Invoked when a pick is completed, on both success or failure.
+  static void PickDone(void* arg, grpc_error_handle error);
+  // Removes the call from the channel's list of queued picks if present.
+  void MaybeRemoveCallFromLbQueuedCallsLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_);
+  // Adds the call to the channel's list of queued picks if not already present.
+  void MaybeAddCallToLbQueuedCallsLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannel::data_plane_mu_);
+
+  ClientChannel* chand_;
+
+  // TODO(roth): Instead of duplicating these fields in every filter
+  // that uses any one of them, we should store them in the call
+  // context.  This will save per-call memory overhead.
+  grpc_slice path_;  // Request path.
+  gpr_cycle_counter call_start_time_;
+  grpc_millis deadline_;
+  Arena* arena_;
+  grpc_call_stack* owning_call_;
+  CallCombiner* call_combiner_;
+  grpc_call_context_element* call_context_;
+  grpc_polling_entity* pollent_;
+  grpc_closure* on_call_destruction_complete_;
+
+  // Set when we get a cancel_stream op.
+  grpc_error_handle cancel_error_ = GRPC_ERROR_NONE;
+
+  // Set when we fail inside the LB call.
+  grpc_error_handle failure_error_ = GRPC_ERROR_NONE;
+
+  grpc_closure pick_closure_;
+
+  // Accessed while holding ClientChannel::data_plane_mu_.
+  ClientChannel::LbQueuedCall queued_call_
+      ABSL_GUARDED_BY(&ClientChannel::data_plane_mu_);
+  bool queued_pending_lb_pick_ ABSL_GUARDED_BY(&ClientChannel::data_plane_mu_) =
+      false;
+  LbQueuedCallCanceller* lb_call_canceller_
+      ABSL_GUARDED_BY(&ClientChannel::data_plane_mu_) = nullptr;
+
+  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
+  const LoadBalancingPolicy::BackendMetricData* backend_metric_data_ = nullptr;
+  std::function<void(grpc_error_handle, LoadBalancingPolicy::MetadataInterface*,
+                     LoadBalancingPolicy::CallState*)>
+      lb_recv_trailing_metadata_ready_;
+
+  RefCountedPtr<SubchannelCall> subchannel_call_;
+
+  // For intercepting recv_trailing_metadata_ready for the LB policy.
+  grpc_metadata_batch* recv_trailing_metadata_ = nullptr;
+  grpc_closure recv_trailing_metadata_ready_;
+  grpc_closure* original_recv_trailing_metadata_ready_ = nullptr;
+
+  // Batches are added to this list when received from above.
+  // They are removed when we are done handling the batch (i.e., when
+  // either we have invoked all of the batch's callbacks or we have
+  // passed the batch down to the subchannel call and are not
+  // intercepting any of its callbacks).
+  grpc_transport_stream_op_batch* pending_batches_[MAX_PENDING_BATCHES] = {};
+};
+
+}  // namespace grpc_core
 
 #endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
diff --git a/grpc/src/core/ext/filters/client_channel/client_channel_channelz.h b/grpc/src/core/ext/filters/client_channel/client_channel_channelz.h
index 1a35abe..a106897 100644
--- a/grpc/src/core/ext/filters/client_channel/client_channel_channelz.h
+++ b/grpc/src/core/ext/filters/client_channel/client_channel_channelz.h
@@ -63,7 +63,7 @@
  private:
   Atomic<grpc_connectivity_state> connectivity_state_{GRPC_CHANNEL_IDLE};
   Mutex socket_mu_;
-  RefCountedPtr<SocketNode> child_socket_;
+  RefCountedPtr<SocketNode> child_socket_ ABSL_GUARDED_BY(socket_mu_);
   std::string target_;
   CallCountingHelper call_counter_;
   ChannelTrace trace_;
diff --git a/grpc/src/core/ext/filters/client_channel/client_channel_factory.h b/grpc/src/core/ext/filters/client_channel/client_channel_factory.h
index 79797bb..75d74d6 100644
--- a/grpc/src/core/ext/filters/client_channel/client_channel_factory.h
+++ b/grpc/src/core/ext/filters/client_channel/client_channel_factory.h
@@ -32,7 +32,8 @@
   virtual ~ClientChannelFactory() = default;
 
   // Creates a subchannel with the specified args.
-  virtual Subchannel* CreateSubchannel(const grpc_channel_args* args) = 0;
+  virtual RefCountedPtr<Subchannel> CreateSubchannel(
+      const grpc_channel_args* args) = 0;
 
   // Returns a channel arg containing the specified factory.
   static grpc_arg CreateChannelArg(ClientChannelFactory* factory);
diff --git a/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc b/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc
index 5690545..1d33d25 100644
--- a/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc
+++ b/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc
@@ -34,6 +34,7 @@
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
+#include "src/core/ext/filters/client_channel/retry_service_config.h"
 #include "src/core/ext/filters/client_channel/retry_throttle.h"
 #include "src/core/ext/filters/client_channel/service_config_parser.h"
 #include "src/core/lib/surface/channel_init.h"
@@ -46,6 +47,7 @@
 void grpc_client_channel_init(void) {
   grpc_core::ServiceConfigParser::Init();
   grpc_core::internal::ClientChannelServiceConfigParser::Register();
+  grpc_core::internal::RetryServiceConfigParser::Register();
   grpc_core::LoadBalancingPolicyRegistry::Builder::InitRegistry();
   grpc_core::ResolverRegistry::Builder::InitRegistry();
   grpc_core::internal::ServerRetryThrottleMap::Init();
@@ -54,7 +56,8 @@
   grpc_core::GlobalSubchannelPool::Init();
   grpc_channel_init_register_stage(
       GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter,
-      const_cast<grpc_channel_filter*>(&grpc_client_channel_filter));
+      const_cast<grpc_channel_filter*>(
+          &grpc_core::ClientChannel::kFilterVtable));
   grpc_http_connect_register_handshaker_factory();
   grpc_client_channel_global_init_backup_polling();
 }
diff --git a/grpc/src/core/ext/filters/client_channel/config_selector.h b/grpc/src/core/ext/filters/client_channel/config_selector.h
index 62e4ce5..98ae07e 100644
--- a/grpc/src/core/ext/filters/client_channel/config_selector.h
+++ b/grpc/src/core/ext/filters/client_channel/config_selector.h
@@ -52,7 +52,7 @@
 
   struct CallConfig {
     // Can be set to indicate the call should be failed.
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     // The per-method parsed configs that will be passed to
     // ServiceConfigCallData.
     const ServiceConfigParser::ParsedConfigVector* method_configs = nullptr;
@@ -82,8 +82,16 @@
     return cs1->Equals(cs2);
   }
 
+  // The channel will call this when the resolver returns a new ConfigSelector
+  // to determine what set of dynamic filters will be configured.
   virtual std::vector<const grpc_channel_filter*> GetFilters() { return {}; }
 
+  // Modifies channel args to be passed to the dynamic filter stack.
+  // Takes ownership of argument.  Caller takes ownership of result.
+  virtual grpc_channel_args* ModifyChannelArgs(grpc_channel_args* args) {
+    return args;
+  }
+
   virtual CallConfig GetCallConfig(GetCallConfigArgs args) = 0;
 
   grpc_arg MakeChannelArg() const;
@@ -106,7 +114,7 @@
 
   // Only comparing the ConfigSelector itself, not the underlying
   // service config, so we always return true.
-  bool Equals(const ConfigSelector* other) const override { return true; }
+  bool Equals(const ConfigSelector* /*other*/) const override { return true; }
 
   CallConfig GetCallConfig(GetCallConfigArgs args) override {
     CallConfig call_config;
diff --git a/grpc/src/core/ext/filters/client_channel/connector.h b/grpc/src/core/ext/filters/client_channel/connector.h
index 2564714..20e25b5 100644
--- a/grpc/src/core/ext/filters/client_channel/connector.h
+++ b/grpc/src/core/ext/filters/client_channel/connector.h
@@ -66,7 +66,7 @@
 
   // Cancels any in-flight connection attempt and shuts down the
   // connector.
-  virtual void Shutdown(grpc_error* error) = 0;
+  virtual void Shutdown(grpc_error_handle error) = 0;
 
   void Orphan() override {
     Shutdown(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Subchannel disconnected"));
diff --git a/grpc/src/core/ext/filters/client_channel/dynamic_filters.cc b/grpc/src/core/ext/filters/client_channel/dynamic_filters.cc
index afde3c7..47c05a3 100644
--- a/grpc/src/core/ext/filters/client_channel/dynamic_filters.cc
+++ b/grpc/src/core/ext/filters/client_channel/dynamic_filters.cc
@@ -18,6 +18,7 @@
 
 #include "src/core/ext/filters/client_channel/dynamic_filters.h"
 
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/surface/lame_client.h"
 
@@ -36,7 +37,7 @@
 // DynamicFilters::Call
 //
 
-DynamicFilters::Call::Call(Args args, grpc_error** error)
+DynamicFilters::Call::Call(Args args, grpc_error_handle* error)
     : channel_stack_(std::move(args.channel_stack)) {
   grpc_call_stack* call_stack = CALL_TO_CALL_STACK(this);
   const grpc_call_element_args call_args = {
@@ -52,8 +53,7 @@
   *error = grpc_call_stack_init(channel_stack_->channel_stack_, 1, Destroy,
                                 this, &call_args);
   if (GPR_UNLIKELY(*error != GRPC_ERROR_NONE)) {
-    const char* error_string = grpc_error_string(*error);
-    gpr_log(GPR_ERROR, "error: %s", error_string);
+    gpr_log(GPR_ERROR, "error: %s", grpc_error_std_string(*error).c_str());
     return;
   }
   grpc_call_stack_set_pollset_or_pollset_set(call_stack, args.pollent);
@@ -93,7 +93,7 @@
   GRPC_CALL_STACK_UNREF(CALL_TO_CALL_STACK(this), reason);
 }
 
-void DynamicFilters::Call::Destroy(void* arg, grpc_error* /*error*/) {
+void DynamicFilters::Call::Destroy(void* arg, grpc_error_handle /*error*/) {
   DynamicFilters::Call* self = static_cast<DynamicFilters::Call*>(arg);
   // Keep some members before destroying the subchannel call.
   grpc_closure* after_call_stack_destroy = self->after_call_stack_destroy_;
@@ -123,13 +123,13 @@
 
 namespace {
 
-void DestroyChannelStack(void* arg, grpc_error* /*error*/) {
+void DestroyChannelStack(void* arg, grpc_error_handle /*error*/) {
   grpc_channel_stack* channel_stack = static_cast<grpc_channel_stack*>(arg);
   grpc_channel_stack_destroy(channel_stack);
   gpr_free(channel_stack);
 }
 
-std::pair<grpc_channel_stack*, grpc_error*> CreateChannelStack(
+std::pair<grpc_channel_stack*, grpc_error_handle> CreateChannelStack(
     const grpc_channel_args* args,
     std::vector<const grpc_channel_filter*> filters) {
   // Allocate memory for channel stack.
@@ -138,13 +138,13 @@
   grpc_channel_stack* channel_stack =
       reinterpret_cast<grpc_channel_stack*>(gpr_zalloc(channel_stack_size));
   // Initialize stack.
-  grpc_error* error = grpc_channel_stack_init(
+  grpc_error_handle error = grpc_channel_stack_init(
       /*initial_refs=*/1, DestroyChannelStack, channel_stack, filters.data(),
       filters.size(), args, /*optional_transport=*/nullptr, "DynamicFilters",
       channel_stack);
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "error initializing client internal stack: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     grpc_channel_stack_destroy(channel_stack);
     gpr_free(channel_stack);
     return {nullptr, error};
@@ -160,12 +160,16 @@
   // Attempt to create channel stack from requested filters.
   auto p = CreateChannelStack(args, std::move(filters));
   if (p.second != GRPC_ERROR_NONE) {
-    // Initial pass failed.  Create with lame filter.
-    grpc_error* error = p.second;
-    p = CreateChannelStack(args, {&grpc_lame_filter});
+    // Channel stack creation failed with requested filters.
+    // Create with lame filter instead.
+    grpc_error_handle error = p.second;
+    grpc_arg error_arg = MakeLameClientErrorArg(error);
+    grpc_channel_args* new_args =
+        grpc_channel_args_copy_and_add(args, &error_arg, 1);
+    GRPC_ERROR_UNREF(error);
+    p = CreateChannelStack(new_args, {&grpc_lame_filter});
     GPR_ASSERT(p.second == GRPC_ERROR_NONE);
-    grpc_channel_element* elem = grpc_channel_stack_element(p.first, 0);
-    SetLameFilterError(elem, error);
+    grpc_channel_args_destroy(new_args);
   }
   return MakeRefCounted<DynamicFilters>(p.first);
 }
@@ -175,7 +179,7 @@
 }
 
 RefCountedPtr<DynamicFilters::Call> DynamicFilters::CreateCall(
-    DynamicFilters::Call::Args args, grpc_error** error) {
+    DynamicFilters::Call::Args args, grpc_error_handle* error) {
   size_t allocation_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Call)) +
                            channel_stack_->call_stack_size;
   Call* call = static_cast<Call*>(args.arena->Alloc(allocation_size));
diff --git a/grpc/src/core/ext/filters/client_channel/dynamic_filters.h b/grpc/src/core/ext/filters/client_channel/dynamic_filters.h
index bcdc6d3..08a7f49 100644
--- a/grpc/src/core/ext/filters/client_channel/dynamic_filters.h
+++ b/grpc/src/core/ext/filters/client_channel/dynamic_filters.h
@@ -46,7 +46,7 @@
       CallCombiner* call_combiner;
     };
 
-    Call(Args args, grpc_error** error);
+    Call(Args args, grpc_error_handle* error);
 
     // Continues processing a transport stream op batch.
     void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
@@ -73,7 +73,7 @@
     void IncrementRefCount();
     void IncrementRefCount(const DebugLocation& location, const char* reason);
 
-    static void Destroy(void* arg, grpc_error* error);
+    static void Destroy(void* arg, grpc_error_handle error);
 
     RefCountedPtr<DynamicFilters> channel_stack_;
     grpc_closure* after_call_stack_destroy_ = nullptr;
@@ -88,7 +88,7 @@
 
   ~DynamicFilters() override;
 
-  RefCountedPtr<Call> CreateCall(Call::Args args, grpc_error** error);
+  RefCountedPtr<Call> CreateCall(Call::Args args, grpc_error_handle* error);
 
  private:
   grpc_channel_stack* channel_stack_;
diff --git a/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.cc b/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.cc
index 546d1c4..72593a6 100644
--- a/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.cc
+++ b/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.cc
@@ -27,16 +27,6 @@
 #define GRPC_REGISTER_SUBCHANNEL_CALM_DOWN_AFTER_ATTEMPTS 100
 #define GRPC_REGISTER_SUBCHANNEL_CALM_DOWN_MICROS 10
 
-GlobalSubchannelPool::GlobalSubchannelPool() {
-  subchannel_map_ = grpc_avl_create(&subchannel_avl_vtable_);
-  gpr_mu_init(&mu_);
-}
-
-GlobalSubchannelPool::~GlobalSubchannelPool() {
-  gpr_mu_destroy(&mu_);
-  grpc_avl_unref(subchannel_map_, nullptr);
-}
-
 void GlobalSubchannelPool::Init() {
   instance_ = new RefCountedPtr<GlobalSubchannelPool>(
       MakeRefCounted<GlobalSubchannelPool>());
@@ -57,145 +47,37 @@
   return *instance_;
 }
 
-Subchannel* GlobalSubchannelPool::RegisterSubchannel(SubchannelKey* key,
-                                                     Subchannel* constructed) {
-  Subchannel* c = nullptr;
-  // Compare and swap (CAS) loop:
-  for (int attempt_count = 0; c == nullptr; attempt_count++) {
-    // Ref the shared map to have a local copy.
-    gpr_mu_lock(&mu_);
-    grpc_avl old_map = grpc_avl_ref(subchannel_map_, nullptr);
-    gpr_mu_unlock(&mu_);
-    // Check to see if a subchannel already exists.
-    c = static_cast<Subchannel*>(grpc_avl_get(old_map, key, nullptr));
-    if (c != nullptr) {
-      // The subchannel already exists. Try to reuse it.
-      c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "subchannel_register+reuse");
-      if (c != nullptr) {
-        GRPC_SUBCHANNEL_UNREF(constructed,
-                              "subchannel_register+found_existing");
-        // Exit the CAS loop without modifying the shared map.
-      } else {
-        // Reuse of the subchannel failed, so retry CAS loop
-        if (attempt_count >=
-            GRPC_REGISTER_SUBCHANNEL_CALM_DOWN_AFTER_ATTEMPTS) {
-          // GRPC_SUBCHANNEL_REF_FROM_WEAK_REF returning nullptr means that the
-          // subchannel we got is no longer valid and it's going to be removed
-          // from the AVL tree soon. Spinning here excesively here can actually
-          // prevent another thread from removing the subchannel, basically
-          // resulting in a live lock. See b/157516542 for more details.
-          // TODO(jtattermusch): the entire ref-counting mechanism for
-          // subchannels should be overhaulded, but the current workaround
-          // is fine for short-term.
-          // TODO(jtattermusch): gpr does not support thread yield operation,
-          // so a very short wait is the best we can do.
-          gpr_sleep_until(gpr_time_add(
-              gpr_now(GPR_CLOCK_REALTIME),
-              gpr_time_from_micros(GRPC_REGISTER_SUBCHANNEL_CALM_DOWN_MICROS,
-                                   GPR_TIMESPAN)));
-        }
-      }
-    } else {
-      // There hasn't been such subchannel. Add one.
-      // Note that we should ref the old map first because grpc_avl_add() will
-      // unref it while we still need to access it later.
-      grpc_avl new_map = grpc_avl_add(
-          grpc_avl_ref(old_map, nullptr), new SubchannelKey(*key),
-          GRPC_SUBCHANNEL_WEAK_REF(constructed, "subchannel_register+new"),
-          nullptr);
-      // Try to publish the change to the shared map. It may happen (but
-      // unlikely) that some other thread has changed the shared map, so compare
-      // to make sure it's unchanged before swapping. Retry if it's changed.
-      gpr_mu_lock(&mu_);
-      if (old_map.root == subchannel_map_.root) {
-        GPR_SWAP(grpc_avl, new_map, subchannel_map_);
-        c = constructed;
-      }
-      gpr_mu_unlock(&mu_);
-      grpc_avl_unref(new_map, nullptr);
-    }
-    grpc_avl_unref(old_map, nullptr);
+RefCountedPtr<Subchannel> GlobalSubchannelPool::RegisterSubchannel(
+    const SubchannelKey& key, RefCountedPtr<Subchannel> constructed) {
+  MutexLock lock(&mu_);
+  auto it = subchannel_map_.find(key);
+  if (it != subchannel_map_.end()) {
+    RefCountedPtr<Subchannel> existing = it->second->RefIfNonZero();
+    if (existing != nullptr) return existing;
   }
-  return c;
-}
-
-void GlobalSubchannelPool::UnregisterSubchannel(SubchannelKey* key) {
-  bool done = false;
-  // Compare and swap (CAS) loop:
-  while (!done) {
-    // Ref the shared map to have a local copy.
-    gpr_mu_lock(&mu_);
-    grpc_avl old_map = grpc_avl_ref(subchannel_map_, nullptr);
-    gpr_mu_unlock(&mu_);
-    // Remove the subchannel.
-    // Note that we should ref the old map first because grpc_avl_remove() will
-    // unref it while we still need to access it later.
-    grpc_avl new_map =
-        grpc_avl_remove(grpc_avl_ref(old_map, nullptr), key, nullptr);
-    // Try to publish the change to the shared map. It may happen (but
-    // unlikely) that some other thread has changed the shared map, so compare
-    // to make sure it's unchanged before swapping. Retry if it's changed.
-    gpr_mu_lock(&mu_);
-    if (old_map.root == subchannel_map_.root) {
-      GPR_SWAP(grpc_avl, new_map, subchannel_map_);
-      done = true;
-    }
-    gpr_mu_unlock(&mu_);
-    grpc_avl_unref(new_map, nullptr);
-    grpc_avl_unref(old_map, nullptr);
-  }
-}
-
-Subchannel* GlobalSubchannelPool::FindSubchannel(SubchannelKey* key) {
-  // Lock, and take a reference to the subchannel map.
-  // We don't need to do the search under a lock as AVL's are immutable.
-  gpr_mu_lock(&mu_);
-  grpc_avl index = grpc_avl_ref(subchannel_map_, nullptr);
-  gpr_mu_unlock(&mu_);
-  Subchannel* c = static_cast<Subchannel*>(grpc_avl_get(index, key, nullptr));
-  if (c != nullptr) c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "found_from_pool");
-  grpc_avl_unref(index, nullptr);
-  return c;
+  subchannel_map_[key] = constructed.get();
+  return constructed;
 }
 
 RefCountedPtr<GlobalSubchannelPool>* GlobalSubchannelPool::instance_ = nullptr;
 
-namespace {
-
-void sck_avl_destroy(void* p, void* /*user_data*/) {
-  SubchannelKey* key = static_cast<SubchannelKey*>(p);
-  delete key;
+void GlobalSubchannelPool::UnregisterSubchannel(const SubchannelKey& key,
+                                                Subchannel* subchannel) {
+  MutexLock lock(&mu_);
+  auto it = subchannel_map_.find(key);
+  // delete only if key hasn't been re-registered to a different subchannel
+  // between strong-unreffing and unregistration of subchannel.
+  if (it != subchannel_map_.end() && it->second == subchannel) {
+    subchannel_map_.erase(it);
+  }
 }
 
-void* sck_avl_copy(void* p, void* /*unused*/) {
-  const SubchannelKey* key = static_cast<const SubchannelKey*>(p);
-  auto* new_key = new SubchannelKey(*key);
-  return static_cast<void*>(new_key);
+RefCountedPtr<Subchannel> GlobalSubchannelPool::FindSubchannel(
+    const SubchannelKey& key) {
+  MutexLock lock(&mu_);
+  auto it = subchannel_map_.find(key);
+  if (it == subchannel_map_.end()) return nullptr;
+  return it->second->RefIfNonZero();
 }
 
-long sck_avl_compare(void* a, void* b, void* /*unused*/) {
-  const SubchannelKey* key_a = static_cast<const SubchannelKey*>(a);
-  const SubchannelKey* key_b = static_cast<const SubchannelKey*>(b);
-  return key_a->Cmp(*key_b);
-}
-
-void scv_avl_destroy(void* p, void* /*user_data*/) {
-  GRPC_SUBCHANNEL_WEAK_UNREF((Subchannel*)p, "global_subchannel_pool");
-}
-
-void* scv_avl_copy(void* p, void* /*unused*/) {
-  GRPC_SUBCHANNEL_WEAK_REF((Subchannel*)p, "global_subchannel_pool");
-  return p;
-}
-
-}  // namespace
-
-const grpc_avl_vtable GlobalSubchannelPool::subchannel_avl_vtable_ = {
-    sck_avl_destroy,  // destroy_key
-    sck_avl_copy,     // copy_key
-    sck_avl_compare,  // compare_keys
-    scv_avl_destroy,  // destroy_value
-    scv_avl_copy      // copy_value
-};
-
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.h b/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.h
index 96dc8d7..7ff9b07 100644
--- a/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.h
+++ b/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.h
@@ -21,7 +21,10 @@
 
 #include <grpc/support/port_platform.h>
 
+#include <map>
+
 #include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
+#include "src/core/lib/gprpp/sync.h"
 
 namespace grpc_core {
 
@@ -33,8 +36,8 @@
 class GlobalSubchannelPool final : public SubchannelPoolInterface {
  public:
   // The ctor and dtor are not intended to use directly.
-  GlobalSubchannelPool();
-  ~GlobalSubchannelPool() override;
+  GlobalSubchannelPool() {}
+  ~GlobalSubchannelPool() override {}
 
   // Should be called exactly once at filter initialization time.
   static void Init();
@@ -45,22 +48,24 @@
   static RefCountedPtr<GlobalSubchannelPool> instance();
 
   // Implements interface methods.
-  Subchannel* RegisterSubchannel(SubchannelKey* key,
-                                 Subchannel* constructed) override;
-  void UnregisterSubchannel(SubchannelKey* key) override;
-  Subchannel* FindSubchannel(SubchannelKey* key) override;
+  RefCountedPtr<Subchannel> RegisterSubchannel(
+      const SubchannelKey& key, RefCountedPtr<Subchannel> constructed) override
+      ABSL_LOCKS_EXCLUDED(mu_);
+  void UnregisterSubchannel(const SubchannelKey& key,
+                            Subchannel* subchannel) override
+      ABSL_LOCKS_EXCLUDED(mu_);
+  RefCountedPtr<Subchannel> FindSubchannel(const SubchannelKey& key) override
+      ABSL_LOCKS_EXCLUDED(mu_);
 
  private:
   // The singleton instance. (It's a pointer to RefCountedPtr so that this
   // non-local static object can be trivially destructible.)
   static RefCountedPtr<GlobalSubchannelPool>* instance_;
 
-  // The vtable for subchannel operations in an AVL tree.
-  static const grpc_avl_vtable subchannel_avl_vtable_;
   // A map from subchannel key to subchannel.
-  grpc_avl subchannel_map_;
+  std::map<SubchannelKey, Subchannel*> subchannel_map_ ABSL_GUARDED_BY(mu_);
   // To protect subchannel_map_.
-  gpr_mu mu_;
+  Mutex mu_;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/health/health_check_client.cc b/grpc/src/core/ext/filters/client_channel/health/health_check_client.cc
index 7885fad..adde23d 100644
--- a/grpc/src/core/ext/filters/client_channel/health/health_check_client.cc
+++ b/grpc/src/core/ext/filters/client_channel/health/health_check_client.cc
@@ -157,7 +157,7 @@
   grpc_timer_init(&retry_timer_, next_try, &retry_timer_callback_);
 }
 
-void HealthCheckClient::OnRetryTimer(void* arg, grpc_error* error) {
+void HealthCheckClient::OnRetryTimer(void* arg, grpc_error_handle error) {
   HealthCheckClient* self = static_cast<HealthCheckClient*>(arg);
   {
     MutexLock lock(&self->mu_);
@@ -202,7 +202,7 @@
 
 // Returns true if healthy.
 // If there was an error parsing the response, sets *error and returns false.
-bool DecodeResponse(grpc_slice_buffer* slice_buffer, grpc_error** error) {
+bool DecodeResponse(grpc_slice_buffer* slice_buffer, grpc_error_handle* error) {
   // If message is empty, assume unhealthy.
   if (slice_buffer->length == 0) {
     *error =
@@ -269,11 +269,8 @@
   // Unset the call combiner cancellation closure.  This has the
   // effect of scheduling the previously set cancellation closure, if
   // any, so that it can release any internal references it may be
-  // holding to the call stack. Also flush the closures on exec_ctx so that
-  // filters that schedule cancel notification closures on exec_ctx do not
-  // need to take a ref of the call stack to guarantee closure liveness.
+  // holding to the call stack.
   call_combiner_.SetNotifyOnCancel(nullptr);
-  ExecCtx::Get()->Flush();
   arena_->Destroy();
 }
 
@@ -293,7 +290,7 @@
       context_,
       &call_combiner_,
   };
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   call_ = SubchannelCall::Create(std::move(args), &error).release();
   // Register after-destruction callback.
   GRPC_CLOSURE_INIT(&after_call_stack_destruction_, AfterCallStackDestruction,
@@ -304,7 +301,8 @@
     gpr_log(GPR_ERROR,
             "HealthCheckClient %p CallState %p: error creating health "
             "checking call on subchannel (%s); will retry",
-            health_check_client_.get(), this, grpc_error_string(error));
+            health_check_client_.get(), this,
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     CallEndedLocked(/*retry=*/true);
     return;
@@ -381,7 +379,7 @@
 }
 
 void HealthCheckClient::CallState::StartBatchInCallCombiner(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   SubchannelCall* call =
@@ -399,14 +397,14 @@
 }
 
 void HealthCheckClient::CallState::AfterCallStackDestruction(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   delete self;
 }
 
-void HealthCheckClient::CallState::OnCancelComplete(void* arg,
-                                                    grpc_error* /*error*/) {
+void HealthCheckClient::CallState::OnCancelComplete(
+    void* arg, grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "health_cancel");
@@ -414,7 +412,7 @@
 }
 
 void HealthCheckClient::CallState::StartCancel(void* arg,
-                                               grpc_error* /*error*/) {
+                                               grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   auto* batch = grpc_make_transport_stream_op(
@@ -437,7 +435,7 @@
 }
 
 void HealthCheckClient::CallState::OnComplete(void* arg,
-                                              grpc_error* /*error*/) {
+                                              grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "on_complete");
@@ -447,7 +445,7 @@
 }
 
 void HealthCheckClient::CallState::RecvInitialMetadataReady(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_initial_metadata_ready");
@@ -455,7 +453,8 @@
   self->call_->Unref(DEBUG_LOCATION, "recv_initial_metadata_ready");
 }
 
-void HealthCheckClient::CallState::DoneReadingRecvMessage(grpc_error* error) {
+void HealthCheckClient::CallState::DoneReadingRecvMessage(
+    grpc_error_handle error) {
   recv_message_.reset();
   if (error != GRPC_ERROR_NONE) {
     GRPC_ERROR_UNREF(error);
@@ -467,10 +466,10 @@
   const bool healthy = DecodeResponse(&recv_message_buffer_, &error);
   const grpc_connectivity_state state =
       healthy ? GRPC_CHANNEL_READY : GRPC_CHANNEL_TRANSIENT_FAILURE;
-  const char* reason = error == GRPC_ERROR_NONE && !healthy
-                           ? "backend unhealthy"
-                           : grpc_error_string(error);
-  health_check_client_->SetHealthStatus(state, reason);
+  health_check_client_->SetHealthStatus(
+      state, error == GRPC_ERROR_NONE && !healthy
+                 ? "backend unhealthy"
+                 : grpc_error_std_string(error).c_str());
   seen_response_.Store(true, MemoryOrder::RELEASE);
   grpc_slice_buffer_destroy_internal(&recv_message_buffer_);
   // Start another recv_message batch.
@@ -485,9 +484,9 @@
   StartBatch(&recv_message_batch_);
 }
 
-grpc_error* HealthCheckClient::CallState::PullSliceFromRecvMessage() {
+grpc_error_handle HealthCheckClient::CallState::PullSliceFromRecvMessage() {
   grpc_slice slice;
-  grpc_error* error = recv_message_->Pull(&slice);
+  grpc_error_handle error = recv_message_->Pull(&slice);
   if (error == GRPC_ERROR_NONE) {
     grpc_slice_buffer_add(&recv_message_buffer_, slice);
   }
@@ -496,7 +495,7 @@
 
 void HealthCheckClient::CallState::ContinueReadingRecvMessage() {
   while (recv_message_->Next(SIZE_MAX, &recv_message_ready_)) {
-    grpc_error* error = PullSliceFromRecvMessage();
+    grpc_error_handle error = PullSliceFromRecvMessage();
     if (error != GRPC_ERROR_NONE) {
       DoneReadingRecvMessage(error);
       return;
@@ -509,7 +508,7 @@
 }
 
 void HealthCheckClient::CallState::OnByteStreamNext(void* arg,
-                                                    grpc_error* error) {
+                                                    grpc_error_handle error) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   if (error != GRPC_ERROR_NONE) {
@@ -528,8 +527,8 @@
   }
 }
 
-void HealthCheckClient::CallState::RecvMessageReady(void* arg,
-                                                    grpc_error* /*error*/) {
+void HealthCheckClient::CallState::RecvMessageReady(
+    void* arg, grpc_error_handle /*error*/) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_message_ready");
@@ -545,7 +544,7 @@
 }
 
 void HealthCheckClient::CallState::RecvTrailingMetadataReady(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   HealthCheckClient::CallState* self =
       static_cast<HealthCheckClient::CallState*>(arg);
   GRPC_CALL_COMBINER_STOP(&self->call_combiner_,
diff --git a/grpc/src/core/ext/filters/client_channel/health/health_check_client.h b/grpc/src/core/ext/filters/client_channel/health/health_check_client.h
index 0fc39b0..d1f063b 100644
--- a/grpc/src/core/ext/filters/client_channel/health/health_check_client.h
+++ b/grpc/src/core/ext/filters/client_channel/health/health_check_client.h
@@ -64,30 +64,30 @@
 
     void Orphan() override;
 
-    void StartCall();
+    void StartCall() ABSL_EXCLUSIVE_LOCKS_REQUIRED(&HealthCheckClient::mu_);
 
    private:
     void Cancel();
 
     void StartBatch(grpc_transport_stream_op_batch* batch);
-    static void StartBatchInCallCombiner(void* arg, grpc_error* error);
+    static void StartBatchInCallCombiner(void* arg, grpc_error_handle error);
 
-    // Requires holding health_check_client_->mu_.
-    void CallEndedLocked(bool retry);
+    void CallEndedLocked(bool retry)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(health_check_client_->mu_);
 
-    static void OnComplete(void* arg, grpc_error* error);
-    static void RecvInitialMetadataReady(void* arg, grpc_error* error);
-    static void RecvMessageReady(void* arg, grpc_error* error);
-    static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
-    static void StartCancel(void* arg, grpc_error* error);
-    static void OnCancelComplete(void* arg, grpc_error* error);
+    static void OnComplete(void* arg, grpc_error_handle error);
+    static void RecvInitialMetadataReady(void* arg, grpc_error_handle error);
+    static void RecvMessageReady(void* arg, grpc_error_handle error);
+    static void RecvTrailingMetadataReady(void* arg, grpc_error_handle error);
+    static void StartCancel(void* arg, grpc_error_handle error);
+    static void OnCancelComplete(void* arg, grpc_error_handle error);
 
-    static void OnByteStreamNext(void* arg, grpc_error* error);
+    static void OnByteStreamNext(void* arg, grpc_error_handle error);
     void ContinueReadingRecvMessage();
-    grpc_error* PullSliceFromRecvMessage();
-    void DoneReadingRecvMessage(grpc_error* error);
+    grpc_error_handle PullSliceFromRecvMessage();
+    void DoneReadingRecvMessage(grpc_error_handle error);
 
-    static void AfterCallStackDestruction(void* arg, grpc_error* error);
+    static void AfterCallStackDestruction(void* arg, grpc_error_handle error);
 
     RefCountedPtr<HealthCheckClient> health_check_client_;
     grpc_polling_entity pollent_;
@@ -141,14 +141,14 @@
   };
 
   void StartCall();
-  void StartCallLocked();  // Requires holding mu_.
+  void StartCallLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
-  void StartRetryTimerLocked();  // Requires holding mu_.
-  static void OnRetryTimer(void* arg, grpc_error* error);
+  void StartRetryTimerLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+  static void OnRetryTimer(void* arg, grpc_error_handle error);
 
   void SetHealthStatus(grpc_connectivity_state state, const char* reason);
-  void SetHealthStatusLocked(grpc_connectivity_state state,
-                             const char* reason);  // Requires holding mu_.
+  void SetHealthStatusLocked(grpc_connectivity_state state, const char* reason)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   std::string service_name_;
   RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
@@ -156,18 +156,19 @@
   RefCountedPtr<channelz::SubchannelNode> channelz_node_;
 
   Mutex mu_;
-  RefCountedPtr<ConnectivityStateWatcherInterface> watcher_;
-  bool shutting_down_ = false;
+  RefCountedPtr<ConnectivityStateWatcherInterface> watcher_
+      ABSL_GUARDED_BY(mu_);
+  bool shutting_down_ ABSL_GUARDED_BY(mu_) = false;
 
   // The data associated with the current health check call.  It holds a ref
   // to this HealthCheckClient object.
-  OrphanablePtr<CallState> call_state_;
+  OrphanablePtr<CallState> call_state_ ABSL_GUARDED_BY(mu_);
 
   // Call retry state.
-  BackOff retry_backoff_;
-  grpc_timer retry_timer_;
-  grpc_closure retry_timer_callback_;
-  bool retry_timer_callback_pending_ = false;
+  BackOff retry_backoff_ ABSL_GUARDED_BY(mu_);
+  grpc_timer retry_timer_ ABSL_GUARDED_BY(mu_);
+  grpc_closure retry_timer_callback_ ABSL_GUARDED_BY(mu_);
+  bool retry_timer_callback_pending_ ABSL_GUARDED_BY(mu_) = false;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc
index f469a5a..3dff824 100644
--- a/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc
+++ b/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc
@@ -47,7 +47,7 @@
 class HttpConnectHandshaker : public Handshaker {
  public:
   HttpConnectHandshaker();
-  void Shutdown(grpc_error* why) override;
+  void Shutdown(grpc_error_handle why) override;
   void DoHandshake(grpc_tcp_server_acceptor* acceptor,
                    grpc_closure* on_handshake_done,
                    HandshakerArgs* args) override;
@@ -55,30 +55,31 @@
 
  private:
   ~HttpConnectHandshaker() override;
-  void CleanupArgsForFailureLocked();
-  void HandshakeFailedLocked(grpc_error* error);
-  static void OnWriteDone(void* arg, grpc_error* error);
-  static void OnReadDone(void* arg, grpc_error* error);
-  static void OnWriteDoneScheduler(void* arg, grpc_error* error);
-  static void OnReadDoneScheduler(void* arg, grpc_error* error);
+  void CleanupArgsForFailureLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+  void HandshakeFailedLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+  static void OnWriteDone(void* arg, grpc_error_handle error);
+  static void OnReadDone(void* arg, grpc_error_handle error);
+  static void OnWriteDoneScheduler(void* arg, grpc_error_handle error);
+  static void OnReadDoneScheduler(void* arg, grpc_error_handle error);
 
   Mutex mu_;
 
-  bool is_shutdown_ = false;
+  bool is_shutdown_ ABSL_GUARDED_BY(mu_) = false;
   // Endpoint and read buffer to destroy after a shutdown.
-  grpc_endpoint* endpoint_to_destroy_ = nullptr;
-  grpc_slice_buffer* read_buffer_to_destroy_ = nullptr;
+  grpc_endpoint* endpoint_to_destroy_ ABSL_GUARDED_BY(mu_) = nullptr;
+  grpc_slice_buffer* read_buffer_to_destroy_ ABSL_GUARDED_BY(mu_) = nullptr;
 
   // State saved while performing the handshake.
   HandshakerArgs* args_ = nullptr;
   grpc_closure* on_handshake_done_ = nullptr;
 
   // Objects for processing the HTTP CONNECT request and response.
-  grpc_slice_buffer write_buffer_;
-  grpc_closure request_done_closure_;
-  grpc_closure response_read_closure_;
-  grpc_http_parser http_parser_;
-  grpc_http_response http_response_;
+  grpc_slice_buffer write_buffer_ ABSL_GUARDED_BY(mu_);
+  grpc_closure request_done_closure_ ABSL_GUARDED_BY(mu_);
+  grpc_closure response_read_closure_ ABSL_GUARDED_BY(mu_);
+  grpc_http_parser http_parser_ ABSL_GUARDED_BY(mu_);
+  grpc_http_response http_response_ ABSL_GUARDED_BY(mu_);
 };
 
 HttpConnectHandshaker::~HttpConnectHandshaker() {
@@ -107,7 +108,7 @@
 
 // If the handshake failed or we're shutting down, clean up and invoke the
 // callback with the error.
-void HttpConnectHandshaker::HandshakeFailedLocked(grpc_error* error) {
+void HttpConnectHandshaker::HandshakeFailedLocked(grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) {
     // If we were shut down after an endpoint operation succeeded but
     // before the endpoint callback was invoked, we need to generate our
@@ -133,7 +134,8 @@
 
 // This callback can be invoked inline while already holding onto the mutex. To
 // avoid deadlocks, schedule OnWriteDone on ExecCtx.
-void HttpConnectHandshaker::OnWriteDoneScheduler(void* arg, grpc_error* error) {
+void HttpConnectHandshaker::OnWriteDoneScheduler(void* arg,
+                                                 grpc_error_handle error) {
   auto* handshaker = static_cast<HttpConnectHandshaker*>(arg);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION,
@@ -144,14 +146,14 @@
 }
 
 // Callback invoked when finished writing HTTP CONNECT request.
-void HttpConnectHandshaker::OnWriteDone(void* arg, grpc_error* error) {
+void HttpConnectHandshaker::OnWriteDone(void* arg, grpc_error_handle error) {
   auto* handshaker = static_cast<HttpConnectHandshaker*>(arg);
   ReleasableMutexLock lock(&handshaker->mu_);
   if (error != GRPC_ERROR_NONE || handshaker->is_shutdown_) {
     // If the write failed or we're shutting down, clean up and invoke the
     // callback with the error.
     handshaker->HandshakeFailedLocked(GRPC_ERROR_REF(error));
-    lock.Unlock();
+    lock.Release();
     handshaker->Unref();
   } else {
     // Otherwise, read the response.
@@ -167,7 +169,8 @@
 
 // This callback can be invoked inline while already holding onto the mutex. To
 // avoid deadlocks, schedule OnReadDone on ExecCtx.
-void HttpConnectHandshaker::OnReadDoneScheduler(void* arg, grpc_error* error) {
+void HttpConnectHandshaker::OnReadDoneScheduler(void* arg,
+                                                grpc_error_handle error) {
   auto* handshaker = static_cast<HttpConnectHandshaker*>(arg);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION,
@@ -178,7 +181,7 @@
 }
 
 // Callback invoked for reading HTTP CONNECT response.
-void HttpConnectHandshaker::OnReadDone(void* arg, grpc_error* error) {
+void HttpConnectHandshaker::OnReadDone(void* arg, grpc_error_handle error) {
   auto* handshaker = static_cast<HttpConnectHandshaker*>(arg);
   ReleasableMutexLock lock(&handshaker->mu_);
   if (error != GRPC_ERROR_NONE || handshaker->is_shutdown_) {
@@ -256,7 +259,7 @@
   // Set shutdown to true so that subsequent calls to
   // http_connect_handshaker_shutdown() do nothing.
   handshaker->is_shutdown_ = true;
-  lock.Unlock();
+  lock.Release();
   handshaker->Unref();
 }
 
@@ -264,7 +267,7 @@
 // Public handshaker methods
 //
 
-void HttpConnectHandshaker::Shutdown(grpc_error* why) {
+void HttpConnectHandshaker::Shutdown(grpc_error_handle why) {
   {
     MutexLock lock(&mu_);
     if (!is_shutdown_) {
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy.cc b/grpc/src/core/ext/filters/client_channel/lb_policy.cc
index 4ef8cbb..b927224 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy.cc
@@ -70,6 +70,9 @@
 
 LoadBalancingPolicy::UpdateArgs& LoadBalancingPolicy::UpdateArgs::operator=(
     const UpdateArgs& other) {
+  if (&other == this) {
+    return *this;
+  }
   addresses = other.addresses;
   config = other.config;
   grpc_channel_args_destroy(args);
@@ -110,7 +113,7 @@
     auto* parent = parent_->Ref().release();  // ref held by lambda.
     ExecCtx::Run(DEBUG_LOCATION,
                  GRPC_CLOSURE_CREATE(
-                     [](void* arg, grpc_error* /*error*/) {
+                     [](void* arg, grpc_error_handle /*error*/) {
                        auto* parent = static_cast<LoadBalancingPolicy*>(arg);
                        parent->work_serializer()->Run(
                            [parent]() {
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy.h b/grpc/src/core/ext/filters/client_channel/lb_policy.h
index c9fc142..1c6f309 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy.h
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy.h
@@ -230,7 +230,7 @@
     /// Error to be set when returning a failure.
     // TODO(roth): Replace this with something similar to grpc::Status,
     // so that we don't expose grpc_error to this API.
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
 
     /// Used only if type is PICK_COMPLETE.
     /// Callback set by LB policy to be notified of trailing metadata.
@@ -243,7 +243,7 @@
     // TODO(roth): The arguments to this callback should be moved into a
     // struct, so that we can later add new fields without breaking
     // existing implementations.
-    std::function<void(grpc_error*, MetadataInterface*, CallState*)>
+    std::function<void(grpc_error_handle, MetadataInterface*, CallState*)>
         recv_trailing_metadata_ready;
   };
 
@@ -387,13 +387,13 @@
   // A picker that returns PICK_TRANSIENT_FAILURE for all picks.
   class TransientFailurePicker : public SubchannelPicker {
    public:
-    explicit TransientFailurePicker(grpc_error* error) : error_(error) {}
+    explicit TransientFailurePicker(grpc_error_handle error) : error_(error) {}
     ~TransientFailurePicker() override { GRPC_ERROR_UNREF(error_); }
 
     PickResult Pick(PickArgs args) override;
 
    private:
-    grpc_error* error_;
+    grpc_error_handle error_;
   };
 
  protected:
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
index c8d1b1d..5f7d75c 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
@@ -30,8 +30,8 @@
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/profiling/timers.h"
 
-static grpc_error* clr_init_channel_elem(grpc_channel_element* /*elem*/,
-                                         grpc_channel_element_args* /*args*/) {
+static grpc_error_handle clr_init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
@@ -54,7 +54,7 @@
 
 }  // namespace
 
-static void on_complete_for_send(void* arg, grpc_error* error) {
+static void on_complete_for_send(void* arg, grpc_error_handle error) {
   call_data* calld = static_cast<call_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
     calld->send_initial_metadata_succeeded = true;
@@ -63,7 +63,7 @@
                           GRPC_ERROR_REF(error));
 }
 
-static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
+static void recv_initial_metadata_ready(void* arg, grpc_error_handle error) {
   call_data* calld = static_cast<call_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
     calld->recv_initial_metadata_succeeded = true;
@@ -73,8 +73,8 @@
                           GRPC_ERROR_REF(error));
 }
 
-static grpc_error* clr_init_call_elem(grpc_call_element* elem,
-                                      const grpc_call_element_args* args) {
+static grpc_error_handle clr_init_call_elem(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   GPR_ASSERT(args->context != nullptr);
   new (elem->call_data) call_data();
   return GRPC_ERROR_NONE;
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index 6a46a0b..4b4f1ab 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -90,6 +90,8 @@
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
@@ -98,9 +100,7 @@
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
@@ -186,17 +186,17 @@
     void ScheduleNextClientLoadReportLocked();
     void SendClientLoadReportLocked();
 
-    static void MaybeSendClientLoadReport(void* arg, grpc_error* error);
-    static void ClientLoadReportDone(void* arg, grpc_error* error);
-    static void OnInitialRequestSent(void* arg, grpc_error* error);
-    static void OnBalancerMessageReceived(void* arg, grpc_error* error);
-    static void OnBalancerStatusReceived(void* arg, grpc_error* error);
+    static void MaybeSendClientLoadReport(void* arg, grpc_error_handle error);
+    static void ClientLoadReportDone(void* arg, grpc_error_handle error);
+    static void OnInitialRequestSent(void* arg, grpc_error_handle error);
+    static void OnBalancerMessageReceived(void* arg, grpc_error_handle error);
+    static void OnBalancerStatusReceived(void* arg, grpc_error_handle error);
 
-    void MaybeSendClientLoadReportLocked(grpc_error* error);
-    void ClientLoadReportDoneLocked(grpc_error* error);
+    void MaybeSendClientLoadReportLocked(grpc_error_handle error);
+    void ClientLoadReportDoneLocked(grpc_error_handle error);
     void OnInitialRequestSentLocked();
     void OnBalancerMessageReceivedLocked();
-    void OnBalancerStatusReceivedLocked(grpc_error* error);
+    void OnBalancerStatusReceivedLocked(grpc_error_handle error);
 
     // The owning LB policy.
     RefCountedPtr<LoadBalancingPolicy> grpclb_policy_;
@@ -410,14 +410,14 @@
 
   // Methods for dealing with fallback state.
   void MaybeEnterFallbackModeAfterStartup();
-  static void OnFallbackTimer(void* arg, grpc_error* error);
-  void OnFallbackTimerLocked(grpc_error* error);
+  static void OnFallbackTimer(void* arg, grpc_error_handle error);
+  void OnFallbackTimerLocked(grpc_error_handle error);
 
   // Methods for dealing with the balancer call.
   void StartBalancerCallLocked();
   void StartBalancerCallRetryTimerLocked();
-  static void OnBalancerCallRetryTimer(void* arg, grpc_error* error);
-  void OnBalancerCallRetryTimerLocked(grpc_error* error);
+  static void OnBalancerCallRetryTimer(void* arg, grpc_error_handle error);
+  void OnBalancerCallRetryTimerLocked(grpc_error_handle error);
 
   // Methods for dealing with the child policy.
   grpc_channel_args* CreateChildPolicyArgsLocked(
@@ -893,6 +893,10 @@
 }
 
 void GrpcLb::BalancerCallState::ScheduleNextClientLoadReportLocked() {
+  // InvalidateNow to avoid getting stuck re-initializing this timer
+  // in a loop while draining the currently-held WorkSerializer.
+  // Also see https://github.com/grpc/grpc/issues/26079.
+  ExecCtx::Get()->InvalidateNow();
   const grpc_millis next_client_load_report_time =
       ExecCtx::Get()->Now() + client_stats_report_interval_;
   GRPC_CLOSURE_INIT(&client_load_report_closure_, MaybeSendClientLoadReport,
@@ -902,8 +906,8 @@
   client_load_report_timer_callback_pending_ = true;
 }
 
-void GrpcLb::BalancerCallState::MaybeSendClientLoadReport(void* arg,
-                                                          grpc_error* error) {
+void GrpcLb::BalancerCallState::MaybeSendClientLoadReport(
+    void* arg, grpc_error_handle error) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   lb_calld->grpclb_policy()->work_serializer()->Run(
@@ -912,7 +916,7 @@
 }
 
 void GrpcLb::BalancerCallState::MaybeSendClientLoadReportLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   client_load_report_timer_callback_pending_ = false;
   if (error != GRPC_ERROR_NONE || this != grpclb_policy()->lb_calld_.get()) {
     Unref(DEBUG_LOCATION, "client_load_report");
@@ -982,7 +986,7 @@
 }
 
 void GrpcLb::BalancerCallState::ClientLoadReportDone(void* arg,
-                                                     grpc_error* error) {
+                                                     grpc_error_handle error) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   lb_calld->grpclb_policy()->work_serializer()->Run(
@@ -990,7 +994,8 @@
       DEBUG_LOCATION);
 }
 
-void GrpcLb::BalancerCallState::ClientLoadReportDoneLocked(grpc_error* error) {
+void GrpcLb::BalancerCallState::ClientLoadReportDoneLocked(
+    grpc_error_handle error) {
   grpc_byte_buffer_destroy(send_message_payload_);
   send_message_payload_ = nullptr;
   if (error != GRPC_ERROR_NONE || this != grpclb_policy()->lb_calld_.get()) {
@@ -1001,8 +1006,8 @@
   ScheduleNextClientLoadReportLocked();
 }
 
-void GrpcLb::BalancerCallState::OnInitialRequestSent(void* arg,
-                                                     grpc_error* /*error*/) {
+void GrpcLb::BalancerCallState::OnInitialRequestSent(
+    void* arg, grpc_error_handle /*error*/) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   lb_calld->grpclb_policy()->work_serializer()->Run(
       [lb_calld]() { lb_calld->OnInitialRequestSentLocked(); }, DEBUG_LOCATION);
@@ -1021,7 +1026,7 @@
 }
 
 void GrpcLb::BalancerCallState::OnBalancerMessageReceived(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   lb_calld->grpclb_policy()->work_serializer()->Run(
       [lb_calld]() { lb_calld->OnBalancerMessageReceivedLocked(); },
@@ -1183,8 +1188,8 @@
   }
 }
 
-void GrpcLb::BalancerCallState::OnBalancerStatusReceived(void* arg,
-                                                         grpc_error* error) {
+void GrpcLb::BalancerCallState::OnBalancerStatusReceived(
+    void* arg, grpc_error_handle error) {
   BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
   GRPC_ERROR_REF(error);  // owned by lambda
   lb_calld->grpclb_policy()->work_serializer()->Run(
@@ -1193,7 +1198,7 @@
 }
 
 void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   GPR_ASSERT(lb_call_ != nullptr);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) {
     char* status_details = grpc_slice_to_c_string(lb_call_status_details_);
@@ -1201,7 +1206,7 @@
             "[grpclb %p] lb_calld=%p: Status from LB server received. "
             "Status = %d, details = '%s', (lb_call: %p), error '%s'",
             grpclb_policy(), this, lb_call_status_, status_details, lb_call_,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     gpr_free(status_details);
   }
   GRPC_ERROR_UNREF(error);
@@ -1259,12 +1264,10 @@
  * stream for the reception of load balancing updates.
  *
  * Inputs:
- *   - \a addresses: corresponding to the balancers.
  *   - \a response_generator: in order to propagate updates from the resolver
  *   above the grpclb policy.
  *   - \a args: other args inherited from the grpclb policy. */
 grpc_channel_args* BuildBalancerChannelArgs(
-    const ServerAddressList& addresses,
     FakeResolverResponseGenerator* response_generator,
     const grpc_channel_args* args) {
   // Channel args to remove.
@@ -1313,7 +1316,7 @@
       args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(),
       args_to_add.size());
   // Make any necessary modifications for security.
-  return ModifyGrpclbBalancerChannelArgs(addresses, new_args);
+  return ModifyGrpclbBalancerChannelArgs(new_args);
 }
 
 //
@@ -1422,13 +1425,12 @@
     // Start watching the channel's connectivity state.  If the channel
     // goes into state TRANSIENT_FAILURE before the timer fires, we go into
     // fallback mode even if the fallback timeout has not elapsed.
-    grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-        grpc_channel_get_channel_stack(lb_channel_));
-    GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
+    ClientChannel* client_channel = ClientChannel::GetFromChannel(lb_channel_);
+    GPR_ASSERT(client_channel != nullptr);
     // Ref held by callback.
     watcher_ = new StateWatcher(Ref(DEBUG_LOCATION, "StateWatcher"));
-    grpc_client_channel_start_connectivity_watch(
-        client_channel_elem, GRPC_CHANNEL_IDLE,
+    client_channel->AddConnectivityWatcher(
+        GRPC_CHANNEL_IDLE,
         OrphanablePtr<AsyncConnectivityStateWatcherInterface>(watcher_));
     // Start balancer call.
     StartBalancerCallLocked();
@@ -1464,8 +1466,8 @@
       &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1);
   // Construct args for balancer channel.
   ServerAddressList balancer_addresses = ExtractBalancerAddresses(args);
-  grpc_channel_args* lb_channel_args = BuildBalancerChannelArgs(
-      balancer_addresses, response_generator_.get(), &args);
+  grpc_channel_args* lb_channel_args =
+      BuildBalancerChannelArgs(response_generator_.get(), &args);
   // Create balancer channel if needed.
   if (lb_channel_ == nullptr) {
     std::string uri_str = absl::StrCat("fake:///", server_name_);
@@ -1492,10 +1494,9 @@
 }
 
 void GrpcLb::CancelBalancerChannelConnectivityWatchLocked() {
-  grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-      grpc_channel_get_channel_stack(lb_channel_));
-  GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
-  grpc_client_channel_stop_connectivity_watch(client_channel_elem, watcher_);
+  ClientChannel* client_channel = ClientChannel::GetFromChannel(lb_channel_);
+  GPR_ASSERT(client_channel != nullptr);
+  client_channel->RemoveConnectivityWatcher(watcher_);
 }
 
 //
@@ -1538,7 +1539,7 @@
   grpc_timer_init(&lb_call_retry_timer_, next_try, &lb_on_call_retry_);
 }
 
-void GrpcLb::OnBalancerCallRetryTimer(void* arg, grpc_error* error) {
+void GrpcLb::OnBalancerCallRetryTimer(void* arg, grpc_error_handle error) {
   GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   grpclb_policy->work_serializer()->Run(
@@ -1548,7 +1549,7 @@
       DEBUG_LOCATION);
 }
 
-void GrpcLb::OnBalancerCallRetryTimerLocked(grpc_error* error) {
+void GrpcLb::OnBalancerCallRetryTimerLocked(grpc_error_handle error) {
   retry_timer_callback_pending_ = false;
   if (!shutting_down_ && error == GRPC_ERROR_NONE && lb_calld_ == nullptr) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) {
@@ -1582,7 +1583,7 @@
   }
 }
 
-void GrpcLb::OnFallbackTimer(void* arg, grpc_error* error) {
+void GrpcLb::OnFallbackTimer(void* arg, grpc_error_handle error) {
   GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   grpclb_policy->work_serializer()->Run(
@@ -1590,7 +1591,7 @@
       DEBUG_LOCATION);
 }
 
-void GrpcLb::OnFallbackTimerLocked(grpc_error* error) {
+void GrpcLb::OnFallbackTimerLocked(grpc_error_handle error) {
   // If we receive a serverlist after the timer fires but before this callback
   // actually runs, don't fall back.
   if (fallback_at_startup_checks_pending_ && !shutting_down_ &&
@@ -1694,12 +1695,12 @@
   const char* name() const override { return kGrpclb; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       return MakeRefCounted<GrpcLbConfig>(nullptr, "");
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     Json child_policy_config_json_tmp;
     const Json* child_policy_config_json;
     std::string service_name;
@@ -1722,12 +1723,12 @@
     } else {
       child_policy_config_json = &it->second;
     }
-    grpc_error* parse_error = GRPC_ERROR_NONE;
+    grpc_error_handle parse_error = GRPC_ERROR_NONE;
     RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config =
         LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
             *child_policy_config_json, &parse_error);
     if (parse_error != GRPC_ERROR_NONE) {
-      std::vector<grpc_error*> child_errors;
+      std::vector<grpc_error_handle> child_errors;
       child_errors.push_back(parse_error);
       error_list.push_back(
           GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
index f8197a8..07c5fd6 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
@@ -24,8 +24,7 @@
 
 namespace grpc_core {
 
-grpc_channel_args* ModifyGrpclbBalancerChannelArgs(
-    const ServerAddressList& /*addresses*/, grpc_channel_args* args) {
+grpc_channel_args* ModifyGrpclbBalancerChannelArgs(grpc_channel_args* args) {
   return args;
 }
 
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
index 1458233..8ea4885 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
@@ -33,8 +33,7 @@
 /// Takes ownership of \a args.
 ///
 /// Caller takes ownership of the returned args.
-grpc_channel_args* ModifyGrpclbBalancerChannelArgs(
-    const ServerAddressList& addresses, grpc_channel_args* args);
+grpc_channel_args* ModifyGrpclbBalancerChannelArgs(grpc_channel_args* args);
 
 grpc_channel* CreateGrpclbBalancerChannel(const char* target_uri,
                                           const grpc_channel_args& args);
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
index 62fbe15..837cc09 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
@@ -31,16 +31,15 @@
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 namespace grpc_core {
 
-grpc_channel_args* ModifyGrpclbBalancerChannelArgs(
-    const ServerAddressList& addresses, grpc_channel_args* args) {
+grpc_channel_args* ModifyGrpclbBalancerChannelArgs(grpc_channel_args* args) {
   absl::InlinedVector<const char*, 1> args_to_remove;
   absl::InlinedVector<grpc_arg, 1> args_to_add;
   // Substitute the channel credentials with a version without call
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
index f6e9440..c369827 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
@@ -66,7 +66,8 @@
   gpr_atm num_calls_finished_with_client_failed_to_send_ = 0;
   gpr_atm num_calls_finished_known_received_ = 0;
   Mutex drop_count_mu_;  // Guards drop_token_counts_.
-  std::unique_ptr<DroppedCallCounts> drop_token_counts_;
+  std::unique_ptr<DroppedCallCounts> drop_token_counts_
+      ABSL_GUARDED_BY(drop_count_mu_);
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
index 8b64f2b..6b7568c 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
@@ -26,9 +26,9 @@
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/sync.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/error_utils.h"
 
@@ -197,7 +197,7 @@
     // (If we are idle, then this will happen in ExitIdleLocked() if we
     // haven't gotten a non-empty update by the time the application tries
     // to start a new call.)
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
                            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
     channel_control_helper()->UpdateState(
@@ -314,7 +314,7 @@
       p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_);
       // Set our state to that of the pending subchannel list.
       if (p->subchannel_list_->in_transient_failure()) {
-        grpc_error* error = grpc_error_set_int(
+        grpc_error_handle error = grpc_error_set_int(
             GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                 "selected subchannel failed; switching to pending update"),
             GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
@@ -393,7 +393,7 @@
         subchannel_list()->set_in_transient_failure(true);
         // Only report new state in case 1.
         if (subchannel_list() == p->subchannel_list_.get()) {
-          grpc_error* error = grpc_error_set_int(
+          grpc_error_handle error = grpc_error_set_int(
               GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                   "failed to connect to all addresses"),
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
@@ -497,7 +497,7 @@
   const char* name() const override { return kPickFirst; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** /*error*/) const override {
+      const Json& /*json*/, grpc_error_handle* /*error*/) const override {
     return MakeRefCounted<PickFirstConfig>();
   }
 };
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
index 037eea5..3cd7c54 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
@@ -179,10 +179,10 @@
 
     void StartFailoverTimerLocked();
 
-    static void OnFailoverTimer(void* arg, grpc_error* error);
-    void OnFailoverTimerLocked(grpc_error* error);
-    static void OnDeactivationTimer(void* arg, grpc_error* error);
-    void OnDeactivationTimerLocked(grpc_error* error);
+    static void OnFailoverTimer(void* arg, grpc_error_handle error);
+    void OnFailoverTimerLocked(grpc_error_handle error);
+    static void OnDeactivationTimer(void* arg, grpc_error_handle error);
+    void OnDeactivationTimerLocked(grpc_error_handle error);
 
     RefCountedPtr<PriorityLb> priority_policy_;
     const std::string name_;
@@ -363,8 +363,10 @@
   // Otherwise, find the child's priority.
   uint32_t child_priority = GetChildPriorityLocked(child->name());
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_priority_trace)) {
-    gpr_log(GPR_INFO, "[priority_lb %p] state update for priority %d, child %s",
-            this, child_priority, child->name().c_str());
+    gpr_log(GPR_INFO,
+            "[priority_lb %p] state update for priority %u, child %s, current "
+            "priority %u",
+            this, child_priority, child->name().c_str(), current_priority_);
   }
   // Ignore priorities not in the current config.
   if (child_priority == UINT32_MAX) return;
@@ -412,12 +414,13 @@
 }
 
 void PriorityLb::TryNextPriorityLocked(bool report_connecting) {
+  current_priority_ = UINT32_MAX;
   for (uint32_t priority = 0; priority < config_->priorities().size();
        ++priority) {
     // If the child for the priority does not exist yet, create it.
     const std::string& child_name = config_->priorities()[priority];
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_priority_trace)) {
-      gpr_log(GPR_INFO, "[priority_lb %p] trying priority %d, child %s", this,
+      gpr_log(GPR_INFO, "[priority_lb %p] trying priority %u, child %s", this,
               priority, child_name.c_str());
     }
     auto& child = children_[child_name];
@@ -448,7 +451,7 @@
     if (child->failover_timer_callback_pending()) {
       if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_priority_trace)) {
         gpr_log(GPR_INFO,
-                "[priority_lb %p] priority %d, child %s: child still "
+                "[priority_lb %p] priority %u, child %s: child still "
                 "attempting to connect, will wait",
                 this, priority, child_name.c_str());
       }
@@ -468,9 +471,8 @@
             "TRANSIENT_FAILURE",
             this);
   }
-  current_priority_ = UINT32_MAX;
   current_child_from_before_update_ = nullptr;
-  grpc_error* error = grpc_error_set_int(
+  grpc_error_handle error = grpc_error_set_int(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("no ready priority"),
       GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
   channel_control_helper()->UpdateState(
@@ -480,7 +482,7 @@
 
 void PriorityLb::SelectPriorityLocked(uint32_t priority) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_priority_trace)) {
-    gpr_log(GPR_INFO, "[priority_lb %p] selected priority %d, child %s", this,
+    gpr_log(GPR_INFO, "[priority_lb %p] selected priority %u, child %s", this,
             priority, config_->priorities()[priority].c_str());
   }
   current_priority_ = priority;
@@ -653,14 +655,15 @@
   }
 }
 
-void PriorityLb::ChildPriority::OnFailoverTimer(void* arg, grpc_error* error) {
+void PriorityLb::ChildPriority::OnFailoverTimer(void* arg,
+                                                grpc_error_handle error) {
   ChildPriority* self = static_cast<ChildPriority*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   self->priority_policy_->work_serializer()->Run(
       [self, error]() { self->OnFailoverTimerLocked(error); }, DEBUG_LOCATION);
 }
 
-void PriorityLb::ChildPriority::OnFailoverTimerLocked(grpc_error* error) {
+void PriorityLb::ChildPriority::OnFailoverTimerLocked(grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE && failover_timer_callback_pending_ &&
       !priority_policy_->shutting_down_) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_priority_trace)) {
@@ -710,7 +713,7 @@
 }
 
 void PriorityLb::ChildPriority::OnDeactivationTimer(void* arg,
-                                                    grpc_error* error) {
+                                                    grpc_error_handle error) {
   ChildPriority* self = static_cast<ChildPriority*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   self->priority_policy_->work_serializer()->Run(
@@ -718,7 +721,8 @@
       DEBUG_LOCATION);
 }
 
-void PriorityLb::ChildPriority::OnDeactivationTimerLocked(grpc_error* error) {
+void PriorityLb::ChildPriority::OnDeactivationTimerLocked(
+    grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE && deactivation_timer_callback_pending_ &&
       !priority_policy_->shutting_down_) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_priority_trace)) {
@@ -783,7 +787,7 @@
   const char* name() const override { return kPriority; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // priority was mentioned as a policy in the deprecated
@@ -794,7 +798,7 @@
           "config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     // Children.
     std::map<std::string, PriorityLbConfig::PriorityLbChild> children;
     auto it = json.object_value().find("children");
@@ -822,7 +826,7 @@
                              " error:missing 'config' field")
                     .c_str()));
           } else {
-            grpc_error* parse_error = GRPC_ERROR_NONE;
+            grpc_error_handle parse_error = GRPC_ERROR_NONE;
             auto config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
                 it2->second, &parse_error);
             bool ignore_resolution_requests = false;
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
new file mode 100644
index 0000000..921bd2e
--- /dev/null
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
@@ -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
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h b/grpc/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h
new file mode 100644
index 0000000..dc176c2
--- /dev/null
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h
@@ -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
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
index efc7942..529d90d 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
@@ -34,11 +34,11 @@
 #include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h"
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/error_utils.h"
 #include "src/core/lib/transport/static_metadata.h"
@@ -331,7 +331,7 @@
         absl::make_unique<QueuePicker>(p->Ref(DEBUG_LOCATION, "QueuePicker")));
   } else if (num_transient_failure_ == num_subchannels()) {
     /* 3) TRANSIENT_FAILURE */
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                "connections to all backends failing"),
                            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
@@ -449,7 +449,7 @@
   if (latest_pending_subchannel_list_->num_subchannels() == 0) {
     // If the new list is empty, immediately promote the new list to the
     // current list and transition to TRANSIENT_FAILURE.
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
                            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
     channel_control_helper()->UpdateState(
@@ -487,7 +487,7 @@
   const char* name() const override { return kRoundRobin; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& /*json*/, grpc_error** /*error*/) const override {
+      const Json& /*json*/, grpc_error_handle* /*error*/) const override {
     return MakeRefCounted<RoundRobinConfig>();
   }
 };
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
index a240a2d..b894c59 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
@@ -33,13 +33,13 @@
 // that implementation should be hidden from the LB policy API.
 #include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/ext/filters/client_channel/subchannel_interface.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/transport/connectivity_state.h"
 
 // Code for maintaining a list of subchannels within an LB policy.
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc
index 1eca478..ac1857b 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc
@@ -165,8 +165,8 @@
         grpc_connectivity_state state, const absl::Status& status,
         std::unique_ptr<SubchannelPicker> picker);
 
-    static void OnDelayedRemovalTimer(void* arg, grpc_error* error);
-    void OnDelayedRemovalTimerLocked(grpc_error* error);
+    static void OnDelayedRemovalTimer(void* arg, grpc_error_handle error);
+    void OnDelayedRemovalTimerLocked(grpc_error_handle error);
 
     // The owning LB policy.
     RefCountedPtr<WeightedTargetLb> weighted_target_policy_;
@@ -387,7 +387,7 @@
           absl::make_unique<QueuePicker>(Ref(DEBUG_LOCATION, "QueuePicker"));
       break;
     default:
-      grpc_error* error = grpc_error_set_int(
+      grpc_error_handle error = grpc_error_set_int(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "weighted_target: all children report state TRANSIENT_FAILURE"),
           GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
@@ -564,8 +564,8 @@
                   &on_delayed_removal_timer_);
 }
 
-void WeightedTargetLb::WeightedChild::OnDelayedRemovalTimer(void* arg,
-                                                            grpc_error* error) {
+void WeightedTargetLb::WeightedChild::OnDelayedRemovalTimer(
+    void* arg, grpc_error_handle error) {
   WeightedChild* self = static_cast<WeightedChild*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   self->weighted_target_policy_->work_serializer()->Run(
@@ -574,7 +574,7 @@
 }
 
 void WeightedTargetLb::WeightedChild::OnDelayedRemovalTimerLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE && delayed_removal_timer_callback_pending_ &&
       !shutdown_ && weight_ == 0) {
     delayed_removal_timer_callback_pending_ = false;
@@ -631,7 +631,7 @@
   const char* name() const override { return kWeightedTarget; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // weighted_target was mentioned as a policy in the deprecated
@@ -642,7 +642,7 @@
           "config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     // Weight map.
     WeightedTargetLbConfig::TargetMap target_map;
     auto it = json.object_value().find("targets");
@@ -655,14 +655,14 @@
     } else {
       for (const auto& p : it->second.object_value()) {
         WeightedTargetLbConfig::ChildConfig child_config;
-        std::vector<grpc_error*> child_errors =
+        std::vector<grpc_error_handle> child_errors =
             ParseChildConfig(p.second, &child_config);
         if (!child_errors.empty()) {
           // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
           // string is not static in this case.
-          grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
               absl::StrCat("field:targets key:", p.first).c_str());
-          for (grpc_error* child_error : child_errors) {
+          for (grpc_error_handle child_error : child_errors) {
             error = grpc_error_add_child(error, child_error);
           }
           error_list.push_back(error);
@@ -680,9 +680,9 @@
   }
 
  private:
-  static std::vector<grpc_error*> ParseChildConfig(
+  static std::vector<grpc_error_handle> ParseChildConfig(
       const Json& json, WeightedTargetLbConfig::ChildConfig* child_config) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "value should be of type object"));
@@ -711,13 +711,13 @@
     // Child policy.
     it = json.object_value().find("childPolicy");
     if (it != json.object_value().end()) {
-      grpc_error* parse_error = GRPC_ERROR_NONE;
+      grpc_error_handle parse_error = GRPC_ERROR_NONE;
       child_config->config =
           LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(it->second,
                                                                 &parse_error);
       if (child_config->config == nullptr) {
         GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
-        std::vector<grpc_error*> child_errors;
+        std::vector<grpc_error_handle> child_errors;
         child_errors.push_back(parse_error);
         error_list.push_back(
             GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
index 8a10db5..49bff27 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
@@ -63,40 +63,55 @@
 
   void UpdateLocked(UpdateArgs args) override;
   void ResetBackoffLocked() override;
+  void ExitIdleLocked() override;
 
  private:
   // Watcher for getting cluster data from XdsClient.
   class ClusterWatcher : public XdsClient::ClusterWatcherInterface {
    public:
-    explicit ClusterWatcher(RefCountedPtr<CdsLb> parent)
-        : parent_(std::move(parent)) {}
+    ClusterWatcher(RefCountedPtr<CdsLb> parent, std::string name)
+        : parent_(std::move(parent)), name_(std::move(name)) {}
 
     void OnClusterChanged(XdsApi::CdsUpdate cluster_data) override {
-      new Notifier(parent_, std::move(cluster_data));
+      new Notifier(parent_, name_, std::move(cluster_data));
     }
-    void OnError(grpc_error* error) override { new Notifier(parent_, error); }
-    void OnResourceDoesNotExist() override { new Notifier(parent_); }
+    void OnError(grpc_error_handle error) override {
+      new Notifier(parent_, name_, error);
+    }
+    void OnResourceDoesNotExist() override { new Notifier(parent_, name_); }
 
    private:
     class Notifier {
      public:
-      Notifier(RefCountedPtr<CdsLb> parent, XdsApi::CdsUpdate update);
-      Notifier(RefCountedPtr<CdsLb> parent, grpc_error* error);
-      explicit Notifier(RefCountedPtr<CdsLb> parent);
+      Notifier(RefCountedPtr<CdsLb> parent, std::string name,
+               XdsApi::CdsUpdate update);
+      Notifier(RefCountedPtr<CdsLb> parent, std::string name,
+               grpc_error_handle error);
+      explicit Notifier(RefCountedPtr<CdsLb> parent, std::string name);
 
      private:
       enum Type { kUpdate, kError, kDoesNotExist };
 
-      static void RunInExecCtx(void* arg, grpc_error* error);
-      void RunInWorkSerializer(grpc_error* error);
+      static void RunInExecCtx(void* arg, grpc_error_handle error);
+      void RunInWorkSerializer(grpc_error_handle error);
 
       RefCountedPtr<CdsLb> parent_;
+      std::string name_;
       grpc_closure closure_;
       XdsApi::CdsUpdate update_;
       Type type_;
     };
 
     RefCountedPtr<CdsLb> parent_;
+    std::string name_;
+  };
+
+  struct WatcherState {
+    // Pointer to watcher, to be used when cancelling.
+    // Not owned, so do not dereference.
+    ClusterWatcher* watcher = nullptr;
+    // Most recent update obtained from this watcher.
+    absl::optional<XdsApi::CdsUpdate> update;
   };
 
   // Delegating helper to be passed to child policy.
@@ -119,12 +134,20 @@
 
   void ShutdownLocked() override;
 
-  void OnClusterChanged(XdsApi::CdsUpdate cluster_data);
-  void OnError(grpc_error* error);
-  void OnResourceDoesNotExist();
+  bool GenerateDiscoveryMechanismForCluster(
+      const std::string& name, Json::Array* discovery_mechanisms,
+      std::set<std::string>* clusters_needed);
+  void OnClusterChanged(const std::string& name,
+                        XdsApi::CdsUpdate cluster_data);
+  void OnError(const std::string& name, grpc_error_handle error);
+  void OnResourceDoesNotExist(const std::string& name);
 
-  grpc_error* UpdateXdsCertificateProvider(
-      const XdsApi::CdsUpdate& cluster_data);
+  grpc_error_handle UpdateXdsCertificateProvider(
+      const std::string& cluster_name, const XdsApi::CdsUpdate& cluster_data);
+
+  void CancelClusterDataWatch(absl::string_view cluster_name,
+                              XdsClient::ClusterWatcherInterface* watcher,
+                              bool delay_unsubscription = false);
 
   void MaybeDestroyChildPolicyLocked();
 
@@ -135,9 +158,10 @@
 
   // The xds client.
   RefCountedPtr<XdsClient> xds_client_;
-  // A pointer to the cluster watcher, to be used when cancelling the watch.
-  // Note that this is not owned, so this pointer must never be derefernced.
-  ClusterWatcher* cluster_watcher_ = nullptr;
+
+  // Maps from cluster name to the state for that cluster.
+  // The root of the tree is config_->cluster().
+  std::map<std::string, WatcherState> watchers_;
 
   RefCountedPtr<grpc_tls_certificate_provider> root_certificate_provider_;
   RefCountedPtr<grpc_tls_certificate_provider> identity_certificate_provider_;
@@ -155,43 +179,50 @@
 //
 
 CdsLb::ClusterWatcher::Notifier::Notifier(RefCountedPtr<CdsLb> parent,
+                                          std::string name,
                                           XdsApi::CdsUpdate update)
-    : parent_(std::move(parent)), update_(std::move(update)), type_(kUpdate) {
+    : parent_(std::move(parent)),
+      name_(std::move(name)),
+      update_(std::move(update)),
+      type_(kUpdate) {
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, GRPC_ERROR_NONE);
 }
 
 CdsLb::ClusterWatcher::Notifier::Notifier(RefCountedPtr<CdsLb> parent,
-                                          grpc_error* error)
-    : parent_(std::move(parent)), type_(kError) {
+                                          std::string name,
+                                          grpc_error_handle error)
+    : parent_(std::move(parent)), name_(std::move(name)), type_(kError) {
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, error);
 }
 
-CdsLb::ClusterWatcher::Notifier::Notifier(RefCountedPtr<CdsLb> parent)
-    : parent_(std::move(parent)), type_(kDoesNotExist) {
+CdsLb::ClusterWatcher::Notifier::Notifier(RefCountedPtr<CdsLb> parent,
+                                          std::string name)
+    : parent_(std::move(parent)), name_(std::move(name)), type_(kDoesNotExist) {
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, GRPC_ERROR_NONE);
 }
 
 void CdsLb::ClusterWatcher::Notifier::RunInExecCtx(void* arg,
-                                                   grpc_error* error) {
+                                                   grpc_error_handle error) {
   Notifier* self = static_cast<Notifier*>(arg);
   GRPC_ERROR_REF(error);
   self->parent_->work_serializer()->Run(
       [self, error]() { self->RunInWorkSerializer(error); }, DEBUG_LOCATION);
 }
 
-void CdsLb::ClusterWatcher::Notifier::RunInWorkSerializer(grpc_error* error) {
+void CdsLb::ClusterWatcher::Notifier::RunInWorkSerializer(
+    grpc_error_handle error) {
   switch (type_) {
     case kUpdate:
-      parent_->OnClusterChanged(std::move(update_));
+      parent_->OnClusterChanged(name_, std::move(update_));
       break;
     case kError:
-      parent_->OnError(error);
+      parent_->OnError(name_, error);
       break;
     case kDoesNotExist:
-      parent_->OnResourceDoesNotExist();
+      parent_->OnResourceDoesNotExist(name_);
       break;
   };
   delete this;
@@ -261,13 +292,15 @@
   shutting_down_ = true;
   MaybeDestroyChildPolicyLocked();
   if (xds_client_ != nullptr) {
-    if (cluster_watcher_ != nullptr) {
+    for (auto& watcher : watchers_) {
       if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
         gpr_log(GPR_INFO, "[cdslb %p] cancelling watch for cluster %s", this,
-                config_->cluster().c_str());
+                watcher.first.c_str());
       }
-      xds_client_->CancelClusterDataWatch(config_->cluster(), cluster_watcher_);
+      CancelClusterDataWatch(watcher.first, watcher.second.watcher,
+                             /*delay_unsubscription=*/false);
     }
+    watchers_.clear();
     xds_client_.reset(DEBUG_LOCATION, "CdsLb");
   }
   grpc_channel_args_destroy(args_);
@@ -286,6 +319,10 @@
   if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked();
 }
 
+void CdsLb::ExitIdleLocked() {
+  if (child_policy_ != nullptr) child_policy_->ExitIdleLocked();
+}
+
 void CdsLb::UpdateLocked(UpdateArgs args) {
   // Update config.
   auto old_config = std::move(config_);
@@ -301,119 +338,214 @@
   // If cluster name changed, cancel watcher and restart.
   if (old_config == nullptr || old_config->cluster() != config_->cluster()) {
     if (old_config != nullptr) {
-      if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
-        gpr_log(GPR_INFO, "[cdslb %p] cancelling watch for cluster %s", this,
-                old_config->cluster().c_str());
+      for (auto& watcher : watchers_) {
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
+          gpr_log(GPR_INFO, "[cdslb %p] cancelling watch for cluster %s", this,
+                  watcher.first.c_str());
+        }
+        CancelClusterDataWatch(watcher.first, watcher.second.watcher,
+                               /*delay_unsubscription=*/true);
       }
-      xds_client_->CancelClusterDataWatch(old_config->cluster(),
-                                          cluster_watcher_,
-                                          /*delay_unsubscription=*/true);
+      watchers_.clear();
     }
-    if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
-      gpr_log(GPR_INFO, "[cdslb %p] starting watch for cluster %s", this,
-              config_->cluster().c_str());
-    }
-    auto watcher = absl::make_unique<ClusterWatcher>(Ref());
-    cluster_watcher_ = watcher.get();
+    auto watcher = absl::make_unique<ClusterWatcher>(Ref(), config_->cluster());
+    watchers_[config_->cluster()].watcher = watcher.get();
     xds_client_->WatchClusterData(config_->cluster(), std::move(watcher));
   }
 }
 
-void CdsLb::OnClusterChanged(XdsApi::CdsUpdate cluster_data) {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
-    gpr_log(GPR_INFO, "[cdslb %p] received CDS update from xds client %p: %s",
-            this, xds_client_.get(), cluster_data.ToString().c_str());
-  }
-  grpc_error* error = GRPC_ERROR_NONE;
-  error = UpdateXdsCertificateProvider(cluster_data);
-  if (error != GRPC_ERROR_NONE) {
-    return OnError(error);
-  }
-  // Construct config for child policy.
-  Json::Object discovery_mechanism = {
-      {"clusterName", config_->cluster()},
-      {"max_concurrent_requests", cluster_data.max_concurrent_requests},
-      {"type", "EDS"},
-  };
-  if (!cluster_data.eds_service_name.empty()) {
-    discovery_mechanism["edsServiceName"] = cluster_data.eds_service_name;
-  }
-  if (cluster_data.lrs_load_reporting_server_name.has_value()) {
-    discovery_mechanism["lrsLoadReportingServerName"] =
-        cluster_data.lrs_load_reporting_server_name.value();
-  }
-  Json::Object child_config = {
-      {"discoveryMechanisms",
-       Json::Array{
-           discovery_mechanism,
-       }},
-      {"localityPickingPolicy",
-       Json::Array{
-           Json::Object{
-               {"weighted_target_experimental",
-                Json::Object{
-                    {"targets", Json::Object()},
-                }},
-           },
-       }},
-      {"endpointPickingPolicy",
-       Json::Array{
-           Json::Object{
-               {"round_robin", Json::Object()},
-           },
-       }},
-  };
-  Json json = Json::Array{
-      Json::Object{
-          {"xds_cluster_resolver_experimental", std::move(child_config)},
-      },
-  };
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
-    std::string json_str = json.Dump(/*indent=*/1);
-    gpr_log(GPR_INFO, "[cdslb %p] generated config for child policy: %s", this,
-            json_str.c_str());
-  }
-  RefCountedPtr<LoadBalancingPolicy::Config> config =
-      LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error);
-  if (error != GRPC_ERROR_NONE) {
-    OnError(error);
-    return;
-  }
-  // Create child policy if not already present.
-  if (child_policy_ == nullptr) {
-    LoadBalancingPolicy::Args args;
-    args.work_serializer = work_serializer();
-    args.args = args_;
-    args.channel_control_helper = absl::make_unique<Helper>(Ref());
-    child_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
-        config->name(), std::move(args));
-    if (child_policy_ == nullptr) {
-      OnError(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "failed to create child policy"));
-      return;
-    }
-    grpc_pollset_set_add_pollset_set(child_policy_->interested_parties(),
-                                     interested_parties());
+// This method will attempt to generate one or multiple entries of discovery
+// mechanism recursively:
+// For cluster types EDS or LOGICAL_DNS, one discovery mechanism entry may be
+// generated cluster name, type and other data from the CdsUpdate inserted into
+// the entry and the entry appended to the array of entries.
+// Note, discovery mechanism entry can be generated if an CdsUpdate is
+// available; otherwise, just return false. For cluster type AGGREGATE,
+// recursively call the method for each child cluster.
+bool CdsLb::GenerateDiscoveryMechanismForCluster(
+    const std::string& name, Json::Array* discovery_mechanisms,
+    std::set<std::string>* clusters_needed) {
+  clusters_needed->insert(name);
+  auto& state = watchers_[name];
+  // Create a new watcher if needed.
+  if (state.watcher == nullptr) {
+    auto watcher = absl::make_unique<ClusterWatcher>(Ref(), name);
     if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
-      gpr_log(GPR_INFO, "[cdslb %p] created child policy %s (%p)", this,
-              config->name(), child_policy_.get());
+      gpr_log(GPR_INFO, "[cdslb %p] starting watch for cluster %s", this,
+              name.c_str());
     }
+    state.watcher = watcher.get();
+    xds_client_->WatchClusterData(name, std::move(watcher));
+    return false;
   }
-  // Update child policy.
-  UpdateArgs args;
-  args.config = std::move(config);
-  if (xds_certificate_provider_ != nullptr) {
-    grpc_arg arg_to_add = xds_certificate_provider_->MakeChannelArg();
-    args.args = grpc_channel_args_copy_and_add(args_, &arg_to_add, 1);
-  } else {
-    args.args = grpc_channel_args_copy(args_);
+  // Don't have the update we need yet.
+  if (!state.update.has_value()) return false;
+  // For AGGREGATE clusters, recursively expand to child clusters.
+  if (state.update->cluster_type == XdsApi::CdsUpdate::ClusterType::AGGREGATE) {
+    bool missing_cluster = false;
+    for (const std::string& child_name :
+         state.update->prioritized_cluster_names) {
+      if (!GenerateDiscoveryMechanismForCluster(
+              child_name, discovery_mechanisms, clusters_needed)) {
+        missing_cluster = true;
+      }
+    }
+    return !missing_cluster;
   }
-  child_policy_->UpdateLocked(std::move(args));
+  std::string type;
+  switch (state.update->cluster_type) {
+    case XdsApi::CdsUpdate::ClusterType::EDS:
+      type = "EDS";
+      break;
+    case XdsApi::CdsUpdate::ClusterType::LOGICAL_DNS:
+      type = "LOGICAL_DNS";
+      break;
+    default:
+      GPR_ASSERT(0);
+      break;
+  }
+  Json::Object mechanism = {
+      {"clusterName", name},
+      {"max_concurrent_requests", state.update->max_concurrent_requests},
+      {"type", std::move(type)},
+  };
+  if (!state.update->eds_service_name.empty()) {
+    mechanism["edsServiceName"] = state.update->eds_service_name;
+  }
+  if (state.update->lrs_load_reporting_server_name.has_value()) {
+    mechanism["lrsLoadReportingServerName"] =
+        state.update->lrs_load_reporting_server_name.value();
+  }
+  discovery_mechanisms->emplace_back(std::move(mechanism));
+  return true;
 }
 
-void CdsLb::OnError(grpc_error* error) {
+void CdsLb::OnClusterChanged(const std::string& name,
+                             XdsApi::CdsUpdate cluster_data) {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
+    gpr_log(
+        GPR_INFO,
+        "[cdslb %p] received CDS update for cluster %s from xds client %p: %s",
+        this, name.c_str(), xds_client_.get(), cluster_data.ToString().c_str());
+  }
+  // Store the update in the map if we are still interested in watching this
+  // cluster (i.e., it is not cancelled already).
+  // If we've already deleted this entry, then this is an update notification
+  // that was scheduled before the deletion, so we can just ignore it.
+  auto it = watchers_.find(name);
+  if (it == watchers_.end()) return;
+  it->second.update = cluster_data;
+  // Take care of integration with new certificate code.
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  error = UpdateXdsCertificateProvider(name, it->second.update.value());
+  if (error != GRPC_ERROR_NONE) {
+    return OnError(name, error);
+  }
+  // Scan the map starting from the root cluster to generate the list of
+  // discovery mechanisms. If we don't have some of the data we need (i.e., we
+  // just started up and not all watchers have returned data yet), then don't
+  // update the child policy at all.
+  Json::Array discovery_mechanisms;
+  std::set<std::string> clusters_needed;
+  if (GenerateDiscoveryMechanismForCluster(
+          config_->cluster(), &discovery_mechanisms, &clusters_needed)) {
+    // Construct config for child policy.
+    Json::Object xds_lb_policy;
+    if (cluster_data.lb_policy == "RING_HASH") {
+      std::string hash_function;
+      switch (cluster_data.hash_function) {
+        case XdsApi::CdsUpdate::HashFunction::XX_HASH:
+          hash_function = "XX_HASH";
+          break;
+        case XdsApi::CdsUpdate::HashFunction::MURMUR_HASH_2:
+          hash_function = "MURMUR_HASH_2";
+          break;
+        default:
+          GPR_ASSERT(0);
+          break;
+      }
+      xds_lb_policy["RING_HASH"] = Json::Object{
+          {"min_ring_size", cluster_data.min_ring_size},
+          {"max_ring_size", cluster_data.max_ring_size},
+          {"hash_function", hash_function},
+      };
+    } else {
+      xds_lb_policy["ROUND_ROBIN"] = Json::Object();
+    }
+    Json::Object child_config = {
+        {"xdsLbPolicy",
+         Json::Array{
+             xds_lb_policy,
+         }},
+        {"discoveryMechanisms", std::move(discovery_mechanisms)},
+    };
+    Json json = Json::Array{
+        Json::Object{
+            {"xds_cluster_resolver_experimental", std::move(child_config)},
+        },
+    };
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
+      std::string json_str = json.Dump(/*indent=*/1);
+      gpr_log(GPR_INFO, "[cdslb %p] generated config for child policy: %s",
+              this, json_str.c_str());
+    }
+    RefCountedPtr<LoadBalancingPolicy::Config> config =
+        LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error);
+    if (error != GRPC_ERROR_NONE) {
+      OnError(name, error);
+      return;
+    }
+    // Create child policy if not already present.
+    if (child_policy_ == nullptr) {
+      LoadBalancingPolicy::Args args;
+      args.work_serializer = work_serializer();
+      args.args = args_;
+      args.channel_control_helper = absl::make_unique<Helper>(Ref());
+      child_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
+          config->name(), std::move(args));
+      if (child_policy_ == nullptr) {
+        OnError(name, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                          "failed to create child policy"));
+        return;
+      }
+      grpc_pollset_set_add_pollset_set(child_policy_->interested_parties(),
+                                       interested_parties());
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
+        gpr_log(GPR_INFO, "[cdslb %p] created child policy %s (%p)", this,
+                config->name(), child_policy_.get());
+      }
+    }
+    // Update child policy.
+    UpdateArgs args;
+    args.config = std::move(config);
+    if (xds_certificate_provider_ != nullptr) {
+      grpc_arg arg_to_add = xds_certificate_provider_->MakeChannelArg();
+      args.args = grpc_channel_args_copy_and_add(args_, &arg_to_add, 1);
+    } else {
+      args.args = grpc_channel_args_copy(args_);
+    }
+    child_policy_->UpdateLocked(std::move(args));
+  }
+  // Remove entries in watchers_ for any clusters not in clusters_needed
+  for (auto it = watchers_.begin(); it != watchers_.end();) {
+    const std::string& cluster_name = it->first;
+    if (clusters_needed.find(cluster_name) != clusters_needed.end()) {
+      ++it;
+      continue;
+    }
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
+      gpr_log(GPR_INFO, "[cdslb %p] cancelling watch for cluster %s", this,
+              cluster_name.c_str());
+    }
+    CancelClusterDataWatch(cluster_name, it->second.watcher,
+                           /*delay_unsubscription=*/false);
+    it = watchers_.erase(it);
+  }
+}
+
+void CdsLb::OnError(const std::string& name, grpc_error_handle error) {
   gpr_log(GPR_ERROR, "[cdslb %p] xds error obtaining data for cluster %s: %s",
-          this, config_->cluster().c_str(), grpc_error_string(error));
+          this, name.c_str(), grpc_error_std_string(error).c_str());
   // Go into TRANSIENT_FAILURE if we have not yet created the child
   // policy (i.e., we have not yet received data from xds).  Otherwise,
   // we keep running with the data we had previously.
@@ -426,12 +558,12 @@
   }
 }
 
-void CdsLb::OnResourceDoesNotExist() {
+void CdsLb::OnResourceDoesNotExist(const std::string& name) {
   gpr_log(GPR_ERROR,
           "[cdslb %p] CDS resource for %s does not exist -- reporting "
           "TRANSIENT_FAILURE",
-          this, config_->cluster().c_str());
-  grpc_error* error =
+          this, name.c_str());
+  grpc_error_handle error =
       grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
                              absl::StrCat("CDS resource \"", config_->cluster(),
                                           "\" does not exist")
@@ -443,8 +575,8 @@
   MaybeDestroyChildPolicyLocked();
 }
 
-grpc_error* CdsLb::UpdateXdsCertificateProvider(
-    const XdsApi::CdsUpdate& cluster_data) {
+grpc_error_handle CdsLb::UpdateXdsCertificateProvider(
+    const std::string& cluster_name, const XdsApi::CdsUpdate& cluster_data) {
   // Early out if channel is not configured to use xds security.
   grpc_channel_credentials* channel_credentials =
       grpc_channel_credentials_find_in_args(args_);
@@ -453,28 +585,28 @@
     xds_certificate_provider_ = nullptr;
     return GRPC_ERROR_NONE;
   }
+  if (xds_certificate_provider_ == nullptr) {
+    xds_certificate_provider_ = MakeRefCounted<XdsCertificateProvider>();
+  }
+  // Configure root cert.
   absl::string_view root_provider_instance_name =
       cluster_data.common_tls_context.combined_validation_context
           .validation_context_certificate_provider_instance.instance_name;
   absl::string_view root_provider_cert_name =
       cluster_data.common_tls_context.combined_validation_context
           .validation_context_certificate_provider_instance.certificate_name;
-  absl::string_view identity_provider_instance_name =
-      cluster_data.common_tls_context
-          .tls_certificate_certificate_provider_instance.instance_name;
-  absl::string_view identity_provider_cert_name =
-      cluster_data.common_tls_context
-          .tls_certificate_certificate_provider_instance.certificate_name;
   RefCountedPtr<XdsCertificateProvider> new_root_provider;
   if (!root_provider_instance_name.empty()) {
     new_root_provider =
         xds_client_->certificate_provider_store()
             .CreateOrGetCertificateProvider(root_provider_instance_name);
     if (new_root_provider == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
-          absl::StrCat("Certificate provider instance name: \"",
-                       root_provider_instance_name, "\" not recognized.")
-              .c_str());
+      return grpc_error_set_int(
+          GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat("Certificate provider instance name: \"",
+                           root_provider_instance_name, "\" not recognized.")
+                  .c_str()),
+          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
     }
   }
   if (root_certificate_provider_ != new_root_provider) {
@@ -491,16 +623,31 @@
     }
     root_certificate_provider_ = std::move(new_root_provider);
   }
+  xds_certificate_provider_->UpdateRootCertNameAndDistributor(
+      cluster_name, root_provider_cert_name,
+      root_certificate_provider_ == nullptr
+          ? nullptr
+          : root_certificate_provider_->distributor());
+  // Configure identity cert.
+  absl::string_view identity_provider_instance_name =
+      cluster_data.common_tls_context
+          .tls_certificate_certificate_provider_instance.instance_name;
+  absl::string_view identity_provider_cert_name =
+      cluster_data.common_tls_context
+          .tls_certificate_certificate_provider_instance.certificate_name;
   RefCountedPtr<XdsCertificateProvider> new_identity_provider;
   if (!identity_provider_instance_name.empty()) {
     new_identity_provider =
         xds_client_->certificate_provider_store()
             .CreateOrGetCertificateProvider(identity_provider_instance_name);
     if (new_identity_provider == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
-          absl::StrCat("Certificate provider instance name: \"",
-                       identity_provider_instance_name, "\" not recognized.")
-              .c_str());
+      return grpc_error_set_int(
+          GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat("Certificate provider instance name: \"",
+                           identity_provider_instance_name,
+                           "\" not recognized.")
+                  .c_str()),
+          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
     }
   }
   if (identity_certificate_provider_ != new_identity_provider) {
@@ -517,56 +664,34 @@
     }
     identity_certificate_provider_ = std::move(new_identity_provider);
   }
-  const std::vector<XdsApi::StringMatcher>& match_subject_alt_names =
+  xds_certificate_provider_->UpdateIdentityCertNameAndDistributor(
+      cluster_name, identity_provider_cert_name,
+      identity_certificate_provider_ == nullptr
+          ? nullptr
+          : identity_certificate_provider_->distributor());
+  // Configure SAN matchers.
+  const std::vector<StringMatcher>& match_subject_alt_names =
       cluster_data.common_tls_context.combined_validation_context
           .default_validation_context.match_subject_alt_names;
-  if (!root_provider_instance_name.empty() &&
-      !identity_provider_instance_name.empty()) {
-    // Using mTLS configuration
-    if (xds_certificate_provider_ != nullptr &&
-        xds_certificate_provider_->ProvidesRootCerts() &&
-        xds_certificate_provider_->ProvidesIdentityCerts()) {
-      xds_certificate_provider_->UpdateRootCertNameAndDistributor(
-          root_provider_cert_name, root_certificate_provider_->distributor());
-      xds_certificate_provider_->UpdateIdentityCertNameAndDistributor(
-          identity_provider_cert_name,
-          identity_certificate_provider_->distributor());
-      xds_certificate_provider_->UpdateSubjectAlternativeNameMatchers(
-          match_subject_alt_names);
-    } else {
-      // Existing xDS certificate provider does not have mTLS configuration.
-      // Create new certificate provider so that new subchannel connectors are
-      // created.
-      xds_certificate_provider_ = MakeRefCounted<XdsCertificateProvider>(
-          root_provider_cert_name, root_certificate_provider_->distributor(),
-          identity_provider_cert_name,
-          identity_certificate_provider_->distributor(),
-          match_subject_alt_names);
-    }
-  } else if (!root_provider_instance_name.empty()) {
-    // Using TLS configuration
-    if (xds_certificate_provider_ != nullptr &&
-        xds_certificate_provider_->ProvidesRootCerts() &&
-        !xds_certificate_provider_->ProvidesIdentityCerts()) {
-      xds_certificate_provider_->UpdateRootCertNameAndDistributor(
-          root_provider_cert_name, root_certificate_provider_->distributor());
-      xds_certificate_provider_->UpdateSubjectAlternativeNameMatchers(
-          match_subject_alt_names);
-    } else {
-      // Existing xDS certificate provider does not have TLS configuration.
-      // Create new certificate provider so that new subchannel connectors are
-      // created.
-      xds_certificate_provider_ = MakeRefCounted<XdsCertificateProvider>(
-          root_provider_cert_name, root_certificate_provider_->distributor(),
-          "", nullptr, match_subject_alt_names);
-    }
-  } else {
-    // No configuration provided.
-    xds_certificate_provider_ = nullptr;
-  }
+  xds_certificate_provider_->UpdateSubjectAlternativeNameMatchers(
+      cluster_name, match_subject_alt_names);
   return GRPC_ERROR_NONE;
 }
 
+void CdsLb::CancelClusterDataWatch(absl::string_view cluster_name,
+                                   XdsClient::ClusterWatcherInterface* watcher,
+                                   bool delay_unsubscription) {
+  if (xds_certificate_provider_ != nullptr) {
+    std::string name(cluster_name);
+    xds_certificate_provider_->UpdateRootCertNameAndDistributor(name, "",
+                                                                nullptr);
+    xds_certificate_provider_->UpdateIdentityCertNameAndDistributor(name, "",
+                                                                    nullptr);
+    xds_certificate_provider_->UpdateSubjectAlternativeNameMatchers(name, {});
+  }
+  xds_client_->CancelClusterDataWatch(cluster_name, watcher,
+                                      delay_unsubscription);
+}
 //
 // factory
 //
@@ -575,13 +700,12 @@
  public:
   OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
       LoadBalancingPolicy::Args args) const override {
-    grpc_error* error = GRPC_ERROR_NONE;
-    RefCountedPtr<XdsClient> xds_client = XdsClient::GetOrCreate(&error);
-    if (error != GRPC_ERROR_NONE) {
+    RefCountedPtr<XdsClient> xds_client =
+        XdsClient::GetFromChannelArgs(*args.args);
+    if (xds_client == nullptr) {
       gpr_log(GPR_ERROR,
-              "cannot get XdsClient to instantiate cds LB policy: %s",
-              grpc_error_string(error));
-      GRPC_ERROR_UNREF(error);
+              "XdsClient not present in channel args -- cannot instantiate "
+              "cds LB policy");
       return nullptr;
     }
     return MakeOrphanable<CdsLb>(std::move(xds_client), std::move(args));
@@ -590,7 +714,7 @@
   const char* name() const override { return kCds; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // xds was mentioned as a policy in the deprecated loadBalancingPolicy
@@ -600,7 +724,8 @@
           "Please use loadBalancingConfig field of service config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
+    // cluster name.
     std::string cluster;
     auto it = json.object_value().find("cluster");
     if (it == json.object_value().end()) {
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h
index dd64ea7..2351502 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h
@@ -21,4 +21,9 @@
 // Set by xds_cluster_impl LB policy and used by GoogleDefaultCredentials.
 #define GRPC_ARG_XDS_CLUSTER_NAME "grpc.internal.xds_cluster_name"
 
+// For testing purpose, this channel arg indicating xds_cluster_resolver LB
+// policy should use the fake DNS resolver to resolve logical dns cluster.
+#define GRPC_ARG_XDS_LOGICAL_DNS_CLUSTER_FAKE_RESOLVER_RESPONSE_GENERATOR \
+  "grpc.internal.xds_logical_dns_cluster_fake_resolver_response_generator"
+
 #endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CHANNEL_ARGS_H
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
index c2d9ec0..7dbba64 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc
@@ -31,6 +31,7 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/atomic.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
@@ -56,6 +57,7 @@
     explicit CallCounter(Key key) : key_(std::move(key)) {}
     ~CallCounter() override;
 
+    uint32_t Load() { return concurrent_requests_.Load(MemoryOrder::SEQ_CST); }
     uint32_t Increment() { return concurrent_requests_.FetchAdd(1); }
     void Decrement() { concurrent_requests_.FetchSub(1); }
 
@@ -69,7 +71,7 @@
 
  private:
   Mutex mu_;
-  std::map<Key, CallCounter*> map_;
+  std::map<Key, CallCounter*> map_ ABSL_GUARDED_BY(mu_);
 };
 
 CircuitBreakerCallCounterMap* g_call_counter_map = nullptr;
@@ -107,17 +109,6 @@
 
 constexpr char kXdsClusterImpl[] = "xds_cluster_impl_experimental";
 
-// TODO (donnadionne): Check to see if circuit breaking is enabled, this will be
-// removed once circuit breaking feature is fully integrated and enabled by
-// default.
-bool XdsCircuitBreakingEnabled() {
-  char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_CIRCUIT_BREAKING");
-  bool parsed_value;
-  bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
-  gpr_free(value);
-  return parse_succeeded && parsed_value;
-}
-
 // Config for xDS Cluster Impl LB policy.
 class XdsClusterImplLbConfig : public LoadBalancingPolicy::Config {
  public:
@@ -145,9 +136,7 @@
   const absl::optional<std::string>& lrs_load_reporting_server_name() const {
     return lrs_load_reporting_server_name_;
   };
-  const uint32_t max_concurrent_requests() const {
-    return max_concurrent_requests_;
-  }
+  uint32_t max_concurrent_requests() const { return max_concurrent_requests_; }
   RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config() const {
     return drop_config_;
   }
@@ -210,7 +199,6 @@
 
    private:
     RefCountedPtr<CircuitBreakerCallCounterMap::CallCounter> call_counter_;
-    bool xds_circuit_breaking_enabled_;
     uint32_t max_concurrent_requests_;
     RefCountedPtr<XdsApi::EdsUpdate::DropConfig> drop_config_;
     RefCountedPtr<XdsClusterDropStats> drop_stats_;
@@ -279,7 +267,6 @@
 XdsClusterImplLb::Picker::Picker(XdsClusterImplLb* xds_cluster_impl_lb,
                                  RefCountedPtr<RefCountedPicker> picker)
     : call_counter_(xds_cluster_impl_lb->call_counter_),
-      xds_circuit_breaking_enabled_(XdsCircuitBreakingEnabled()),
       max_concurrent_requests_(
           xds_cluster_impl_lb->config_->max_concurrent_requests()),
       drop_config_(xds_cluster_impl_lb->config_->drop_config()),
@@ -302,17 +289,15 @@
     return result;
   }
   // Handle circuit breaking.
-  uint32_t current = call_counter_->Increment();
-  if (xds_circuit_breaking_enabled_) {
-    // Check and see if we exceeded the max concurrent requests count.
-    if (current >= max_concurrent_requests_) {
-      call_counter_->Decrement();
-      if (drop_stats_ != nullptr) drop_stats_->AddUncategorizedDrops();
-      PickResult result;
-      result.type = PickResult::PICK_COMPLETE;
-      return result;
-    }
+  uint32_t current = call_counter_->Load();
+  // Check and see if we exceeded the max concurrent requests count.
+  if (current >= max_concurrent_requests_) {
+    if (drop_stats_ != nullptr) drop_stats_->AddUncategorizedDrops();
+    PickResult result;
+    result.type = PickResult::PICK_COMPLETE;
+    return result;
   }
+  call_counter_->Increment();
   // If we're not dropping the call, we should always have a child picker.
   if (picker_ == nullptr) {  // Should never happen.
     PickResult result;
@@ -346,7 +331,7 @@
         // Note: This callback does not run in either the control plane
         // work serializer or in the data plane mutex.
         [locality_stats, original_recv_trailing_metadata_ready, call_counter](
-            grpc_error* error, MetadataInterface* metadata,
+            grpc_error_handle error, MetadataInterface* metadata,
             CallState* call_state) {
           // Record call completion for load reporting.
           if (locality_stats != nullptr) {
@@ -611,14 +596,12 @@
  public:
   OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
       LoadBalancingPolicy::Args args) const override {
-    grpc_error* error = GRPC_ERROR_NONE;
-    RefCountedPtr<XdsClient> xds_client = XdsClient::GetOrCreate(&error);
-    if (error != GRPC_ERROR_NONE) {
-      gpr_log(
-          GPR_ERROR,
-          "cannot get XdsClient to instantiate xds_cluster_impl LB policy: %s",
-          grpc_error_string(error));
-      GRPC_ERROR_UNREF(error);
+    RefCountedPtr<XdsClient> xds_client =
+        XdsClient::GetFromChannelArgs(*args.args);
+    if (xds_client == nullptr) {
+      gpr_log(GPR_ERROR,
+              "XdsClient not present in channel args -- cannot instantiate "
+              "xds_cluster_impl LB policy");
       return nullptr;
     }
     return MakeOrphanable<XdsClusterImplLb>(std::move(xds_client),
@@ -628,7 +611,7 @@
   const char* name() const override { return kXdsClusterImpl; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // This policy was configured in the deprecated loadBalancingPolicy
@@ -639,7 +622,7 @@
           "config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     // Child policy.
     RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
     auto it = json.object_value().find("childPolicy");
@@ -647,12 +630,12 @@
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "field:childPolicy error:required field missing"));
     } else {
-      grpc_error* parse_error = GRPC_ERROR_NONE;
+      grpc_error_handle parse_error = GRPC_ERROR_NONE;
       child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
           it->second, &parse_error);
       if (child_policy == nullptr) {
         GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
-        std::vector<grpc_error*> child_errors;
+        std::vector<grpc_error_handle> child_errors;
         child_errors.push_back(parse_error);
         error_list.push_back(
             GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
@@ -711,7 +694,7 @@
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "field:dropCategories error:required field missing"));
     } else {
-      std::vector<grpc_error*> child_errors =
+      std::vector<grpc_error_handle> child_errors =
           ParseDropCategories(it->second, drop_config.get());
       if (!child_errors.empty()) {
         error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -730,9 +713,9 @@
   }
 
  private:
-  static std::vector<grpc_error*> ParseDropCategories(
+  static std::vector<grpc_error_handle> ParseDropCategories(
       const Json& json, XdsApi::EdsUpdate::DropConfig* drop_config) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::ARRAY) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "dropCategories field is not an array"));
@@ -740,10 +723,10 @@
     }
     for (size_t i = 0; i < json.array_value().size(); ++i) {
       const Json& entry = json.array_value()[i];
-      std::vector<grpc_error*> child_errors =
+      std::vector<grpc_error_handle> child_errors =
           ParseDropCategory(entry, drop_config);
       if (!child_errors.empty()) {
-        grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrCat("errors parsing index ", i).c_str());
         for (size_t i = 0; i < child_errors.size(); ++i) {
           error = grpc_error_add_child(error, child_errors[i]);
@@ -754,9 +737,9 @@
     return error_list;
   }
 
-  static std::vector<grpc_error*> ParseDropCategory(
+  static std::vector<grpc_error_handle> ParseDropCategory(
       const Json& json, XdsApi::EdsUpdate::DropConfig* drop_config) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "dropCategories entry is not an object"));
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc
index 4d76b39..1d4f143 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc
@@ -162,8 +162,8 @@
     OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
         const grpc_channel_args* args);
 
-    static void OnDelayedRemovalTimer(void* arg, grpc_error* error);
-    void OnDelayedRemovalTimerLocked(grpc_error* error);
+    static void OnDelayedRemovalTimer(void* arg, grpc_error_handle error);
+    void OnDelayedRemovalTimerLocked(grpc_error_handle error);
 
     // The owning LB policy.
     RefCountedPtr<XdsClusterManagerLb> xds_cluster_manager_policy_;
@@ -337,44 +337,29 @@
     gpr_log(GPR_INFO, "[xds_cluster_manager_lb %p] connectivity changed to %s",
             this, ConnectivityStateName(connectivity_state));
   }
-  std::unique_ptr<SubchannelPicker> picker;
-  absl::Status status;
-  switch (connectivity_state) {
-    case GRPC_CHANNEL_READY: {
-      ClusterPicker::ClusterMap cluster_map;
-      for (const auto& p : config_->cluster_map()) {
-        const std::string& cluster_name = p.first;
-        RefCountedPtr<ChildPickerWrapper>& child_picker =
-            cluster_map[cluster_name];
-        child_picker = children_[cluster_name]->picker_wrapper();
-        if (child_picker == nullptr) {
-          if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_manager_lb_trace)) {
-            gpr_log(
-                GPR_INFO,
+  ClusterPicker::ClusterMap cluster_map;
+  for (const auto& p : config_->cluster_map()) {
+    const std::string& cluster_name = p.first;
+    RefCountedPtr<ChildPickerWrapper>& child_picker = cluster_map[cluster_name];
+    child_picker = children_[cluster_name]->picker_wrapper();
+    if (child_picker == nullptr) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_cluster_manager_lb_trace)) {
+        gpr_log(GPR_INFO,
                 "[xds_cluster_manager_lb %p] child %s has not yet returned a "
                 "picker; creating a QueuePicker.",
                 this, cluster_name.c_str());
-          }
-          child_picker = MakeRefCounted<ChildPickerWrapper>(
-              cluster_name, absl::make_unique<QueuePicker>(
-                                Ref(DEBUG_LOCATION, "QueuePicker")));
-        }
       }
-      picker = absl::make_unique<ClusterPicker>(std::move(cluster_map));
-      break;
+      child_picker = MakeRefCounted<ChildPickerWrapper>(
+          cluster_name,
+          absl::make_unique<QueuePicker>(Ref(DEBUG_LOCATION, "QueuePicker")));
     }
-    case GRPC_CHANNEL_CONNECTING:
-    case GRPC_CHANNEL_IDLE:
-      picker =
-          absl::make_unique<QueuePicker>(Ref(DEBUG_LOCATION, "QueuePicker"));
-      break;
-    default:
-      grpc_error* error = grpc_error_set_int(
-          GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-              "TRANSIENT_FAILURE from XdsClusterManagerLb"),
-          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
-      status = grpc_error_to_absl_status(error);
-      picker = absl::make_unique<TransientFailurePicker>(error);
+  }
+  std::unique_ptr<SubchannelPicker> picker =
+      absl::make_unique<ClusterPicker>(std::move(cluster_map));
+  absl::Status status;
+  if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+    status = absl::Status(absl::StatusCode::kUnavailable,
+                          "TRANSIENT_FAILURE from XdsClusterManagerLb");
   }
   channel_control_helper()->UpdateState(connectivity_state, status,
                                         std::move(picker));
@@ -501,7 +486,7 @@
 
 void XdsClusterManagerLb::ClusterChild::DeactivateLocked() {
   // If already deactivated, don't do that again.
-  if (delayed_removal_timer_callback_pending_ == true) return;
+  if (delayed_removal_timer_callback_pending_) return;
   // Set the child weight to 0 so that future picker won't contain this child.
   // Start a timer to delete the child.
   Ref(DEBUG_LOCATION, "ClusterChild+timer").release();
@@ -513,7 +498,7 @@
 }
 
 void XdsClusterManagerLb::ClusterChild::OnDelayedRemovalTimer(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   ClusterChild* self = static_cast<ClusterChild*>(arg);
   GRPC_ERROR_REF(error);  // Ref owned by the lambda
   self->xds_cluster_manager_policy_->work_serializer()->Run(
@@ -522,7 +507,7 @@
 }
 
 void XdsClusterManagerLb::ClusterChild::OnDelayedRemovalTimerLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   delayed_removal_timer_callback_pending_ = false;
   if (error == GRPC_ERROR_NONE && !shutdown_) {
     xds_cluster_manager_policy_->children_.erase(name_);
@@ -616,7 +601,7 @@
   const char* name() const override { return kXdsClusterManager; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // xds_cluster_manager was mentioned as a policy in the deprecated
@@ -627,7 +612,7 @@
           "config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     XdsClusterManagerLbConfig::ClusterMap cluster_map;
     std::set<std::string /*cluster_name*/> clusters_to_be_used;
     auto it = json.object_value().find("children");
@@ -646,14 +631,14 @@
           continue;
         }
         RefCountedPtr<LoadBalancingPolicy::Config> child_config;
-        std::vector<grpc_error*> child_errors =
+        std::vector<grpc_error_handle> child_errors =
             ParseChildConfig(p.second, &child_config);
         if (!child_errors.empty()) {
           // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
           // string is not static in this case.
-          grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
               absl::StrCat("field:children name:", child_name).c_str());
-          for (grpc_error* child_error : child_errors) {
+          for (grpc_error_handle child_error : child_errors) {
             error = grpc_error_add_child(error, child_error);
           }
           error_list.push_back(error);
@@ -676,10 +661,10 @@
   }
 
  private:
-  static std::vector<grpc_error*> ParseChildConfig(
+  static std::vector<grpc_error_handle> ParseChildConfig(
       const Json& json,
       RefCountedPtr<LoadBalancingPolicy::Config>* child_config) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "value should be of type object"));
@@ -690,12 +675,12 @@
       error_list.push_back(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("did not find childPolicy"));
     } else {
-      grpc_error* parse_error = GRPC_ERROR_NONE;
+      grpc_error_handle parse_error = GRPC_ERROR_NONE;
       *child_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
           it->second, &parse_error);
       if (*child_config == nullptr) {
         GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
-        std::vector<grpc_error*> child_errors;
+        std::vector<grpc_error_handle> child_errors;
         child_errors.push_back(parse_error);
         error_list.push_back(
             GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
index 0133a71..bcb8194 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
@@ -29,8 +29,10 @@
 #include "src/core/ext/filters/client_channel/lb_policy/address_filtering.h"
 #include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
 #include "src/core/ext/filters/client_channel/lb_policy/xds/xds.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h"
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
 #include "src/core/ext/xds/xds_channel_args.h"
@@ -80,39 +82,33 @@
   };
 
   XdsClusterResolverLbConfig(
-      std::vector<DiscoveryMechanism> discovery_mechanisms,
-      Json locality_picking_policy, Json endpoint_picking_policy)
+      std::vector<DiscoveryMechanism> discovery_mechanisms, Json xds_lb_policy)
       : discovery_mechanisms_(std::move(discovery_mechanisms)),
-        locality_picking_policy_(std::move(locality_picking_policy)),
-        endpoint_picking_policy_(std::move(endpoint_picking_policy)) {}
+        xds_lb_policy_(std::move(xds_lb_policy)) {}
 
   const char* name() const override { return kXdsClusterResolver; }
-
   const std::vector<DiscoveryMechanism>& discovery_mechanisms() const {
     return discovery_mechanisms_;
   }
-  const Json& locality_picking_policy() const {
-    return locality_picking_policy_;
-  }
-  const Json& endpoint_picking_policy() const {
-    return endpoint_picking_policy_;
-  }
+
+  const Json& xds_lb_policy() const { return xds_lb_policy_; }
 
  private:
   std::vector<DiscoveryMechanism> discovery_mechanisms_;
-  Json locality_picking_policy_;
-  Json endpoint_picking_policy_;
+  Json xds_lb_policy_;
 };
 
 // Xds Cluster Resolver LB policy.
 class XdsClusterResolverLb : public LoadBalancingPolicy {
  public:
-  XdsClusterResolverLb(RefCountedPtr<XdsClient> xds_client, Args args);
+  XdsClusterResolverLb(RefCountedPtr<XdsClient> xds_client, Args args,
+                       std::string server_name, bool is_xds_uri);
 
   const char* name() const override { return kXdsClusterResolver; }
 
   void UpdateLocked(UpdateArgs args) override;
   void ResetBackoffLocked() override;
+  void ExitIdleLocked() override;
 
  private:
   // Discovery Mechanism Base class
@@ -132,9 +128,11 @@
         : parent_(std::move(xds_cluster_resolver_lb)), index_(index) {}
     virtual void Start() = 0;
     void Orphan() override = 0;
+    virtual Json::Array override_child_policy() = 0;
+    virtual bool disable_reresolution() = 0;
 
     // Caller must ensure that config_ is set before calling.
-    const absl::string_view GetXdsClusterResolverResourceName() const {
+    absl::string_view GetXdsClusterResolverResourceName() const {
       if (!parent_->is_xds_uri_) return parent_->server_name_;
       if (!parent_->config_->discovery_mechanisms()[index_]
                .eds_service_name.empty()) {
@@ -172,6 +170,8 @@
         : DiscoveryMechanism(std::move(xds_cluster_resolver_lb), index) {}
     void Start() override;
     void Orphan() override;
+    Json::Array override_child_policy() override { return Json::Array{}; }
+    bool disable_reresolution() override { return true; }
 
    private:
     class EndpointWatcher : public XdsClient::EndpointWatcherInterface {
@@ -185,7 +185,7 @@
       void OnEndpointChanged(XdsApi::EdsUpdate update) override {
         new Notifier(discovery_mechanism_, std::move(update));
       }
-      void OnError(grpc_error* error) override {
+      void OnError(grpc_error_handle error) override {
         new Notifier(discovery_mechanism_, error);
       }
       void OnResourceDoesNotExist() override {
@@ -198,7 +198,7 @@
         Notifier(RefCountedPtr<EdsDiscoveryMechanism> discovery_mechanism,
                  XdsApi::EdsUpdate update);
         Notifier(RefCountedPtr<EdsDiscoveryMechanism> discovery_mechanism,
-                 grpc_error* error);
+                 grpc_error_handle error);
         explicit Notifier(
             RefCountedPtr<EdsDiscoveryMechanism> discovery_mechanism);
         ~Notifier() { discovery_mechanism_.reset(DEBUG_LOCATION, "Notifier"); }
@@ -206,8 +206,8 @@
        private:
         enum Type { kUpdate, kError, kDoesNotExist };
 
-        static void RunInExecCtx(void* arg, grpc_error* error);
-        void RunInWorkSerializer(grpc_error* error);
+        static void RunInExecCtx(void* arg, grpc_error_handle error);
+        void RunInWorkSerializer(grpc_error_handle error);
 
         RefCountedPtr<EdsDiscoveryMechanism> discovery_mechanism_;
         grpc_closure closure_;
@@ -230,6 +230,14 @@
         : DiscoveryMechanism(std::move(xds_cluster_resolver_lb), index) {}
     void Start() override;
     void Orphan() override;
+    Json::Array override_child_policy() override {
+      return Json::Array{
+          Json::Object{
+              {"pick_first", Json::Object()},
+          },
+      };
+    }
+    bool disable_reresolution() override { return false; };
 
    private:
     class ResolverResultHandler : public Resolver::ResultHandler {
@@ -242,7 +250,7 @@
 
       void ReturnResult(Resolver::Result result) override;
 
-      void ReturnError(grpc_error* error) override;
+      void ReturnError(grpc_error_handle error) override;
 
      private:
       RefCountedPtr<LogicalDNSDiscoveryMechanism> discovery_mechanism_;
@@ -296,7 +304,7 @@
   void ShutdownLocked() override;
 
   void OnEndpointChanged(size_t index, XdsApi::EdsUpdate update);
-  void OnError(size_t index, grpc_error* error);
+  void OnError(size_t index, grpc_error_handle error);
   void OnResourceDoesNotExist(size_t index);
 
   void MaybeDestroyChildPolicyLocked();
@@ -310,6 +318,9 @@
   grpc_channel_args* CreateChildPolicyArgsLocked(
       const grpc_channel_args* args_in);
 
+  // The xds client and endpoint watcher.
+  RefCountedPtr<XdsClient> xds_client_;
+
   // Server name from target URI.
   std::string server_name_;
   bool is_xds_uri_;
@@ -321,9 +332,6 @@
   // Internal state.
   bool shutting_down_ = false;
 
-  // The xds client and endpoint watcher.
-  RefCountedPtr<XdsClient> xds_client_;
-
   // Vector of discovery mechansism entries in priority order.
   std::vector<DiscoveryMechanismEntry> discovery_mechanisms_;
 
@@ -422,7 +430,7 @@
 XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
     Notifier(RefCountedPtr<XdsClusterResolverLb::EdsDiscoveryMechanism>
                  discovery_mechanism,
-             grpc_error* error)
+             grpc_error_handle error)
     : discovery_mechanism_(std::move(discovery_mechanism)), type_(kError) {
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, error);
@@ -438,7 +446,7 @@
 }
 
 void XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
-    RunInExecCtx(void* arg, grpc_error* error) {
+    RunInExecCtx(void* arg, grpc_error_handle error) {
   Notifier* self = static_cast<Notifier*>(arg);
   GRPC_ERROR_REF(error);
   self->discovery_mechanism_->parent()->work_serializer()->Run(
@@ -446,7 +454,7 @@
 }
 
 void XdsClusterResolverLb::EdsDiscoveryMechanism::EndpointWatcher::Notifier::
-    RunInWorkSerializer(grpc_error* error) {
+    RunInWorkSerializer(grpc_error_handle error) {
   switch (type_) {
     case kUpdate:
       discovery_mechanism_->parent()->OnEndpointChanged(
@@ -469,11 +477,26 @@
 //
 
 void XdsClusterResolverLb::LogicalDNSDiscoveryMechanism::Start() {
+  std::string target = parent()->server_name_;
+  grpc_channel_args* args = nullptr;
+  FakeResolverResponseGenerator* fake_resolver_response_generator =
+      grpc_channel_args_find_pointer<FakeResolverResponseGenerator>(
+          parent()->args_,
+          GRPC_ARG_XDS_LOGICAL_DNS_CLUSTER_FAKE_RESOLVER_RESPONSE_GENERATOR);
+  if (fake_resolver_response_generator != nullptr) {
+    target = absl::StrCat("fake:", target);
+    grpc_arg new_arg = FakeResolverResponseGenerator::MakeChannelArg(
+        fake_resolver_response_generator);
+    args = grpc_channel_args_copy_and_add(parent()->args_, &new_arg, 1);
+  } else {
+    args = grpc_channel_args_copy(parent()->args_);
+  }
   resolver_ = ResolverRegistry::CreateResolver(
-      parent()->server_name_.c_str(), parent()->args_,
-      grpc_pollset_set_create(), parent()->work_serializer(),
+      target.c_str(), args, parent()->interested_parties(),
+      parent()->work_serializer(),
       absl::make_unique<ResolverResultHandler>(
           Ref(DEBUG_LOCATION, "LogicalDNSDiscoveryMechanism")));
+  grpc_channel_args_destroy(args);
   if (resolver_ == nullptr) {
     parent()->OnResourceDoesNotExist(index());
     return;
@@ -509,15 +532,17 @@
   XdsApi::EdsUpdate update;
   XdsApi::EdsUpdate::Priority::Locality locality;
   locality.name = MakeRefCounted<XdsLocalityName>("", "", "");
+  locality.lb_weight = 1;
   locality.endpoints = std::move(result.addresses);
-  update.priorities[0].localities.emplace(locality.name.get(),
-                                          std::move(locality));
+  XdsApi::EdsUpdate::Priority priority;
+  priority.localities.emplace(locality.name.get(), std::move(locality));
+  update.priorities.emplace_back(std::move(priority));
   discovery_mechanism_->parent()->OnEndpointChanged(
       discovery_mechanism_->index(), std::move(update));
 }
 
 void XdsClusterResolverLb::LogicalDNSDiscoveryMechanism::ResolverResultHandler::
-    ReturnError(grpc_error* error) {
+    ReturnError(grpc_error_handle error) {
   discovery_mechanism_->parent()->OnError(discovery_mechanism_->index(), error);
 }
 
@@ -526,26 +551,17 @@
 //
 
 XdsClusterResolverLb::XdsClusterResolverLb(RefCountedPtr<XdsClient> xds_client,
-                                           Args args)
-    : LoadBalancingPolicy(std::move(args)), xds_client_(std::move(xds_client)) {
+                                           Args args, std::string server_name,
+                                           bool is_xds_uri)
+    : LoadBalancingPolicy(std::move(args)),
+      xds_client_(std::move(xds_client)),
+      server_name_(std::move(server_name)),
+      is_xds_uri_(is_xds_uri) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_cluster_resolver_trace)) {
     gpr_log(GPR_INFO,
-            "[xds_cluster_resolver_lb %p] created -- using xds client %p", this,
-            xds_client_.get());
-  }
-  // Record server name.
-  const char* server_uri =
-      grpc_channel_args_find_string(args.args, GRPC_ARG_SERVER_URI);
-  GPR_ASSERT(server_uri != nullptr);
-  absl::StatusOr<URI> uri = URI::Parse(server_uri);
-  GPR_ASSERT(uri.ok() && !uri->path().empty());
-  server_name_ = std::string(absl::StripPrefix(uri->path(), "/"));
-  is_xds_uri_ = uri->scheme() == "xds";
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_cluster_resolver_trace)) {
-    gpr_log(GPR_INFO,
-            "[xds_cluster_resolver_lb %p] server name from channel "
-            "(is_xds_uri=%d): %s",
-            this, is_xds_uri_, server_name_.c_str());
+            "[xds_cluster_resolver_lb %p] created -- xds_client=%p, "
+            "server_name=%s, is_xds_uri=%d",
+            this, xds_client_.get(), server_name_.c_str(), is_xds_uri_);
   }
   // EDS-only flow.
   if (!is_xds_uri_) {
@@ -655,6 +671,10 @@
   }
 }
 
+void XdsClusterResolverLb::ExitIdleLocked() {
+  if (child_policy_ != nullptr) child_policy_->ExitIdleLocked();
+}
+
 void XdsClusterResolverLb::OnEndpointChanged(size_t index,
                                              XdsApi::EdsUpdate update) {
   if (shutting_down_) return;
@@ -673,10 +693,17 @@
   discovery_mechanisms_[index].pending_priority_list =
       std::move(update.priorities);
   discovery_mechanisms_[index].first_update_received = true;
-  if (!discovery_mechanisms_[0].first_update_received) {
-    // We have not yet received an update for index 0, so wait until that
-    // happens to create the child policy.
-    return;
+  // If any discovery mechanism has not received its first update,
+  // wait until that happens before creating the child policy.
+  // TODO(roth): If this becomes problematic in the future (e.g., a
+  // secondary discovery mechanism delaying us from starting up at all),
+  // we can consider some sort of optimization whereby we can create the
+  // priority policy with only a subset of its children.  But we need to
+  // make sure not to get into a situation where the priority policy
+  // will put the channel into TRANSIENT_FAILURE instead of CONNECTING
+  // while we're still waiting for the other discovery mechanism(s).
+  for (DiscoveryMechanismEntry& mechanism : discovery_mechanisms_) {
+    if (!mechanism.first_update_received) return;
   }
   // Construct new priority list.
   XdsApi::EdsUpdate::PriorityList priority_list;
@@ -703,11 +730,11 @@
   UpdatePriorityList(std::move(priority_list));
 }
 
-void XdsClusterResolverLb::OnError(size_t index, grpc_error* error) {
+void XdsClusterResolverLb::OnError(size_t index, grpc_error_handle error) {
   gpr_log(GPR_ERROR,
           "[xds_cluster_resolver_lb %p] discovery mechanism %" PRIuPTR
           " xds watcher reported error: %s",
-          this, index, grpc_error_string(error));
+          this, index, grpc_error_std_string(error).c_str());
   GRPC_ERROR_UNREF(error);
   if (shutting_down_) return;
   if (!discovery_mechanisms_[index].first_update_received) {
@@ -813,7 +840,11 @@
                                MakeHierarchicalPathAttribute(hierarchical_path))
                 .WithAttribute(kXdsLocalityNameAttributeKey,
                                absl::make_unique<XdsLocalityAttribute>(
-                                   locality_name->Ref())));
+                                   locality_name->Ref()))
+                .WithAttribute(ServerAddressWeightAttribute::
+                                   kServerAddressWeightAttributeKey,
+                               absl::make_unique<ServerAddressWeightAttribute>(
+                                   locality.lb_weight)));
       }
     }
   }
@@ -825,53 +856,76 @@
   Json::Object priority_children;
   Json::Array priority_priorities;
   // Setting up index to iterate through the discovery mechanisms and keeping
-  // track the discovery_mechanism each prioirty belongs to.
+  // track the discovery_mechanism each priority belongs to.
   size_t discovery_index = 0;
   // Setting up num_priorities_remaining to track the priorities in each
   // discovery_mechanism.
   size_t num_priorities_remaining_in_discovery =
       discovery_mechanisms_[discovery_index].num_priorities;
   for (size_t priority = 0; priority < priority_list_.size(); ++priority) {
-    // Each prioirty in the priority_list_ should correspond to a priority in a
-    // discovery mechanism in discovery_mechanisms_ (both in the same order).
-    // Keeping track of the discovery_mechanism each prioirty belongs to.
-    if (num_priorities_remaining_in_discovery == 0) {
-      ++discovery_index;
-      num_priorities_remaining_in_discovery =
-          discovery_mechanisms_[discovery_index].num_priorities;
+    Json child_policy;
+    if (!discovery_mechanisms_[discovery_index]
+             .discovery_mechanism->override_child_policy()
+             .empty()) {
+      child_policy = discovery_mechanisms_[discovery_index]
+                         .discovery_mechanism->override_child_policy();
     } else {
-      --num_priorities_remaining_in_discovery;
+      const auto& xds_lb_policy = config_->xds_lb_policy().object_value();
+      if (xds_lb_policy.find("ROUND_ROBIN") != xds_lb_policy.end()) {
+        const auto& localities = priority_list_[priority].localities;
+        Json::Object weighted_targets;
+        for (const auto& p : localities) {
+          XdsLocalityName* locality_name = p.first;
+          const auto& locality = p.second;
+          // Construct JSON object containing locality name.
+          Json::Object locality_name_json;
+          if (!locality_name->region().empty()) {
+            locality_name_json["region"] = locality_name->region();
+          }
+          if (!locality_name->zone().empty()) {
+            locality_name_json["zone"] = locality_name->zone();
+          }
+          if (!locality_name->sub_zone().empty()) {
+            locality_name_json["sub_zone"] = locality_name->sub_zone();
+          }
+          // Add weighted target entry.
+          weighted_targets[locality_name->AsHumanReadableString()] =
+              Json::Object{
+                  {"weight", locality.lb_weight},
+                  {"childPolicy",
+                   Json::Array{
+                       Json::Object{
+                           {"round_robin", Json::Object()},
+                       },
+                   }},
+              };
+        }
+        // Construct locality-picking policy.
+        // Start with field from our config and add the "targets" field.
+        child_policy = Json::Array{
+            Json::Object{
+                {"weighted_target_experimental",
+                 Json::Object{
+                     {"targets", Json::Object()},
+                 }},
+            },
+        };
+        Json::Object& config =
+            *(*child_policy.mutable_array())[0].mutable_object();
+        auto it = config.begin();
+        GPR_ASSERT(it != config.end());
+        (*it->second.mutable_object())["targets"] = std::move(weighted_targets);
+      } else {
+        auto it = xds_lb_policy.find("RING_HASH");
+        GPR_ASSERT(it != xds_lb_policy.end());
+        Json::Object ring_hash_experimental_policy = it->second.object_value();
+        child_policy = Json::Array{
+            Json::Object{
+                {"ring_hash_experimental", ring_hash_experimental_policy},
+            },
+        };
+      }
     }
-    const auto& localities = priority_list_[priority].localities;
-    Json::Object weighted_targets;
-    for (const auto& p : localities) {
-      XdsLocalityName* locality_name = p.first;
-      const auto& locality = p.second;
-      // Construct JSON object containing locality name.
-      Json::Object locality_name_json;
-      if (!locality_name->region().empty()) {
-        locality_name_json["region"] = locality_name->region();
-      }
-      if (!locality_name->zone().empty()) {
-        locality_name_json["zone"] = locality_name->zone();
-      }
-      if (!locality_name->sub_zone().empty()) {
-        locality_name_json["subzone"] = locality_name->sub_zone();
-      }
-      // Add weighted target entry.
-      weighted_targets[locality_name->AsHumanReadableString()] = Json::Object{
-          {"weight", locality.lb_weight},
-          {"childPolicy", config_->endpoint_picking_policy()},
-      };
-    }
-    // Construct locality-picking policy.
-    // Start with field from our config and add the "targets" field.
-    Json locality_picking_config = config_->locality_picking_policy();
-    Json::Object& config =
-        *(*locality_picking_config.mutable_array())[0].mutable_object();
-    auto it = config.begin();
-    GPR_ASSERT(it != config.end());
-    (*it->second.mutable_object())["targets"] = std::move(weighted_targets);
     // Wrap it in the drop policy.
     Json::Array drop_categories;
     if (discovery_mechanisms_[discovery_index].drop_config != nullptr) {
@@ -887,7 +941,7 @@
                              .discovery_mechanism->GetLrsClusterKey();
     Json::Object xds_cluster_impl_config = {
         {"clusterName", std::string(lrs_key.first)},
-        {"childPolicy", std::move(locality_picking_config)},
+        {"childPolicy", std::move(child_policy)},
         {"dropCategories", std::move(drop_categories)},
         {"maxConcurrentRequests",
          config_->discovery_mechanisms()[discovery_index]
@@ -909,10 +963,24 @@
     const size_t child_number = priority_child_numbers_[priority];
     std::string child_name = absl::StrCat("child", child_number);
     priority_priorities.emplace_back(child_name);
-    priority_children[child_name] = Json::Object{
+    Json::Object child_config = {
         {"config", std::move(locality_picking_policy)},
-        {"ignore_reresolution_requests", true},
     };
+    if (discovery_mechanisms_[discovery_index]
+            .discovery_mechanism->disable_reresolution()) {
+      child_config["ignore_reresolution_requests"] = true;
+    }
+    priority_children[child_name] = std::move(child_config);
+    // Each priority in the priority_list_ should correspond to a priority in a
+    // discovery mechanism in discovery_mechanisms_ (both in the same order).
+    // Keeping track of the discovery_mechanism each priority belongs to.
+    --num_priorities_remaining_in_discovery;
+    while (num_priorities_remaining_in_discovery == 0 &&
+           discovery_index < discovery_mechanisms_.size() - 1) {
+      ++discovery_index;
+      num_priorities_remaining_in_discovery =
+          discovery_mechanisms_[discovery_index].num_priorities;
+    }
   }
   // There should be matching number of priorities in discovery_mechanisms_ and
   // in priority_list_; therefore at the end of looping through all the
@@ -934,7 +1002,7 @@
         "[xds_cluster_resolver_lb %p] generated config for child policy: %s",
         this, json_str.c_str());
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   RefCountedPtr<LoadBalancingPolicy::Config> config =
       LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error);
   if (error != GRPC_ERROR_NONE) {
@@ -944,7 +1012,7 @@
             "[xds_cluster_resolver_lb %p] error parsing generated child policy "
             "config -- "
             "will put channel in TRANSIENT_FAILURE: %s",
-            this, grpc_error_string(error));
+            this, grpc_error_std_string(error).c_str());
     error = grpc_error_set_int(
         grpc_error_add_child(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                  "xds_cluster_resolver LB policy: error "
@@ -978,10 +1046,14 @@
 
 grpc_channel_args* XdsClusterResolverLb::CreateChildPolicyArgsLocked(
     const grpc_channel_args* args) {
-  // Inhibit client-side health checking, since the balancer does this for us.
-  grpc_arg new_arg = grpc_channel_arg_integer_create(
-      const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1);
-  return grpc_channel_args_copy_and_add(args, &new_arg, 1);
+  absl::InlinedVector<grpc_arg, 2> new_args = {
+      // Inhibit client-side health checking, since the balancer does this
+      // for us.
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1),
+  };
+  if (!is_xds_uri_) new_args.push_back(xds_client_->MakeChannelArg());
+  return grpc_channel_args_copy_and_add(args, new_args.data(), new_args.size());
 }
 
 OrphanablePtr<LoadBalancingPolicy>
@@ -1020,24 +1092,45 @@
  public:
   OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
       LoadBalancingPolicy::Args args) const override {
-    grpc_error* error = GRPC_ERROR_NONE;
-    RefCountedPtr<XdsClient> xds_client = XdsClient::GetOrCreate(&error);
-    if (error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_ERROR,
-              "cannot get XdsClient to instantiate xds_cluster_resolver LB "
-              "policy: %s",
-              grpc_error_string(error));
-      GRPC_ERROR_UNREF(error);
-      return nullptr;
+    // Find server name.
+    const char* server_uri =
+        grpc_channel_args_find_string(args.args, GRPC_ARG_SERVER_URI);
+    GPR_ASSERT(server_uri != nullptr);
+    absl::StatusOr<URI> uri = URI::Parse(server_uri);
+    GPR_ASSERT(uri.ok() && !uri->path().empty());
+    absl::string_view server_name = absl::StripPrefix(uri->path(), "/");
+    // Determine if it's an xds URI.
+    bool is_xds_uri = uri->scheme() == "xds";
+    // Get XdsClient.
+    RefCountedPtr<XdsClient> xds_client =
+        XdsClient::GetFromChannelArgs(*args.args);
+    if (xds_client == nullptr) {
+      if (!is_xds_uri) {
+        grpc_error_handle error = GRPC_ERROR_NONE;
+        xds_client = XdsClient::GetOrCreate(args.args, &error);
+        if (error != GRPC_ERROR_NONE) {
+          gpr_log(GPR_ERROR,
+                  "cannot get or create XdsClient to instantiate "
+                  "xds_cluster_resolver LB policy: %s",
+                  grpc_error_std_string(error).c_str());
+          GRPC_ERROR_UNREF(error);
+          return nullptr;
+        }
+      } else {
+        gpr_log(GPR_ERROR,
+                "XdsClient not present in channel args -- cannot instantiate "
+                "xds_cluster_resolver LB policy");
+        return nullptr;
+      }
     }
-    return MakeOrphanable<XdsClusterResolverChildHandler>(std::move(xds_client),
-                                                          std::move(args));
+    return MakeOrphanable<XdsClusterResolverChildHandler>(
+        std::move(xds_client), std::move(args), server_name, is_xds_uri);
   }
 
   const char* name() const override { return kXdsClusterResolver; }
 
   RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const override {
+      const Json& json, grpc_error_handle* error) const override {
     GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
     if (json.type() == Json::Type::JSON_NULL) {
       // xds_cluster_resolver was mentioned as a policy in the deprecated
@@ -1048,7 +1141,7 @@
           "Please use loadBalancingConfig field of service config instead.");
       return nullptr;
     }
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     std::vector<XdsClusterResolverLbConfig::DiscoveryMechanism>
         discovery_mechanisms;
     auto it = json.object_value().find("discoveryMechanisms");
@@ -1062,13 +1155,13 @@
       const Json::Array& array = it->second.array_value();
       for (size_t i = 0; i < array.size(); ++i) {
         XdsClusterResolverLbConfig::DiscoveryMechanism discovery_mechanism;
-        std::vector<grpc_error*> discovery_mechanism_errors =
+        std::vector<grpc_error_handle> discovery_mechanism_errors =
             ParseDiscoveryMechanism(array[i], &discovery_mechanism);
         if (!discovery_mechanism_errors.empty()) {
-          grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
               absl::StrCat("field:discovery_mechanism element: ", i, " error")
                   .c_str());
-          for (grpc_error* discovery_mechanism_error :
+          for (grpc_error_handle discovery_mechanism_error :
                discovery_mechanism_errors) {
             error = grpc_error_add_child(error, discovery_mechanism_error);
           }
@@ -1077,58 +1170,104 @@
         discovery_mechanisms.emplace_back(std::move(discovery_mechanism));
       }
     }
-    // Locality-picking policy.
-    Json locality_picking_policy;
-    it = json.object_value().find("localityPickingPolicy");
-    if (it == json.object_value().end()) {
-      locality_picking_policy = Json::Array{
-          Json::Object{
-              {"weighted_target_experimental",
-               Json::Object{
-                   {"targets", Json::Object()},
-               }},
-          },
-      };
-    } else {
-      locality_picking_policy = it->second;
-    }
-    grpc_error* parse_error = GRPC_ERROR_NONE;
-    if (LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
-            locality_picking_policy, &parse_error) == nullptr) {
-      GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
-      error_list.push_back(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-          "localityPickingPolicy", &parse_error, 1));
-      GRPC_ERROR_UNREF(parse_error);
-    }
-    // Endpoint-picking policy.  Called "childPolicy" for xds policy.
-    Json endpoint_picking_policy;
-    it = json.object_value().find("endpointPickingPolicy");
-    if (it == json.object_value().end()) {
-      endpoint_picking_policy = Json::Array{
-          Json::Object{
-              {"round_robin", Json::Object()},
-          },
-      };
-    } else {
-      endpoint_picking_policy = it->second;
-    }
-    parse_error = GRPC_ERROR_NONE;
-    if (LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
-            endpoint_picking_policy, &parse_error) == nullptr) {
-      GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
-      error_list.push_back(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-          "endpointPickingPolicy", &parse_error, 1));
-      GRPC_ERROR_UNREF(parse_error);
-    }
     if (discovery_mechanisms.empty()) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "field:discovery_mechanism error:list is missing or empty"));
     }
+    Json xds_lb_policy = Json::Object{
+        {"ROUND_ROBIN", Json::Object()},
+    };
+    it = json.object_value().find("xdsLbPolicy");
+    if (it != json.object_value().end()) {
+      if (it->second.type() != Json::Type::ARRAY) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:xdsLbPolicy error:type should be array"));
+      } else {
+        const Json::Array& array = it->second.array_value();
+        for (size_t i = 0; i < array.size(); ++i) {
+          if (array[i].type() != Json::Type::OBJECT) {
+            error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                "field:xdsLbPolicy error:element should be of type object"));
+            continue;
+          }
+          const Json::Object& policy = array[i].object_value();
+          auto policy_it = policy.find("ROUND_ROBIN");
+          if (policy_it != policy.end()) {
+            if (policy_it->second.type() != Json::Type::OBJECT) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:ROUND_ROBIN error:type should be object"));
+            }
+            break;
+          }
+          policy_it = policy.find("RING_HASH");
+          if (policy_it != policy.end()) {
+            if (policy_it->second.type() != Json::Type::OBJECT) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:RING_HASH error:type should be object"));
+              continue;
+            }
+            // TODO(donnadionne): Move this to a method in
+            // ring_hash_experimental and call it here.
+            const Json::Object& ring_hash = policy_it->second.object_value();
+            xds_lb_policy = array[i];
+            size_t min_ring_size = 1024;
+            size_t max_ring_size = 8388608;
+            auto ring_hash_it = ring_hash.find("min_ring_size");
+            if (ring_hash_it == ring_hash.end()) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:min_ring_size missing"));
+            } else if (ring_hash_it->second.type() != Json::Type::NUMBER) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:min_ring_size error: should be of "
+                  "number"));
+            } else {
+              min_ring_size = gpr_parse_nonnegative_int(
+                  ring_hash_it->second.string_value().c_str());
+            }
+            ring_hash_it = ring_hash.find("max_ring_size");
+            if (ring_hash_it == ring_hash.end()) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:max_ring_size missing"));
+            } else if (ring_hash_it->second.type() != Json::Type::NUMBER) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:max_ring_size error: should be of "
+                  "number"));
+            } else {
+              max_ring_size = gpr_parse_nonnegative_int(
+                  ring_hash_it->second.string_value().c_str());
+            }
+            if (min_ring_size <= 0 || min_ring_size > 8388608 ||
+                max_ring_size <= 0 || max_ring_size > 8388608 ||
+                min_ring_size > max_ring_size) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:max_ring_size and or min_ring_size error: "
+                  "values need to be in the range of 1 to 8388608 "
+                  "and max_ring_size cannot be smaller than "
+                  "min_ring_size"));
+            }
+            ring_hash_it = ring_hash.find("hash_function");
+            if (ring_hash_it == ring_hash.end()) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:hash_function missing"));
+            } else if (ring_hash_it->second.type() != Json::Type::STRING) {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:hash_function error: should be a "
+                  "string"));
+            } else if (ring_hash_it->second.string_value() != "XX_HASH" &&
+                       ring_hash_it->second.string_value() != "MURMUR_HASH_2") {
+              error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                  "field:hash_function error: unsupported "
+                  "hash_function"));
+            }
+            break;
+          }
+        }
+      }
+    }
     // Construct config.
     if (error_list.empty()) {
       return MakeRefCounted<XdsClusterResolverLbConfig>(
-          std::move(discovery_mechanisms), std::move(locality_picking_policy),
-          std::move(endpoint_picking_policy));
+          std::move(discovery_mechanisms), std::move(xds_lb_policy));
     } else {
       *error = GRPC_ERROR_CREATE_FROM_VECTOR(
           "xds_cluster_resolver_experimental LB policy config", &error_list);
@@ -1137,10 +1276,10 @@
   }
 
  private:
-  static std::vector<grpc_error*> ParseDiscoveryMechanism(
+  static std::vector<grpc_error_handle> ParseDiscoveryMechanism(
       const Json& json,
       XdsClusterResolverLbConfig::DiscoveryMechanism* discovery_mechanism) {
-    std::vector<grpc_error*> error_list;
+    std::vector<grpc_error_handle> error_list;
     if (json.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "value should be of type object"));
@@ -1217,10 +1356,13 @@
   class XdsClusterResolverChildHandler : public ChildPolicyHandler {
    public:
     XdsClusterResolverChildHandler(RefCountedPtr<XdsClient> xds_client,
-                                   Args args)
+                                   Args args, absl::string_view server_name,
+                                   bool is_xds_uri)
         : ChildPolicyHandler(std::move(args),
                              &grpc_lb_xds_cluster_resolver_trace),
-          xds_client_(std::move(xds_client)) {}
+          xds_client_(std::move(xds_client)),
+          server_name_(server_name),
+          is_xds_uri_(is_xds_uri) {}
 
     bool ConfigChangeRequiresNewPolicyInstance(
         LoadBalancingPolicy::Config* old_config,
@@ -1236,12 +1378,15 @@
     }
 
     OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
-        const char* name, LoadBalancingPolicy::Args args) const override {
-      return MakeOrphanable<XdsClusterResolverLb>(xds_client_, std::move(args));
+        const char* /*name*/, LoadBalancingPolicy::Args args) const override {
+      return MakeOrphanable<XdsClusterResolverLb>(xds_client_, std::move(args),
+                                                  server_name_, is_xds_uri_);
     }
 
    private:
     RefCountedPtr<XdsClient> xds_client_;
+    std::string server_name_;
+    bool is_xds_uri_;
   };
 };
 
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy_factory.h b/grpc/src/core/ext/filters/client_channel/lb_policy_factory.h
index 9e4425f..a595c27 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy_factory.h
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy_factory.h
@@ -39,7 +39,7 @@
   virtual const char* name() const = 0;
 
   virtual RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error) const = 0;
+      const Json& json, grpc_error_handle* error) const = 0;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc b/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc
index d64a643..a3f0347 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc
@@ -109,7 +109,7 @@
     return false;
   }
   if (requires_config != nullptr) {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     // Check if the load balancing policy allows an empty config
     *requires_config =
         factory->ParseLoadBalancingConfig(Json(), &error) == nullptr;
@@ -122,7 +122,7 @@
 
 // Returns the JSON node of policy (with both policy name and config content)
 // given the JSON node of a LoadBalancingConfig array.
-grpc_error* ParseLoadBalancingConfigHelper(
+grpc_error_handle ParseLoadBalancingConfigHelper(
     const Json& lb_config_array, Json::Object::const_iterator* result) {
   if (lb_config_array.type() != Json::Type::ARRAY) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("type should be array");
@@ -163,8 +163,8 @@
 }  // namespace
 
 RefCountedPtr<LoadBalancingPolicy::Config>
-LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const Json& json,
-                                                      grpc_error** error) {
+LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
+    const Json& json, grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
   GPR_ASSERT(g_state != nullptr);
   Json::Object::const_iterator policy;
diff --git a/grpc/src/core/ext/filters/client_channel/lb_policy_registry.h b/grpc/src/core/ext/filters/client_channel/lb_policy_registry.h
index 8d2e3e3..aba44a8 100644
--- a/grpc/src/core/ext/filters/client_channel/lb_policy_registry.h
+++ b/grpc/src/core/ext/filters/client_channel/lb_policy_registry.h
@@ -57,7 +57,7 @@
   /// Returns a parsed object of the load balancing policy to be used from a
   /// LoadBalancingConfig array \a json.
   static RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
-      const Json& json, grpc_error** error);
+      const Json& json, grpc_error_handle* error);
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.cc b/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.cc
index e575999..49338ec 100644
--- a/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.cc
+++ b/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.cc
@@ -24,73 +24,33 @@
 
 namespace grpc_core {
 
-LocalSubchannelPool::LocalSubchannelPool() {
-  subchannel_map_ = grpc_avl_create(&subchannel_avl_vtable_);
+RefCountedPtr<Subchannel> LocalSubchannelPool::RegisterSubchannel(
+    const SubchannelKey& key, RefCountedPtr<Subchannel> constructed) {
+  auto it = subchannel_map_.find(key);
+  // Because this pool is only accessed under the client channel's work
+  // serializer, and because FindSubchannel is checked before invoking
+  // RegisterSubchannel, no such subchannel should exist in the map.
+  GPR_ASSERT(it == subchannel_map_.end());
+  subchannel_map_[key] = constructed.get();
+  return constructed;
 }
 
-LocalSubchannelPool::~LocalSubchannelPool() {
-  grpc_avl_unref(subchannel_map_, nullptr);
+void LocalSubchannelPool::UnregisterSubchannel(const SubchannelKey& key,
+                                               Subchannel* subchannel) {
+  auto it = subchannel_map_.find(key);
+  // Because this subchannel pool is accessed only under the client
+  // channel's work serializer, any subchannel created by RegisterSubchannel
+  // will be deleted from the map in UnregisterSubchannel.
+  GPR_ASSERT(it != subchannel_map_.end());
+  GPR_ASSERT(it->second == subchannel);
+  subchannel_map_.erase(it);
 }
 
-Subchannel* LocalSubchannelPool::RegisterSubchannel(SubchannelKey* key,
-                                                    Subchannel* constructed) {
-  // Check to see if a subchannel already exists.
-  Subchannel* c =
-      static_cast<Subchannel*>(grpc_avl_get(subchannel_map_, key, nullptr));
-  if (c != nullptr) {
-    // The subchannel already exists. Reuse it.
-    c = GRPC_SUBCHANNEL_REF(c, "subchannel_register+reuse");
-    GRPC_SUBCHANNEL_UNREF(constructed, "subchannel_register+found_existing");
-  } else {
-    // There hasn't been such subchannel. Add one.
-    subchannel_map_ = grpc_avl_add(subchannel_map_, new SubchannelKey(*key),
-                                   constructed, nullptr);
-    c = constructed;
-  }
-  return c;
+RefCountedPtr<Subchannel> LocalSubchannelPool::FindSubchannel(
+    const SubchannelKey& key) {
+  auto it = subchannel_map_.find(key);
+  if (it == subchannel_map_.end()) return nullptr;
+  return it->second->Ref();
 }
 
-void LocalSubchannelPool::UnregisterSubchannel(SubchannelKey* key) {
-  subchannel_map_ = grpc_avl_remove(subchannel_map_, key, nullptr);
-}
-
-Subchannel* LocalSubchannelPool::FindSubchannel(SubchannelKey* key) {
-  Subchannel* c =
-      static_cast<Subchannel*>(grpc_avl_get(subchannel_map_, key, nullptr));
-  return c == nullptr ? c : GRPC_SUBCHANNEL_REF(c, "found_from_pool");
-}
-
-namespace {
-
-void sck_avl_destroy(void* p, void* /*user_data*/) {
-  SubchannelKey* key = static_cast<SubchannelKey*>(p);
-  delete key;
-}
-
-void* sck_avl_copy(void* p, void* /*unused*/) {
-  const SubchannelKey* key = static_cast<const SubchannelKey*>(p);
-  auto new_key = new SubchannelKey(*key);
-  return static_cast<void*>(new_key);
-}
-
-long sck_avl_compare(void* a, void* b, void* /*unused*/) {
-  const SubchannelKey* key_a = static_cast<const SubchannelKey*>(a);
-  const SubchannelKey* key_b = static_cast<const SubchannelKey*>(b);
-  return key_a->Cmp(*key_b);
-}
-
-void scv_avl_destroy(void* /*p*/, void* /*user_data*/) {}
-
-void* scv_avl_copy(void* p, void* /*unused*/) { return p; }
-
-}  // namespace
-
-const grpc_avl_vtable LocalSubchannelPool::subchannel_avl_vtable_ = {
-    sck_avl_destroy,  // destroy_key
-    sck_avl_copy,     // copy_key
-    sck_avl_compare,  // compare_keys
-    scv_avl_destroy,  // destroy_value
-    scv_avl_copy      // copy_value
-};
-
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.h b/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.h
index 7d18d9b..f039f6d 100644
--- a/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.h
+++ b/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.h
@@ -21,6 +21,8 @@
 
 #include <grpc/support/port_platform.h>
 
+#include <map>
+
 #include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
 
 namespace grpc_core {
@@ -34,22 +36,21 @@
 // Thread-unsafe.
 class LocalSubchannelPool final : public SubchannelPoolInterface {
  public:
-  LocalSubchannelPool();
-  ~LocalSubchannelPool() override;
+  LocalSubchannelPool() {}
+  ~LocalSubchannelPool() override {}
 
   // Implements interface methods.
   // Thread-unsafe. Intended to be invoked within the client_channel work
   // serializer.
-  Subchannel* RegisterSubchannel(SubchannelKey* key,
-                                 Subchannel* constructed) override;
-  void UnregisterSubchannel(SubchannelKey* key) override;
-  Subchannel* FindSubchannel(SubchannelKey* key) override;
+  RefCountedPtr<Subchannel> RegisterSubchannel(
+      const SubchannelKey& key, RefCountedPtr<Subchannel> constructed) override;
+  void UnregisterSubchannel(const SubchannelKey& key,
+                            Subchannel* subchannel) override;
+  RefCountedPtr<Subchannel> FindSubchannel(const SubchannelKey& key) override;
 
  private:
-  // The vtable for subchannel operations in an AVL tree.
-  static const grpc_avl_vtable subchannel_avl_vtable_;
   // A map from subchannel key to subchannel.
-  grpc_avl subchannel_map_;
+  std::map<SubchannelKey, Subchannel*> subchannel_map_;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/resolver.cc b/grpc/src/core/ext/filters/client_channel/resolver.cc
index 8831db2..a5494b1 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver.cc
@@ -29,13 +29,10 @@
 // Resolver
 //
 
-Resolver::Resolver(std::shared_ptr<WorkSerializer> work_serializer,
-                   std::unique_ptr<ResultHandler> result_handler)
+Resolver::Resolver()
     : InternallyRefCounted(GRPC_TRACE_FLAG_ENABLED(grpc_trace_resolver_refcount)
                                ? "Resolver"
-                               : nullptr),
-      work_serializer_(std::move(work_serializer)),
-      result_handler_(std::move(result_handler)) {}
+                               : nullptr) {}
 
 //
 // Resolver::Result
@@ -63,6 +60,9 @@
 }
 
 Resolver::Result& Resolver::Result::operator=(const Result& other) {
+  if (&other == this) {
+    return *this;
+  }
   addresses = other.addresses;
   service_config = other.service_config;
   GRPC_ERROR_UNREF(service_config_error);
diff --git a/grpc/src/core/ext/filters/client_channel/resolver.h b/grpc/src/core/ext/filters/client_channel/resolver.h
index 31d9c83..2ab7409 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver.h
+++ b/grpc/src/core/ext/filters/client_channel/resolver.h
@@ -55,7 +55,7 @@
   struct Result {
     ServerAddressList addresses;
     RefCountedPtr<ServiceConfig> service_config;
-    grpc_error* service_config_error = GRPC_ERROR_NONE;
+    grpc_error_handle service_config_error = GRPC_ERROR_NONE;
     const grpc_channel_args* args = nullptr;
 
     // TODO(roth): Remove everything below once grpc_error and
@@ -81,7 +81,7 @@
     /// Returns a transient error to the channel.
     /// If the resolver does not set the GRPC_ERROR_INT_GRPC_STATUS
     /// attribute on the error, calls will be failed with status UNKNOWN.
-    virtual void ReturnError(grpc_error* error) = 0;
+    virtual void ReturnError(grpc_error_handle error) = 0;
 
     // TODO(yashkt): As part of the service config error handling
     // changes, add a method to parse the service config JSON string.
@@ -125,21 +125,10 @@
   }
 
  protected:
-  Resolver(std::shared_ptr<WorkSerializer> work_serializer,
-           std::unique_ptr<ResultHandler> result_handler);
+  Resolver();
 
   /// Shuts down the resolver.
   virtual void ShutdownLocked() = 0;
-
-  std::shared_ptr<WorkSerializer> work_serializer() const {
-    return work_serializer_;
-  }
-
-  ResultHandler* result_handler() const { return result_handler_.get(); }
-
- private:
-  std::shared_ptr<WorkSerializer> work_serializer_;
-  std::unique_ptr<ResultHandler> result_handler_;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index 0060ad9..2911eae 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -80,10 +80,10 @@
   void MaybeStartResolvingLocked();
   void StartResolvingLocked();
 
-  static void OnNextResolution(void* arg, grpc_error* error);
-  static void OnResolved(void* arg, grpc_error* error);
-  void OnNextResolutionLocked(grpc_error* error);
-  void OnResolvedLocked(grpc_error* error);
+  static void OnNextResolution(void* arg, grpc_error_handle error);
+  static void OnResolved(void* arg, grpc_error_handle error);
+  void OnNextResolutionLocked(grpc_error_handle error);
+  void OnResolvedLocked(grpc_error_handle error);
 
   /// DNS server to use (if not system default)
   std::string dns_server_;
@@ -91,10 +91,20 @@
   std::string name_to_resolve_;
   /// channel args
   grpc_channel_args* channel_args_;
-  /// whether to request the service config
-  bool request_service_config_;
+  std::shared_ptr<WorkSerializer> work_serializer_;
+  std::unique_ptr<ResultHandler> result_handler_;
   /// pollset_set to drive the name resolution process
   grpc_pollset_set* interested_parties_;
+
+  /// whether to request the service config
+  bool request_service_config_;
+  // whether or not to enable SRV DNS queries
+  bool enable_srv_queries_;
+  // timeout in milliseconds for active DNS queries
+  int query_timeout_ms_;
+  /// min interval between DNS requests
+  grpc_millis min_time_between_resolutions_;
+
   /// closures used by the work_serializer
   grpc_closure on_next_resolution_;
   grpc_closure on_resolved_;
@@ -105,8 +115,6 @@
   /// next resolution timer
   bool have_next_resolution_timer_ = false;
   grpc_timer next_resolution_timer_;
-  /// min interval between DNS requests
-  grpc_millis min_time_between_resolutions_;
   /// timestamp of last DNS request
   grpc_millis last_resolution_timestamp_ = -1;
   /// retry backoff state
@@ -119,14 +127,25 @@
   char* service_config_json_ = nullptr;
   // has shutdown been initiated
   bool shutdown_initiated_ = false;
-  // timeout in milliseconds for active DNS queries
-  int query_timeout_ms_;
-  // whether or not to enable SRV DNS queries
-  bool enable_srv_queries_;
 };
 
 AresDnsResolver::AresDnsResolver(ResolverArgs args)
-    : Resolver(std::move(args.work_serializer), std::move(args.result_handler)),
+    : dns_server_(args.uri.authority()),
+      name_to_resolve_(absl::StripPrefix(args.uri.path(), "/")),
+      channel_args_(grpc_channel_args_copy(args.args)),
+      work_serializer_(std::move(args.work_serializer)),
+      result_handler_(std::move(args.result_handler)),
+      interested_parties_(args.pollset_set),
+      request_service_config_(!grpc_channel_args_find_bool(
+          channel_args_, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION, true)),
+      enable_srv_queries_(grpc_channel_args_find_bool(
+          channel_args_, GRPC_ARG_DNS_ENABLE_SRV_QUERIES, false)),
+      query_timeout_ms_(grpc_channel_args_find_integer(
+          channel_args_, GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS,
+          {GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, 0, INT_MAX})),
+      min_time_between_resolutions_(grpc_channel_args_find_integer(
+          channel_args_, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS,
+          {1000 * 30, 0, INT_MAX})),
       backoff_(
           BackOff::Options()
               .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
@@ -134,42 +153,14 @@
               .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
               .set_jitter(GRPC_DNS_RECONNECT_JITTER)
               .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
-  // Closure Initialization
+  // Closure initialization.
   GRPC_CLOSURE_INIT(&on_next_resolution_, OnNextResolution, this,
                     grpc_schedule_on_exec_ctx);
   GRPC_CLOSURE_INIT(&on_resolved_, OnResolved, this, grpc_schedule_on_exec_ctx);
-  // Get name to resolve from URI path.
-  name_to_resolve_ = std::string(absl::StripPrefix(args.uri.path(), "/"));
-  // Get DNS server from URI authority.
-  dns_server_ = args.uri.authority();
-  channel_args_ = grpc_channel_args_copy(args.args);
-  // Disable service config option
-  const grpc_arg* arg = grpc_channel_args_find(
-      channel_args_, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION);
-  request_service_config_ = !grpc_channel_arg_get_bool(arg, true);
-  // Min time b/t resolutions option
-  arg = grpc_channel_args_find(channel_args_,
-                               GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
-  min_time_between_resolutions_ =
-      grpc_channel_arg_get_integer(arg, {1000 * 30, 0, INT_MAX});
-  // Enable SRV queries option
-  arg = grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ENABLE_SRV_QUERIES);
-  enable_srv_queries_ = grpc_channel_arg_get_bool(arg, false);
-  interested_parties_ = grpc_pollset_set_create();
-  if (args.pollset_set != nullptr) {
-    grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
-  }
-
-  const grpc_arg* query_timeout_ms_arg =
-      grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS);
-  query_timeout_ms_ = grpc_channel_arg_get_integer(
-      query_timeout_ms_arg,
-      {GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS, 0, INT_MAX});
 }
 
 AresDnsResolver::~AresDnsResolver() {
   GRPC_CARES_TRACE_LOG("resolver:%p destroying AresDnsResolver", this);
-  grpc_pollset_set_destroy(interested_parties_);
   grpc_channel_args_destroy(channel_args_);
 }
 
@@ -202,18 +193,18 @@
   }
 }
 
-void AresDnsResolver::OnNextResolution(void* arg, grpc_error* error) {
+void AresDnsResolver::OnNextResolution(void* arg, grpc_error_handle error) {
   AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
-  r->work_serializer()->Run([r, error]() { r->OnNextResolutionLocked(error); },
-                            DEBUG_LOCATION);
+  r->work_serializer_->Run([r, error]() { r->OnNextResolutionLocked(error); },
+                           DEBUG_LOCATION);
 }
 
-void AresDnsResolver::OnNextResolutionLocked(grpc_error* error) {
+void AresDnsResolver::OnNextResolutionLocked(grpc_error_handle error) {
   GRPC_CARES_TRACE_LOG(
       "resolver:%p re-resolution timer fired. error: %s. shutdown_initiated_: "
       "%d",
-      this, grpc_error_string(error), shutdown_initiated_);
+      this, grpc_error_std_string(error).c_str(), shutdown_initiated_);
   have_next_resolution_timer_ = false;
   if (error == GRPC_ERROR_NONE && !shutdown_initiated_) {
     if (!resolving_) {
@@ -236,7 +227,7 @@
 }
 
 std::string ChooseServiceConfig(char* service_config_choice_json,
-                                grpc_error** error) {
+                                grpc_error_handle* error) {
   Json json = Json::Parse(service_config_choice_json, error);
   if (*error != GRPC_ERROR_NONE) return "";
   if (json.type() != Json::Type::ARRAY) {
@@ -245,7 +236,7 @@
     return "";
   }
   const Json* service_config = nullptr;
-  absl::InlinedVector<grpc_error*, 4> error_list;
+  absl::InlinedVector<grpc_error_handle, 4> error_list;
   for (const Json& choice : json.array_value()) {
     if (choice.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -314,14 +305,14 @@
   return service_config->Dump();
 }
 
-void AresDnsResolver::OnResolved(void* arg, grpc_error* error) {
+void AresDnsResolver::OnResolved(void* arg, grpc_error_handle error) {
   AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
-  r->work_serializer()->Run([r, error]() { r->OnResolvedLocked(error); },
-                            DEBUG_LOCATION);
+  r->work_serializer_->Run([r, error]() { r->OnResolvedLocked(error); },
+                           DEBUG_LOCATION);
 }
 
-void AresDnsResolver::OnResolvedLocked(grpc_error* error) {
+void AresDnsResolver::OnResolvedLocked(grpc_error_handle error) {
   GPR_ASSERT(resolving_);
   resolving_ = false;
   gpr_free(pending_request_);
@@ -355,7 +346,7 @@
     }
     result.args = grpc_channel_args_copy_and_add(channel_args_, new_args.data(),
                                                  new_args.size());
-    result_handler()->ReturnResult(std::move(result));
+    result_handler_->ReturnResult(std::move(result));
     addresses_.reset();
     balancer_addresses_.reset();
     // Reset backoff state so that we start from the beginning when the
@@ -363,18 +354,22 @@
     backoff_.Reset();
   } else {
     GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed: %s", this,
-                         grpc_error_string(error));
+                         grpc_error_std_string(error).c_str());
     std::string error_message =
         absl::StrCat("DNS resolution failed for service: ", name_to_resolve_);
-    result_handler()->ReturnError(grpc_error_set_int(
+    result_handler_->ReturnError(grpc_error_set_int(
         GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(error_message.c_str(),
                                                          &error, 1),
         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
     // Set retry timer.
+    // InvalidateNow to avoid getting stuck re-initializing this timer
+    // in a loop while draining the currently-held WorkSerializer.
+    // Also see https://github.com/grpc/grpc/issues/26079.
+    ExecCtx::Get()->InvalidateNow();
     grpc_millis next_try = backoff_.NextAttemptTime();
     grpc_millis timeout = next_try - ExecCtx::Get()->Now();
     GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed (will retry): %s",
-                         this, grpc_error_string(error));
+                         this, grpc_error_std_string(error).c_str());
     GPR_ASSERT(!have_next_resolution_timer_);
     have_next_resolution_timer_ = true;
     // TODO(roth): We currently deal with this ref manually.  Once the
@@ -398,6 +393,10 @@
   // can start the next resolution.
   if (have_next_resolution_timer_) return;
   if (last_resolution_timestamp_ >= 0) {
+    // InvalidateNow to avoid getting stuck re-initializing this timer
+    // in a loop while draining the currently-held WorkSerializer.
+    // Also see https://github.com/grpc/grpc/issues/26079.
+    ExecCtx::Get()->InvalidateNow();
     const grpc_millis earliest_next_resolution =
         last_resolution_timestamp_ + min_time_between_resolutions_;
     const grpc_millis ms_until_next_resolution =
@@ -436,7 +435,7 @@
       interested_parties_, &on_resolved_, &addresses_,
       enable_srv_queries_ ? &balancer_addresses_ : nullptr,
       request_service_config_ ? &service_config_json_ : nullptr,
-      query_timeout_ms_, work_serializer());
+      query_timeout_ms_, work_serializer_);
   last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
   GRPC_CARES_TRACE_LOG("resolver:%p Started resolving. pending_request_:%p",
                        this, pending_request_);
@@ -464,7 +463,7 @@
 extern grpc_address_resolver_vtable* grpc_resolve_address_impl;
 static grpc_address_resolver_vtable* default_resolver;
 
-static grpc_error* blocking_resolve_address_ares(
+static grpc_error_handle blocking_resolve_address_ares(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   return default_resolver->blocking_resolve_address(name, default_port,
@@ -499,7 +498,7 @@
     g_use_ares_dns_resolver = true;
     gpr_log(GPR_DEBUG, "Using ares dns resolver");
     address_sorting_init();
-    grpc_error* error = grpc_ares_init();
+    grpc_error_handle error = grpc_ares_init();
     if (error != GRPC_ERROR_NONE) {
       GRPC_LOG_IF_ERROR("grpc_ares_init() failed", error);
       return;
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
index cc88486..0806923 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
@@ -42,7 +42,7 @@
   virtual bool IsFdStillReadableLocked() = 0;
   /* Called once and only once. Must cause cancellation of any pending
    * read/write callbacks. */
-  virtual void ShutdownLocked(grpc_error* error) = 0;
+  virtual void ShutdownLocked(grpc_error_handle error) = 0;
   /* Get the underlying ares_socket_t that this was created from */
   virtual ares_socket_t GetWrappedAresSocketLocked() = 0;
   /* A unique name, for logging */
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
index e5eea5c..5c4c535 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
@@ -75,7 +75,7 @@
     return false;
   }
 
-  void ShutdownInternalLocked(grpc_error* error) {
+  void ShutdownInternalLocked(grpc_error_handle error) {
     uv_poll_stop(handle_);
     uv_close(reinterpret_cast<uv_handle_t*>(handle_), ares_uv_poll_close_cb);
     if (read_closure_ != nullptr) {
@@ -88,7 +88,7 @@
     }
   }
 
-  void ShutdownLocked(grpc_error* error) override {
+  void ShutdownLocked(grpc_error_handle error) override {
     if (grpc_core::ExecCtx::Get() == nullptr) {
       grpc_core::ExecCtx exec_ctx;
       ShutdownInternalLocked(error);
@@ -127,7 +127,7 @@
   int events = arg_struct->events;
   GrpcPolledFdLibuv* polled_fd =
       reinterpret_cast<GrpcPolledFdLibuv*>(handle->data);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (status < 0) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("cares polling error");
     error =
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
index ff18f76..31de679 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
@@ -33,10 +33,10 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 namespace grpc_core {
 
@@ -54,8 +54,8 @@
     /* c-ares library will close the fd inside grpc_fd. This fd may be picked up
        immediately by another thread, and should not be closed by the following
        grpc_fd_orphan. */
-    int dummy_release_fd;
-    grpc_fd_orphan(fd_, nullptr, &dummy_release_fd, "c-ares query finished");
+    int phony_release_fd;
+    grpc_fd_orphan(fd_, nullptr, &phony_release_fd, "c-ares query finished");
   }
 
   void RegisterForOnReadableLocked(grpc_closure* read_closure) override {
@@ -72,7 +72,7 @@
            bytes_available > 0;
   }
 
-  void ShutdownLocked(grpc_error* error) override {
+  void ShutdownLocked(grpc_error_handle error) override {
     grpc_fd_shutdown(fd_, error);
   }
 
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
index 9b6a0d5..0b4675f 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
@@ -30,10 +30,10 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include <string.h>
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/sockaddr_windows.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_windows.h"
@@ -131,12 +131,12 @@
     grpc_winsocket_destroy(winsocket_);
   }
 
-  void ScheduleAndNullReadClosure(grpc_error* error) {
+  void ScheduleAndNullReadClosure(grpc_error_handle error) {
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, read_closure_, error);
     read_closure_ = nullptr;
   }
 
-  void ScheduleAndNullWriteClosure(grpc_error* error) {
+  void ScheduleAndNullWriteClosure(grpc_error_handle error) {
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, write_closure_, error);
     write_closure_ = nullptr;
   }
@@ -251,9 +251,9 @@
     }
   }
 
-  bool IsFdStillReadableLocked() { return GRPC_SLICE_LENGTH(read_buf_) > 0; }
+  bool IsFdStillReadableLocked() { return read_buf_has_data_; }
 
-  void ShutdownLocked(grpc_error* error) {
+  void ShutdownLocked(grpc_error_handle error) {
     grpc_winsocket_shutdown(winsocket_);
   }
 
@@ -362,6 +362,8 @@
     DWORD bytes_sent = 0;
     int wsa_error_code = 0;
     if (SendWriteBuf(&bytes_sent, nullptr, &wsa_error_code) != 0) {
+      grpc_slice_unref_internal(write_buf_);
+      write_buf_ = grpc_empty_slice();
       wsa_error_ctx->SetWSAError(wsa_error_code);
       char* msg = gpr_format_message(wsa_error_code);
       GRPC_CARES_TRACE_LOG(
@@ -418,7 +420,7 @@
     abort();
   }
 
-  static void OnTcpConnect(void* arg, grpc_error* error) {
+  static void OnTcpConnect(void* arg, grpc_error_handle error) {
     GrpcPolledFdWindows* grpc_polled_fd =
         static_cast<GrpcPolledFdWindows*>(arg);
     GRPC_ERROR_REF(error);  // ref owned by lambda
@@ -429,12 +431,12 @@
         DEBUG_LOCATION);
   }
 
-  void OnTcpConnectLocked(grpc_error* error) {
+  void OnTcpConnectLocked(grpc_error_handle error) {
     GRPC_CARES_TRACE_LOG(
         "fd:%s InnerOnTcpConnectLocked error:|%s| "
         "pending_register_for_readable:%d"
         " pending_register_for_writeable:%d",
-        GetName(), grpc_error_string(error),
+        GetName(), grpc_error_std_string(error).c_str(),
         pending_continue_register_for_on_readable_locked_,
         pending_continue_register_for_on_writeable_locked_);
     GPR_ASSERT(!connect_done_);
@@ -574,7 +576,7 @@
     return out;
   }
 
-  static void OnIocpReadable(void* arg, grpc_error* error) {
+  static void OnIocpReadable(void* arg, grpc_error_handle error) {
     GrpcPolledFdWindows* polled_fd = static_cast<GrpcPolledFdWindows*>(arg);
     GRPC_ERROR_REF(error);  // ref owned by lambda
     polled_fd->work_serializer_->Run(
@@ -587,7 +589,7 @@
   // c-ares reads from this socket later, but it shouldn't necessarily cancel
   // the entire resolution attempt. Doing so will allow the "inject broken
   // nameserver list" test to pass on Windows.
-  void OnIocpReadableLocked(grpc_error* error) {
+  void OnIocpReadableLocked(grpc_error_handle error) {
     if (error == GRPC_ERROR_NONE) {
       if (winsocket_->read_info.wsa_error != 0) {
         /* WSAEMSGSIZE would be due to receiving more data
@@ -601,7 +603,7 @@
               "fd:|%s| OnIocpReadableInner winsocket_->read_info.wsa_error "
               "code:|%d| msg:|%s|",
               GetName(), winsocket_->read_info.wsa_error,
-              grpc_error_string(error));
+              grpc_error_std_string(error).c_str());
         }
       }
     }
@@ -619,7 +621,7 @@
     ScheduleAndNullReadClosure(error);
   }
 
-  static void OnIocpWriteable(void* arg, grpc_error* error) {
+  static void OnIocpWriteable(void* arg, grpc_error_handle error) {
     GrpcPolledFdWindows* polled_fd = static_cast<GrpcPolledFdWindows*>(arg);
     GRPC_ERROR_REF(error);  // error owned by lambda
     polled_fd->work_serializer_->Run(
@@ -627,7 +629,7 @@
         DEBUG_LOCATION);
   }
 
-  void OnIocpWriteableLocked(grpc_error* error) {
+  void OnIocpWriteableLocked(grpc_error_handle error) {
     GRPC_CARES_TRACE_LOG("OnIocpWriteableInner. fd:|%s|", GetName());
     GPR_ASSERT(socket_type_ == SOCK_STREAM);
     if (error == GRPC_ERROR_NONE) {
@@ -638,7 +640,7 @@
             "fd:|%s| OnIocpWriteableInner. winsocket_->write_info.wsa_error "
             "code:|%d| msg:|%s|",
             GetName(), winsocket_->write_info.wsa_error,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
       }
     }
     GPR_ASSERT(tcp_write_state_ == WRITE_PENDING);
@@ -849,7 +851,7 @@
     return wrapped_->IsFdStillReadableLocked();
   }
 
-  void ShutdownLocked(grpc_error* error) override {
+  void ShutdownLocked(grpc_error_handle error) override {
     wrapped_->ShutdownLocked(error);
   }
 
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
index ede8045..82dbb00 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
@@ -38,14 +38,14 @@
 
 #include <address_sorting/address_sorting.h>
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/nameser.h"
-#include "src/core/lib/iomgr/parse_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/transport/authority_override.h"
 
@@ -77,7 +77,7 @@
   size_t pending_queries;
 
   /** the errors explaining query failures, appended to in query callbacks */
-  grpc_error* error;
+  grpc_error_handle error;
 };
 
 typedef struct fd_node {
@@ -114,8 +114,6 @@
   std::shared_ptr<grpc_core::WorkSerializer> work_serializer;
   /** a list of grpc_fd that this event driver is currently using. */
   fd_node* fds;
-  /** is this event driver currently working? */
-  bool working;
   /** is this event driver being shut down */
   bool shutting_down;
   /** request object that's using this ev driver */
@@ -219,9 +217,9 @@
 
 void grpc_ares_ev_driver_on_queries_complete_locked(
     grpc_ares_ev_driver* ev_driver) {
-  // We mark the event driver as being shut down. If the event driver
-  // is working, grpc_ares_notify_on_event_locked will shut down the
-  // fds; if it's not working, there are no fds to shut down.
+  // We mark the event driver as being shut down.
+  // grpc_ares_notify_on_event_locked will shut down any remaining
+  // fds.
   ev_driver->shutting_down = true;
   grpc_timer_cancel(&ev_driver->query_timeout);
   grpc_timer_cancel(&ev_driver->ares_backup_poll_alarm);
@@ -240,14 +238,14 @@
 // Search fd in the fd_node list head. This is an O(n) search, the max possible
 // value of n is ARES_GETSOCK_MAXNUM (16). n is typically 1 - 2 in our tests.
 static fd_node* pop_fd_node_locked(fd_node** head, ares_socket_t as) {
-  fd_node dummy_head;
-  dummy_head.next = *head;
-  fd_node* node = &dummy_head;
+  fd_node phony_head;
+  phony_head.next = *head;
+  fd_node* node = &phony_head;
   while (node->next != nullptr) {
     if (node->next->grpc_polled_fd->GetWrappedAresSocketLocked() == as) {
       fd_node* ret = node->next;
       node->next = node->next->next;
-      *head = dummy_head.next;
+      *head = phony_head.next;
       return ret;
     }
     node = node->next;
@@ -270,11 +268,13 @@
          grpc_core::ExecCtx::Get()->Now();
 }
 
-static void on_timeout_locked(grpc_ares_ev_driver* driver, grpc_error* error) {
+static void on_timeout_locked(grpc_ares_ev_driver* driver,
+                              grpc_error_handle error) {
   GRPC_CARES_TRACE_LOG(
       "request:%p ev_driver=%p on_timeout_locked. driver->shutting_down=%d. "
       "err=%s",
-      driver->request, driver, driver->shutting_down, grpc_error_string(error));
+      driver->request, driver, driver->shutting_down,
+      grpc_error_std_string(error).c_str());
   if (!driver->shutting_down && error == GRPC_ERROR_NONE) {
     grpc_ares_ev_driver_shutdown_locked(driver);
   }
@@ -282,7 +282,7 @@
   GRPC_ERROR_UNREF(error);
 }
 
-static void on_timeout(void* arg, grpc_error* error) {
+static void on_timeout(void* arg, grpc_error_handle error) {
   grpc_ares_ev_driver* driver = static_cast<grpc_ares_ev_driver*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
   driver->work_serializer->Run(
@@ -292,9 +292,9 @@
 static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver);
 
 static void on_ares_backup_poll_alarm_locked(grpc_ares_ev_driver* driver,
-                                             grpc_error* error);
+                                             grpc_error_handle error);
 
-static void on_ares_backup_poll_alarm(void* arg, grpc_error* error) {
+static void on_ares_backup_poll_alarm(void* arg, grpc_error_handle error) {
   grpc_ares_ev_driver* driver = static_cast<grpc_ares_ev_driver*>(arg);
   GRPC_ERROR_REF(error);
   driver->work_serializer->Run(
@@ -311,12 +311,13 @@
  * For the latter, we use this backup poller. Also see
  * https://github.com/grpc/grpc/pull/17688 description for more details. */
 static void on_ares_backup_poll_alarm_locked(grpc_ares_ev_driver* driver,
-                                             grpc_error* error) {
+                                             grpc_error_handle error) {
   GRPC_CARES_TRACE_LOG(
       "request:%p ev_driver=%p on_ares_backup_poll_alarm_locked. "
       "driver->shutting_down=%d. "
       "err=%s",
-      driver->request, driver, driver->shutting_down, grpc_error_string(error));
+      driver->request, driver, driver->shutting_down,
+      grpc_error_std_string(error).c_str());
   if (!driver->shutting_down && error == GRPC_ERROR_NONE) {
     fd_node* fdn = driver->fds;
     while (fdn != nullptr) {
@@ -331,6 +332,10 @@
       fdn = fdn->next;
     }
     if (!driver->shutting_down) {
+      // InvalidateNow to avoid getting stuck re-initializing this timer
+      // in a loop while draining the currently-held WorkSerializer.
+      // Also see https://github.com/grpc/grpc/issues/26079.
+      grpc_core::ExecCtx::Get()->InvalidateNow();
       grpc_millis next_ares_backup_poll_alarm =
           calculate_next_ares_backup_poll_alarm_ms(driver);
       grpc_ares_ev_driver_ref(driver);
@@ -347,7 +352,7 @@
   GRPC_ERROR_UNREF(error);
 }
 
-static void on_readable_locked(fd_node* fdn, grpc_error* error) {
+static void on_readable_locked(fd_node* fdn, grpc_error_handle error) {
   GPR_ASSERT(fdn->readable_registered);
   grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
   const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
@@ -372,14 +377,14 @@
   GRPC_ERROR_UNREF(error);
 }
 
-static void on_readable(void* arg, grpc_error* error) {
+static void on_readable(void* arg, grpc_error_handle error) {
   fd_node* fdn = static_cast<fd_node*>(arg);
   GRPC_ERROR_REF(error); /* ref owned by lambda */
   fdn->ev_driver->work_serializer->Run(
       [fdn, error]() { on_readable_locked(fdn, error); }, DEBUG_LOCATION);
 }
 
-static void on_writable_locked(fd_node* fdn, grpc_error* error) {
+static void on_writable_locked(fd_node* fdn, grpc_error_handle error) {
   GPR_ASSERT(fdn->writable_registered);
   grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
   const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
@@ -402,7 +407,7 @@
   GRPC_ERROR_UNREF(error);
 }
 
-static void on_writable(void* arg, grpc_error* error) {
+static void on_writable(void* arg, grpc_error_handle error) {
   fd_node* fdn = static_cast<fd_node*>(arg);
   GRPC_ERROR_REF(error); /* ref owned by lambda */
   fdn->ev_driver->work_serializer->Run(
@@ -483,43 +488,34 @@
     }
   }
   ev_driver->fds = new_list;
-  // If the ev driver has no working fd, all the tasks are done.
-  if (new_list == nullptr) {
-    ev_driver->working = false;
-    GRPC_CARES_TRACE_LOG("request:%p ev driver stop working",
-                         ev_driver->request);
-  }
 }
 
 void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) {
-  if (!ev_driver->working) {
-    ev_driver->working = true;
-    grpc_ares_notify_on_event_locked(ev_driver);
-    // Initialize overall DNS resolution timeout alarm
-    grpc_millis timeout =
-        ev_driver->query_timeout_ms == 0
-            ? GRPC_MILLIS_INF_FUTURE
-            : ev_driver->query_timeout_ms + grpc_core::ExecCtx::Get()->Now();
-    GRPC_CARES_TRACE_LOG(
-        "request:%p ev_driver=%p grpc_ares_ev_driver_start_locked. timeout in "
-        "%" PRId64 " ms",
-        ev_driver->request, ev_driver, timeout);
-    grpc_ares_ev_driver_ref(ev_driver);
-    GRPC_CLOSURE_INIT(&ev_driver->on_timeout_locked, on_timeout, ev_driver,
-                      grpc_schedule_on_exec_ctx);
-    grpc_timer_init(&ev_driver->query_timeout, timeout,
-                    &ev_driver->on_timeout_locked);
-    // Initialize the backup poll alarm
-    grpc_millis next_ares_backup_poll_alarm =
-        calculate_next_ares_backup_poll_alarm_ms(ev_driver);
-    grpc_ares_ev_driver_ref(ev_driver);
-    GRPC_CLOSURE_INIT(&ev_driver->on_ares_backup_poll_alarm_locked,
-                      on_ares_backup_poll_alarm, ev_driver,
-                      grpc_schedule_on_exec_ctx);
-    grpc_timer_init(&ev_driver->ares_backup_poll_alarm,
-                    next_ares_backup_poll_alarm,
-                    &ev_driver->on_ares_backup_poll_alarm_locked);
-  }
+  grpc_ares_notify_on_event_locked(ev_driver);
+  // Initialize overall DNS resolution timeout alarm
+  grpc_millis timeout =
+      ev_driver->query_timeout_ms == 0
+          ? GRPC_MILLIS_INF_FUTURE
+          : ev_driver->query_timeout_ms + grpc_core::ExecCtx::Get()->Now();
+  GRPC_CARES_TRACE_LOG(
+      "request:%p ev_driver=%p grpc_ares_ev_driver_start_locked. timeout in "
+      "%" PRId64 " ms",
+      ev_driver->request, ev_driver, timeout);
+  grpc_ares_ev_driver_ref(ev_driver);
+  GRPC_CLOSURE_INIT(&ev_driver->on_timeout_locked, on_timeout, ev_driver,
+                    grpc_schedule_on_exec_ctx);
+  grpc_timer_init(&ev_driver->query_timeout, timeout,
+                  &ev_driver->on_timeout_locked);
+  // Initialize the backup poll alarm
+  grpc_millis next_ares_backup_poll_alarm =
+      calculate_next_ares_backup_poll_alarm_ms(ev_driver);
+  grpc_ares_ev_driver_ref(ev_driver);
+  GRPC_CLOSURE_INIT(&ev_driver->on_ares_backup_poll_alarm_locked,
+                    on_ares_backup_poll_alarm, ev_driver,
+                    grpc_schedule_on_exec_ctx);
+  grpc_timer_init(&ev_driver->ares_backup_poll_alarm,
+                  next_ares_backup_poll_alarm,
+                  &ev_driver->on_ares_backup_poll_alarm_locked);
 }
 
 static void noop_inject_channel_config(ares_channel /*channel*/) {}
@@ -527,7 +523,7 @@
 void (*grpc_ares_test_only_inject_config)(ares_channel channel) =
     noop_inject_channel_config;
 
-grpc_error* grpc_ares_ev_driver_create_locked(
+grpc_error_handle grpc_ares_ev_driver_create_locked(
     grpc_ares_ev_driver** ev_driver, grpc_pollset_set* pollset_set,
     int query_timeout_ms,
     std::shared_ptr<grpc_core::WorkSerializer> work_serializer,
@@ -540,7 +536,7 @@
   grpc_ares_test_only_inject_config((*ev_driver)->channel);
   GRPC_CARES_TRACE_LOG("request:%p grpc_ares_ev_driver_create_locked", request);
   if (status != ARES_SUCCESS) {
-    grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+    grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
         absl::StrCat("Failed to init ares channel. C-ares error: ",
                      ares_strerror(status))
             .c_str());
@@ -551,7 +547,6 @@
   gpr_ref_init(&(*ev_driver)->refs, 1);
   (*ev_driver)->pollset_set = pollset_set;
   (*ev_driver)->fds = nullptr;
-  (*ev_driver)->working = false;
   (*ev_driver)->shutting_down = false;
   (*ev_driver)->request = request;
   (*ev_driver)->polled_fd_factory =
@@ -725,7 +720,8 @@
         hr->qtype, hr->host, hr->is_balancer, ares_strerror(status));
     GRPC_CARES_TRACE_LOG("request:%p on_hostbyname_done_locked: %s", r,
                          error_msg.c_str());
-    grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg.c_str());
+    grpc_error_handle error =
+        GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg.c_str());
     r->error = grpc_error_add_child(error, r->error);
   }
   destroy_hostbyname_request_locked(hr);
@@ -757,7 +753,7 @@
             r, srv_it->host, htons(srv_it->port), true /* is_balancer */, "A");
         ares_gethostbyname(r->ev_driver->channel, hr->host, AF_INET,
                            on_hostbyname_done_locked, hr);
-        grpc_ares_ev_driver_start_locked(r->ev_driver);
+        grpc_ares_notify_on_event_locked(r->ev_driver);
       }
     }
     if (reply != nullptr) {
@@ -769,7 +765,8 @@
         ares_strerror(status));
     GRPC_CARES_TRACE_LOG("request:%p on_srv_query_done_locked: %s", r,
                          error_msg.c_str());
-    grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg.c_str());
+    grpc_error_handle error =
+        GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg.c_str());
     r->error = grpc_error_add_child(error, r->error);
   }
   delete q;
@@ -785,7 +782,7 @@
   const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1;
   struct ares_txt_ext* result = nullptr;
   struct ares_txt_ext* reply = nullptr;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (status != ARES_SUCCESS) goto fail;
   GRPC_CARES_TRACE_LOG("request:%p on_txt_done_locked name=%s ARES_SUCCESS", r,
                        q->name().c_str());
@@ -837,7 +834,7 @@
     const char* default_port, grpc_pollset_set* interested_parties,
     int query_timeout_ms,
     std::shared_ptr<grpc_core::WorkSerializer> work_serializer) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_ares_hostbyname_request* hr = nullptr;
   /* parse name, splitting it into host and port parts */
   std::string host;
@@ -983,11 +980,7 @@
     gpr_log(GPR_ERROR, "Unable to split host and port for name: %s", name);
     return false;
   }
-  if (gpr_stricmp(host->c_str(), "localhost") == 0) {
-    return true;
-  } else {
-    return false;
-  }
+  return gpr_stricmp(host->c_str(), "localhost") == 0;
 }
 
 static bool target_matches_localhost(const char* name) {
@@ -1132,7 +1125,7 @@
 // Windows. Calling them may cause race conditions when other parts of the
 // binary calls these functions concurrently.
 #ifdef GPR_WINDOWS
-grpc_error* grpc_ares_init(void) {
+grpc_error_handle grpc_ares_init(void) {
   int status = ares_library_init(ARES_LIB_INIT_ALL);
   if (status != ARES_SUCCESS) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -1144,7 +1137,7 @@
 
 void grpc_ares_cleanup(void) { ares_library_cleanup(); }
 #else
-grpc_error* grpc_ares_init(void) { return GRPC_ERROR_NONE; }
+grpc_error_handle grpc_ares_init(void) { return GRPC_ERROR_NONE; }
 void grpc_ares_cleanup(void) {}
 #endif  // GPR_WINDOWS
 
@@ -1175,7 +1168,7 @@
 } grpc_resolve_address_ares_request;
 
 static void on_dns_lookup_done_locked(grpc_resolve_address_ares_request* r,
-                                      grpc_error* error) {
+                                      grpc_error_handle error) {
   gpr_free(r->ares_request);
   grpc_resolved_addresses** resolved_addresses = r->addrs_out;
   if (r->addresses == nullptr || r->addresses->empty()) {
@@ -1196,7 +1189,7 @@
   delete r;
 }
 
-static void on_dns_lookup_done(void* arg, grpc_error* error) {
+static void on_dns_lookup_done(void* arg, grpc_error_handle error) {
   grpc_resolve_address_ares_request* r =
       static_cast<grpc_resolve_address_ares_request*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
index 6c29bb6..675dfc8 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
@@ -76,7 +76,7 @@
 
 /* Initialize gRPC ares wrapper. Must be called at least once before
    grpc_resolve_address_ares(). */
-grpc_error* grpc_ares_init(void);
+grpc_error_handle grpc_ares_init(void);
 
 /* Uninitialized gRPC ares wrapper. If there was more than one previous call to
    grpc_ares_init(), this function uninitializes the gRPC ares wrapper only if
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
index 1d4a90f..8735aa8 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
@@ -25,8 +25,8 @@
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/parse_address.h"
 
 bool grpc_ares_query_ipv6() {
   /* The libuv grpc code currently does not have the code to probe for this,
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
index df11db3..f76c6a4 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
@@ -25,8 +25,8 @@
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 
 bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); }
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index 3e072aa..3265e29 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -68,15 +68,17 @@
   void MaybeStartResolvingLocked();
   void StartResolvingLocked();
 
-  static void OnNextResolution(void* arg, grpc_error* error);
-  void OnNextResolutionLocked(grpc_error* error);
-  static void OnResolved(void* arg, grpc_error* error);
-  void OnResolvedLocked(grpc_error* error);
+  static void OnNextResolution(void* arg, grpc_error_handle error);
+  void OnNextResolutionLocked(grpc_error_handle error);
+  static void OnResolved(void* arg, grpc_error_handle error);
+  void OnResolvedLocked(grpc_error_handle error);
 
   /// name to resolve
   std::string name_to_resolve_;
   /// channel args
   grpc_channel_args* channel_args_ = nullptr;
+  std::shared_ptr<WorkSerializer> work_serializer_;
+  std::unique_ptr<ResultHandler> result_handler_;
   /// pollset_set to drive the name resolution process
   grpc_pollset_set* interested_parties_ = nullptr;
   /// are we shutting down?
@@ -99,7 +101,14 @@
 };
 
 NativeDnsResolver::NativeDnsResolver(ResolverArgs args)
-    : Resolver(std::move(args.work_serializer), std::move(args.result_handler)),
+    : name_to_resolve_(absl::StripPrefix(args.uri.path(), "/")),
+      channel_args_(grpc_channel_args_copy(args.args)),
+      work_serializer_(std::move(args.work_serializer)),
+      result_handler_(std::move(args.result_handler)),
+      interested_parties_(grpc_pollset_set_create()),
+      min_time_between_resolutions_(grpc_channel_args_find_integer(
+          channel_args_, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS,
+          {1000 * 30, 0, INT_MAX})),
       backoff_(
           BackOff::Options()
               .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
@@ -107,13 +116,6 @@
               .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
               .set_jitter(GRPC_DNS_RECONNECT_JITTER)
               .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
-  name_to_resolve_ = std::string(absl::StripPrefix(args.uri.path(), "/"));
-  channel_args_ = grpc_channel_args_copy(args.args);
-  const grpc_arg* arg = grpc_channel_args_find(
-      args.args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
-  min_time_between_resolutions_ =
-      grpc_channel_arg_get_integer(arg, {1000 * 30, 0, INT_MAX});
-  interested_parties_ = grpc_pollset_set_create();
   if (args.pollset_set != nullptr) {
     grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
   }
@@ -146,14 +148,14 @@
   }
 }
 
-void NativeDnsResolver::OnNextResolution(void* arg, grpc_error* error) {
+void NativeDnsResolver::OnNextResolution(void* arg, grpc_error_handle error) {
   NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
   GRPC_ERROR_REF(error);  // ref owned by lambda
-  r->work_serializer()->Run([r, error]() { r->OnNextResolutionLocked(error); },
-                            DEBUG_LOCATION);
+  r->work_serializer_->Run([r, error]() { r->OnNextResolutionLocked(error); },
+                           DEBUG_LOCATION);
 }
 
-void NativeDnsResolver::OnNextResolutionLocked(grpc_error* error) {
+void NativeDnsResolver::OnNextResolutionLocked(grpc_error_handle error) {
   have_next_resolution_timer_ = false;
   if (error == GRPC_ERROR_NONE && !resolving_) {
     StartResolvingLocked();
@@ -162,14 +164,14 @@
   GRPC_ERROR_UNREF(error);
 }
 
-void NativeDnsResolver::OnResolved(void* arg, grpc_error* error) {
+void NativeDnsResolver::OnResolved(void* arg, grpc_error_handle error) {
   NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
   GRPC_ERROR_REF(error);  // owned by lambda
-  r->work_serializer()->Run([r, error]() { r->OnResolvedLocked(error); },
-                            DEBUG_LOCATION);
+  r->work_serializer_->Run([r, error]() { r->OnResolvedLocked(error); },
+                           DEBUG_LOCATION);
 }
 
-void NativeDnsResolver::OnResolvedLocked(grpc_error* error) {
+void NativeDnsResolver::OnResolvedLocked(grpc_error_handle error) {
   GPR_ASSERT(resolving_);
   resolving_ = false;
   if (shutdown_) {
@@ -186,21 +188,25 @@
     }
     grpc_resolved_addresses_destroy(addresses_);
     result.args = grpc_channel_args_copy(channel_args_);
-    result_handler()->ReturnResult(std::move(result));
+    result_handler_->ReturnResult(std::move(result));
     // Reset backoff state so that we start from the beginning when the
     // next request gets triggered.
     backoff_.Reset();
   } else {
     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     // Return transient error.
     std::string error_message =
         absl::StrCat("DNS resolution failed for service: ", name_to_resolve_);
-    result_handler()->ReturnError(grpc_error_set_int(
+    result_handler_->ReturnError(grpc_error_set_int(
         GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(error_message.c_str(),
                                                          &error, 1),
         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
     // Set up for retry.
+    // InvalidateNow to avoid getting stuck re-initializing this timer
+    // in a loop while draining the currently-held WorkSerializer.
+    // Also see https://github.com/grpc/grpc/issues/26079.
+    ExecCtx::Get()->InvalidateNow();
     grpc_millis next_try = backoff_.NextAttemptTime();
     grpc_millis timeout = next_try - ExecCtx::Get()->Now();
     GPR_ASSERT(!have_next_resolution_timer_);
@@ -227,6 +233,10 @@
   // can start the next resolution.
   if (have_next_resolution_timer_) return;
   if (last_resolution_timestamp_ >= 0) {
+    // InvalidateNow to avoid getting stuck re-initializing this timer
+    // in a loop while draining the currently-held WorkSerializer.
+    // Also see https://github.com/grpc/grpc/issues/26079.
+    ExecCtx::Get()->InvalidateNow();
     const grpc_millis earliest_next_resolution =
         last_resolution_timestamp_ + min_time_between_resolutions_;
     const grpc_millis ms_until_next_resolution =
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
index a779cd4..7978d59 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -30,11 +30,11 @@
 
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/iomgr/work_serializer.h"
@@ -69,6 +69,8 @@
 
   // passed-in parameters
   grpc_channel_args* channel_args_ = nullptr;
+  std::shared_ptr<WorkSerializer> work_serializer_;
+  std::unique_ptr<ResultHandler> result_handler_;
   RefCountedPtr<FakeResolverResponseGenerator> response_generator_;
   // If has_next_result_ is true, next_result_ is the next resolution result
   // to be returned.
@@ -89,7 +91,8 @@
 };
 
 FakeResolver::FakeResolver(ResolverArgs args)
-    : Resolver(std::move(args.work_serializer), std::move(args.result_handler)),
+    : work_serializer_(std::move(args.work_serializer)),
+      result_handler_(std::move(args.result_handler)),
       response_generator_(
           FakeResolverResponseGenerator::GetFromArgs(args.args)) {
   // Channels sharing the same subchannels may have different resolver response
@@ -121,8 +124,8 @@
     if (!reresolution_closure_pending_) {
       reresolution_closure_pending_ = true;
       Ref().release();  // ref held by closure
-      work_serializer()->Run([this]() { ReturnReresolutionResult(); },
-                             DEBUG_LOCATION);
+      work_serializer_->Run([this]() { ReturnReresolutionResult(); },
+                            DEBUG_LOCATION);
     }
   }
 }
@@ -140,7 +143,7 @@
   if (return_failure_) {
     // TODO(roth): Change resolver result generator to be able to inject
     // the error to be returned.
-    result_handler()->ReturnError(grpc_error_set_int(
+    result_handler_->ReturnError(grpc_error_set_int(
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver transient failure"),
         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
     return_failure_ = false;
@@ -155,7 +158,7 @@
     // name, only the one in next_results_ will be kept since next_results_ is
     // before channel_args_.
     result.args = grpc_channel_args_union(next_result_.args, channel_args_);
-    result_handler()->ReturnResult(std::move(result));
+    result_handler_->ReturnResult(std::move(result));
     has_next_result_ = false;
   }
 }
@@ -236,8 +239,8 @@
   }
   FakeResolverResponseSetter* arg =
       new FakeResolverResponseSetter(resolver, std::move(result));
-  resolver->work_serializer()->Run([arg]() { arg->SetResponseLocked(); },
-                                   DEBUG_LOCATION);
+  resolver->work_serializer_->Run([arg]() { arg->SetResponseLocked(); },
+                                  DEBUG_LOCATION);
 }
 
 void FakeResolverResponseGenerator::SetReresolutionResponse(
@@ -250,7 +253,7 @@
   }
   FakeResolverResponseSetter* arg = new FakeResolverResponseSetter(
       resolver, std::move(result), true /* has_result */);
-  resolver->work_serializer()->Run(
+  resolver->work_serializer_->Run(
       [arg]() { arg->SetReresolutionResponseLocked(); }, DEBUG_LOCATION);
 }
 
@@ -263,7 +266,7 @@
   }
   FakeResolverResponseSetter* arg =
       new FakeResolverResponseSetter(resolver, Resolver::Result());
-  resolver->work_serializer()->Run(
+  resolver->work_serializer_->Run(
       [arg]() { arg->SetReresolutionResponseLocked(); }, DEBUG_LOCATION);
 }
 
@@ -276,8 +279,8 @@
   }
   FakeResolverResponseSetter* arg =
       new FakeResolverResponseSetter(resolver, Resolver::Result());
-  resolver->work_serializer()->Run([arg]() { arg->SetFailureLocked(); },
-                                   DEBUG_LOCATION);
+  resolver->work_serializer_->Run([arg]() { arg->SetFailureLocked(); },
+                                  DEBUG_LOCATION);
 }
 
 void FakeResolverResponseGenerator::SetFailureOnReresolution() {
@@ -290,8 +293,8 @@
   FakeResolverResponseSetter* arg = new FakeResolverResponseSetter(
       resolver, Resolver::Result(), false /* has_result */,
       false /* immediate */);
-  resolver->work_serializer()->Run([arg]() { arg->SetFailureLocked(); },
-                                   DEBUG_LOCATION);
+  resolver->work_serializer_->Run([arg]() { arg->SetFailureLocked(); },
+                                  DEBUG_LOCATION);
 }
 
 void FakeResolverResponseGenerator::SetFakeResolver(
@@ -302,56 +305,48 @@
   if (has_result_) {
     FakeResolverResponseSetter* arg =
         new FakeResolverResponseSetter(resolver_, std::move(result_));
-    resolver_->work_serializer()->Run([arg]() { arg->SetResponseLocked(); },
-                                      DEBUG_LOCATION);
+    resolver_->work_serializer_->Run([arg]() { arg->SetResponseLocked(); },
+                                     DEBUG_LOCATION);
     has_result_ = false;
   }
 }
 
 namespace {
 
-static void* response_generator_arg_copy(void* p) {
-  FakeResolverResponseGenerator* generator =
-      static_cast<FakeResolverResponseGenerator*>(p);
-  // TODO(roth): We currently deal with this ref manually.  Once the
-  // new channel args code is converted to C++, find a way to track this ref
-  // in a cleaner way.
-  RefCountedPtr<FakeResolverResponseGenerator> copy = generator->Ref();
-  copy.release();
+void* ResponseGeneratorChannelArgCopy(void* p) {
+  auto* generator = static_cast<FakeResolverResponseGenerator*>(p);
+  generator->Ref().release();
   return p;
 }
 
-static void response_generator_arg_destroy(void* p) {
-  FakeResolverResponseGenerator* generator =
-      static_cast<FakeResolverResponseGenerator*>(p);
+void ResponseGeneratorChannelArgDestroy(void* p) {
+  auto* generator = static_cast<FakeResolverResponseGenerator*>(p);
   generator->Unref();
 }
 
-static int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
-
-static const grpc_arg_pointer_vtable response_generator_arg_vtable = {
-    response_generator_arg_copy, response_generator_arg_destroy,
-    response_generator_cmp};
+int ResponseGeneratorChannelArgCmp(void* a, void* b) { return GPR_ICMP(a, b); }
 
 }  // namespace
 
+const grpc_arg_pointer_vtable
+    FakeResolverResponseGenerator::kChannelArgPointerVtable = {
+        ResponseGeneratorChannelArgCopy, ResponseGeneratorChannelArgDestroy,
+        ResponseGeneratorChannelArgCmp};
+
 grpc_arg FakeResolverResponseGenerator::MakeChannelArg(
     FakeResolverResponseGenerator* generator) {
-  grpc_arg arg;
-  arg.type = GRPC_ARG_POINTER;
-  arg.key = const_cast<char*>(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
-  arg.value.pointer.p = generator;
-  arg.value.pointer.vtable = &response_generator_arg_vtable;
-  return arg;
+  return grpc_channel_arg_pointer_create(
+      const_cast<char*>(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR), generator,
+      &kChannelArgPointerVtable);
 }
 
 RefCountedPtr<FakeResolverResponseGenerator>
 FakeResolverResponseGenerator::GetFromArgs(const grpc_channel_args* args) {
-  const grpc_arg* arg =
-      grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
-  if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return nullptr;
-  return static_cast<FakeResolverResponseGenerator*>(arg->value.pointer.p)
-      ->Ref();
+  auto* response_generator =
+      grpc_channel_args_find_pointer<FakeResolverResponseGenerator>(
+          args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
+  if (response_generator == nullptr) return nullptr;
+  return response_generator->Ref();
 }
 
 //
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
index b9ca69d..94d7c22 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
+++ b/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
@@ -42,6 +42,8 @@
 class FakeResolverResponseGenerator
     : public RefCounted<FakeResolverResponseGenerator> {
  public:
+  static const grpc_arg_pointer_vtable kChannelArgPointerVtable;
+
   FakeResolverResponseGenerator();
   ~FakeResolverResponseGenerator() override;
 
@@ -69,6 +71,7 @@
   void SetFailureOnReresolution();
 
   // Returns a channel arg containing \a generator.
+  // TODO(roth): When we have time, make this a non-static method.
   static grpc_arg MakeChannelArg(FakeResolverResponseGenerator* generator);
 
   // Returns the response generator in \a args, or null if not found.
@@ -82,12 +85,11 @@
 
   // Mutex protecting the members below.
   Mutex mu_;
-  RefCountedPtr<FakeResolver> resolver_;
-  Resolver::Result result_;
-  bool has_result_ = false;
+  RefCountedPtr<FakeResolver> resolver_ ABSL_GUARDED_BY(mu_);
+  Resolver::Result result_ ABSL_GUARDED_BY(mu_);
+  bool has_result_ ABSL_GUARDED_BY(mu_) = false;
 };
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H \
-        */
+#endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc b/grpc/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
new file mode 100644
index 0000000..208ec67
--- /dev/null
+++ b/grpc/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
@@ -0,0 +1,379 @@
+//
+// Copyright 2021 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>
+
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/ext/xds/xds_client.h"
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+namespace grpc_core {
+
+namespace {
+
+class GoogleCloud2ProdResolver : public Resolver {
+ public:
+  explicit GoogleCloud2ProdResolver(ResolverArgs args);
+
+  void StartLocked() override;
+  void RequestReresolutionLocked() override;
+  void ResetBackoffLocked() override;
+  void ShutdownLocked() override;
+
+ private:
+  // Represents an HTTP request to the metadata server.
+  class MetadataQuery : public InternallyRefCounted<MetadataQuery> {
+   public:
+    MetadataQuery(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
+                  const char* path, grpc_polling_entity* pollent);
+    ~MetadataQuery() override;
+
+    void Orphan() override;
+
+   private:
+    static void OnHttpRequestDone(void* arg, grpc_error_handle error);
+
+    // Calls OnDone() if not already called.  Releases a ref.
+    void MaybeCallOnDone(grpc_error_handle error);
+
+    // If error is not GRPC_ERROR_NONE, then it's not safe to look at response.
+    virtual void OnDone(GoogleCloud2ProdResolver* resolver,
+                        const grpc_http_response* response,
+                        grpc_error_handle error) = 0;
+
+    RefCountedPtr<GoogleCloud2ProdResolver> resolver_;
+    grpc_httpcli_context context_;
+    grpc_httpcli_response response_;
+    grpc_closure on_done_;
+    Atomic<bool> on_done_called_{false};
+  };
+
+  // A metadata server query to get the zone.
+  class ZoneQuery : public MetadataQuery {
+   public:
+    ZoneQuery(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
+              grpc_polling_entity* pollent);
+
+   private:
+    void OnDone(GoogleCloud2ProdResolver* resolver,
+                const grpc_http_response* response,
+                grpc_error_handle error) override;
+  };
+
+  // A metadata server query to get the IPv6 address.
+  class IPv6Query : public MetadataQuery {
+   public:
+    IPv6Query(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
+              grpc_polling_entity* pollent);
+
+   private:
+    void OnDone(GoogleCloud2ProdResolver* resolver,
+                const grpc_http_response* response,
+                grpc_error_handle error) override;
+  };
+
+  void ZoneQueryDone(std::string zone);
+  void IPv6QueryDone(bool ipv6_supported);
+  void StartXdsResolver();
+
+  std::shared_ptr<WorkSerializer> work_serializer_;
+  grpc_polling_entity pollent_;
+  bool using_dns_ = false;
+  OrphanablePtr<Resolver> child_resolver_;
+
+  OrphanablePtr<ZoneQuery> zone_query_;
+  absl::optional<std::string> zone_;
+
+  OrphanablePtr<IPv6Query> ipv6_query_;
+  absl::optional<bool> supports_ipv6_;
+};
+
+//
+// GoogleCloud2ProdResolver::MetadataQuery
+//
+
+GoogleCloud2ProdResolver::MetadataQuery::MetadataQuery(
+    RefCountedPtr<GoogleCloud2ProdResolver> resolver, const char* path,
+    grpc_polling_entity* pollent)
+    : resolver_(std::move(resolver)) {
+  grpc_httpcli_context_init(&context_);
+  // Start HTTP request.
+  GRPC_CLOSURE_INIT(&on_done_, OnHttpRequestDone, this, nullptr);
+  Ref().release();  // Ref held by callback.
+  grpc_httpcli_request request;
+  memset(&request, 0, sizeof(grpc_httpcli_request));
+  grpc_http_header header = {const_cast<char*>("Metadata-Flavor"),
+                             const_cast<char*>("Google")};
+  request.host = const_cast<char*>("metadata.google.internal");
+  request.http.path = const_cast<char*>(path);
+  request.http.hdr_count = 1;
+  request.http.hdrs = &header;
+  grpc_resource_quota* resource_quota =
+      grpc_resource_quota_create("c2p_resolver");
+  grpc_httpcli_get(&context_, pollent, resource_quota, &request,
+                   ExecCtx::Get()->Now() + 10000,  // 10s timeout
+                   &on_done_, &response_);
+  grpc_resource_quota_unref_internal(resource_quota);
+}
+
+GoogleCloud2ProdResolver::MetadataQuery::~MetadataQuery() {
+  grpc_httpcli_context_destroy(&context_);
+  grpc_http_response_destroy(&response_);
+}
+
+void GoogleCloud2ProdResolver::MetadataQuery::Orphan() {
+  // TODO(roth): Once the HTTP client library supports cancellation,
+  // use that here.
+  MaybeCallOnDone(GRPC_ERROR_CANCELLED);
+}
+
+void GoogleCloud2ProdResolver::MetadataQuery::OnHttpRequestDone(
+    void* arg, grpc_error_handle error) {
+  auto* self = static_cast<MetadataQuery*>(arg);
+  self->MaybeCallOnDone(GRPC_ERROR_REF(error));
+}
+
+void GoogleCloud2ProdResolver::MetadataQuery::MaybeCallOnDone(
+    grpc_error_handle error) {
+  bool expected = false;
+  if (!on_done_called_.CompareExchangeStrong(
+          &expected, true, MemoryOrder::RELAXED, MemoryOrder::RELAXED)) {
+    // We've already called OnDone(), so just clean up.
+    GRPC_ERROR_UNREF(error);
+    Unref();
+    return;
+  }
+  // Hop back into WorkSerializer to call OnDone().
+  // Note: We implicitly pass our ref to the callback here.
+  resolver_->work_serializer_->Run(
+      [this, error]() {
+        OnDone(resolver_.get(), &response_, error);
+        Unref();
+      },
+      DEBUG_LOCATION);
+}
+
+//
+// GoogleCloud2ProdResolver::ZoneQuery
+//
+
+GoogleCloud2ProdResolver::ZoneQuery::ZoneQuery(
+    RefCountedPtr<GoogleCloud2ProdResolver> resolver,
+    grpc_polling_entity* pollent)
+    : MetadataQuery(std::move(resolver), "/computeMetadata/v1/instance/zone",
+                    pollent) {}
+
+void GoogleCloud2ProdResolver::ZoneQuery::OnDone(
+    GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
+    grpc_error_handle error) {
+  if (error != GRPC_ERROR_NONE) {
+    gpr_log(GPR_ERROR, "error fetching zone from metadata server: %s",
+            grpc_error_std_string(error).c_str());
+  }
+  std::string zone;
+  if (error == GRPC_ERROR_NONE && response->status == 200) {
+    absl::string_view body(response->body, response->body_length);
+    size_t i = body.find_last_of('/');
+    if (i == body.npos) {
+      gpr_log(GPR_ERROR, "could not parse zone from metadata server: %s",
+              std::string(body).c_str());
+    } else {
+      zone = std::string(body.substr(i));
+    }
+  }
+  resolver->ZoneQueryDone(std::move(zone));
+  GRPC_ERROR_UNREF(error);
+}
+
+//
+// GoogleCloud2ProdResolver::IPv6Query
+//
+
+GoogleCloud2ProdResolver::IPv6Query::IPv6Query(
+    RefCountedPtr<GoogleCloud2ProdResolver> resolver,
+    grpc_polling_entity* pollent)
+    : MetadataQuery(std::move(resolver),
+                    "/computeMetadata/v1/instance/network-interfaces/0/ipv6s",
+                    pollent) {}
+
+void GoogleCloud2ProdResolver::IPv6Query::OnDone(
+    GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
+    grpc_error_handle error) {
+  if (error != GRPC_ERROR_NONE) {
+    gpr_log(GPR_ERROR, "error fetching IPv6 address from metadata server: %s",
+            grpc_error_std_string(error).c_str());
+  }
+  resolver->IPv6QueryDone(error == GRPC_ERROR_NONE && response->status == 200);
+  GRPC_ERROR_UNREF(error);
+}
+
+//
+// GoogleCloud2ProdResolver
+//
+
+GoogleCloud2ProdResolver::GoogleCloud2ProdResolver(ResolverArgs args)
+    : work_serializer_(std::move(args.work_serializer)),
+      pollent_(grpc_polling_entity_create_from_pollset_set(args.pollset_set)) {
+  absl::string_view name_to_resolve = absl::StripPrefix(args.uri.path(), "/");
+  // If we're not running on GCP, we can't use DirectPath, so delegate
+  // to the DNS resolver.
+  if (!grpc_alts_is_running_on_gcp() ||
+      // If the client is already using xDS, we can't use it here, because
+      // they may be talking to a completely different xDS server than we
+      // want to.
+      // TODO(roth): When we implement xDS federation, remove this constraint.
+      UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP")) != nullptr ||
+      UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG")) != nullptr) {
+    using_dns_ = true;
+    child_resolver_ = ResolverRegistry::CreateResolver(
+        absl::StrCat("dns:", name_to_resolve).c_str(), args.args,
+        args.pollset_set, work_serializer_, std::move(args.result_handler));
+    GPR_ASSERT(child_resolver_ != nullptr);
+    return;
+  }
+  // Create xds resolver.
+  child_resolver_ = ResolverRegistry::CreateResolver(
+      absl::StrCat("xds:", name_to_resolve).c_str(), args.args,
+      args.pollset_set, work_serializer_, std::move(args.result_handler));
+  GPR_ASSERT(child_resolver_ != nullptr);
+}
+
+void GoogleCloud2ProdResolver::StartLocked() {
+  if (using_dns_) {
+    child_resolver_->StartLocked();
+    return;
+  }
+  // Using xDS.  Start metadata server queries.
+  zone_query_ = MakeOrphanable<ZoneQuery>(Ref(), &pollent_);
+  ipv6_query_ = MakeOrphanable<IPv6Query>(Ref(), &pollent_);
+}
+
+void GoogleCloud2ProdResolver::RequestReresolutionLocked() {
+  if (child_resolver_ != nullptr) {
+    child_resolver_->RequestReresolutionLocked();
+  }
+}
+
+void GoogleCloud2ProdResolver::ResetBackoffLocked() {
+  if (child_resolver_ != nullptr) {
+    child_resolver_->ResetBackoffLocked();
+  }
+}
+
+void GoogleCloud2ProdResolver::ShutdownLocked() {
+  zone_query_.reset();
+  ipv6_query_.reset();
+  child_resolver_.reset();
+}
+
+void GoogleCloud2ProdResolver::ZoneQueryDone(std::string zone) {
+  zone_query_.reset();
+  zone_ = std::move(zone);
+  if (supports_ipv6_.has_value()) StartXdsResolver();
+}
+
+void GoogleCloud2ProdResolver::IPv6QueryDone(bool ipv6_supported) {
+  ipv6_query_.reset();
+  supports_ipv6_ = ipv6_supported;
+  if (zone_.has_value()) StartXdsResolver();
+}
+
+void GoogleCloud2ProdResolver::StartXdsResolver() {
+  // Construct bootstrap JSON.
+  Json::Object node = {
+      {"id", "C2P"},
+  };
+  if (!zone_->empty()) {
+    node["locality"] = Json::Object{
+        {"zone", *zone_},
+    };
+  };
+  if (*supports_ipv6_) {
+    node["metadata"] = Json::Object{
+        {"TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE", true},
+    };
+  }
+  // Allow the TD server uri to be overridden for testing purposes.
+  UniquePtr<char> override_server(
+      gpr_getenv("GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI"));
+  const char* server_uri =
+      override_server != nullptr && strlen(override_server.get()) > 0
+          ? override_server.get()
+          : "directpath-trafficdirector.googleapis.com";
+  Json bootstrap = Json::Object{
+      {"xds_servers",
+       Json::Array{
+           Json::Object{
+               {"server_uri", server_uri},
+               {"channel_creds",
+                Json::Array{
+                    Json::Object{
+                        {"type", "google_default"},
+                    },
+                }},
+               {"server_features", Json::Array{"xds_v3"}},
+           },
+       }},
+      {"node", std::move(node)},
+  };
+  // Inject bootstrap JSON as fallback config.
+  internal::SetXdsFallbackBootstrapConfig(bootstrap.Dump().c_str());
+  // Now start xDS resolver.
+  child_resolver_->StartLocked();
+}
+
+//
+// Factory
+//
+
+class GoogleCloud2ProdResolverFactory : public ResolverFactory {
+ public:
+  bool IsValidUri(const URI& uri) const override {
+    if (GPR_UNLIKELY(!uri.authority().empty())) {
+      gpr_log(GPR_ERROR, "google-c2p URI scheme does not support authorities");
+      return false;
+    }
+    return true;
+  }
+
+  OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
+    if (!IsValidUri(args.uri)) return nullptr;
+    return MakeOrphanable<GoogleCloud2ProdResolver>(std::move(args));
+  }
+
+  const char* scheme() const override { return "google-c2p"; }
+};
+
+}  // namespace
+
+void GoogleCloud2ProdResolverInit() {
+  // TODO(roth): Remove env var protection once this code is proven stable.
+  UniquePtr<char> value(gpr_getenv("GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER"));
+  bool parsed_value;
+  bool parse_succeeded = gpr_parse_bool_value(value.get(), &parsed_value);
+  if (parse_succeeded && parsed_value) {
+    ResolverRegistry::Builder::RegisterResolverFactory(
+        absl::make_unique<GoogleCloud2ProdResolverFactory>());
+  }
+}
+
+void GoogleCloud2ProdResolverShutdown() {}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
index dfa2dd9..46efbb0 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
@@ -30,12 +30,11 @@
 
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
-#include "src/core/lib/iomgr/work_serializer.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 
@@ -53,13 +52,14 @@
   void ShutdownLocked() override {}
 
  private:
+  std::unique_ptr<ResultHandler> result_handler_;
   ServerAddressList addresses_;
   const grpc_channel_args* channel_args_ = nullptr;
 };
 
 SockaddrResolver::SockaddrResolver(ServerAddressList addresses,
                                    ResolverArgs args)
-    : Resolver(std::move(args.work_serializer), std::move(args.result_handler)),
+    : result_handler_(std::move(args.result_handler)),
       addresses_(std::move(addresses)),
       channel_args_(grpc_channel_args_copy(args.args)) {}
 
@@ -73,7 +73,7 @@
   // TODO(roth): Use std::move() once channel args is converted to C++.
   result.args = channel_args_;
   channel_args_ = nullptr;
-  result_handler()->ReturnResult(std::move(result));
+  result_handler_->ReturnResult(std::move(result));
 }
 
 //
@@ -150,7 +150,7 @@
     return CreateSockaddrResolver(std::move(args), grpc_parse_unix);
   }
 
-  std::string GetDefaultAuthority(const URI& uri) const override {
+  std::string GetDefaultAuthority(const URI& /*uri*/) const override {
     return "localhost";
   }
 
diff --git a/grpc/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc b/grpc/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
index e902809..3a10a42 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
@@ -22,13 +22,19 @@
 #include "absl/strings/str_join.h"
 #include "absl/strings/str_split.h"
 #include "re2/re2.h"
+#define XXH_INLINE_ALL
+#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_channel_args.h"
 #include "src/core/ext/xds/xds_client.h"
+#include "src/core/ext/xds/xds_http_filters.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/surface/lame_client.h"
 #include "src/core/lib/transport/timeout_encoding.h"
 
 namespace grpc_core {
@@ -46,8 +52,8 @@
 class XdsResolver : public Resolver {
  public:
   explicit XdsResolver(ResolverArgs args)
-      : Resolver(std::move(args.work_serializer),
-                 std::move(args.result_handler)),
+      : work_serializer_(std::move(args.work_serializer)),
+        result_handler_(std::move(args.result_handler)),
         server_name_(absl::StripPrefix(args.uri.path(), "/")),
         args_(grpc_channel_args_copy(args.args)),
         interested_parties_(args.pollset_set) {
@@ -68,19 +74,23 @@
 
   void ShutdownLocked() override;
 
+  void ResetBackoffLocked() override {
+    if (xds_client_ != nullptr) xds_client_->ResetBackoff();
+  }
+
  private:
   class Notifier {
    public:
     Notifier(RefCountedPtr<XdsResolver> resolver, XdsApi::LdsUpdate update);
     Notifier(RefCountedPtr<XdsResolver> resolver, XdsApi::RdsUpdate update);
-    Notifier(RefCountedPtr<XdsResolver> resolver, grpc_error* error);
+    Notifier(RefCountedPtr<XdsResolver> resolver, grpc_error_handle error);
     explicit Notifier(RefCountedPtr<XdsResolver> resolver);
 
    private:
     enum Type { kLdsUpdate, kRdsUpdate, kError, kDoesNotExist };
 
-    static void RunInExecCtx(void* arg, grpc_error* error);
-    void RunInWorkSerializer(grpc_error* error);
+    static void RunInExecCtx(void* arg, grpc_error_handle error);
+    void RunInWorkSerializer(grpc_error_handle error);
 
     RefCountedPtr<XdsResolver> resolver_;
     grpc_closure closure_;
@@ -95,7 +105,9 @@
     void OnListenerChanged(XdsApi::LdsUpdate listener) override {
       new Notifier(resolver_, std::move(listener));
     }
-    void OnError(grpc_error* error) override { new Notifier(resolver_, error); }
+    void OnError(grpc_error_handle error) override {
+      new Notifier(resolver_, error);
+    }
     void OnResourceDoesNotExist() override { new Notifier(resolver_); }
 
    private:
@@ -109,7 +121,9 @@
     void OnRouteConfigChanged(XdsApi::RdsUpdate route_config) override {
       new Notifier(resolver_, std::move(route_config));
     }
-    void OnError(grpc_error* error) override { new Notifier(resolver_, error); }
+    void OnError(grpc_error_handle error) override {
+      new Notifier(resolver_, error);
+    }
     void OnResourceDoesNotExist() override { new Notifier(resolver_); }
 
    private:
@@ -117,7 +131,7 @@
   };
 
   class ClusterState
-      : public RefCounted<ClusterState, PolymorphicRefCount, false> {
+      : public RefCounted<ClusterState, PolymorphicRefCount, kUnrefNoDelete> {
    public:
     using ClusterStateMap =
         std::map<std::string, std::unique_ptr<ClusterState>>;
@@ -136,8 +150,7 @@
   class XdsConfigSelector : public ConfigSelector {
    public:
     XdsConfigSelector(RefCountedPtr<XdsResolver> resolver,
-                      const std::vector<XdsApi::Route>& routes,
-                      grpc_error* error);
+                      grpc_error_handle* error);
     ~XdsConfigSelector() override;
 
     const char* name() const override { return "XdsConfigSelector"; }
@@ -151,47 +164,72 @@
 
     CallConfig GetCallConfig(GetCallConfigArgs args) override;
 
+    std::vector<const grpc_channel_filter*> GetFilters() override {
+      return filters_;
+    }
+
+    grpc_channel_args* ModifyChannelArgs(grpc_channel_args* args) override;
+
    private:
     struct Route {
+      struct ClusterWeightState {
+        uint32_t range_end;
+        absl::string_view cluster;
+        RefCountedPtr<ServiceConfig> method_config;
+
+        bool operator==(const ClusterWeightState& other) const;
+      };
+
       XdsApi::Route route;
-      absl::InlinedVector<std::pair<uint32_t, absl::string_view>, 2>
-          weighted_cluster_state;
       RefCountedPtr<ServiceConfig> method_config;
-      bool operator==(const Route& other) const {
-        return route == other.route &&
-               weighted_cluster_state == other.weighted_cluster_state;
-      }
+      absl::InlinedVector<ClusterWeightState, 2> weighted_cluster_state;
+
+      bool operator==(const Route& other) const;
     };
     using RouteTable = std::vector<Route>;
 
     void MaybeAddCluster(const std::string& name);
-    grpc_error* CreateMethodConfig(RefCountedPtr<ServiceConfig>* method_config,
-                                   const XdsApi::Route& route);
+    grpc_error_handle CreateMethodConfig(
+        const XdsApi::Route& route,
+        const XdsApi::Route::ClusterWeight* cluster_weight,
+        RefCountedPtr<ServiceConfig>* method_config);
 
     RefCountedPtr<XdsResolver> resolver_;
     RouteTable route_table_;
     std::map<absl::string_view, RefCountedPtr<ClusterState>> clusters_;
+    std::vector<const grpc_channel_filter*> filters_;
+    grpc_error_handle filter_error_ = GRPC_ERROR_NONE;
   };
 
   void OnListenerUpdate(XdsApi::LdsUpdate listener);
   void OnRouteConfigUpdate(XdsApi::RdsUpdate rds_update);
-  void OnError(grpc_error* error);
+  void OnError(grpc_error_handle error);
   void OnResourceDoesNotExist();
 
-  grpc_error* CreateServiceConfig(RefCountedPtr<ServiceConfig>* service_config);
+  grpc_error_handle CreateServiceConfig(
+      RefCountedPtr<ServiceConfig>* service_config);
   void GenerateResult();
   void MaybeRemoveUnusedClusters();
 
+  std::shared_ptr<WorkSerializer> work_serializer_;
+  std::unique_ptr<ResultHandler> result_handler_;
   std::string server_name_;
   const grpc_channel_args* args_;
   grpc_pollset_set* interested_parties_;
+
   RefCountedPtr<XdsClient> xds_client_;
+
   XdsClient::ListenerWatcherInterface* listener_watcher_ = nullptr;
+  // This will not contain the RouteConfiguration, even if it comes with the
+  // LDS response; instead, the relevant VirtualHost from the
+  // RouteConfiguration will be saved in current_virtual_host_.
+  XdsApi::LdsUpdate current_listener_;
+
   std::string route_config_name_;
   XdsClient::RouteConfigWatcherInterface* route_config_watcher_ = nullptr;
+  XdsApi::RdsUpdate::VirtualHost current_virtual_host_;
+
   ClusterState::ClusterStateMap cluster_state_map_;
-  std::vector<XdsApi::Route> current_update_;
-  XdsApi::Duration http_max_stream_duration_;
 };
 
 //
@@ -210,13 +248,13 @@
 XdsResolver::Notifier::Notifier(RefCountedPtr<XdsResolver> resolver,
                                 XdsApi::RdsUpdate update)
     : resolver_(std::move(resolver)), type_(kRdsUpdate) {
-  update_.rds_update = std::move(update);
+  update_.http_connection_manager.rds_update = std::move(update);
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, GRPC_ERROR_NONE);
 }
 
 XdsResolver::Notifier::Notifier(RefCountedPtr<XdsResolver> resolver,
-                                grpc_error* error)
+                                grpc_error_handle error)
     : resolver_(std::move(resolver)), type_(kError) {
   GRPC_CLOSURE_INIT(&closure_, &RunInExecCtx, this, nullptr);
   ExecCtx::Run(DEBUG_LOCATION, &closure_, error);
@@ -228,14 +266,14 @@
   ExecCtx::Run(DEBUG_LOCATION, &closure_, GRPC_ERROR_NONE);
 }
 
-void XdsResolver::Notifier::RunInExecCtx(void* arg, grpc_error* error) {
+void XdsResolver::Notifier::RunInExecCtx(void* arg, grpc_error_handle error) {
   Notifier* self = static_cast<Notifier*>(arg);
   GRPC_ERROR_REF(error);
-  self->resolver_->work_serializer()->Run(
+  self->resolver_->work_serializer_->Run(
       [self, error]() { self->RunInWorkSerializer(error); }, DEBUG_LOCATION);
 }
 
-void XdsResolver::Notifier::RunInWorkSerializer(grpc_error* error) {
+void XdsResolver::Notifier::RunInWorkSerializer(grpc_error_handle error) {
   if (resolver_->xds_client_ == nullptr) {
     GRPC_ERROR_UNREF(error);
     delete this;
@@ -246,7 +284,8 @@
       resolver_->OnListenerUpdate(std::move(update_));
       break;
     case kRdsUpdate:
-      resolver_->OnRouteConfigUpdate(std::move(*update_.rds_update));
+      resolver_->OnRouteConfigUpdate(
+          std::move(*update_.http_connection_manager.rds_update));
       break;
     case kError:
       resolver_->OnError(error);
@@ -259,12 +298,34 @@
 }
 
 //
+// XdsResolver::XdsConfigSelector::Route
+//
+
+bool MethodConfigsEqual(const ServiceConfig* sc1, const ServiceConfig* sc2) {
+  if (sc1 == nullptr) return sc2 == nullptr;
+  if (sc2 == nullptr) return false;
+  return sc1->json_string() == sc2->json_string();
+}
+
+bool XdsResolver::XdsConfigSelector::Route::ClusterWeightState::operator==(
+    const ClusterWeightState& other) const {
+  return range_end == other.range_end && cluster == other.cluster &&
+         MethodConfigsEqual(method_config.get(), other.method_config.get());
+}
+
+bool XdsResolver::XdsConfigSelector::Route::operator==(
+    const Route& other) const {
+  return route == other.route &&
+         weighted_cluster_state == other.weighted_cluster_state &&
+         MethodConfigsEqual(method_config.get(), other.method_config.get());
+}
+
+//
 // XdsResolver::XdsConfigSelector
 //
 
 XdsResolver::XdsConfigSelector::XdsConfigSelector(
-    RefCountedPtr<XdsResolver> resolver,
-    const std::vector<XdsApi::Route>& routes, grpc_error* error)
+    RefCountedPtr<XdsResolver> resolver, grpc_error_handle* error)
     : resolver_(std::move(resolver)) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
     gpr_log(GPR_INFO, "[xds_resolver %p] creating XdsConfigSelector %p",
@@ -279,8 +340,8 @@
   // weighted_cluster_state field points to the memory in the route field, so
   // moving the entry in a reallocation will cause the string_view to point to
   // invalid data.
-  route_table_.reserve(routes.size());
-  for (auto& route : routes) {
+  route_table_.reserve(resolver_->current_virtual_host_.routes.size());
+  for (auto& route : resolver_->current_virtual_host_.routes) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
       gpr_log(GPR_INFO, "[xds_resolver %p] XdsConfigSelector %p: route: %s",
               resolver_.get(), this, route.ToString().c_str());
@@ -292,27 +353,95 @@
     // one.
     if (!route.max_stream_duration.has_value()) {
       route_entry.route.max_stream_duration =
-          resolver_->http_max_stream_duration_;
+          resolver_->current_listener_.http_connection_manager
+              .http_max_stream_duration;
     }
-    error = CreateMethodConfig(&route_entry.method_config, route_entry.route);
     if (route.weighted_clusters.empty()) {
+      *error = CreateMethodConfig(route_entry.route, nullptr,
+                                  &route_entry.method_config);
       MaybeAddCluster(route.cluster_name);
     } else {
       uint32_t end = 0;
       for (const auto& weighted_cluster : route_entry.route.weighted_clusters) {
-        MaybeAddCluster(weighted_cluster.name);
+        Route::ClusterWeightState cluster_weight_state;
+        *error = CreateMethodConfig(route_entry.route, &weighted_cluster,
+                                    &cluster_weight_state.method_config);
+        if (*error != GRPC_ERROR_NONE) return;
         end += weighted_cluster.weight;
-        route_entry.weighted_cluster_state.emplace_back(end,
-                                                        weighted_cluster.name);
+        cluster_weight_state.range_end = end;
+        cluster_weight_state.cluster = weighted_cluster.name;
+        route_entry.weighted_cluster_state.push_back(
+            std::move(cluster_weight_state));
+        MaybeAddCluster(weighted_cluster.name);
       }
     }
   }
+  // Populate filter list.
+  bool found_router = false;
+  for (const auto& http_filter :
+       resolver_->current_listener_.http_connection_manager.http_filters) {
+    // Stop at the router filter.  It's a no-op for us, and we ignore
+    // anything that may come after it, for compatibility with Envoy.
+    if (http_filter.config.config_proto_type_name ==
+        kXdsHttpRouterFilterConfigName) {
+      found_router = true;
+      break;
+    }
+    // Find filter.  This is guaranteed to succeed, because it's checked
+    // at config validation time in the XdsApi code.
+    const XdsHttpFilterImpl* filter_impl =
+        XdsHttpFilterRegistry::GetFilterForType(
+            http_filter.config.config_proto_type_name);
+    GPR_ASSERT(filter_impl != nullptr);
+    // Add C-core filter to list.
+    filters_.push_back(filter_impl->channel_filter());
+  }
+  // For compatibility with Envoy, if the router filter is not
+  // configured, we fail all RPCs.
+  if (!found_router) {
+    filter_error_ =
+        grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                               "no xDS HTTP router filter configured"),
+                           GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
+    filters_.push_back(&grpc_lame_filter);
+  }
 }
 
-grpc_error* XdsResolver::XdsConfigSelector::CreateMethodConfig(
-    RefCountedPtr<ServiceConfig>* method_config, const XdsApi::Route& route) {
-  grpc_error* error = GRPC_ERROR_NONE;
+XdsResolver::XdsConfigSelector::~XdsConfigSelector() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
+    gpr_log(GPR_INFO, "[xds_resolver %p] destroying XdsConfigSelector %p",
+            resolver_.get(), this);
+  }
+  clusters_.clear();
+  resolver_->MaybeRemoveUnusedClusters();
+  GRPC_ERROR_UNREF(filter_error_);
+}
+
+const XdsHttpFilterImpl::FilterConfig* FindFilterConfigOverride(
+    const std::string& instance_name,
+    const XdsApi::RdsUpdate::VirtualHost& vhost, const XdsApi::Route& route,
+    const XdsApi::Route::ClusterWeight* cluster_weight) {
+  // Check ClusterWeight, if any.
+  if (cluster_weight != nullptr) {
+    auto it = cluster_weight->typed_per_filter_config.find(instance_name);
+    if (it != cluster_weight->typed_per_filter_config.end()) return &it->second;
+  }
+  // Check Route.
+  auto it = route.typed_per_filter_config.find(instance_name);
+  if (it != route.typed_per_filter_config.end()) return &it->second;
+  // Check VirtualHost.
+  it = vhost.typed_per_filter_config.find(instance_name);
+  if (it != vhost.typed_per_filter_config.end()) return &it->second;
+  // Not found.
+  return nullptr;
+}
+
+grpc_error_handle XdsResolver::XdsConfigSelector::CreateMethodConfig(
+    const XdsApi::Route& route,
+    const XdsApi::Route::ClusterWeight* cluster_weight,
+    RefCountedPtr<ServiceConfig>* method_config) {
   std::vector<std::string> fields;
+  // Set timeout.
   if (route.max_stream_duration.has_value() &&
       (route.max_stream_duration->seconds != 0 ||
        route.max_stream_duration->nanos != 0)) {
@@ -320,6 +449,51 @@
                                         route.max_stream_duration->seconds,
                                         route.max_stream_duration->nanos));
   }
+  // Handle xDS HTTP filters.
+  std::map<std::string, std::vector<std::string>> per_filter_configs;
+  grpc_channel_args* args = grpc_channel_args_copy(resolver_->args_);
+  for (const auto& http_filter :
+       resolver_->current_listener_.http_connection_manager.http_filters) {
+    // Stop at the router filter.  It's a no-op for us, and we ignore
+    // anything that may come after it, for compatibility with Envoy.
+    if (http_filter.config.config_proto_type_name ==
+        kXdsHttpRouterFilterConfigName) {
+      break;
+    }
+    // Find filter.  This is guaranteed to succeed, because it's checked
+    // at config validation time in the XdsApi code.
+    const XdsHttpFilterImpl* filter_impl =
+        XdsHttpFilterRegistry::GetFilterForType(
+            http_filter.config.config_proto_type_name);
+    GPR_ASSERT(filter_impl != nullptr);
+    // Allow filter to add channel args that may affect service config
+    // parsing.
+    args = filter_impl->ModifyChannelArgs(args);
+    // Find config override, if any.
+    const XdsHttpFilterImpl::FilterConfig* config_override =
+        FindFilterConfigOverride(http_filter.name,
+                                 resolver_->current_virtual_host_, route,
+                                 cluster_weight);
+    // Generate service config for filter.
+    auto method_config_field =
+        filter_impl->GenerateServiceConfig(http_filter.config, config_override);
+    if (!method_config_field.ok()) {
+      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("failed to generate method config for HTTP filter ",
+                       http_filter.name, ": ",
+                       method_config_field.status().ToString())
+              .c_str());
+    }
+    per_filter_configs[method_config_field->service_config_field_name]
+        .push_back(method_config_field->element);
+  }
+  for (const auto& p : per_filter_configs) {
+    fields.emplace_back(absl::StrCat("    \"", p.first, "\": [\n",
+                                     absl::StrJoin(p.second, ",\n"),
+                                     "\n    ]"));
+  }
+  // Construct service config.
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (!fields.empty()) {
     std::string json = absl::StrCat(
         "{\n"
@@ -331,19 +505,20 @@
         absl::StrJoin(fields, ",\n"),
         "\n  } ]\n"
         "}");
-    *method_config =
-        ServiceConfig::Create(resolver_->args_, json.c_str(), &error);
+    *method_config = ServiceConfig::Create(args, json.c_str(), &error);
   }
+  grpc_channel_args_destroy(args);
   return error;
 }
 
-XdsResolver::XdsConfigSelector::~XdsConfigSelector() {
-  if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
-    gpr_log(GPR_INFO, "[xds_resolver %p] destroying XdsConfigSelector %p",
-            resolver_.get(), this);
-  }
-  clusters_.clear();
-  resolver_->MaybeRemoveUnusedClusters();
+grpc_channel_args* XdsResolver::XdsConfigSelector::ModifyChannelArgs(
+    grpc_channel_args* args) {
+  if (filter_error_ == GRPC_ERROR_NONE) return args;
+  grpc_arg error_arg = MakeLameClientErrorArg(filter_error_);
+  grpc_channel_args* new_args =
+      grpc_channel_args_copy_and_add(args, &error_arg, 1);
+  grpc_channel_args_destroy(args);
+  return new_args;
 }
 
 void XdsResolver::XdsConfigSelector::MaybeAddCluster(const std::string& name) {
@@ -359,108 +534,50 @@
   }
 }
 
-bool PathMatch(const absl::string_view& path,
-               const XdsApi::Route::Matchers::PathMatcher& path_matcher) {
-  switch (path_matcher.type) {
-    case XdsApi::Route::Matchers::PathMatcher::PathMatcherType::PREFIX:
-      return path_matcher.case_sensitive
-                 ? absl::StartsWith(path, path_matcher.string_matcher)
-                 : absl::StartsWithIgnoreCase(path,
-                                              path_matcher.string_matcher);
-    case XdsApi::Route::Matchers::PathMatcher::PathMatcherType::PATH:
-      return path_matcher.case_sensitive
-                 ? path == path_matcher.string_matcher
-                 : absl::EqualsIgnoreCase(path, path_matcher.string_matcher);
-    case XdsApi::Route::Matchers::PathMatcher::PathMatcherType::REGEX:
-      // Note: Case-sensitive option will already have been set appropriately
-      // in path_matcher.regex_matcher when it was constructed, so no
-      // need to check it here.
-      return RE2::FullMatch(path.data(), *path_matcher.regex_matcher);
-    default:
-      return false;
-  }
-}
-
-absl::optional<absl::string_view> GetMetadataValue(
-    const std::string& target_key, grpc_metadata_batch* initial_metadata,
+absl::optional<absl::string_view> GetHeaderValue(
+    grpc_metadata_batch* initial_metadata, absl::string_view header_name,
     std::string* concatenated_value) {
-  // Find all values for the specified key.
-  GPR_DEBUG_ASSERT(initial_metadata != nullptr);
-  absl::InlinedVector<absl::string_view, 1> values;
-  for (grpc_linked_mdelem* md = initial_metadata->list.head; md != nullptr;
-       md = md->next) {
-    absl::string_view key = StringViewFromSlice(GRPC_MDKEY(md->md));
-    absl::string_view value = StringViewFromSlice(GRPC_MDVALUE(md->md));
-    if (target_key == key) values.push_back(value);
-  }
-  // If none found, no match.
-  if (values.empty()) return absl::nullopt;
-  // If exactly one found, return it as-is.
-  if (values.size() == 1) return values.front();
-  // If more than one found, concatenate the values, using
-  // *concatenated_values as a temporary holding place for the
-  // concatenated string.
-  *concatenated_value = absl::StrJoin(values, ",");
-  return *concatenated_value;
-}
-
-bool HeaderMatchHelper(
-    const XdsApi::Route::Matchers::HeaderMatcher& header_matcher,
-    grpc_metadata_batch* initial_metadata) {
-  std::string concatenated_value;
-  absl::optional<absl::string_view> 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 = GetMetadataValue(header_matcher.name, initial_metadata,
-                             &concatenated_value);
+  if (absl::EndsWith(header_name, "-bin")) {
+    return absl::nullopt;
+  } else if (header_name == "content-type") {
+    return "application/grpc";
   }
-  if (!value.has_value()) {
-    if (header_matcher.type ==
-        XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::PRESENT) {
-      return !header_matcher.present_match;
-    } else {
-      // For all other header matcher types, we need the header value to
-      // exist to consider matches.
+  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) {
+    std::string concatenated_value;
+    if (!header_matcher.Match(GetHeaderValue(
+            initial_metadata, header_matcher.name(), &concatenated_value))) {
       return false;
     }
   }
-  switch (header_matcher.type) {
-    case XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::EXACT:
-      return value.value() == header_matcher.string_matcher;
-    case XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::REGEX:
-      return RE2::FullMatch(value.value().data(), *header_matcher.regex_match);
-    case XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::RANGE:
-      int64_t int_value;
-      if (!absl::SimpleAtoi(value.value(), &int_value)) {
-        return false;
-      }
-      return int_value >= header_matcher.range_start &&
-             int_value < header_matcher.range_end;
-    case XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::PREFIX:
-      return absl::StartsWith(value.value(), header_matcher.string_matcher);
-    case XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::SUFFIX:
-      return absl::EndsWith(value.value(), header_matcher.string_matcher);
-    default:
-      return false;
-  }
+  return true;
 }
 
-bool HeadersMatch(
-    const std::vector<XdsApi::Route::Matchers::HeaderMatcher>& header_matchers,
+absl::optional<uint64_t> HeaderHashHelper(
+    const XdsApi::Route::HashPolicy& policy,
     grpc_metadata_batch* initial_metadata) {
-  for (const auto& header_matcher : header_matchers) {
-    bool match = HeaderMatchHelper(header_matcher, initial_metadata);
-    if (header_matcher.invert_match) match = !match;
-    if (!match) return false;
+  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 true;
+  return XXH64(header_value->data(), header_value->size(), 0);
 }
 
 bool UnderFraction(const uint32_t fraction_per_million) {
@@ -473,8 +590,8 @@
     GetCallConfigArgs args) {
   for (const auto& entry : route_table_) {
     // Path matching.
-    if (!PathMatch(StringViewFromSlice(*args.path),
-                   entry.route.matchers.path_matcher)) {
+    if (!entry.route.matchers.path_matcher.Match(
+            StringViewFromSlice(*args.path))) {
       continue;
     }
     // Header Matching.
@@ -489,13 +606,15 @@
     }
     // Found a route match
     absl::string_view cluster_name;
+    RefCountedPtr<ServiceConfig> method_config;
     if (entry.route.weighted_clusters.empty()) {
       cluster_name = entry.route.cluster_name;
+      method_config = entry.method_config;
     } else {
       const uint32_t key =
           rand() %
           entry.weighted_cluster_state[entry.weighted_cluster_state.size() - 1]
-              .first;
+              .range_end;
       // Find the index in weighted clusters corresponding to key.
       size_t mid = 0;
       size_t start_index = 0;
@@ -503,9 +622,9 @@
       size_t index = 0;
       while (end_index > start_index) {
         mid = (start_index + end_index) / 2;
-        if (entry.weighted_cluster_state[mid].first > key) {
+        if (entry.weighted_cluster_state[mid].range_end > key) {
           end_index = mid;
-        } else if (entry.weighted_cluster_state[mid].first < key) {
+        } else if (entry.weighted_cluster_state[mid].range_end < key) {
           start_index = mid + 1;
         } else {
           index = mid + 1;
@@ -513,21 +632,56 @@
         }
       }
       if (index == 0) index = start_index;
-      GPR_ASSERT(entry.weighted_cluster_state[index].first > key);
-      cluster_name = entry.weighted_cluster_state[index].second;
+      GPR_ASSERT(entry.weighted_cluster_state[index].range_end > key);
+      cluster_name = entry.weighted_cluster_state[index].cluster;
+      method_config = entry.weighted_cluster_state[index].method_config;
     }
     auto it = clusters_.find(cluster_name);
     GPR_ASSERT(it != clusters_.end());
     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 (entry.method_config != nullptr) {
-      call_config.service_config = entry.method_config;
+    if (method_config != nullptr) {
       call_config.method_configs =
-          entry.method_config->GetMethodParsedConfigVector(grpc_empty_slice());
+          method_config->GetMethodParsedConfigVector(grpc_empty_slice());
+      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(
@@ -541,9 +695,9 @@
           // the data plane mutex.
           DEBUG_LOCATION,
           GRPC_CLOSURE_CREATE(
-              [](void* arg, grpc_error* /*error*/) {
+              [](void* arg, grpc_error_handle /*error*/) {
                 auto* resolver = static_cast<XdsResolver*>(arg);
-                resolver->work_serializer()->Run(
+                resolver->work_serializer_->Run(
                     [resolver]() {
                       resolver->MaybeRemoveUnusedClusters();
                       resolver->Unref();
@@ -563,14 +717,14 @@
 //
 
 void XdsResolver::StartLocked() {
-  grpc_error* error = GRPC_ERROR_NONE;
-  xds_client_ = XdsClient::GetOrCreate(&error);
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  xds_client_ = XdsClient::GetOrCreate(args_, &error);
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "Failed to create xds client -- channel will remain in "
             "TRANSIENT_FAILURE: %s",
-            grpc_error_string(error));
-    result_handler()->ReturnError(error);
+            grpc_error_std_string(error).c_str());
+    result_handler_->ReturnError(error);
     return;
   }
   grpc_pollset_set_add_pollset_set(xds_client_->interested_parties(),
@@ -615,24 +769,34 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
     gpr_log(GPR_INFO, "[xds_resolver %p] received updated listener data", this);
   }
-  if (listener.route_config_name != route_config_name_) {
+  if (listener.http_connection_manager.route_config_name !=
+      route_config_name_) {
     if (route_config_watcher_ != nullptr) {
       xds_client_->CancelRouteConfigDataWatch(
           route_config_name_, route_config_watcher_,
-          /*delay_unsubscription=*/!listener.route_config_name.empty());
+          /*delay_unsubscription=*/
+          !listener.http_connection_manager.route_config_name.empty());
       route_config_watcher_ = nullptr;
     }
-    route_config_name_ = std::move(listener.route_config_name);
+    route_config_name_ =
+        std::move(listener.http_connection_manager.route_config_name);
     if (!route_config_name_.empty()) {
+      current_virtual_host_.routes.clear();
       auto watcher = absl::make_unique<RouteConfigWatcher>(Ref());
       route_config_watcher_ = watcher.get();
       xds_client_->WatchRouteConfigData(route_config_name_, std::move(watcher));
     }
   }
-  http_max_stream_duration_ = listener.http_max_stream_duration;
+  current_listener_ = std::move(listener);
   if (route_config_name_.empty()) {
-    GPR_ASSERT(listener.rds_update.has_value());
-    OnRouteConfigUpdate(std::move(*listener.rds_update));
+    GPR_ASSERT(
+        current_listener_.http_connection_manager.rds_update.has_value());
+    OnRouteConfigUpdate(
+        std::move(*current_listener_.http_connection_manager.rds_update));
+  } else {
+    // HCM may contain newer filter config. We need to propagate the update as
+    // config selector to the channel
+    GenerateResult();
   }
 }
 
@@ -650,19 +814,20 @@
             .c_str()));
     return;
   }
-  // Save the list of routes in the resolver.
-  current_update_ = std::move(vhost->routes);
+  // Save the virtual host in the resolver.
+  current_virtual_host_ = std::move(*vhost);
   // Send a new result to the channel.
   GenerateResult();
 }
 
-void XdsResolver::OnError(grpc_error* error) {
+void XdsResolver::OnError(grpc_error_handle error) {
   gpr_log(GPR_ERROR, "[xds_resolver %p] received error from XdsClient: %s",
-          this, grpc_error_string(error));
+          this, grpc_error_std_string(error).c_str());
   Result result;
-  result.args = grpc_channel_args_copy(args_);
+  grpc_arg new_arg = xds_client_->MakeChannelArg();
+  result.args = grpc_channel_args_copy_and_add(args_, &new_arg, 1);
   result.service_config_error = error;
-  result_handler()->ReturnResult(std::move(result));
+  result_handler_->ReturnResult(std::move(result));
 }
 
 void XdsResolver::OnResourceDoesNotExist() {
@@ -670,16 +835,16 @@
           "[xds_resolver %p] LDS/RDS resource does not exist -- clearing "
           "update and returning empty service config",
           this);
-  current_update_.clear();
+  current_virtual_host_.routes.clear();
   Result result;
   result.service_config =
       ServiceConfig::Create(args_, "{}", &result.service_config_error);
   GPR_ASSERT(result.service_config != nullptr);
   result.args = grpc_channel_args_copy(args_);
-  result_handler()->ReturnResult(std::move(result));
+  result_handler_->ReturnResult(std::move(result));
 }
 
-grpc_error* XdsResolver::CreateServiceConfig(
+grpc_error_handle XdsResolver::CreateServiceConfig(
     RefCountedPtr<ServiceConfig>* service_config) {
   std::vector<std::string> clusters;
   for (const auto& cluster : cluster_state_map_) {
@@ -706,18 +871,17 @@
       "  ]\n"
       "}");
   std::string json = absl::StrJoin(config_parts, "");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   *service_config = ServiceConfig::Create(args_, json.c_str(), &error);
   return error;
 }
 
 void XdsResolver::GenerateResult() {
-  if (current_update_.empty()) return;
+  if (current_virtual_host_.routes.empty()) return;
   // First create XdsConfigSelector, which may add new entries to the cluster
   // state map, and then CreateServiceConfig for LB policies.
-  grpc_error* error = GRPC_ERROR_NONE;
-  auto config_selector =
-      MakeRefCounted<XdsConfigSelector>(Ref(), current_update_, error);
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto config_selector = MakeRefCounted<XdsConfigSelector>(Ref(), &error);
   if (error != GRPC_ERROR_NONE) {
     OnError(error);
     return;
@@ -732,9 +896,13 @@
     gpr_log(GPR_INFO, "[xds_resolver %p] generated service config: %s", this,
             result.service_config->json_string().c_str());
   }
-  grpc_arg new_arg = config_selector->MakeChannelArg();
-  result.args = grpc_channel_args_copy_and_add(args_, &new_arg, 1);
-  result_handler()->ReturnResult(std::move(result));
+  grpc_arg new_args[] = {
+      xds_client_->MakeChannelArg(),
+      config_selector->MakeChannelArg(),
+  };
+  result.args =
+      grpc_channel_args_copy_and_add(args_, new_args, GPR_ARRAY_SIZE(new_args));
+  result_handler_->ReturnResult(std::move(result));
 }
 
 void XdsResolver::MaybeRemoveUnusedClusters() {
diff --git a/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.cc b/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.cc
index 500c740..b0c8eeb 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.cc
+++ b/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.cc
@@ -1,20 +1,18 @@
-/*
- *
- * 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.
- *
- */
+//
+// 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>
 
@@ -63,200 +61,15 @@
 
 namespace {
 
-std::unique_ptr<ClientChannelMethodParsedConfig::RetryPolicy> ParseRetryPolicy(
-    const Json& json, grpc_error** error) {
-  GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
-  auto retry_policy =
-      absl::make_unique<ClientChannelMethodParsedConfig::RetryPolicy>();
-  if (json.type() != Json::Type::OBJECT) {
-    *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryPolicy error:should be of type object");
-    return nullptr;
-  }
-  std::vector<grpc_error*> error_list;
-  // Parse maxAttempts.
-  auto it = json.object_value().find("maxAttempts");
-  if (it != json.object_value().end()) {
-    if (it->second.type() != Json::Type::NUMBER) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:maxAttempts error:should be of type number"));
-    } else {
-      retry_policy->max_attempts =
-          gpr_parse_nonnegative_int(it->second.string_value().c_str());
-      if (retry_policy->max_attempts <= 1) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:maxAttempts error:should be at least 2"));
-      } else if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
-        gpr_log(GPR_ERROR,
-                "service config: clamped retryPolicy.maxAttempts at %d",
-                MAX_MAX_RETRY_ATTEMPTS);
-        retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS;
-      }
-    }
-  }
-  // Parse initialBackoff.
-  if (ParseJsonObjectFieldAsDuration(json.object_value(), "initialBackoff",
-                                     &retry_policy->initial_backoff,
-                                     &error_list) &&
-      retry_policy->initial_backoff == 0) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:initialBackoff error:must be greater than 0"));
-  }
-  // Parse maxBackoff.
-  if (ParseJsonObjectFieldAsDuration(json.object_value(), "maxBackoff",
-                                     &retry_policy->max_backoff, &error_list) &&
-      retry_policy->max_backoff == 0) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:maxBackoff error:should be greater than 0"));
-  }
-  // Parse backoffMultiplier.
-  it = json.object_value().find("backoffMultiplier");
-  if (it != json.object_value().end()) {
-    if (it->second.type() != Json::Type::NUMBER) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:backoffMultiplier error:should be of type number"));
-    } else {
-      if (sscanf(it->second.string_value().c_str(), "%f",
-                 &retry_policy->backoff_multiplier) != 1) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:backoffMultiplier error:failed to parse"));
-      } else if (retry_policy->backoff_multiplier <= 0) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:backoffMultiplier error:should be greater than 0"));
-      }
-    }
-  }
-  // Parse retryableStatusCodes.
-  it = json.object_value().find("retryableStatusCodes");
-  if (it != json.object_value().end()) {
-    if (it->second.type() != Json::Type::ARRAY) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryableStatusCodes error:should be of type array"));
-    } else {
-      for (const Json& element : it->second.array_value()) {
-        if (element.type() != Json::Type::STRING) {
-          error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-              "field:retryableStatusCodes error:status codes should be of type "
-              "string"));
-          continue;
-        }
-        grpc_status_code status;
-        if (!grpc_status_code_from_string(element.string_value().c_str(),
-                                          &status)) {
-          error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-              "field:retryableStatusCodes error:failed to parse status code"));
-          continue;
-        }
-        retry_policy->retryable_status_codes.Add(status);
-      }
-      if (retry_policy->retryable_status_codes.Empty()) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:retryableStatusCodes error:should be non-empty"));
-      };
-    }
-  }
-  // Make sure required fields are set.
-  if (error_list.empty()) {
-    if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 ||
-        retry_policy->max_backoff == 0 ||
-        retry_policy->backoff_multiplier == 0 ||
-        retry_policy->retryable_status_codes.Empty()) {
-      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryPolicy error:Missing required field(s)");
-      return nullptr;
-    }
-  }
-  *error = GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
-  return *error == GRPC_ERROR_NONE ? std::move(retry_policy) : nullptr;
-}
-
-grpc_error* ParseRetryThrottling(
-    const Json& json,
-    ClientChannelGlobalParsedConfig::RetryThrottling* retry_throttling) {
-  if (json.type() != Json::Type::OBJECT) {
-    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling error:Type should be object");
-  }
-  std::vector<grpc_error*> error_list;
-  // Parse maxTokens.
-  auto it = json.object_value().find("maxTokens");
-  if (it == json.object_value().end()) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling field:maxTokens error:Not found"));
-  } else if (it->second.type() != Json::Type::NUMBER) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling field:maxTokens error:Type should be "
-        "number"));
-  } else {
-    retry_throttling->max_milli_tokens =
-        gpr_parse_nonnegative_int(it->second.string_value().c_str()) * 1000;
-    if (retry_throttling->max_milli_tokens <= 0) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryThrottling field:maxTokens error:should be "
-          "greater than zero"));
-    }
-  }
-  // Parse tokenRatio.
-  it = json.object_value().find("tokenRatio");
-  if (it == json.object_value().end()) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling field:tokenRatio error:Not found"));
-  } else if (it->second.type() != Json::Type::NUMBER) {
-    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "field:retryThrottling field:tokenRatio error:type should be "
-        "number"));
-  } else {
-    // We support up to 3 decimal digits.
-    size_t whole_len = it->second.string_value().size();
-    const char* value = it->second.string_value().c_str();
-    uint32_t multiplier = 1;
-    uint32_t decimal_value = 0;
-    const char* decimal_point = strchr(value, '.');
-    if (decimal_point != nullptr) {
-      whole_len = static_cast<size_t>(decimal_point - value);
-      multiplier = 1000;
-      size_t decimal_len = strlen(decimal_point + 1);
-      if (decimal_len > 3) decimal_len = 3;
-      if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
-                                     &decimal_value)) {
-        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "field:retryThrottling field:tokenRatio error:Failed "
-            "parsing"));
-        return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
-      }
-      uint32_t decimal_multiplier = 1;
-      for (size_t i = 0; i < (3 - decimal_len); ++i) {
-        decimal_multiplier *= 10;
-      }
-      decimal_value *= decimal_multiplier;
-    }
-    uint32_t whole_value;
-    if (!gpr_parse_bytes_to_uint32(value, whole_len, &whole_value)) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryThrottling field:tokenRatio error:Failed "
-          "parsing"));
-      return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
-    }
-    retry_throttling->milli_token_ratio =
-        static_cast<int>((whole_value * multiplier) + decimal_value);
-    if (retry_throttling->milli_token_ratio <= 0) {
-      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "field:retryThrottling field:tokenRatio error:value should "
-          "be greater than 0"));
-    }
-  }
-  return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
-}
-
 absl::optional<std::string> ParseHealthCheckConfig(const Json& field,
-                                                   grpc_error** error) {
+                                                   grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
   if (field.type() != Json::Type::OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "field:healthCheckConfig error:should be of type object");
     return absl::nullopt;
   }
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   absl::optional<std::string> service_name;
   auto it = field.object_value().find("serviceName");
   if (it != field.object_value().end()) {
@@ -276,18 +89,19 @@
 
 std::unique_ptr<ServiceConfigParser::ParsedConfig>
 ClientChannelServiceConfigParser::ParseGlobalParams(
-    const grpc_channel_args* /*args*/, const Json& json, grpc_error** error) {
+    const grpc_channel_args* /*args*/, const Json& json,
+    grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   // Parse LB config.
   RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
   auto it = json.object_value().find("loadBalancingConfig");
   if (it != json.object_value().end()) {
-    grpc_error* parse_error = GRPC_ERROR_NONE;
+    grpc_error_handle parse_error = GRPC_ERROR_NONE;
     parsed_lb_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
         it->second, &parse_error);
     if (parsed_lb_config == nullptr) {
-      std::vector<grpc_error*> lb_errors;
+      std::vector<grpc_error_handle> lb_errors;
       lb_errors.push_back(parse_error);
       error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
           "field:loadBalancingConfig", &lb_errors));
@@ -319,24 +133,11 @@
       }
     }
   }
-  // Parse retry throttling.
-  absl::optional<ClientChannelGlobalParsedConfig::RetryThrottling>
-      retry_throttling;
-  it = json.object_value().find("retryThrottling");
-  if (it != json.object_value().end()) {
-    ClientChannelGlobalParsedConfig::RetryThrottling data;
-    grpc_error* parsing_error = ParseRetryThrottling(it->second, &data);
-    if (parsing_error != GRPC_ERROR_NONE) {
-      error_list.push_back(parsing_error);
-    } else {
-      retry_throttling.emplace(data);
-    }
-  }
   // Parse health check config.
   absl::optional<std::string> health_check_service_name;
   it = json.object_value().find("healthCheckConfig");
   if (it != json.object_value().end()) {
-    grpc_error* parsing_error = GRPC_ERROR_NONE;
+    grpc_error_handle parsing_error = GRPC_ERROR_NONE;
     health_check_service_name =
         ParseHealthCheckConfig(it->second, &parsing_error);
     if (parsing_error != GRPC_ERROR_NONE) {
@@ -348,20 +149,19 @@
   if (*error == GRPC_ERROR_NONE) {
     return absl::make_unique<ClientChannelGlobalParsedConfig>(
         std::move(parsed_lb_config), std::move(lb_policy_name),
-        retry_throttling, std::move(health_check_service_name));
+        std::move(health_check_service_name));
   }
   return nullptr;
 }
 
 std::unique_ptr<ServiceConfigParser::ParsedConfig>
 ClientChannelServiceConfigParser::ParsePerMethodParams(
-    const grpc_channel_args* /*args*/, const Json& json, grpc_error** error) {
+    const grpc_channel_args* /*args*/, const Json& json,
+    grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
-  std::vector<grpc_error*> error_list;
-  absl::optional<bool> wait_for_ready;
-  grpc_millis timeout = 0;
-  std::unique_ptr<ClientChannelMethodParsedConfig::RetryPolicy> retry_policy;
+  std::vector<grpc_error_handle> error_list;
   // Parse waitForReady.
+  absl::optional<bool> wait_for_ready;
   auto it = json.object_value().find("waitForReady");
   if (it != json.object_value().end()) {
     if (it->second.type() == Json::Type::JSON_TRUE) {
@@ -374,21 +174,14 @@
     }
   }
   // Parse timeout.
+  grpc_millis timeout = 0;
   ParseJsonObjectFieldAsDuration(json.object_value(), "timeout", &timeout,
                                  &error_list, false);
-  // Parse retry policy.
-  it = json.object_value().find("retryPolicy");
-  if (it != json.object_value().end()) {
-    grpc_error* error = GRPC_ERROR_NONE;
-    retry_policy = ParseRetryPolicy(it->second, &error);
-    if (retry_policy == nullptr) {
-      error_list.push_back(error);
-    }
-  }
+  // Return result.
   *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list);
   if (*error == GRPC_ERROR_NONE) {
-    return absl::make_unique<ClientChannelMethodParsedConfig>(
-        timeout, wait_for_ready, std::move(retry_policy));
+    return absl::make_unique<ClientChannelMethodParsedConfig>(timeout,
+                                                              wait_for_ready);
   }
   return nullptr;
 }
diff --git a/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.h b/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.h
index cdf89d3..b70068e 100644
--- a/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.h
+++ b/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.h
@@ -1,20 +1,18 @@
-/*
- *
- * 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.
- *
- */
+//
+// 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_RESOLVER_RESULT_PARSING_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H
@@ -26,7 +24,6 @@
 #include "src/core/ext/filters/client_channel/lb_policy.h"
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/ext/filters/client_channel/resolver.h"
-#include "src/core/ext/filters/client_channel/retry_throttle.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gprpp/ref_counted.h"
@@ -40,19 +37,12 @@
 class ClientChannelGlobalParsedConfig
     : public ServiceConfigParser::ParsedConfig {
  public:
-  struct RetryThrottling {
-    intptr_t max_milli_tokens = 0;
-    intptr_t milli_token_ratio = 0;
-  };
-
   ClientChannelGlobalParsedConfig(
       RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config,
       std::string parsed_deprecated_lb_policy,
-      const absl::optional<RetryThrottling>& retry_throttling,
       absl::optional<std::string> health_check_service_name)
       : parsed_lb_config_(std::move(parsed_lb_config)),
         parsed_deprecated_lb_policy_(std::move(parsed_deprecated_lb_policy)),
-        retry_throttling_(retry_throttling),
         health_check_service_name_(std::move(health_check_service_name)) {}
 
   RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config() const {
@@ -63,10 +53,6 @@
     return parsed_deprecated_lb_policy_;
   }
 
-  absl::optional<RetryThrottling> retry_throttling() const {
-    return retry_throttling_;
-  }
-
   const absl::optional<std::string>& health_check_service_name() const {
     return health_check_service_name_;
   }
@@ -74,49 +60,34 @@
  private:
   RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_;
   std::string parsed_deprecated_lb_policy_;
-  absl::optional<RetryThrottling> retry_throttling_;
   absl::optional<std::string> health_check_service_name_;
 };
 
 class ClientChannelMethodParsedConfig
     : public ServiceConfigParser::ParsedConfig {
  public:
-  struct RetryPolicy {
-    int max_attempts = 0;
-    grpc_millis initial_backoff = 0;
-    grpc_millis max_backoff = 0;
-    float backoff_multiplier = 0;
-    StatusCodeSet retryable_status_codes;
-  };
-
   ClientChannelMethodParsedConfig(grpc_millis timeout,
-                                  const absl::optional<bool>& wait_for_ready,
-                                  std::unique_ptr<RetryPolicy> retry_policy)
-      : timeout_(timeout),
-        wait_for_ready_(wait_for_ready),
-        retry_policy_(std::move(retry_policy)) {}
+                                  const absl::optional<bool>& wait_for_ready)
+      : timeout_(timeout), wait_for_ready_(wait_for_ready) {}
 
   grpc_millis timeout() const { return timeout_; }
 
   absl::optional<bool> wait_for_ready() const { return wait_for_ready_; }
 
-  const RetryPolicy* retry_policy() const { return retry_policy_.get(); }
-
  private:
   grpc_millis timeout_ = 0;
   absl::optional<bool> wait_for_ready_;
-  std::unique_ptr<RetryPolicy> retry_policy_;
 };
 
 class ClientChannelServiceConfigParser : public ServiceConfigParser::Parser {
  public:
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
       const grpc_channel_args* /*args*/, const Json& json,
-      grpc_error** error) override;
+      grpc_error_handle* error) override;
 
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
       const grpc_channel_args* /*args*/, const Json& json,
-      grpc_error** error) override;
+      grpc_error_handle* error) override;
 
   static size_t ParserIndex();
   static void Register();
@@ -125,4 +96,4 @@
 }  // namespace internal
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H */
+#endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H
diff --git a/grpc/src/core/ext/filters/client_channel/retry_filter.cc b/grpc/src/core/ext/filters/client_channel/retry_filter.cc
new file mode 100644
index 0000000..a03d2da
--- /dev/null
+++ b/grpc/src/core/ext/filters/client_channel/retry_filter.cc
@@ -0,0 +1,2188 @@
+//
+// Copyright 2015 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>
+
+#include "src/core/ext/filters/client_channel/retry_filter.h"
+
+#include "absl/container/inlined_vector.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/strip.h"
+
+#include <grpc/support/log.h>
+
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/retry_service_config.h"
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/ext/filters/client_channel/service_config_call_data.h"
+#include "src/core/lib/backoff/backoff.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/transport/error_utils.h"
+#include "src/core/lib/transport/metadata.h"
+#include "src/core/lib/transport/metadata_batch.h"
+#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/status_metadata.h"
+#include "src/core/lib/uri/uri_parser.h"
+
+//
+// Retry filter
+//
+
+// This filter is intended to be used in the DynamicFilter stack in the
+// client channel, which is situated between the name resolver and the
+// LB policy.  Normally, the last filter in the DynamicFilter stack is
+// the DynamicTerminationFilter (see client_channel.cc), which creates a
+// LoadBalancedCall and delegates to it.  However, when retries are
+// enabled, this filter is used instead of the DynamicTerminationFilter.
+//
+// In order to support retries, we act as a proxy for stream op batches.
+// When we get a batch from the surface, we add it to our list of pending
+// batches, and we then use those batches to construct separate "child"
+// batches to be started on an LB call.  When the child batches return, we
+// then decide which pending batches have been completed and schedule their
+// callbacks accordingly.  If a call attempt fails and we want to retry it,
+// we create a new LB call and start again, constructing new "child" batches
+// for the new LB call.
+//
+// Note that retries are committed when receiving data from the server
+// (except for Trailers-Only responses).  However, there may be many
+// send ops started before receiving any data, so we may have already
+// completed some number of send ops (and returned the completions up to
+// the surface) by the time we realize that we need to retry.  To deal
+// with this, we cache data for send ops, so that we can replay them on a
+// different LB call even after we have completed the original batches.
+//
+// The code is structured as follows:
+// - In CallData (in the parent channel), we maintain a list of pending
+//   ops and cached data for send ops.
+// - There is a CallData::CallAttempt object for each retry attempt.
+//   This object contains the LB call for that attempt and state to indicate
+//   which ops from the CallData object have already been sent down to that
+//   LB call.
+// - There is a CallData::CallAttempt::BatchData object for each "child"
+//   batch sent on the LB call.
+//
+// When constructing the "child" batches, we compare the state in the
+// CallAttempt object against the state in the CallData object to see
+// which batches need to be sent on the LB call for a given attempt.
+
+// TODO(roth): In subsequent PRs:
+// - add support for transparent retries (including initial metadata)
+// - figure out how to record stats in census for retries
+//   (census filter is on top of this one)
+// - add census stats for retries
+
+// By default, we buffer 256 KiB per RPC for retries.
+// TODO(roth): Do we have any data to suggest a better value?
+#define DEFAULT_PER_RPC_RETRY_BUFFER_SIZE (256 << 10)
+
+// This value was picked arbitrarily.  It can be changed if there is
+// any even moderately compelling reason to do so.
+#define RETRY_BACKOFF_JITTER 0.2
+
+namespace grpc_core {
+
+namespace {
+
+using internal::RetryGlobalConfig;
+using internal::RetryMethodConfig;
+using internal::RetryServiceConfigParser;
+using internal::ServerRetryThrottleData;
+
+TraceFlag grpc_retry_trace(false, "retry");
+
+//
+// RetryFilter
+//
+
+class RetryFilter {
+ public:
+  class CallData;
+
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args) {
+    GPR_ASSERT(args->is_last);
+    GPR_ASSERT(elem->filter == &kRetryFilterVtable);
+    grpc_error_handle error = GRPC_ERROR_NONE;
+    new (elem->channel_data) RetryFilter(args->channel_args, &error);
+    return error;
+  }
+
+  static void Destroy(grpc_channel_element* elem) {
+    auto* chand = static_cast<RetryFilter*>(elem->channel_data);
+    chand->~RetryFilter();
+  }
+
+  // Will never be called.
+  static void StartTransportOp(grpc_channel_element* /*elem*/,
+                               grpc_transport_op* /*op*/) {}
+  static void GetChannelInfo(grpc_channel_element* /*elem*/,
+                             const grpc_channel_info* /*info*/) {}
+
+ private:
+  static size_t GetMaxPerRpcRetryBufferSize(const grpc_channel_args* args) {
+    return static_cast<size_t>(grpc_channel_args_find_integer(
+        args, GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE,
+        {DEFAULT_PER_RPC_RETRY_BUFFER_SIZE, 0, INT_MAX}));
+  }
+
+  RetryFilter(const grpc_channel_args* args, grpc_error_handle* error)
+      : client_channel_(grpc_channel_args_find_pointer<ClientChannel>(
+            args, GRPC_ARG_CLIENT_CHANNEL)),
+        per_rpc_retry_buffer_size_(GetMaxPerRpcRetryBufferSize(args)) {
+    // Get retry throttling parameters from service config.
+    auto* service_config = grpc_channel_args_find_pointer<ServiceConfig>(
+        args, GRPC_ARG_SERVICE_CONFIG_OBJ);
+    if (service_config == nullptr) return;
+    const auto* config = static_cast<const RetryGlobalConfig*>(
+        service_config->GetGlobalParsedConfig(
+            RetryServiceConfigParser::ParserIndex()));
+    if (config == nullptr) return;
+    // Get server name from target URI.
+    const char* server_uri =
+        grpc_channel_args_find_string(args, GRPC_ARG_SERVER_URI);
+    if (server_uri == nullptr) {
+      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "server URI channel arg missing or wrong type in client channel "
+          "filter");
+      return;
+    }
+    absl::StatusOr<URI> uri = URI::Parse(server_uri);
+    if (!uri.ok() || uri->path().empty()) {
+      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "could not extract server name from target URI");
+      return;
+    }
+    std::string server_name(absl::StripPrefix(uri->path(), "/"));
+    // Get throttling config for server_name.
+    retry_throttle_data_ = internal::ServerRetryThrottleMap::GetDataForServer(
+        server_name, config->max_milli_tokens(), config->milli_token_ratio());
+  }
+
+  ClientChannel* client_channel_;
+  size_t per_rpc_retry_buffer_size_;
+  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
+};
+
+//
+// RetryFilter::CallData
+//
+
+class RetryFilter::CallData {
+ public:
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args);
+  static void Destroy(grpc_call_element* elem,
+                      const grpc_call_final_info* /*final_info*/,
+                      grpc_closure* then_schedule_closure);
+  static void StartTransportStreamOpBatch(
+      grpc_call_element* elem, grpc_transport_stream_op_batch* batch);
+  static void SetPollent(grpc_call_element* elem, grpc_polling_entity* pollent);
+
+ private:
+  class Canceller;
+  class CallStackDestructionBarrier;
+
+  // Pending batches stored in call data.
+  struct PendingBatch {
+    // The pending batch.  If nullptr, this slot is empty.
+    grpc_transport_stream_op_batch* batch = nullptr;
+    // Indicates whether payload for send ops has been cached in CallData.
+    bool send_ops_cached = false;
+  };
+
+  // State associated with each call attempt.
+  // Allocated on the arena.
+  class CallAttempt
+      : public RefCounted<CallAttempt, PolymorphicRefCount, kUnrefCallDtor> {
+   public:
+    explicit CallAttempt(CallData* calld);
+
+    ClientChannel::LoadBalancedCall* lb_call() const { return lb_call_.get(); }
+
+    // Constructs and starts whatever batches are needed on this call
+    // attempt.
+    void StartRetriableBatches();
+
+    // Frees cached send ops that have already been completed after
+    // committing the call.
+    void FreeCachedSendOpDataAfterCommit();
+
+   private:
+    // State used for starting a retryable batch on the call attempt's LB call.
+    // This provides its own grpc_transport_stream_op_batch and other data
+    // structures needed to populate the ops in the batch.
+    // We allocate one struct on the arena for each attempt at starting a
+    // batch on a given LB call.
+    class BatchData
+        : public RefCounted<CallAttempt, PolymorphicRefCount, kUnrefCallDtor> {
+     public:
+      BatchData(RefCountedPtr<CallAttempt> call_attempt, int refcount,
+                bool set_on_complete);
+      ~BatchData() override;
+
+      grpc_transport_stream_op_batch* batch() { return &batch_; }
+
+      // Adds retriable send_initial_metadata op to batch_data.
+      void AddRetriableSendInitialMetadataOp();
+      // Adds retriable send_message op to batch_data.
+      void AddRetriableSendMessageOp();
+      // Adds retriable send_trailing_metadata op to batch_data.
+      void AddRetriableSendTrailingMetadataOp();
+      // Adds retriable recv_initial_metadata op to batch_data.
+      void AddRetriableRecvInitialMetadataOp();
+      // Adds retriable recv_message op to batch_data.
+      void AddRetriableRecvMessageOp();
+      // Adds retriable recv_trailing_metadata op to batch_data.
+      void AddRetriableRecvTrailingMetadataOp();
+
+     private:
+      // Returns true if the call is being retried.
+      bool MaybeRetry(grpc_status_code status, grpc_mdelem* server_pushback_md,
+                      bool is_lb_drop);
+
+      // Frees cached send ops that were completed by the completed batch in
+      // batch_data.  Used when batches are completed after the call is
+      // committed.
+      void FreeCachedSendOpDataForCompletedBatch();
+
+      // Invokes recv_initial_metadata_ready for a batch.
+      static void InvokeRecvInitialMetadataCallback(void* arg,
+                                                    grpc_error_handle error);
+      // Intercepts recv_initial_metadata_ready callback for retries.
+      // Commits the call and returns the initial metadata up the stack.
+      static void RecvInitialMetadataReady(void* arg, grpc_error_handle error);
+
+      // Invokes recv_message_ready for a batch.
+      static void InvokeRecvMessageCallback(void* arg, grpc_error_handle error);
+      // Intercepts recv_message_ready callback for retries.
+      // Commits the call and returns the message up the stack.
+      static void RecvMessageReady(void* arg, grpc_error_handle error);
+
+      // Adds recv_trailing_metadata_ready closure to closures.
+      void AddClosureForRecvTrailingMetadataReady(
+          grpc_error_handle error, CallCombinerClosureList* closures);
+      // Adds any necessary closures for deferred recv_initial_metadata and
+      // recv_message callbacks to closures.
+      void AddClosuresForDeferredRecvCallbacks(
+          CallCombinerClosureList* closures);
+      // For any pending batch containing an op that has not yet been started,
+      // adds the pending batch's completion closures to closures.
+      void AddClosuresToFailUnstartedPendingBatches(
+          grpc_error_handle error, CallCombinerClosureList* closures);
+      // Runs necessary closures upon completion of a call attempt.
+      void RunClosuresForCompletedCall(grpc_error_handle error);
+      // Intercepts recv_trailing_metadata_ready callback for retries.
+      // Commits the call and returns the trailing metadata up the stack.
+      static void RecvTrailingMetadataReady(void* arg, grpc_error_handle error);
+
+      // Adds the on_complete closure for the pending batch completed in
+      // batch_data to closures.
+      void AddClosuresForCompletedPendingBatch(
+          grpc_error_handle error, CallCombinerClosureList* closures);
+
+      // If there are any cached ops to replay or pending ops to start on the
+      // LB call, adds them to closures.
+      void AddClosuresForReplayOrPendingSendOps(
+          CallCombinerClosureList* closures);
+
+      // Callback used to intercept on_complete from LB calls.
+      static void OnComplete(void* arg, grpc_error_handle error);
+
+      RefCountedPtr<CallAttempt> call_attempt_;
+      // The batch to use in the LB call.
+      // Its payload field points to CallAttempt::batch_payload_.
+      grpc_transport_stream_op_batch batch_;
+      // For intercepting on_complete.
+      grpc_closure on_complete_;
+    };
+
+    // Creates a BatchData object on the call's arena with the
+    // specified refcount.  If set_on_complete is true, the batch's
+    // on_complete callback will be set to point to on_complete();
+    // otherwise, the batch's on_complete callback will be null.
+    BatchData* CreateBatch(int refcount, bool set_on_complete) {
+      return calld_->arena_->New<BatchData>(Ref(), refcount, set_on_complete);
+    }
+
+    // If there are any cached send ops that need to be replayed on this
+    // call attempt, creates and returns a new batch to replay those ops.
+    // Otherwise, returns nullptr.
+    BatchData* MaybeCreateBatchForReplay();
+
+    // Adds batches for pending batches to closures.
+    void AddBatchesForPendingBatches(CallCombinerClosureList* closures);
+
+    // Adds whatever batches are needed on this attempt to closures.
+    void AddRetriableBatches(CallCombinerClosureList* closures);
+
+    // Returns true if any op in the batch was not yet started on this attempt.
+    bool PendingBatchIsUnstarted(PendingBatch* pending);
+
+    // Helper function used to start a recv_trailing_metadata batch.  This
+    // is used in the case where a recv_initial_metadata or recv_message
+    // op fails in a way that we know the call is over but when the application
+    // has not yet started its own recv_trailing_metadata op.
+    void StartInternalRecvTrailingMetadata();
+
+    CallData* calld_;
+    RefCountedPtr<ClientChannel::LoadBalancedCall> lb_call_;
+
+    // BatchData.batch.payload points to this.
+    grpc_transport_stream_op_batch_payload batch_payload_;
+    // For send_initial_metadata.
+    // Note that we need to make a copy of the initial metadata for each
+    // call attempt instead of just referring to the copy in call_data,
+    // because filters in the subchannel stack may modify the metadata,
+    // so we need to start in a pristine state for each attempt of the call.
+    grpc_linked_mdelem* send_initial_metadata_storage_;
+    grpc_metadata_batch send_initial_metadata_;
+    // For send_message.
+    // TODO(roth): Restructure this to eliminate use of ManualConstructor.
+    ManualConstructor<ByteStreamCache::CachingByteStream> send_message_;
+    // For send_trailing_metadata.
+    grpc_linked_mdelem* send_trailing_metadata_storage_;
+    grpc_metadata_batch send_trailing_metadata_;
+    // For intercepting recv_initial_metadata.
+    grpc_metadata_batch recv_initial_metadata_;
+    grpc_closure recv_initial_metadata_ready_;
+    bool trailing_metadata_available_ = false;
+    // For intercepting recv_message.
+    grpc_closure recv_message_ready_;
+    OrphanablePtr<ByteStream> recv_message_;
+    // For intercepting recv_trailing_metadata.
+    grpc_metadata_batch recv_trailing_metadata_;
+    grpc_transport_stream_stats collect_stats_;
+    grpc_closure recv_trailing_metadata_ready_;
+    // These fields indicate which ops have been started and completed on
+    // this call attempt.
+    size_t started_send_message_count_ = 0;
+    size_t completed_send_message_count_ = 0;
+    size_t started_recv_message_count_ = 0;
+    size_t completed_recv_message_count_ = 0;
+    bool started_send_initial_metadata_ : 1;
+    bool completed_send_initial_metadata_ : 1;
+    bool started_send_trailing_metadata_ : 1;
+    bool completed_send_trailing_metadata_ : 1;
+    bool started_recv_initial_metadata_ : 1;
+    bool completed_recv_initial_metadata_ : 1;
+    bool started_recv_trailing_metadata_ : 1;
+    bool completed_recv_trailing_metadata_ : 1;
+    // State for callback processing.
+    BatchData* recv_initial_metadata_ready_deferred_batch_ = nullptr;
+    grpc_error_handle recv_initial_metadata_error_ = GRPC_ERROR_NONE;
+    BatchData* recv_message_ready_deferred_batch_ = nullptr;
+    grpc_error_handle recv_message_error_ = GRPC_ERROR_NONE;
+    BatchData* recv_trailing_metadata_internal_batch_ = nullptr;
+    // NOTE: Do not move this next to the metadata bitfields above. That would
+    //       save space but will also result in a data race because compiler
+    //       will generate a 2 byte store which overwrites the meta-data
+    //       fields upon setting this field.
+    bool retry_dispatched_ : 1;
+  };
+
+  CallData(RetryFilter* chand, const grpc_call_element_args& args);
+  ~CallData();
+
+  void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
+
+  // Returns the index into pending_batches_ to be used for batch.
+  static size_t GetBatchIndex(grpc_transport_stream_op_batch* batch);
+  PendingBatch* PendingBatchesAdd(grpc_transport_stream_op_batch* batch);
+  void PendingBatchClear(PendingBatch* pending);
+  void MaybeClearPendingBatch(PendingBatch* pending);
+  static void FailPendingBatchInCallCombiner(void* arg,
+                                             grpc_error_handle error);
+  // Fails all pending batches.  Does NOT yield call combiner.
+  void PendingBatchesFail(grpc_error_handle error);
+  // Returns a pointer to the first pending batch for which predicate(batch)
+  // returns true, or null if not found.
+  template <typename Predicate>
+  PendingBatch* PendingBatchFind(const char* log_message, Predicate predicate);
+
+  // Caches data for send ops so that it can be retried later, if not
+  // already cached.
+  void MaybeCacheSendOpsForBatch(PendingBatch* pending);
+  void FreeCachedSendInitialMetadata();
+  // Frees cached send_message at index idx.
+  void FreeCachedSendMessage(size_t idx);
+  void FreeCachedSendTrailingMetadata();
+  void FreeAllCachedSendOpData();
+
+  // Commits the call so that no further retry attempts will be performed.
+  void RetryCommit(CallAttempt* call_attempt);
+
+  // Starts a retry after appropriate back-off.
+  void DoRetry(grpc_millis server_pushback_ms);
+  static void OnRetryTimer(void* arg, grpc_error_handle error);
+
+  RefCountedPtr<ClientChannel::LoadBalancedCall> CreateLoadBalancedCall();
+
+  void CreateCallAttempt();
+
+  // Adds a closure to closures that will execute batch in the call combiner.
+  void AddClosureForBatch(grpc_transport_stream_op_batch* batch,
+                          CallCombinerClosureList* closures);
+
+  RetryFilter* chand_;
+  grpc_polling_entity* pollent_;
+  RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
+  const RetryMethodConfig* retry_policy_ = nullptr;
+  BackOff retry_backoff_;
+
+  grpc_slice path_;  // Request path.
+  gpr_cycle_counter call_start_time_;
+  grpc_millis deadline_;
+  Arena* arena_;
+  grpc_call_stack* owning_call_;
+  CallCombiner* call_combiner_;
+  grpc_call_context_element* call_context_;
+
+  RefCountedPtr<CallStackDestructionBarrier> call_stack_destruction_barrier_;
+
+  // TODO(roth): As part of implementing hedging, we will need to maintain a
+  // list of all pending attempts, so that we can cancel them all if the call
+  // gets cancelled.
+  RefCountedPtr<CallAttempt> call_attempt_;
+
+  // LB call used when the call is commited before any CallAttempt is
+  // created.
+  // TODO(roth): Change CallAttempt logic such that once we've committed
+  // and all cached send ops have been replayed, we move the LB call
+  // from the CallAttempt here, thus creating a fast path for the
+  // remainder of the streaming call.
+  RefCountedPtr<ClientChannel::LoadBalancedCall> committed_call_;
+
+  // When are are not yet fully committed to a particular call (i.e.,
+  // either we might still retry or we have committed to the call but
+  // there are still some cached ops to be replayed on the call),
+  // batches received from above will be added to this list, and they
+  // will not be removed until we have invoked their completion callbacks.
+  size_t bytes_buffered_for_retry_ = 0;
+  PendingBatch pending_batches_[MAX_PENDING_BATCHES];
+  bool pending_send_initial_metadata_ : 1;
+  bool pending_send_message_ : 1;
+  bool pending_send_trailing_metadata_ : 1;
+
+  // Retry state.
+  bool retry_committed_ : 1;
+  bool last_attempt_got_server_pushback_ : 1;
+  int num_attempts_completed_ = 0;
+  Mutex timer_mu_;
+  Canceller* canceller_ ABSL_GUARDED_BY(timer_mu_);
+  grpc_timer retry_timer_ ABSL_GUARDED_BY(timer_mu_);
+  grpc_closure retry_closure_;
+
+  // The number of batches containing send ops that are currently in-flight
+  // on any call attempt.
+  // We hold a ref to the call stack while this is non-zero, since replay
+  // batches may not complete until after all callbacks have been returned
+  // to the surface, and we need to make sure that the call is not destroyed
+  // until all of these batches have completed.
+  // Note that we actually only need to track replay batches, but it's
+  // easier to track all batches with send ops.
+  int num_in_flight_call_attempt_send_batches_ = 0;
+
+  // Cached data for retrying send ops.
+  // send_initial_metadata
+  bool seen_send_initial_metadata_ = false;
+  grpc_linked_mdelem* send_initial_metadata_storage_ = nullptr;
+  grpc_metadata_batch send_initial_metadata_;
+  uint32_t send_initial_metadata_flags_;
+  // TODO(roth): As part of implementing hedging, we'll probably need to
+  // have the LB call set a value in CallAttempt and then propagate it
+  // from CallAttempt to the parent call when we commit.  Otherwise, we
+  // may leave this with a value for a peer other than the one we
+  // actually commit to.
+  gpr_atm* peer_string_;
+  // send_message
+  // When we get a send_message op, we replace the original byte stream
+  // with a CachingByteStream that caches the slices to a local buffer for
+  // use in retries.
+  // Note: We inline the cache for the first 3 send_message ops and use
+  // dynamic allocation after that.  This number was essentially picked
+  // at random; it could be changed in the future to tune performance.
+  absl::InlinedVector<ByteStreamCache*, 3> send_messages_;
+  // send_trailing_metadata
+  bool seen_send_trailing_metadata_ = false;
+  grpc_linked_mdelem* send_trailing_metadata_storage_ = nullptr;
+  grpc_metadata_batch send_trailing_metadata_;
+};
+
+//
+// RetryFilter::CallData::CallStackDestructionBarrier
+//
+
+// A class to track the existence of LoadBalancedCall call stacks that
+// we've created.  We wait until all such call stacks have been
+// destroyed before we return the on_call_stack_destruction closure up
+// to the surface.
+//
+// The parent RetryFilter::CallData object holds a ref to this object.
+// When it is destroyed, it will store the on_call_stack_destruction
+// closure from the surface in this object and then release its ref.
+// We also take a ref to this object for each LB call we create, and
+// those refs are not released until the LB call stack is destroyed.
+// When this object is destroyed, it will invoke the
+// on_call_stack_destruction closure from the surface.
+class RetryFilter::CallData::CallStackDestructionBarrier
+    : public RefCounted<CallStackDestructionBarrier, PolymorphicRefCount,
+                        kUnrefCallDtor> {
+ public:
+  CallStackDestructionBarrier() {}
+
+  ~CallStackDestructionBarrier() override {
+    // TODO(yashkt) : This can potentially be a Closure::Run
+    ExecCtx::Run(DEBUG_LOCATION, on_call_stack_destruction_, GRPC_ERROR_NONE);
+  }
+
+  // Set the closure from the surface.  This closure will be invoked
+  // when this object is destroyed.
+  void set_on_call_stack_destruction(grpc_closure* on_call_stack_destruction) {
+    on_call_stack_destruction_ = on_call_stack_destruction;
+  }
+
+  // Invoked to get an on_call_stack_destruction closure for a new LB call.
+  grpc_closure* MakeLbCallDestructionClosure(CallData* calld) {
+    Ref().release();  // Ref held by callback.
+    grpc_closure* on_lb_call_destruction_complete =
+        calld->arena_->New<grpc_closure>();
+    GRPC_CLOSURE_INIT(on_lb_call_destruction_complete,
+                      OnLbCallDestructionComplete, this, nullptr);
+    return on_lb_call_destruction_complete;
+  }
+
+ private:
+  static void OnLbCallDestructionComplete(void* arg,
+                                          grpc_error_handle /*error*/) {
+    auto* self = static_cast<CallStackDestructionBarrier*>(arg);
+    self->Unref();
+  }
+
+  grpc_closure* on_call_stack_destruction_ = nullptr;
+};
+
+//
+// RetryFilter::CallData::Canceller
+//
+
+class RetryFilter::CallData::Canceller {
+ public:
+  explicit Canceller(CallData* calld) : calld_(calld) {
+    GRPC_CALL_STACK_REF(calld_->owning_call_, "RetryCanceller");
+    GRPC_CLOSURE_INIT(&closure_, &Cancel, this, nullptr);
+    calld_->call_combiner_->SetNotifyOnCancel(&closure_);
+  }
+
+ private:
+  static void Cancel(void* arg, grpc_error_handle error) {
+    auto* self = static_cast<Canceller*>(arg);
+    auto* calld = self->calld_;
+    {
+      MutexLock lock(&calld->timer_mu_);
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "calld=%p: cancelling retry timer: error=%s self=%p "
+                "calld->canceller_=%p",
+                calld, grpc_error_std_string(error).c_str(), self,
+                calld->canceller_);
+      }
+      if (calld->canceller_ == self && error != GRPC_ERROR_NONE) {
+        calld->canceller_ = nullptr;  // Checked by OnRetryTimer().
+        grpc_timer_cancel(&calld->retry_timer_);
+        calld->FreeAllCachedSendOpData();
+        GRPC_CALL_COMBINER_STOP(calld->call_combiner_, "Canceller");
+      }
+    }
+    GRPC_CALL_STACK_UNREF(calld->owning_call_, "RetryCanceller");
+    delete self;
+  }
+
+  CallData* calld_;
+  grpc_closure closure_;
+};
+
+//
+// RetryFilter::CallData::CallAttempt
+//
+
+RetryFilter::CallData::CallAttempt::CallAttempt(CallData* calld)
+    : calld_(calld),
+      batch_payload_(calld->call_context_),
+      started_send_initial_metadata_(false),
+      completed_send_initial_metadata_(false),
+      started_send_trailing_metadata_(false),
+      completed_send_trailing_metadata_(false),
+      started_recv_initial_metadata_(false),
+      completed_recv_initial_metadata_(false),
+      started_recv_trailing_metadata_(false),
+      completed_recv_trailing_metadata_(false),
+      retry_dispatched_(false) {
+  lb_call_ = calld->CreateLoadBalancedCall();
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: attempt=%p: create lb_call=%p",
+            calld->chand_, calld, this, lb_call_.get());
+  }
+}
+
+void RetryFilter::CallData::CallAttempt::FreeCachedSendOpDataAfterCommit() {
+  // TODO(roth): When we implement hedging, this logic will need to get
+  // a bit more complex, because there may be other (now abandoned) call
+  // attempts still using this data.  We may need to do some sort of
+  // ref-counting instead.
+  if (completed_send_initial_metadata_) {
+    calld_->FreeCachedSendInitialMetadata();
+  }
+  for (size_t i = 0; i < completed_send_message_count_; ++i) {
+    calld_->FreeCachedSendMessage(i);
+  }
+  if (completed_send_trailing_metadata_) {
+    calld_->FreeCachedSendTrailingMetadata();
+  }
+}
+
+bool RetryFilter::CallData::CallAttempt::PendingBatchIsUnstarted(
+    PendingBatch* pending) {
+  // Only look at batches containing send ops, since batches containing
+  // only recv ops are always started immediately.
+  if (pending->batch == nullptr || pending->batch->on_complete == nullptr) {
+    return false;
+  }
+  if (pending->batch->send_initial_metadata &&
+      !started_send_initial_metadata_) {
+    return true;
+  }
+  if (pending->batch->send_message &&
+      started_send_message_count_ < calld_->send_messages_.size()) {
+    return true;
+  }
+  if (pending->batch->send_trailing_metadata &&
+      !started_send_trailing_metadata_) {
+    return true;
+  }
+  return false;
+}
+
+void RetryFilter::CallData::CallAttempt::StartInternalRecvTrailingMetadata() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: call failed but recv_trailing_metadata not "
+            "started; starting it internally",
+            calld_->chand_, calld_);
+  }
+  // Create batch_data with 2 refs, since this batch will be unreffed twice:
+  // once for the recv_trailing_metadata_ready callback when the batch
+  // completes, and again when we actually get a recv_trailing_metadata
+  // op from the surface.
+  BatchData* batch_data = CreateBatch(2, false /* set_on_complete */);
+  batch_data->AddRetriableRecvTrailingMetadataOp();
+  recv_trailing_metadata_internal_batch_ = batch_data;
+  // Note: This will release the call combiner.
+  lb_call_->StartTransportStreamOpBatch(batch_data->batch());
+}
+
+// If there are any cached send ops that need to be replayed on the
+// current call attempt, creates and returns a new batch to replay those ops.
+// Otherwise, returns nullptr.
+RetryFilter::CallData::CallAttempt::BatchData*
+RetryFilter::CallData::CallAttempt::MaybeCreateBatchForReplay() {
+  BatchData* replay_batch_data = nullptr;
+  // send_initial_metadata.
+  if (calld_->seen_send_initial_metadata_ && !started_send_initial_metadata_ &&
+      !calld_->pending_send_initial_metadata_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_initial_metadata op",
+              calld_->chand_, calld_);
+    }
+    replay_batch_data = CreateBatch(1, true /* set_on_complete */);
+    replay_batch_data->AddRetriableSendInitialMetadataOp();
+  }
+  // send_message.
+  // Note that we can only have one send_message op in flight at a time.
+  if (started_send_message_count_ < calld_->send_messages_.size() &&
+      started_send_message_count_ == completed_send_message_count_ &&
+      !calld_->pending_send_message_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_message op",
+              calld_->chand_, calld_);
+    }
+    if (replay_batch_data == nullptr) {
+      replay_batch_data = CreateBatch(1, true /* set_on_complete */);
+    }
+    replay_batch_data->AddRetriableSendMessageOp();
+  }
+  // send_trailing_metadata.
+  // Note that we only add this op if we have no more send_message ops
+  // to start, since we can't send down any more send_message ops after
+  // send_trailing_metadata.
+  if (calld_->seen_send_trailing_metadata_ &&
+      started_send_message_count_ == calld_->send_messages_.size() &&
+      !started_send_trailing_metadata_ &&
+      !calld_->pending_send_trailing_metadata_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_trailing_metadata op",
+              calld_->chand_, calld_);
+    }
+    if (replay_batch_data == nullptr) {
+      replay_batch_data = CreateBatch(1, true /* set_on_complete */);
+    }
+    replay_batch_data->AddRetriableSendTrailingMetadataOp();
+  }
+  return replay_batch_data;
+}
+
+void RetryFilter::CallData::CallAttempt::AddBatchesForPendingBatches(
+    CallCombinerClosureList* closures) {
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld_->pending_batches_); ++i) {
+    PendingBatch* pending = &calld_->pending_batches_[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch == nullptr) continue;
+    // Skip any batch that either (a) has already been started on this
+    // call attempt or (b) we can't start yet because we're still
+    // replaying send ops that need to be completed first.
+    // TODO(roth): Note that if any one op in the batch can't be sent
+    // yet due to ops that we're replaying, we don't start any of the ops
+    // in the batch.  This is probably okay, but it could conceivably
+    // lead to increased latency in some cases -- e.g., we could delay
+    // starting a recv op due to it being in the same batch with a send
+    // op.  If/when we revamp the callback protocol in
+    // transport_stream_op_batch, we may be able to fix this.
+    if (batch->send_initial_metadata && started_send_initial_metadata_) {
+      continue;
+    }
+    if (batch->send_message &&
+        completed_send_message_count_ < started_send_message_count_) {
+      continue;
+    }
+    // Note that we only start send_trailing_metadata if we have no more
+    // send_message ops to start, since we can't send down any more
+    // send_message ops after send_trailing_metadata.
+    if (batch->send_trailing_metadata &&
+        (started_send_message_count_ + batch->send_message <
+             calld_->send_messages_.size() ||
+         started_send_trailing_metadata_)) {
+      continue;
+    }
+    if (batch->recv_initial_metadata && started_recv_initial_metadata_) {
+      continue;
+    }
+    if (batch->recv_message &&
+        completed_recv_message_count_ < started_recv_message_count_) {
+      continue;
+    }
+    if (batch->recv_trailing_metadata && started_recv_trailing_metadata_) {
+      // If we previously completed a recv_trailing_metadata op
+      // initiated by StartInternalRecvTrailingMetadata(), use the
+      // result of that instead of trying to re-start this op.
+      if (GPR_UNLIKELY(recv_trailing_metadata_internal_batch_ != nullptr)) {
+        // If the batch completed, then trigger the completion callback
+        // directly, so that we return the previously returned results to
+        // the application.  Otherwise, just unref the internally started
+        // batch, since we'll propagate the completion when it completes.
+        if (completed_recv_trailing_metadata_) {
+          // Batches containing recv_trailing_metadata always succeed.
+          closures->Add(
+              &recv_trailing_metadata_ready_, GRPC_ERROR_NONE,
+              "re-executing recv_trailing_metadata_ready to propagate "
+              "internally triggered result");
+        } else {
+          recv_trailing_metadata_internal_batch_->Unref();
+        }
+        recv_trailing_metadata_internal_batch_ = nullptr;
+      }
+      continue;
+    }
+    // If we're already committed, just send the batch as-is.
+    if (calld_->retry_committed_) {
+      calld_->AddClosureForBatch(batch, closures);
+      calld_->PendingBatchClear(pending);
+      continue;
+    }
+    // Create batch with the right number of callbacks.
+    const bool has_send_ops = batch->send_initial_metadata ||
+                              batch->send_message ||
+                              batch->send_trailing_metadata;
+    const int num_callbacks = has_send_ops + batch->recv_initial_metadata +
+                              batch->recv_message +
+                              batch->recv_trailing_metadata;
+    CallAttempt::BatchData* batch_data =
+        CreateBatch(num_callbacks, has_send_ops /* set_on_complete */);
+    // Cache send ops if needed.
+    calld_->MaybeCacheSendOpsForBatch(pending);
+    // send_initial_metadata.
+    if (batch->send_initial_metadata) {
+      batch_data->AddRetriableSendInitialMetadataOp();
+    }
+    // send_message.
+    if (batch->send_message) {
+      batch_data->AddRetriableSendMessageOp();
+    }
+    // send_trailing_metadata.
+    if (batch->send_trailing_metadata) {
+      batch_data->AddRetriableSendTrailingMetadataOp();
+    }
+    // recv_initial_metadata.
+    if (batch->recv_initial_metadata) {
+      // recv_flags is only used on the server side.
+      GPR_ASSERT(batch->payload->recv_initial_metadata.recv_flags == nullptr);
+      batch_data->AddRetriableRecvInitialMetadataOp();
+    }
+    // recv_message.
+    if (batch->recv_message) {
+      batch_data->AddRetriableRecvMessageOp();
+    }
+    // recv_trailing_metadata.
+    if (batch->recv_trailing_metadata) {
+      batch_data->AddRetriableRecvTrailingMetadataOp();
+    }
+    calld_->AddClosureForBatch(batch_data->batch(), closures);
+    // Track number of in-flight send batches.
+    // If this is the first one, take a ref to the call stack.
+    if (batch->send_initial_metadata || batch->send_message ||
+        batch->send_trailing_metadata) {
+      if (calld_->num_in_flight_call_attempt_send_batches_ == 0) {
+        GRPC_CALL_STACK_REF(calld_->owning_call_, "retriable_send_batches");
+      }
+      ++calld_->num_in_flight_call_attempt_send_batches_;
+    }
+  }
+}
+
+void RetryFilter::CallData::CallAttempt::AddRetriableBatches(
+    CallCombinerClosureList* closures) {
+  // Replay previously-returned send_* ops if needed.
+  BatchData* replay_batch_data = MaybeCreateBatchForReplay();
+  if (replay_batch_data != nullptr) {
+    calld_->AddClosureForBatch(replay_batch_data->batch(), closures);
+    // Track number of pending send batches.
+    // If this is the first one, take a ref to the call stack.
+    if (calld_->num_in_flight_call_attempt_send_batches_ == 0) {
+      GRPC_CALL_STACK_REF(calld_->owning_call_, "retriable_send_batches");
+    }
+    ++calld_->num_in_flight_call_attempt_send_batches_;
+  }
+  // Now add pending batches.
+  AddBatchesForPendingBatches(closures);
+}
+
+void RetryFilter::CallData::CallAttempt::StartRetriableBatches() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: constructing retriable batches",
+            calld_->chand_, calld_);
+  }
+  // Construct list of closures to execute, one for each pending batch.
+  CallCombinerClosureList closures;
+  AddRetriableBatches(&closures);
+  // Note: This will yield the call combiner.
+  // Start batches on LB call.
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: starting %" PRIuPTR
+            " retriable batches on lb_call=%p",
+            calld_->chand_, calld_, closures.size(), lb_call());
+  }
+  closures.RunClosures(calld_->call_combiner_);
+}
+
+//
+// RetryFilter::CallData::CallAttempt::BatchData
+//
+
+RetryFilter::CallData::CallAttempt::BatchData::BatchData(
+    RefCountedPtr<CallAttempt> attempt, int refcount, bool set_on_complete)
+    : RefCounted(nullptr, refcount), call_attempt_(std::move(attempt)) {
+  // TODO(roth): Consider holding this ref on the call stack in
+  // CallAttempt instead of here in BatchData.  This would eliminate the
+  // need for CallData::num_in_flight_call_attempt_send_batches_.
+  // But it would require having a way to unref CallAttempt when it is
+  // no longer needed (i.e., when the call is committed and all cached
+  // send ops have been replayed and the LB call is moved into
+  // CallData::committed_call_).
+  GRPC_CALL_STACK_REF(call_attempt_->calld_->owning_call_, "CallAttempt");
+  batch_.payload = &call_attempt_->batch_payload_;
+  if (set_on_complete) {
+    GRPC_CLOSURE_INIT(&on_complete_, OnComplete, this,
+                      grpc_schedule_on_exec_ctx);
+    batch_.on_complete = &on_complete_;
+  }
+}
+
+RetryFilter::CallData::CallAttempt::BatchData::~BatchData() {
+  if (batch_.send_initial_metadata) {
+    grpc_metadata_batch_destroy(&call_attempt_->send_initial_metadata_);
+  }
+  if (batch_.send_trailing_metadata) {
+    grpc_metadata_batch_destroy(&call_attempt_->send_trailing_metadata_);
+  }
+  if (batch_.recv_initial_metadata) {
+    grpc_metadata_batch_destroy(&call_attempt_->recv_initial_metadata_);
+  }
+  if (batch_.recv_trailing_metadata) {
+    grpc_metadata_batch_destroy(&call_attempt_->recv_trailing_metadata_);
+  }
+  GRPC_CALL_STACK_UNREF(call_attempt_->calld_->owning_call_, "CallAttempt");
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    FreeCachedSendOpDataForCompletedBatch() {
+  auto* calld = call_attempt_->calld_;
+  // TODO(roth): When we implement hedging, this logic will need to get
+  // a bit more complex, because there may be other (now abandoned) call
+  // attempts still using this data.  We may need to do some sort of
+  // ref-counting instead.
+  if (batch_.send_initial_metadata) {
+    calld->FreeCachedSendInitialMetadata();
+  }
+  if (batch_.send_message) {
+    calld->FreeCachedSendMessage(call_attempt_->completed_send_message_count_ -
+                                 1);
+  }
+  if (batch_.send_trailing_metadata) {
+    calld->FreeCachedSendTrailingMetadata();
+  }
+}
+
+bool RetryFilter::CallData::CallAttempt::BatchData::MaybeRetry(
+    grpc_status_code status, grpc_mdelem* server_pushback_md, bool is_lb_drop) {
+  auto* calld = call_attempt_->calld_;
+  // LB drops always inhibit retries.
+  if (is_lb_drop) return false;
+  // Get retry policy.
+  if (calld->retry_policy_ == nullptr) return false;
+  // If we've already dispatched a retry from this call, return true.
+  // This catches the case where the batch has multiple callbacks
+  // (i.e., it includes either recv_message or recv_initial_metadata).
+  if (call_attempt_->retry_dispatched_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: retry already dispatched",
+              calld->chand_, calld);
+    }
+    return true;
+  }
+  // Check status.
+  if (GPR_LIKELY(status == GRPC_STATUS_OK)) {
+    if (calld->retry_throttle_data_ != nullptr) {
+      calld->retry_throttle_data_->RecordSuccess();
+    }
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: call succeeded", calld->chand_,
+              calld);
+    }
+    return false;
+  }
+  // Status is not OK.  Check whether the status is retryable.
+  if (!calld->retry_policy_->retryable_status_codes().Contains(status)) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: status %s not configured as retryable",
+              calld->chand_, calld, grpc_status_code_to_string(status));
+    }
+    return false;
+  }
+  // Record the failure and check whether retries are throttled.
+  // Note that it's important for this check to come after the status
+  // code check above, since we should only record failures whose statuses
+  // match the configured retryable status codes, so that we don't count
+  // things like failures due to malformed requests (INVALID_ARGUMENT).
+  // Conversely, it's important for this to come before the remaining
+  // checks, so that we don't fail to record failures due to other factors.
+  if (calld->retry_throttle_data_ != nullptr &&
+      !calld->retry_throttle_data_->RecordFailure()) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: retries throttled", calld->chand_,
+              calld);
+    }
+    return false;
+  }
+  // Check whether the call is committed.
+  if (calld->retry_committed_) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: retries already committed",
+              calld->chand_, calld);
+    }
+    return false;
+  }
+  // Check whether we have retries remaining.
+  ++calld->num_attempts_completed_;
+  if (calld->num_attempts_completed_ >= calld->retry_policy_->max_attempts()) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: exceeded %d retry attempts",
+              calld->chand_, calld, calld->retry_policy_->max_attempts());
+    }
+    return false;
+  }
+  // Check server push-back.
+  grpc_millis server_pushback_ms = -1;
+  if (server_pushback_md != nullptr) {
+    // If the value is "-1" or any other unparseable string, we do not retry.
+    uint32_t ms;
+    if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(*server_pushback_md), &ms)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: not retrying due to server push-back",
+                calld->chand_, calld);
+      }
+      return false;
+    } else {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO, "chand=%p calld=%p: server push-back: retry in %u ms",
+                calld->chand_, calld, ms);
+      }
+      server_pushback_ms = static_cast<grpc_millis>(ms);
+    }
+  }
+  // Do retry.
+  call_attempt_->retry_dispatched_ = true;
+  calld->DoRetry(server_pushback_ms);
+  return true;
+}
+
+//
+// recv_initial_metadata callback handling
+//
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    InvokeRecvInitialMetadataCallback(void* arg, grpc_error_handle error) {
+  auto* batch_data = static_cast<CallAttempt::BatchData*>(arg);
+  auto* call_attempt = batch_data->call_attempt_.get();
+  // Find pending batch.
+  PendingBatch* pending = call_attempt->calld_->PendingBatchFind(
+      "invoking recv_initial_metadata_ready for",
+      [](grpc_transport_stream_op_batch* batch) {
+        return batch->recv_initial_metadata &&
+               batch->payload->recv_initial_metadata
+                       .recv_initial_metadata_ready != nullptr;
+      });
+  GPR_ASSERT(pending != nullptr);
+  // Return metadata.
+  grpc_metadata_batch_move(
+      &call_attempt->recv_initial_metadata_,
+      pending->batch->payload->recv_initial_metadata.recv_initial_metadata);
+  // Update bookkeeping.
+  // Note: Need to do this before invoking the callback, since invoking
+  // the callback will result in yielding the call combiner.
+  grpc_closure* recv_initial_metadata_ready =
+      pending->batch->payload->recv_initial_metadata
+          .recv_initial_metadata_ready;
+  pending->batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
+      nullptr;
+  call_attempt->calld_->MaybeClearPendingBatch(pending);
+  batch_data->Unref();
+  // Invoke callback.
+  Closure::Run(DEBUG_LOCATION, recv_initial_metadata_ready,
+               GRPC_ERROR_REF(error));
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::RecvInitialMetadataReady(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: got recv_initial_metadata_ready, error=%s",
+            calld->chand_, calld, grpc_error_std_string(error).c_str());
+  }
+  call_attempt->completed_recv_initial_metadata_ = true;
+  // If a retry was already dispatched, then we're not going to use the
+  // result of this recv_initial_metadata op, so do nothing.
+  if (call_attempt->retry_dispatched_) {
+    GRPC_CALL_COMBINER_STOP(
+        calld->call_combiner_,
+        "recv_initial_metadata_ready after retry dispatched");
+    return;
+  }
+  if (!calld->retry_committed_) {
+    // If we got an error or a Trailers-Only response and have not yet gotten
+    // the recv_trailing_metadata_ready callback, then defer propagating this
+    // callback back to the surface.  We can evaluate whether to retry when
+    // recv_trailing_metadata comes back.
+    if (GPR_UNLIKELY((call_attempt->trailing_metadata_available_ ||
+                      error != GRPC_ERROR_NONE) &&
+                     !call_attempt->completed_recv_trailing_metadata_)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: deferring recv_initial_metadata_ready "
+                "(Trailers-Only)",
+                calld->chand_, calld);
+      }
+      call_attempt->recv_initial_metadata_ready_deferred_batch_ = batch_data;
+      call_attempt->recv_initial_metadata_error_ = GRPC_ERROR_REF(error);
+      if (!call_attempt->started_recv_trailing_metadata_) {
+        // recv_trailing_metadata not yet started by application; start it
+        // ourselves to get status.
+        call_attempt->StartInternalRecvTrailingMetadata();
+      } else {
+        GRPC_CALL_COMBINER_STOP(
+            calld->call_combiner_,
+            "recv_initial_metadata_ready trailers-only or error");
+      }
+      return;
+    }
+    // Received valid initial metadata, so commit the call.
+    calld->RetryCommit(call_attempt);
+  }
+  // Invoke the callback to return the result to the surface.
+  // Manually invoking a callback function; it does not take ownership of error.
+  InvokeRecvInitialMetadataCallback(batch_data, error);
+}
+
+//
+// recv_message callback handling
+//
+
+void RetryFilter::CallData::CallAttempt::BatchData::InvokeRecvMessageCallback(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  // Find pending op.
+  PendingBatch* pending = calld->PendingBatchFind(
+      "invoking recv_message_ready for",
+      [](grpc_transport_stream_op_batch* batch) {
+        return batch->recv_message &&
+               batch->payload->recv_message.recv_message_ready != nullptr;
+      });
+  GPR_ASSERT(pending != nullptr);
+  // Return payload.
+  *pending->batch->payload->recv_message.recv_message =
+      std::move(call_attempt->recv_message_);
+  // Update bookkeeping.
+  // Note: Need to do this before invoking the callback, since invoking
+  // the callback will result in yielding the call combiner.
+  grpc_closure* recv_message_ready =
+      pending->batch->payload->recv_message.recv_message_ready;
+  pending->batch->payload->recv_message.recv_message_ready = nullptr;
+  calld->MaybeClearPendingBatch(pending);
+  batch_data->Unref();
+  // Invoke callback.
+  Closure::Run(DEBUG_LOCATION, recv_message_ready, GRPC_ERROR_REF(error));
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::RecvMessageReady(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: got recv_message_ready, error=%s",
+            calld->chand_, calld, grpc_error_std_string(error).c_str());
+  }
+  ++call_attempt->completed_recv_message_count_;
+  // If a retry was already dispatched, then we're not going to use the
+  // result of this recv_message op, so do nothing.
+  if (call_attempt->retry_dispatched_) {
+    GRPC_CALL_COMBINER_STOP(calld->call_combiner_,
+                            "recv_message_ready after retry dispatched");
+    return;
+  }
+  if (!calld->retry_committed_) {
+    // If we got an error or the payload was nullptr and we have not yet gotten
+    // the recv_trailing_metadata_ready callback, then defer propagating this
+    // callback back to the surface.  We can evaluate whether to retry when
+    // recv_trailing_metadata comes back.
+    if (GPR_UNLIKELY((call_attempt->recv_message_ == nullptr ||
+                      error != GRPC_ERROR_NONE) &&
+                     !call_attempt->completed_recv_trailing_metadata_)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: deferring recv_message_ready (nullptr "
+                "message and recv_trailing_metadata pending)",
+                calld->chand_, calld);
+      }
+      call_attempt->recv_message_ready_deferred_batch_ = batch_data;
+      call_attempt->recv_message_error_ = GRPC_ERROR_REF(error);
+      if (!call_attempt->started_recv_trailing_metadata_) {
+        // recv_trailing_metadata not yet started by application; start it
+        // ourselves to get status.
+        call_attempt->StartInternalRecvTrailingMetadata();
+      } else {
+        GRPC_CALL_COMBINER_STOP(calld->call_combiner_,
+                                "recv_message_ready null");
+      }
+      return;
+    }
+    // Received a valid message, so commit the call.
+    calld->RetryCommit(call_attempt);
+  }
+  // Invoke the callback to return the result to the surface.
+  // Manually invoking a callback function; it does not take ownership of error.
+  InvokeRecvMessageCallback(batch_data, error);
+}
+
+//
+// recv_trailing_metadata handling
+//
+
+namespace {
+
+// Sets *status, *server_pushback_md, and *is_lb_drop based on md_batch
+// and error.
+void GetCallStatus(grpc_millis deadline, grpc_metadata_batch* md_batch,
+                   grpc_error_handle error, grpc_status_code* status,
+                   grpc_mdelem** server_pushback_md, bool* is_lb_drop) {
+  if (error != GRPC_ERROR_NONE) {
+    grpc_error_get_status(error, deadline, status, nullptr, nullptr, nullptr);
+    intptr_t value = 0;
+    if (grpc_error_get_int(error, GRPC_ERROR_INT_LB_POLICY_DROP, &value) &&
+        value != 0) {
+      *is_lb_drop = true;
+    }
+  } else {
+    GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
+    *status =
+        grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
+    if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
+      *server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+}  // namespace
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosureForRecvTrailingMetadataReady(grpc_error_handle error,
+                                           CallCombinerClosureList* closures) {
+  auto* calld = call_attempt_->calld_;
+  // Find pending batch.
+  PendingBatch* pending = calld->PendingBatchFind(
+      "invoking recv_trailing_metadata for",
+      [](grpc_transport_stream_op_batch* batch) {
+        return batch->recv_trailing_metadata &&
+               batch->payload->recv_trailing_metadata
+                       .recv_trailing_metadata_ready != nullptr;
+      });
+  // If we generated the recv_trailing_metadata op internally via
+  // StartInternalRecvTrailingMetadata(), then there will be no pending batch.
+  if (pending == nullptr) {
+    GRPC_ERROR_UNREF(error);
+    return;
+  }
+  // Return metadata.
+  grpc_metadata_batch_move(
+      &call_attempt_->recv_trailing_metadata_,
+      pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata);
+  // Add closure.
+  closures->Add(pending->batch->payload->recv_trailing_metadata
+                    .recv_trailing_metadata_ready,
+                error, "recv_trailing_metadata_ready for pending batch");
+  // Update bookkeeping.
+  pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+      nullptr;
+  calld->MaybeClearPendingBatch(pending);
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosuresForDeferredRecvCallbacks(CallCombinerClosureList* closures) {
+  if (batch_.recv_trailing_metadata) {
+    // Add closure for deferred recv_initial_metadata_ready.
+    if (GPR_UNLIKELY(
+            call_attempt_->recv_initial_metadata_ready_deferred_batch_ !=
+            nullptr)) {
+      GRPC_CLOSURE_INIT(
+          &call_attempt_->recv_initial_metadata_ready_,
+          InvokeRecvInitialMetadataCallback,
+          call_attempt_->recv_initial_metadata_ready_deferred_batch_,
+          grpc_schedule_on_exec_ctx);
+      closures->Add(&call_attempt_->recv_initial_metadata_ready_,
+                    call_attempt_->recv_initial_metadata_error_,
+                    "resuming recv_initial_metadata_ready");
+      call_attempt_->recv_initial_metadata_ready_deferred_batch_ = nullptr;
+    }
+    // Add closure for deferred recv_message_ready.
+    if (GPR_UNLIKELY(call_attempt_->recv_message_ready_deferred_batch_ !=
+                     nullptr)) {
+      GRPC_CLOSURE_INIT(&call_attempt_->recv_message_ready_,
+                        InvokeRecvMessageCallback,
+                        call_attempt_->recv_message_ready_deferred_batch_,
+                        grpc_schedule_on_exec_ctx);
+      closures->Add(&call_attempt_->recv_message_ready_,
+                    call_attempt_->recv_message_error_,
+                    "resuming recv_message_ready");
+      call_attempt_->recv_message_ready_deferred_batch_ = nullptr;
+    }
+  }
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosuresToFailUnstartedPendingBatches(
+        grpc_error_handle error, CallCombinerClosureList* closures) {
+  auto* calld = call_attempt_->calld_;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches_); ++i) {
+    PendingBatch* pending = &calld->pending_batches_[i];
+    if (call_attempt_->PendingBatchIsUnstarted(pending)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: failing unstarted pending batch at "
+                "index %" PRIuPTR,
+                calld->chand_, calld, i);
+      }
+      closures->Add(pending->batch->on_complete, GRPC_ERROR_REF(error),
+                    "failing on_complete for pending batch");
+      pending->batch->on_complete = nullptr;
+      calld->MaybeClearPendingBatch(pending);
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::RunClosuresForCompletedCall(
+    grpc_error_handle error) {
+  // Construct list of closures to execute.
+  CallCombinerClosureList closures;
+  // First, add closure for recv_trailing_metadata_ready.
+  AddClosureForRecvTrailingMetadataReady(GRPC_ERROR_REF(error), &closures);
+  // If there are deferred recv_initial_metadata_ready or recv_message_ready
+  // callbacks, add them to closures.
+  AddClosuresForDeferredRecvCallbacks(&closures);
+  // Add closures to fail any pending batches that have not yet been started.
+  AddClosuresToFailUnstartedPendingBatches(GRPC_ERROR_REF(error), &closures);
+  // Schedule all of the closures identified above.
+  // Note: This will release the call combiner.
+  closures.RunClosures(call_attempt_->calld_->call_combiner_);
+  // Don't need batch_data anymore.
+  Unref();
+  GRPC_ERROR_UNREF(error);
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::RecvTrailingMetadataReady(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: got recv_trailing_metadata_ready, error=%s",
+            calld->chand_, calld, grpc_error_std_string(error).c_str());
+  }
+  call_attempt->completed_recv_trailing_metadata_ = true;
+  // Get the call's status and check for server pushback metadata.
+  grpc_status_code status = GRPC_STATUS_OK;
+  grpc_mdelem* server_pushback_md = nullptr;
+  grpc_metadata_batch* md_batch =
+      batch_data->batch_.payload->recv_trailing_metadata.recv_trailing_metadata;
+  bool is_lb_drop = false;
+  GetCallStatus(calld->deadline_, md_batch, GRPC_ERROR_REF(error), &status,
+                &server_pushback_md, &is_lb_drop);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(
+        GPR_INFO, "chand=%p calld=%p: call finished, status=%s is_lb_drop=%d",
+        calld->chand_, calld, grpc_status_code_to_string(status), is_lb_drop);
+  }
+  // Check if we should retry.
+  if (batch_data->MaybeRetry(status, server_pushback_md, is_lb_drop)) {
+    // Unref batch_data for deferred recv_initial_metadata_ready or
+    // recv_message_ready callbacks, if any.
+    if (call_attempt->recv_initial_metadata_ready_deferred_batch_ != nullptr) {
+      GRPC_ERROR_UNREF(call_attempt->recv_initial_metadata_error_);
+      batch_data->Unref();
+    }
+    if (call_attempt->recv_message_ready_deferred_batch_ != nullptr) {
+      GRPC_ERROR_UNREF(call_attempt->recv_message_error_);
+      batch_data->Unref();
+    }
+    batch_data->Unref();
+    return;
+  }
+  // Not retrying, so commit the call.
+  calld->RetryCommit(call_attempt);
+  // Run any necessary closures.
+  batch_data->RunClosuresForCompletedCall(GRPC_ERROR_REF(error));
+}
+
+//
+// on_complete callback handling
+//
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosuresForCompletedPendingBatch(grpc_error_handle error,
+                                        CallCombinerClosureList* closures) {
+  auto* calld = call_attempt_->calld_;
+  PendingBatch* pending = calld->PendingBatchFind(
+      "completed", [this](grpc_transport_stream_op_batch* batch) {
+        // Match the pending batch with the same set of send ops as the
+        // batch we've just completed.
+        return batch->on_complete != nullptr &&
+               batch_.send_initial_metadata == batch->send_initial_metadata &&
+               batch_.send_message == batch->send_message &&
+               batch_.send_trailing_metadata == batch->send_trailing_metadata;
+      });
+  // If batch_data is a replay batch, then there will be no pending
+  // batch to complete.
+  if (pending == nullptr) {
+    GRPC_ERROR_UNREF(error);
+    return;
+  }
+  // Add closure.
+  closures->Add(pending->batch->on_complete, error,
+                "on_complete for pending batch");
+  pending->batch->on_complete = nullptr;
+  calld->MaybeClearPendingBatch(pending);
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddClosuresForReplayOrPendingSendOps(CallCombinerClosureList* closures) {
+  auto* calld = call_attempt_->calld_;
+  // We don't check send_initial_metadata here, because that op will always
+  // be started as soon as it is received from the surface, so it will
+  // never need to be started at this point.
+  bool have_pending_send_message_ops =
+      call_attempt_->started_send_message_count_ < calld->send_messages_.size();
+  bool have_pending_send_trailing_metadata_op =
+      calld->seen_send_trailing_metadata_ &&
+      !call_attempt_->started_send_trailing_metadata_;
+  if (!have_pending_send_message_ops &&
+      !have_pending_send_trailing_metadata_op) {
+    for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches_); ++i) {
+      PendingBatch* pending = &calld->pending_batches_[i];
+      grpc_transport_stream_op_batch* batch = pending->batch;
+      if (batch == nullptr || pending->send_ops_cached) continue;
+      if (batch->send_message) have_pending_send_message_ops = true;
+      if (batch->send_trailing_metadata) {
+        have_pending_send_trailing_metadata_op = true;
+      }
+    }
+  }
+  if (have_pending_send_message_ops || have_pending_send_trailing_metadata_op) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: starting next batch for pending send op(s)",
+              calld->chand_, calld);
+    }
+    call_attempt_->AddRetriableBatches(closures);
+  }
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::OnComplete(
+    void* arg, grpc_error_handle error) {
+  CallAttempt::BatchData* batch_data =
+      static_cast<CallAttempt::BatchData*>(arg);
+  CallAttempt* call_attempt = batch_data->call_attempt_.get();
+  CallData* calld = call_attempt->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: got on_complete, error=%s, batch=%s",
+            calld->chand_, calld, grpc_error_std_string(error).c_str(),
+            grpc_transport_stream_op_batch_string(&batch_data->batch_).c_str());
+  }
+  // Update bookkeeping in call_attempt.
+  if (batch_data->batch_.send_initial_metadata) {
+    call_attempt->completed_send_initial_metadata_ = true;
+  }
+  if (batch_data->batch_.send_message) {
+    ++call_attempt->completed_send_message_count_;
+  }
+  if (batch_data->batch_.send_trailing_metadata) {
+    call_attempt->completed_send_trailing_metadata_ = true;
+  }
+  // If the call is committed, free cached data for send ops that we've just
+  // completed.
+  if (calld->retry_committed_) {
+    batch_data->FreeCachedSendOpDataForCompletedBatch();
+  }
+  // Construct list of closures to execute.
+  CallCombinerClosureList closures;
+  // If a retry was already dispatched, that means we saw
+  // recv_trailing_metadata before this, so we do nothing here.
+  // Otherwise, invoke the callback to return the result to the surface.
+  if (!call_attempt->retry_dispatched_) {
+    // Add closure for the completed pending batch, if any.
+    batch_data->AddClosuresForCompletedPendingBatch(GRPC_ERROR_REF(error),
+                                                    &closures);
+    // If needed, add a callback to start any replay or pending send ops on
+    // the LB call.
+    if (!call_attempt->completed_recv_trailing_metadata_) {
+      batch_data->AddClosuresForReplayOrPendingSendOps(&closures);
+    }
+  }
+  // Track number of in-flight send batches and determine if this was the
+  // last one.
+  --calld->num_in_flight_call_attempt_send_batches_;
+  const bool last_send_batch_complete =
+      calld->num_in_flight_call_attempt_send_batches_ == 0;
+  // Don't need batch_data anymore.
+  batch_data->Unref();
+  // Schedule all of the closures identified above.
+  // Note: This yields the call combiner.
+  closures.RunClosures(calld->call_combiner_);
+  // If this was the last in-flight send batch, unref the call stack.
+  if (last_send_batch_complete) {
+    GRPC_CALL_STACK_UNREF(calld->owning_call_, "retriable_send_batches");
+  }
+}
+
+//
+// retriable batch construction
+//
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableSendInitialMetadataOp() {
+  auto* calld = call_attempt_->calld_;
+  // Maps the number of retries to the corresponding metadata value slice.
+  const grpc_slice* retry_count_strings[] = {&GRPC_MDSTR_1, &GRPC_MDSTR_2,
+                                             &GRPC_MDSTR_3, &GRPC_MDSTR_4};
+  // We need to make a copy of the metadata batch for each attempt, since
+  // the filters in the subchannel stack may modify this batch, and we don't
+  // want those modifications to be passed forward to subsequent attempts.
+  //
+  // If we've already completed one or more attempts, add the
+  // grpc-retry-attempts header.
+  call_attempt_->send_initial_metadata_storage_ =
+      static_cast<grpc_linked_mdelem*>(
+          calld->arena_->Alloc(sizeof(grpc_linked_mdelem) *
+                               (calld->send_initial_metadata_.list.count +
+                                (calld->num_attempts_completed_ > 0))));
+  grpc_metadata_batch_copy(&calld->send_initial_metadata_,
+                           &call_attempt_->send_initial_metadata_,
+                           call_attempt_->send_initial_metadata_storage_);
+  if (GPR_UNLIKELY(call_attempt_->send_initial_metadata_.idx.named
+                       .grpc_previous_rpc_attempts != nullptr)) {
+    grpc_metadata_batch_remove(&call_attempt_->send_initial_metadata_,
+                               GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS);
+  }
+  if (GPR_UNLIKELY(calld->num_attempts_completed_ > 0)) {
+    grpc_mdelem retry_md = grpc_mdelem_create(
+        GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
+        *retry_count_strings[calld->num_attempts_completed_ - 1], nullptr);
+    grpc_error_handle error = grpc_metadata_batch_add_tail(
+        &call_attempt_->send_initial_metadata_,
+        &call_attempt_->send_initial_metadata_storage_
+             [calld->send_initial_metadata_.list.count],
+        retry_md, GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS);
+    if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
+      gpr_log(GPR_ERROR, "error adding retry metadata: %s",
+              grpc_error_std_string(error).c_str());
+      GPR_ASSERT(false);
+    }
+  }
+  call_attempt_->started_send_initial_metadata_ = true;
+  batch_.send_initial_metadata = true;
+  batch_.payload->send_initial_metadata.send_initial_metadata =
+      &call_attempt_->send_initial_metadata_;
+  batch_.payload->send_initial_metadata.send_initial_metadata_flags =
+      calld->send_initial_metadata_flags_;
+  batch_.payload->send_initial_metadata.peer_string = calld->peer_string_;
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableSendMessageOp() {
+  auto* calld = call_attempt_->calld_;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: starting calld->send_messages[%" PRIuPTR "]",
+            calld->chand_, calld, call_attempt_->started_send_message_count_);
+  }
+  ByteStreamCache* cache =
+      calld->send_messages_[call_attempt_->started_send_message_count_];
+  ++call_attempt_->started_send_message_count_;
+  call_attempt_->send_message_.Init(cache);
+  batch_.send_message = true;
+  batch_.payload->send_message.send_message.reset(
+      call_attempt_->send_message_.get());
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableSendTrailingMetadataOp() {
+  auto* calld = call_attempt_->calld_;
+  // We need to make a copy of the metadata batch for each attempt, since
+  // the filters in the subchannel stack may modify this batch, and we don't
+  // want those modifications to be passed forward to subsequent attempts.
+  call_attempt_->send_trailing_metadata_storage_ =
+      static_cast<grpc_linked_mdelem*>(
+          calld->arena_->Alloc(sizeof(grpc_linked_mdelem) *
+                               calld->send_trailing_metadata_.list.count));
+  grpc_metadata_batch_copy(&calld->send_trailing_metadata_,
+                           &call_attempt_->send_trailing_metadata_,
+                           call_attempt_->send_trailing_metadata_storage_);
+  call_attempt_->started_send_trailing_metadata_ = true;
+  batch_.send_trailing_metadata = true;
+  batch_.payload->send_trailing_metadata.send_trailing_metadata =
+      &call_attempt_->send_trailing_metadata_;
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableRecvInitialMetadataOp() {
+  call_attempt_->started_recv_initial_metadata_ = true;
+  batch_.recv_initial_metadata = true;
+  grpc_metadata_batch_init(&call_attempt_->recv_initial_metadata_);
+  batch_.payload->recv_initial_metadata.recv_initial_metadata =
+      &call_attempt_->recv_initial_metadata_;
+  batch_.payload->recv_initial_metadata.trailing_metadata_available =
+      &call_attempt_->trailing_metadata_available_;
+  GRPC_CLOSURE_INIT(&call_attempt_->recv_initial_metadata_ready_,
+                    RecvInitialMetadataReady, this, grpc_schedule_on_exec_ctx);
+  batch_.payload->recv_initial_metadata.recv_initial_metadata_ready =
+      &call_attempt_->recv_initial_metadata_ready_;
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableRecvMessageOp() {
+  ++call_attempt_->started_recv_message_count_;
+  batch_.recv_message = true;
+  batch_.payload->recv_message.recv_message = &call_attempt_->recv_message_;
+  GRPC_CLOSURE_INIT(&call_attempt_->recv_message_ready_, RecvMessageReady, this,
+                    grpc_schedule_on_exec_ctx);
+  batch_.payload->recv_message.recv_message_ready =
+      &call_attempt_->recv_message_ready_;
+}
+
+void RetryFilter::CallData::CallAttempt::BatchData::
+    AddRetriableRecvTrailingMetadataOp() {
+  call_attempt_->started_recv_trailing_metadata_ = true;
+  batch_.recv_trailing_metadata = true;
+  grpc_metadata_batch_init(&call_attempt_->recv_trailing_metadata_);
+  batch_.payload->recv_trailing_metadata.recv_trailing_metadata =
+      &call_attempt_->recv_trailing_metadata_;
+  batch_.payload->recv_trailing_metadata.collect_stats =
+      &call_attempt_->collect_stats_;
+  GRPC_CLOSURE_INIT(&call_attempt_->recv_trailing_metadata_ready_,
+                    RecvTrailingMetadataReady, this, grpc_schedule_on_exec_ctx);
+  batch_.payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+      &call_attempt_->recv_trailing_metadata_ready_;
+}
+
+//
+// CallData vtable functions
+//
+
+grpc_error_handle RetryFilter::CallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
+  auto* chand = static_cast<RetryFilter*>(elem->channel_data);
+  new (elem->call_data) CallData(chand, *args);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p: created call=%p", chand, elem->call_data);
+  }
+  return GRPC_ERROR_NONE;
+}
+
+void RetryFilter::CallData::Destroy(grpc_call_element* elem,
+                                    const grpc_call_final_info* /*final_info*/,
+                                    grpc_closure* then_schedule_closure) {
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  // Save our ref to the CallStackDestructionBarrier until after our
+  // dtor is invoked.
+  RefCountedPtr<CallStackDestructionBarrier> call_stack_destruction_barrier =
+      std::move(calld->call_stack_destruction_barrier_);
+  calld->~CallData();
+  // Now set the callback in the CallStackDestructionBarrier object,
+  // right before we release our ref to it (implicitly upon returning).
+  // The callback will be invoked when the CallStackDestructionBarrier
+  // is destroyed.
+  call_stack_destruction_barrier->set_on_call_stack_destruction(
+      then_schedule_closure);
+}
+
+void RetryFilter::CallData::StartTransportStreamOpBatch(
+    grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  calld->StartTransportStreamOpBatch(batch);
+}
+
+void RetryFilter::CallData::SetPollent(grpc_call_element* elem,
+                                       grpc_polling_entity* pollent) {
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  calld->pollent_ = pollent;
+}
+
+//
+// CallData implementation
+//
+
+const RetryMethodConfig* GetRetryPolicy(
+    const grpc_call_context_element* context) {
+  if (context == nullptr) return nullptr;
+  auto* svc_cfg_call_data = static_cast<ServiceConfigCallData*>(
+      context[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value);
+  if (svc_cfg_call_data == nullptr) return nullptr;
+  return static_cast<const RetryMethodConfig*>(
+      svc_cfg_call_data->GetMethodParsedConfig(
+          RetryServiceConfigParser::ParserIndex()));
+}
+
+RetryFilter::CallData::CallData(RetryFilter* chand,
+                                const grpc_call_element_args& args)
+    : chand_(chand),
+      retry_throttle_data_(chand->retry_throttle_data_),
+      retry_policy_(GetRetryPolicy(args.context)),
+      retry_backoff_(
+          BackOff::Options()
+              .set_initial_backoff(retry_policy_ == nullptr
+                                       ? 0
+                                       : retry_policy_->initial_backoff())
+              .set_multiplier(retry_policy_ == nullptr
+                                  ? 0
+                                  : retry_policy_->backoff_multiplier())
+              .set_jitter(RETRY_BACKOFF_JITTER)
+              .set_max_backoff(
+                  retry_policy_ == nullptr ? 0 : retry_policy_->max_backoff())),
+      path_(grpc_slice_ref_internal(args.path)),
+      call_start_time_(args.start_time),
+      deadline_(args.deadline),
+      arena_(args.arena),
+      owning_call_(args.call_stack),
+      call_combiner_(args.call_combiner),
+      call_context_(args.context),
+      call_stack_destruction_barrier_(
+          arena_->New<CallStackDestructionBarrier>()),
+      pending_send_initial_metadata_(false),
+      pending_send_message_(false),
+      pending_send_trailing_metadata_(false),
+      retry_committed_(false),
+      last_attempt_got_server_pushback_(false) {}
+
+RetryFilter::CallData::~CallData() {
+  grpc_slice_unref_internal(path_);
+  // Make sure there are no remaining pending batches.
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+    GPR_ASSERT(pending_batches_[i].batch == nullptr);
+  }
+}
+
+void RetryFilter::CallData::StartTransportStreamOpBatch(
+    grpc_transport_stream_op_batch* batch) {
+  // If we have an LB call, delegate to the LB call.
+  if (committed_call_ != nullptr) {
+    // Note: This will release the call combiner.
+    committed_call_->StartTransportStreamOpBatch(batch);
+    return;
+  }
+  // Handle cancellation.
+  if (GPR_UNLIKELY(batch->cancel_stream)) {
+    grpc_error_handle cancel_error = batch->payload->cancel_stream.cancel_error;
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: cancelled from surface: %s", chand_,
+              this, grpc_error_std_string(cancel_error).c_str());
+    }
+    // If we have a current call attempt, commit the call, then send
+    // the cancellation down to that attempt.  When the call fails, it
+    // will not be retried, because we have committed it here.
+    if (call_attempt_ != nullptr) {
+      RetryCommit(call_attempt_.get());
+      // Note: This will release the call combiner.
+      call_attempt_->lb_call()->StartTransportStreamOpBatch(batch);
+      return;
+    }
+    // Fail pending batches.
+    PendingBatchesFail(GRPC_ERROR_REF(cancel_error));
+    // Note: This will release the call combiner.
+    grpc_transport_stream_op_batch_finish_with_failure(
+        batch, GRPC_ERROR_REF(cancel_error), call_combiner_);
+    return;
+  }
+  // Add the batch to the pending list.
+  PendingBatch* pending = PendingBatchesAdd(batch);
+  if (call_attempt_ == nullptr) {
+    // If this is the first batch and retries are already committed
+    // (e.g., if this batch put the call above the buffer size limit), then
+    // immediately create an LB call and delegate the batch to it.  This
+    // avoids the overhead of unnecessarily allocating a CallAttempt
+    // object or caching any of the send op data.
+    if (num_attempts_completed_ == 0 && retry_committed_) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: retry committed before first attempt; "
+                "creating LB call",
+                chand_, this);
+      }
+      PendingBatchClear(pending);
+      committed_call_ = CreateLoadBalancedCall();
+      committed_call_->StartTransportStreamOpBatch(batch);
+      return;
+    }
+    // We do not yet have a call attempt, so create one.
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: creating call attempt", chand_,
+              this);
+    }
+    CreateCallAttempt();
+    return;
+  }
+  // Send batches to call attempt.
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: starting batch on attempt=%p lb_call=%p",
+            chand_, this, call_attempt_.get(), call_attempt_->lb_call());
+  }
+  call_attempt_->StartRetriableBatches();
+}
+
+RefCountedPtr<ClientChannel::LoadBalancedCall>
+RetryFilter::CallData::CreateLoadBalancedCall() {
+  grpc_call_element_args args = {owning_call_, nullptr,          call_context_,
+                                 path_,        call_start_time_, deadline_,
+                                 arena_,       call_combiner_};
+  return chand_->client_channel_->CreateLoadBalancedCall(
+      args, pollent_,
+      // This callback holds a ref to the CallStackDestructionBarrier
+      // object until the LB call is destroyed.
+      call_stack_destruction_barrier_->MakeLbCallDestructionClosure(this));
+}
+
+void RetryFilter::CallData::CreateCallAttempt() {
+  call_attempt_.reset(arena_->New<CallAttempt>(this));
+  call_attempt_->StartRetriableBatches();
+  // TODO(roth): When implementing hedging, change this to start a timer
+  // for the next hedging attempt.
+}
+
+namespace {
+
+void StartBatchInCallCombiner(void* arg, grpc_error_handle /*ignored*/) {
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
+  auto* lb_call = static_cast<ClientChannel::LoadBalancedCall*>(
+      batch->handler_private.extra_arg);
+  // Note: This will release the call combiner.
+  lb_call->StartTransportStreamOpBatch(batch);
+}
+
+}  // namespace
+
+void RetryFilter::CallData::AddClosureForBatch(
+    grpc_transport_stream_op_batch* batch, CallCombinerClosureList* closures) {
+  batch->handler_private.extra_arg = call_attempt_->lb_call();
+  GRPC_CLOSURE_INIT(&batch->handler_private.closure, StartBatchInCallCombiner,
+                    batch, grpc_schedule_on_exec_ctx);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: starting batch on LB call: %s",
+            chand_, this, grpc_transport_stream_op_batch_string(batch).c_str());
+  }
+  closures->Add(&batch->handler_private.closure, GRPC_ERROR_NONE,
+                "start_batch_on_lb_call");
+}
+
+//
+// send op data caching
+//
+
+void RetryFilter::CallData::MaybeCacheSendOpsForBatch(PendingBatch* pending) {
+  if (pending->send_ops_cached) return;
+  pending->send_ops_cached = true;
+  grpc_transport_stream_op_batch* batch = pending->batch;
+  // Save a copy of metadata for send_initial_metadata ops.
+  if (batch->send_initial_metadata) {
+    seen_send_initial_metadata_ = true;
+    GPR_ASSERT(send_initial_metadata_storage_ == nullptr);
+    grpc_metadata_batch* send_initial_metadata =
+        batch->payload->send_initial_metadata.send_initial_metadata;
+    send_initial_metadata_storage_ =
+        static_cast<grpc_linked_mdelem*>(arena_->Alloc(
+            sizeof(grpc_linked_mdelem) * send_initial_metadata->list.count));
+    grpc_metadata_batch_copy(send_initial_metadata, &send_initial_metadata_,
+                             send_initial_metadata_storage_);
+    send_initial_metadata_flags_ =
+        batch->payload->send_initial_metadata.send_initial_metadata_flags;
+    peer_string_ = batch->payload->send_initial_metadata.peer_string;
+  }
+  // Set up cache for send_message ops.
+  if (batch->send_message) {
+    ByteStreamCache* cache = arena_->New<ByteStreamCache>(
+        std::move(batch->payload->send_message.send_message));
+    send_messages_.push_back(cache);
+  }
+  // Save metadata batch for send_trailing_metadata ops.
+  if (batch->send_trailing_metadata) {
+    seen_send_trailing_metadata_ = true;
+    GPR_ASSERT(send_trailing_metadata_storage_ == nullptr);
+    grpc_metadata_batch* send_trailing_metadata =
+        batch->payload->send_trailing_metadata.send_trailing_metadata;
+    send_trailing_metadata_storage_ =
+        static_cast<grpc_linked_mdelem*>(arena_->Alloc(
+            sizeof(grpc_linked_mdelem) * send_trailing_metadata->list.count));
+    grpc_metadata_batch_copy(send_trailing_metadata, &send_trailing_metadata_,
+                             send_trailing_metadata_storage_);
+  }
+}
+
+void RetryFilter::CallData::FreeCachedSendInitialMetadata() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: destroying send_initial_metadata",
+            chand_, this);
+  }
+  grpc_metadata_batch_destroy(&send_initial_metadata_);
+}
+
+void RetryFilter::CallData::FreeCachedSendMessage(size_t idx) {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: destroying send_messages[%" PRIuPTR "]", chand_,
+            this, idx);
+  }
+  send_messages_[idx]->Destroy();
+}
+
+void RetryFilter::CallData::FreeCachedSendTrailingMetadata() {
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand_=%p calld=%p: destroying send_trailing_metadata",
+            chand_, this);
+  }
+  grpc_metadata_batch_destroy(&send_trailing_metadata_);
+}
+
+void RetryFilter::CallData::FreeAllCachedSendOpData() {
+  if (seen_send_initial_metadata_) {
+    FreeCachedSendInitialMetadata();
+  }
+  for (size_t i = 0; i < send_messages_.size(); ++i) {
+    FreeCachedSendMessage(i);
+  }
+  if (seen_send_trailing_metadata_) {
+    FreeCachedSendTrailingMetadata();
+  }
+}
+
+//
+// pending_batches management
+//
+
+size_t RetryFilter::CallData::GetBatchIndex(
+    grpc_transport_stream_op_batch* batch) {
+  if (batch->send_initial_metadata) return 0;
+  if (batch->send_message) return 1;
+  if (batch->send_trailing_metadata) return 2;
+  if (batch->recv_initial_metadata) return 3;
+  if (batch->recv_message) return 4;
+  if (batch->recv_trailing_metadata) return 5;
+  GPR_UNREACHABLE_CODE(return (size_t)-1);
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+RetryFilter::CallData::PendingBatch* RetryFilter::CallData::PendingBatchesAdd(
+    grpc_transport_stream_op_batch* batch) {
+  const size_t idx = GetBatchIndex(batch);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand_=%p calld=%p: adding pending batch at index %" PRIuPTR,
+            chand_, this, idx);
+  }
+  PendingBatch* pending = &pending_batches_[idx];
+  GPR_ASSERT(pending->batch == nullptr);
+  pending->batch = batch;
+  pending->send_ops_cached = false;
+  // Update state in calld about pending batches.
+  // Also check if the batch takes us over the retry buffer limit.
+  // Note: We don't check the size of trailing metadata here, because
+  // gRPC clients do not send trailing metadata.
+  if (batch->send_initial_metadata) {
+    pending_send_initial_metadata_ = true;
+    bytes_buffered_for_retry_ += grpc_metadata_batch_size(
+        batch->payload->send_initial_metadata.send_initial_metadata);
+  }
+  if (batch->send_message) {
+    pending_send_message_ = true;
+    bytes_buffered_for_retry_ +=
+        batch->payload->send_message.send_message->length();
+  }
+  if (batch->send_trailing_metadata) {
+    pending_send_trailing_metadata_ = true;
+  }
+  if (GPR_UNLIKELY(bytes_buffered_for_retry_ >
+                   chand_->per_rpc_retry_buffer_size_)) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: exceeded retry buffer size, committing",
+              chand_, this);
+    }
+    RetryCommit(call_attempt_.get());
+  }
+  return pending;
+}
+
+void RetryFilter::CallData::PendingBatchClear(PendingBatch* pending) {
+  if (pending->batch->send_initial_metadata) {
+    pending_send_initial_metadata_ = false;
+  }
+  if (pending->batch->send_message) {
+    pending_send_message_ = false;
+  }
+  if (pending->batch->send_trailing_metadata) {
+    pending_send_trailing_metadata_ = false;
+  }
+  pending->batch = nullptr;
+}
+
+void RetryFilter::CallData::MaybeClearPendingBatch(PendingBatch* pending) {
+  grpc_transport_stream_op_batch* batch = pending->batch;
+  // We clear the pending batch if all of its callbacks have been
+  // scheduled and reset to nullptr.
+  if (batch->on_complete == nullptr &&
+      (!batch->recv_initial_metadata ||
+       batch->payload->recv_initial_metadata.recv_initial_metadata_ready ==
+           nullptr) &&
+      (!batch->recv_message ||
+       batch->payload->recv_message.recv_message_ready == nullptr) &&
+      (!batch->recv_trailing_metadata ||
+       batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready ==
+           nullptr)) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+      gpr_log(GPR_INFO, "chand=%p calld=%p: clearing pending batch", chand_,
+              this);
+    }
+    PendingBatchClear(pending);
+  }
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+void RetryFilter::CallData::FailPendingBatchInCallCombiner(
+    void* arg, grpc_error_handle error) {
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
+  CallData* call = static_cast<CallData*>(batch->handler_private.extra_arg);
+  // Note: This will release the call combiner.
+  grpc_transport_stream_op_batch_finish_with_failure(
+      batch, GRPC_ERROR_REF(error), call->call_combiner_);
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+void RetryFilter::CallData::PendingBatchesFail(grpc_error_handle error) {
+  GPR_ASSERT(error != GRPC_ERROR_NONE);
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    size_t num_batches = 0;
+    for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+      if (pending_batches_[i].batch != nullptr) ++num_batches;
+    }
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
+            chand_, this, num_batches, grpc_error_std_string(error).c_str());
+  }
+  CallCombinerClosureList closures;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+    PendingBatch* pending = &pending_batches_[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch != nullptr) {
+      batch->handler_private.extra_arg = this;
+      GRPC_CLOSURE_INIT(&batch->handler_private.closure,
+                        FailPendingBatchInCallCombiner, batch,
+                        grpc_schedule_on_exec_ctx);
+      closures.Add(&batch->handler_private.closure, GRPC_ERROR_REF(error),
+                   "PendingBatchesFail");
+      PendingBatchClear(pending);
+    }
+  }
+  closures.RunClosuresWithoutYielding(call_combiner_);
+  GRPC_ERROR_UNREF(error);
+}
+
+template <typename Predicate>
+RetryFilter::CallData::PendingBatch* RetryFilter::CallData::PendingBatchFind(
+    const char* log_message, Predicate predicate) {
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
+    PendingBatch* pending = &pending_batches_[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch != nullptr && predicate(batch)) {
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: %s pending batch at index %" PRIuPTR,
+                chand_, this, log_message, i);
+      }
+      return pending;
+    }
+  }
+  return nullptr;
+}
+
+//
+// retry code
+//
+
+void RetryFilter::CallData::RetryCommit(CallAttempt* call_attempt) {
+  if (retry_committed_) return;
+  retry_committed_ = true;
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: committing retries", chand_, this);
+  }
+  if (call_attempt != nullptr) {
+    call_attempt->FreeCachedSendOpDataAfterCommit();
+  }
+}
+
+void RetryFilter::CallData::DoRetry(grpc_millis server_pushback_ms) {
+  // Reset call attempt.
+  call_attempt_.reset();
+  // Compute backoff delay.
+  grpc_millis next_attempt_time;
+  if (server_pushback_ms >= 0) {
+    next_attempt_time = ExecCtx::Get()->Now() + server_pushback_ms;
+    last_attempt_got_server_pushback_ = true;
+  } else {
+    if (num_attempts_completed_ == 1 || last_attempt_got_server_pushback_) {
+      last_attempt_got_server_pushback_ = false;
+    }
+    next_attempt_time = retry_backoff_.NextAttemptTime();
+  }
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
+    gpr_log(GPR_INFO,
+            "chand=%p calld=%p: retrying failed call in %" PRId64 " ms", chand_,
+            this, next_attempt_time - ExecCtx::Get()->Now());
+  }
+  // Schedule retry after computed delay.
+  GRPC_CLOSURE_INIT(&retry_closure_, OnRetryTimer, this, nullptr);
+  GRPC_CALL_STACK_REF(owning_call_, "OnRetryTimer");
+  MutexLock lock(&timer_mu_);
+  canceller_ = new Canceller(this);
+  grpc_timer_init(&retry_timer_, next_attempt_time, &retry_closure_);
+}
+
+void RetryFilter::CallData::OnRetryTimer(void* arg, grpc_error_handle error) {
+  auto* calld = static_cast<CallData*>(arg);
+  if (error == GRPC_ERROR_NONE) {
+    bool start_attempt = false;
+    {
+      MutexLock lock(&calld->timer_mu_);
+      if (calld->canceller_ != nullptr) {
+        calld->canceller_ = nullptr;
+        start_attempt = true;
+      }
+    }
+    if (start_attempt) calld->CreateCallAttempt();
+  }
+  GRPC_CALL_STACK_UNREF(calld->owning_call_, "OnRetryTimer");
+}
+
+}  // namespace
+
+const grpc_channel_filter kRetryFilterVtable = {
+    RetryFilter::CallData::StartTransportStreamOpBatch,
+    RetryFilter::StartTransportOp,
+    sizeof(RetryFilter::CallData),
+    RetryFilter::CallData::Init,
+    RetryFilter::CallData::SetPollent,
+    RetryFilter::CallData::Destroy,
+    sizeof(RetryFilter),
+    RetryFilter::Init,
+    RetryFilter::Destroy,
+    RetryFilter::GetChannelInfo,
+    "retry_filter",
+};
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/retry_filter.h b/grpc/src/core/ext/filters/client_channel/retry_filter.h
new file mode 100644
index 0000000..a96df8a
--- /dev/null
+++ b/grpc/src/core/ext/filters/client_channel/retry_filter.h
@@ -0,0 +1,30 @@
+//
+// Copyright 2021 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_RETRY_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_FILTER_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/channel/channel_stack.h"
+
+namespace grpc_core {
+
+extern const grpc_channel_filter kRetryFilterVtable;
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_FILTER_H
diff --git a/grpc/src/core/ext/filters/client_channel/retry_service_config.cc b/grpc/src/core/ext/filters/client_channel/retry_service_config.cc
new file mode 100644
index 0000000..fc066e6
--- /dev/null
+++ b/grpc/src/core/ext/filters/client_channel/retry_service_config.cc
@@ -0,0 +1,287 @@
+//
+// 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>
+
+#include "src/core/ext/filters/client_channel/retry_service_config.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "absl/strings/str_cat.h"
+#include "absl/types/optional.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/json/json_util.h"
+#include "src/core/lib/uri/uri_parser.h"
+
+// As per the retry design, we do not allow more than 5 retry attempts.
+#define MAX_MAX_RETRY_ATTEMPTS 5
+
+namespace grpc_core {
+namespace internal {
+
+namespace {
+size_t g_retry_service_config_parser_index;
+}
+
+size_t RetryServiceConfigParser::ParserIndex() {
+  return g_retry_service_config_parser_index;
+}
+
+void RetryServiceConfigParser::Register() {
+  g_retry_service_config_parser_index = ServiceConfigParser::RegisterParser(
+      absl::make_unique<RetryServiceConfigParser>());
+}
+
+namespace {
+
+grpc_error_handle ParseRetryThrottling(const Json& json,
+                                       intptr_t* max_milli_tokens,
+                                       intptr_t* milli_token_ratio) {
+  if (json.type() != Json::Type::OBJECT) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling error:Type should be object");
+  }
+  std::vector<grpc_error_handle> error_list;
+  // Parse maxTokens.
+  auto it = json.object_value().find("maxTokens");
+  if (it == json.object_value().end()) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling field:maxTokens error:Not found"));
+  } else if (it->second.type() != Json::Type::NUMBER) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling field:maxTokens error:Type should be "
+        "number"));
+  } else {
+    *max_milli_tokens =
+        gpr_parse_nonnegative_int(it->second.string_value().c_str()) * 1000;
+    if (*max_milli_tokens <= 0) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryThrottling field:maxTokens error:should be "
+          "greater than zero"));
+    }
+  }
+  // Parse tokenRatio.
+  it = json.object_value().find("tokenRatio");
+  if (it == json.object_value().end()) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling field:tokenRatio error:Not found"));
+  } else if (it->second.type() != Json::Type::NUMBER) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryThrottling field:tokenRatio error:type should be "
+        "number"));
+  } else {
+    // We support up to 3 decimal digits.
+    size_t whole_len = it->second.string_value().size();
+    const char* value = it->second.string_value().c_str();
+    uint32_t multiplier = 1;
+    uint32_t decimal_value = 0;
+    const char* decimal_point = strchr(value, '.');
+    if (decimal_point != nullptr) {
+      whole_len = static_cast<size_t>(decimal_point - value);
+      multiplier = 1000;
+      size_t decimal_len = strlen(decimal_point + 1);
+      if (decimal_len > 3) decimal_len = 3;
+      if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
+                                     &decimal_value)) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:retryThrottling field:tokenRatio error:Failed "
+            "parsing"));
+        return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
+      }
+      uint32_t decimal_multiplier = 1;
+      for (size_t i = 0; i < (3 - decimal_len); ++i) {
+        decimal_multiplier *= 10;
+      }
+      decimal_value *= decimal_multiplier;
+    }
+    uint32_t whole_value;
+    if (!gpr_parse_bytes_to_uint32(value, whole_len, &whole_value)) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryThrottling field:tokenRatio error:Failed "
+          "parsing"));
+      return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
+    }
+    *milli_token_ratio =
+        static_cast<int>((whole_value * multiplier) + decimal_value);
+    if (*milli_token_ratio <= 0) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryThrottling field:tokenRatio error:value should "
+          "be greater than 0"));
+    }
+  }
+  return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
+}
+
+}  // namespace
+
+std::unique_ptr<ServiceConfigParser::ParsedConfig>
+RetryServiceConfigParser::ParseGlobalParams(const grpc_channel_args* /*args*/,
+                                            const Json& json,
+                                            grpc_error_handle* error) {
+  GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
+  auto it = json.object_value().find("retryThrottling");
+  if (it == json.object_value().end()) return nullptr;
+  intptr_t max_milli_tokens = 0;
+  intptr_t milli_token_ratio = 0;
+  *error =
+      ParseRetryThrottling(it->second, &max_milli_tokens, &milli_token_ratio);
+  if (*error != GRPC_ERROR_NONE) return nullptr;
+  return absl::make_unique<RetryGlobalConfig>(max_milli_tokens,
+                                              milli_token_ratio);
+}
+
+namespace {
+
+grpc_error_handle ParseRetryPolicy(const Json& json, int* max_attempts,
+                                   grpc_millis* initial_backoff,
+                                   grpc_millis* max_backoff,
+                                   float* backoff_multiplier,
+                                   StatusCodeSet* retryable_status_codes) {
+  if (json.type() != Json::Type::OBJECT) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:retryPolicy error:should be of type object");
+  }
+  std::vector<grpc_error_handle> error_list;
+  // Parse maxAttempts.
+  auto it = json.object_value().find("maxAttempts");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::NUMBER) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:maxAttempts error:should be of type number"));
+    } else {
+      *max_attempts =
+          gpr_parse_nonnegative_int(it->second.string_value().c_str());
+      if (*max_attempts <= 1) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:maxAttempts error:should be at least 2"));
+      } else if (*max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
+        gpr_log(GPR_ERROR,
+                "service config: clamped retryPolicy.maxAttempts at %d",
+                MAX_MAX_RETRY_ATTEMPTS);
+        *max_attempts = MAX_MAX_RETRY_ATTEMPTS;
+      }
+    }
+  }
+  // Parse initialBackoff.
+  if (ParseJsonObjectFieldAsDuration(json.object_value(), "initialBackoff",
+                                     initial_backoff, &error_list) &&
+      *initial_backoff == 0) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:initialBackoff error:must be greater than 0"));
+  }
+  // Parse maxBackoff.
+  if (ParseJsonObjectFieldAsDuration(json.object_value(), "maxBackoff",
+                                     max_backoff, &error_list) &&
+      *max_backoff == 0) {
+    error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "field:maxBackoff error:should be greater than 0"));
+  }
+  // Parse backoffMultiplier.
+  it = json.object_value().find("backoffMultiplier");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::NUMBER) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:backoffMultiplier error:should be of type number"));
+    } else {
+      if (sscanf(it->second.string_value().c_str(), "%f", backoff_multiplier) !=
+          1) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:backoffMultiplier error:failed to parse"));
+      } else if (*backoff_multiplier <= 0) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:backoffMultiplier error:should be greater than 0"));
+      }
+    }
+  }
+  // Parse retryableStatusCodes.
+  it = json.object_value().find("retryableStatusCodes");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::ARRAY) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryableStatusCodes error:should be of type array"));
+    } else {
+      for (const Json& element : it->second.array_value()) {
+        if (element.type() != Json::Type::STRING) {
+          error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+              "field:retryableStatusCodes error:status codes should be of type "
+              "string"));
+          continue;
+        }
+        grpc_status_code status;
+        if (!grpc_status_code_from_string(element.string_value().c_str(),
+                                          &status)) {
+          error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+              "field:retryableStatusCodes error:failed to parse status code"));
+          continue;
+        }
+        retryable_status_codes->Add(status);
+      }
+      if (retryable_status_codes->Empty()) {
+        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:retryableStatusCodes error:should be non-empty"));
+      };
+    }
+  }
+  // Make sure required fields are set.
+  if (error_list.empty()) {
+    if (*max_attempts == 0 || *initial_backoff == 0 || *max_backoff == 0 ||
+        *backoff_multiplier == 0 || retryable_status_codes->Empty()) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "field:retryPolicy error:Missing required field(s)");
+    }
+  }
+  return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
+}
+
+}  // namespace
+
+std::unique_ptr<ServiceConfigParser::ParsedConfig>
+RetryServiceConfigParser::ParsePerMethodParams(
+    const grpc_channel_args* /*args*/, const Json& json,
+    grpc_error_handle* error) {
+  GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
+  // Parse retry policy.
+  auto it = json.object_value().find("retryPolicy");
+  if (it == json.object_value().end()) return nullptr;
+  int max_attempts = 0;
+  grpc_millis initial_backoff = 0;
+  grpc_millis max_backoff = 0;
+  float backoff_multiplier = 0;
+  StatusCodeSet retryable_status_codes;
+  *error = ParseRetryPolicy(it->second, &max_attempts, &initial_backoff,
+                            &max_backoff, &backoff_multiplier,
+                            &retryable_status_codes);
+  if (*error != GRPC_ERROR_NONE) return nullptr;
+  return absl::make_unique<RetryMethodConfig>(max_attempts, initial_backoff,
+                                              max_backoff, backoff_multiplier,
+                                              retryable_status_codes);
+}
+
+}  // namespace internal
+}  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/retry_service_config.h b/grpc/src/core/ext/filters/client_channel/retry_service_config.h
new file mode 100644
index 0000000..256183f
--- /dev/null
+++ b/grpc/src/core/ext/filters/client_channel/retry_service_config.h
@@ -0,0 +1,90 @@
+//
+// 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_RETRY_SERVICE_CONFIG_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_SERVICE_CONFIG_H
+
+#include <grpc/support/port_platform.h>
+
+#include <memory>
+
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/service_config_parser.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/iomgr/exec_ctx.h"  // for grpc_millis
+
+namespace grpc_core {
+namespace internal {
+
+class RetryGlobalConfig : public ServiceConfigParser::ParsedConfig {
+ public:
+  RetryGlobalConfig(intptr_t max_milli_tokens, intptr_t milli_token_ratio)
+      : max_milli_tokens_(max_milli_tokens),
+        milli_token_ratio_(milli_token_ratio) {}
+
+  intptr_t max_milli_tokens() const { return max_milli_tokens_; }
+  intptr_t milli_token_ratio() const { return milli_token_ratio_; }
+
+ private:
+  intptr_t max_milli_tokens_ = 0;
+  intptr_t milli_token_ratio_ = 0;
+};
+
+class RetryMethodConfig : public ServiceConfigParser::ParsedConfig {
+ public:
+  RetryMethodConfig(int max_attempts, grpc_millis initial_backoff,
+                    grpc_millis max_backoff, float backoff_multiplier,
+                    StatusCodeSet retryable_status_codes)
+      : max_attempts_(max_attempts),
+        initial_backoff_(initial_backoff),
+        max_backoff_(max_backoff),
+        backoff_multiplier_(backoff_multiplier),
+        retryable_status_codes_(retryable_status_codes) {}
+
+  int max_attempts() const { return max_attempts_; }
+  grpc_millis initial_backoff() const { return initial_backoff_; }
+  grpc_millis max_backoff() const { return max_backoff_; }
+  float backoff_multiplier() const { return backoff_multiplier_; }
+  StatusCodeSet retryable_status_codes() const {
+    return retryable_status_codes_;
+  }
+
+ private:
+  int max_attempts_ = 0;
+  grpc_millis initial_backoff_ = 0;
+  grpc_millis max_backoff_ = 0;
+  float backoff_multiplier_ = 0;
+  StatusCodeSet retryable_status_codes_;
+};
+
+class RetryServiceConfigParser : public ServiceConfigParser::Parser {
+ public:
+  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
+      const grpc_channel_args* /*args*/, const Json& json,
+      grpc_error_handle* error) override;
+
+  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
+      const grpc_channel_args* /*args*/, const Json& json,
+      grpc_error_handle* error) override;
+
+  static size_t ParserIndex();
+  static void Register();
+};
+
+}  // namespace internal
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_SERVICE_CONFIG_H
diff --git a/grpc/src/core/ext/filters/client_channel/server_address.cc b/grpc/src/core/ext/filters/client_channel/server_address.cc
index c8870ca..e082256 100644
--- a/grpc/src/core/ext/filters/client_channel/server_address.cc
+++ b/grpc/src/core/ext/filters/client_channel/server_address.cc
@@ -27,11 +27,17 @@
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_join.h"
 
-#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 
 namespace grpc_core {
 
 //
+// ServerAddressWeightAttribute
+//
+const char* ServerAddressWeightAttribute::kServerAddressWeightAttributeKey =
+    "server_address_weight";
+
+//
 // ServerAddress
 //
 
@@ -55,6 +61,9 @@
   }
 }
 ServerAddress& ServerAddress::operator=(const ServerAddress& other) {
+  if (&other == this) {
+    return *this;
+  }
   address_ = other.address_;
   grpc_channel_args_destroy(args_);
   args_ = grpc_channel_args_copy(other.args_);
diff --git a/grpc/src/core/ext/filters/client_channel/server_address.h b/grpc/src/core/ext/filters/client_channel/server_address.h
index 7a188a0..1e0eaa1 100644
--- a/grpc/src/core/ext/filters/client_channel/server_address.h
+++ b/grpc/src/core/ext/filters/client_channel/server_address.h
@@ -25,8 +25,10 @@
 #include <memory>
 
 #include "absl/container/inlined_vector.h"
+#include "absl/strings/str_format.h"
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
 namespace grpc_core {
@@ -108,6 +110,35 @@
 
 typedef absl::InlinedVector<ServerAddress, 1> ServerAddressList;
 
+//
+// ServerAddressWeightAttribute
+//
+class ServerAddressWeightAttribute : public ServerAddress::AttributeInterface {
+ public:
+  static const char* kServerAddressWeightAttributeKey;
+
+  explicit ServerAddressWeightAttribute(uint32_t weight) : weight_(weight) {}
+
+  uint32_t weight() const { return weight_; }
+
+  std::unique_ptr<AttributeInterface> Copy() const override {
+    return absl::make_unique<ServerAddressWeightAttribute>(weight_);
+  }
+
+  int Cmp(const AttributeInterface* other) const override {
+    const auto* other_locality_attr =
+        static_cast<const ServerAddressWeightAttribute*>(other);
+    return GPR_ICMP(weight_, other_locality_attr->weight_);
+  }
+
+  std::string ToString() const override {
+    return absl::StrFormat("%d", weight_);
+  }
+
+ private:
+  uint32_t weight_;
+};
+
 }  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVER_ADDRESS_H */
diff --git a/grpc/src/core/ext/filters/client_channel/service_config.cc b/grpc/src/core/ext/filters/client_channel/service_config.cc
index a2794f1..b87226c 100644
--- a/grpc/src/core/ext/filters/client_channel/service_config.cc
+++ b/grpc/src/core/ext/filters/client_channel/service_config.cc
@@ -32,7 +32,7 @@
 
 RefCountedPtr<ServiceConfig> ServiceConfig::Create(
     const grpc_channel_args* args, absl::string_view json_string,
-    grpc_error** error) {
+    grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr);
   Json json = Json::Parse(json_string, error);
   if (*error != GRPC_ERROR_NONE) return nullptr;
@@ -42,7 +42,7 @@
 
 ServiceConfig::ServiceConfig(const grpc_channel_args* args,
                              std::string json_string, Json json,
-                             grpc_error** error)
+                             grpc_error_handle* error)
     : json_string_(std::move(json_string)), json_(std::move(json)) {
   GPR_DEBUG_ASSERT(error != nullptr);
   if (json_.type() != Json::Type::OBJECT) {
@@ -50,12 +50,12 @@
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON value is not an object");
     return;
   }
-  std::vector<grpc_error*> error_list;
-  grpc_error* global_error = GRPC_ERROR_NONE;
+  std::vector<grpc_error_handle> error_list;
+  grpc_error_handle global_error = GRPC_ERROR_NONE;
   parsed_global_configs_ =
       ServiceConfigParser::ParseGlobalParameters(args, json_, &global_error);
   if (global_error != GRPC_ERROR_NONE) error_list.push_back(global_error);
-  grpc_error* local_error = ParsePerMethodParams(args);
+  grpc_error_handle local_error = ParsePerMethodParams(args);
   if (local_error != GRPC_ERROR_NONE) error_list.push_back(local_error);
   if (!error_list.empty()) {
     *error = GRPC_ERROR_CREATE_FROM_VECTOR("Service config parsing error",
@@ -69,13 +69,13 @@
   }
 }
 
-grpc_error* ServiceConfig::ParseJsonMethodConfig(const grpc_channel_args* args,
-                                                 const Json& json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle ServiceConfig::ParseJsonMethodConfig(
+    const grpc_channel_args* args, const Json& json) {
+  std::vector<grpc_error_handle> error_list;
   // Parse method config with each registered parser.
   auto parsed_configs =
       absl::make_unique<ServiceConfigParser::ParsedConfigVector>();
-  grpc_error* parser_error = GRPC_ERROR_NONE;
+  grpc_error_handle parser_error = GRPC_ERROR_NONE;
   *parsed_configs =
       ServiceConfigParser::ParsePerMethodParameters(args, json, &parser_error);
   if (parser_error != GRPC_ERROR_NONE) {
@@ -94,7 +94,7 @@
     }
     const Json::Array& name_array = it->second.array_value();
     for (const Json& name : name_array) {
-      grpc_error* parse_error = GRPC_ERROR_NONE;
+      grpc_error_handle parse_error = GRPC_ERROR_NONE;
       std::string path = ParseJsonMethodName(name, &parse_error);
       if (parse_error != GRPC_ERROR_NONE) {
         error_list.push_back(parse_error);
@@ -130,8 +130,9 @@
   return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list);
 }
 
-grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_channel_args* args) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle ServiceConfig::ParsePerMethodParams(
+    const grpc_channel_args* args) {
+  std::vector<grpc_error_handle> error_list;
   auto it = json_.object_value().find("methodConfig");
   if (it != json_.object_value().end()) {
     if (it->second.type() != Json::Type::ARRAY) {
@@ -144,7 +145,7 @@
             "field:methodConfig error:not of type Object"));
         continue;
       }
-      grpc_error* error = ParseJsonMethodConfig(args, method_config);
+      grpc_error_handle error = ParseJsonMethodConfig(args, method_config);
       if (error != GRPC_ERROR_NONE) {
         error_list.push_back(error);
       }
@@ -154,7 +155,7 @@
 }
 
 std::string ServiceConfig::ParseJsonMethodName(const Json& json,
-                                               grpc_error** error) {
+                                               grpc_error_handle* error) {
   if (json.type() != Json::Type::OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "field:name error:type is not object");
diff --git a/grpc/src/core/ext/filters/client_channel/service_config.h b/grpc/src/core/ext/filters/client_channel/service_config.h
index 2dfd45d..a06ae16 100644
--- a/grpc/src/core/ext/filters/client_channel/service_config.h
+++ b/grpc/src/core/ext/filters/client_channel/service_config.h
@@ -67,10 +67,10 @@
   /// Returns null on parse error.
   static RefCountedPtr<ServiceConfig> Create(const grpc_channel_args* args,
                                              absl::string_view json_string,
-                                             grpc_error** error);
+                                             grpc_error_handle* error);
 
   ServiceConfig(const grpc_channel_args* args, std::string json_string,
-                Json json, grpc_error** error);
+                Json json, grpc_error_handle* error);
   ~ServiceConfig() override;
 
   const std::string& json_string() const { return json_string_; }
@@ -91,13 +91,14 @@
 
  private:
   // Helper functions for parsing the method configs.
-  grpc_error* ParsePerMethodParams(const grpc_channel_args* args);
-  grpc_error* ParseJsonMethodConfig(const grpc_channel_args* args,
-                                    const Json& json);
+  grpc_error_handle ParsePerMethodParams(const grpc_channel_args* args);
+  grpc_error_handle ParseJsonMethodConfig(const grpc_channel_args* args,
+                                          const Json& json);
 
   // Returns a path string for the JSON name object specified by json.
   // Sets *error on error.
-  static std::string ParseJsonMethodName(const Json& json, grpc_error** error);
+  static std::string ParseJsonMethodName(const Json& json,
+                                         grpc_error_handle* error);
 
   std::string json_string_;
   Json json_;
diff --git a/grpc/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc b/grpc/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc
index 679c0f5..5763e17 100644
--- a/grpc/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc
+++ b/grpc/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc
@@ -36,13 +36,14 @@
     const char* service_config_str = grpc_channel_args_find_string(
         args->channel_args, GRPC_ARG_SERVICE_CONFIG);
     if (service_config_str != nullptr) {
-      grpc_error* service_config_error = GRPC_ERROR_NONE;
+      grpc_error_handle service_config_error = GRPC_ERROR_NONE;
       auto service_config = ServiceConfig::Create(
           args->channel_args, service_config_str, &service_config_error);
       if (service_config_error == GRPC_ERROR_NONE) {
         service_config_ = std::move(service_config);
       } else {
-        gpr_log(GPR_ERROR, "%s", grpc_error_string(service_config_error));
+        gpr_log(GPR_ERROR, "%s",
+                grpc_error_std_string(service_config_error).c_str());
       }
       GRPC_ERROR_UNREF(service_config_error);
     }
@@ -73,7 +74,7 @@
   }
 };
 
-grpc_error* ServiceConfigChannelArgInitCallElem(
+grpc_error_handle ServiceConfigChannelArgInitCallElem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   ServiceConfigChannelArgCallData* calld =
       static_cast<ServiceConfigChannelArgCallData*>(elem->call_data);
@@ -89,7 +90,7 @@
   calld->~ServiceConfigChannelArgCallData();
 }
 
-grpc_error* ServiceConfigChannelArgInitChannelElem(
+grpc_error_handle ServiceConfigChannelArgInitChannelElem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   ServiceConfigChannelArgChannelData* chand =
       static_cast<ServiceConfigChannelArgChannelData*>(elem->channel_data);
diff --git a/grpc/src/core/ext/filters/client_channel/service_config_parser.cc b/grpc/src/core/ext/filters/client_channel/service_config_parser.cc
index d116f31..fa8fbea 100644
--- a/grpc/src/core/ext/filters/client_channel/service_config_parser.cc
+++ b/grpc/src/core/ext/filters/client_channel/service_config_parser.cc
@@ -47,11 +47,11 @@
 ServiceConfigParser::ParsedConfigVector
 ServiceConfigParser::ParseGlobalParameters(const grpc_channel_args* args,
                                            const Json& json,
-                                           grpc_error** error) {
+                                           grpc_error_handle* error) {
   ParsedConfigVector parsed_global_configs;
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < g_registered_parsers->size(); i++) {
-    grpc_error* parser_error = GRPC_ERROR_NONE;
+    grpc_error_handle parser_error = GRPC_ERROR_NONE;
     auto parsed_config = (*g_registered_parsers)[i]->ParseGlobalParams(
         args, json, &parser_error);
     if (parser_error != GRPC_ERROR_NONE) {
@@ -68,11 +68,11 @@
 ServiceConfigParser::ParsedConfigVector
 ServiceConfigParser::ParsePerMethodParameters(const grpc_channel_args* args,
                                               const Json& json,
-                                              grpc_error** error) {
+                                              grpc_error_handle* error) {
   ParsedConfigVector parsed_method_configs;
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < g_registered_parsers->size(); i++) {
-    grpc_error* parser_error = GRPC_ERROR_NONE;
+    grpc_error_handle parser_error = GRPC_ERROR_NONE;
     auto parsed_config = (*g_registered_parsers)[i]->ParsePerMethodParams(
         args, json, &parser_error);
     if (parser_error != GRPC_ERROR_NONE) {
diff --git a/grpc/src/core/ext/filters/client_channel/service_config_parser.h b/grpc/src/core/ext/filters/client_channel/service_config_parser.h
index 692a920..ebd3166 100644
--- a/grpc/src/core/ext/filters/client_channel/service_config_parser.h
+++ b/grpc/src/core/ext/filters/client_channel/service_config_parser.h
@@ -47,7 +47,8 @@
     virtual ~Parser() = default;
 
     virtual std::unique_ptr<ParsedConfig> ParseGlobalParams(
-        const grpc_channel_args*, const Json& /* json */, grpc_error** error) {
+        const grpc_channel_args*, const Json& /* json */,
+        grpc_error_handle* error) {
       // Avoid unused parameter warning on debug-only parameter
       (void)error;
       GPR_DEBUG_ASSERT(error != nullptr);
@@ -55,7 +56,8 @@
     }
 
     virtual std::unique_ptr<ParsedConfig> ParsePerMethodParams(
-        const grpc_channel_args*, const Json& /* json */, grpc_error** error) {
+        const grpc_channel_args*, const Json& /* json */,
+        grpc_error_handle* error) {
       // Avoid unused parameter warning on debug-only parameter
       (void)error;
       GPR_DEBUG_ASSERT(error != nullptr);
@@ -81,10 +83,11 @@
 
   static ParsedConfigVector ParseGlobalParameters(const grpc_channel_args* args,
                                                   const Json& json,
-                                                  grpc_error** error);
+                                                  grpc_error_handle* error);
 
   static ParsedConfigVector ParsePerMethodParameters(
-      const grpc_channel_args* args, const Json& json, grpc_error** error);
+      const grpc_channel_args* args, const Json& json,
+      grpc_error_handle* error);
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/subchannel.cc b/grpc/src/core/ext/filters/client_channel/subchannel.cc
index dbac59a..a3db609 100644
--- a/grpc/src/core/ext/filters/client_channel/subchannel.cc
+++ b/grpc/src/core/ext/filters/client_channel/subchannel.cc
@@ -36,6 +36,8 @@
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
 #include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
@@ -45,8 +47,6 @@
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
-#include "src/core/lib/iomgr/parse_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/channel.h"
@@ -131,7 +131,7 @@
 //
 
 RefCountedPtr<SubchannelCall> SubchannelCall::Create(Args args,
-                                                     grpc_error** error) {
+                                                     grpc_error_handle* error) {
   const size_t allocation_size =
       args.connected_subchannel->GetInitialCallSizeEstimate();
   Arena* arena = args.arena;
@@ -139,7 +139,7 @@
       arena->Alloc(allocation_size)) SubchannelCall(std::move(args), error));
 }
 
-SubchannelCall::SubchannelCall(Args args, grpc_error** error)
+SubchannelCall::SubchannelCall(Args args, grpc_error_handle* error)
     : connected_subchannel_(std::move(args.connected_subchannel)),
       deadline_(args.deadline) {
   grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(this);
@@ -156,8 +156,7 @@
   *error = grpc_call_stack_init(connected_subchannel_->channel_stack(), 1,
                                 SubchannelCall::Destroy, this, &call_args);
   if (GPR_UNLIKELY(*error != GRPC_ERROR_NONE)) {
-    const char* error_string = grpc_error_string(*error);
-    gpr_log(GPR_ERROR, "error: %s", error_string);
+    gpr_log(GPR_ERROR, "error: %s", grpc_error_std_string(*error).c_str());
     return;
   }
   grpc_call_stack_set_pollset_or_pollset_set(callstk, args.pollent);
@@ -207,7 +206,7 @@
   GRPC_CALL_STACK_UNREF(SUBCHANNEL_CALL_TO_CALL_STACK(this), reason);
 }
 
-void SubchannelCall::Destroy(void* arg, grpc_error* /*error*/) {
+void SubchannelCall::Destroy(void* arg, grpc_error_handle /*error*/) {
   GPR_TIMER_SCOPE("subchannel_call_destroy", 0);
   SubchannelCall* self = static_cast<SubchannelCall*>(arg);
   // Keep some members before destroying the subchannel call.
@@ -252,7 +251,7 @@
 
 // Sets *status based on the rest of the parameters.
 void GetCallStatus(grpc_status_code* status, grpc_millis deadline,
-                   grpc_metadata_batch* md_batch, grpc_error* error) {
+                   grpc_metadata_batch* md_batch, grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     grpc_error_get_status(error, deadline, status, nullptr, nullptr, nullptr);
   } else {
@@ -268,7 +267,8 @@
 
 }  // namespace
 
-void SubchannelCall::RecvTrailingMetadataReady(void* arg, grpc_error* error) {
+void SubchannelCall::RecvTrailingMetadataReady(void* arg,
+                                               grpc_error_handle error) {
   SubchannelCall* call = static_cast<SubchannelCall*>(arg);
   GPR_ASSERT(call->recv_trailing_metadata_ != nullptr);
   grpc_status_code status = GRPC_STATUS_OK;
@@ -303,20 +303,17 @@
     : public AsyncConnectivityStateWatcherInterface {
  public:
   // Must be instantiated while holding c->mu.
-  explicit ConnectedSubchannelStateWatcher(Subchannel* c) : subchannel_(c) {
-    // Steal subchannel ref for connecting.
-    GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "state_watcher");
-    GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "connecting");
-  }
+  explicit ConnectedSubchannelStateWatcher(WeakRefCountedPtr<Subchannel> c)
+      : subchannel_(std::move(c)) {}
 
   ~ConnectedSubchannelStateWatcher() override {
-    GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "state_watcher");
+    subchannel_.reset(DEBUG_LOCATION, "state_watcher");
   }
 
  private:
   void OnConnectivityStateChange(grpc_connectivity_state new_state,
                                  const absl::Status& status) override {
-    Subchannel* c = subchannel_;
+    Subchannel* c = subchannel_.get();
     MutexLock lock(&c->mu_);
     switch (new_state) {
       case GRPC_CHANNEL_TRANSIENT_FAILURE:
@@ -357,7 +354,7 @@
     }
   }
 
-  Subchannel* subchannel_;
+  WeakRefCountedPtr<Subchannel> subchannel_;
 };
 
 // Asynchronously notifies the \a watcher of a change in the connectvity state
@@ -378,7 +375,7 @@
     ExecCtx::Run(DEBUG_LOCATION,
                  GRPC_CLOSURE_INIT(
                      &closure_,
-                     [](void* arg, grpc_error* /*error*/) {
+                     [](void* arg, grpc_error_handle /*error*/) {
                        auto* self =
                            static_cast<AsyncWatcherNotifierLocked*>(arg);
                        self->watcher_->OnConnectivityStateChange();
@@ -424,19 +421,19 @@
 class Subchannel::HealthWatcherMap::HealthWatcher
     : public AsyncConnectivityStateWatcherInterface {
  public:
-  HealthWatcher(Subchannel* c, std::string health_check_service_name,
-                grpc_connectivity_state subchannel_state)
-      : subchannel_(c),
+  HealthWatcher(WeakRefCountedPtr<Subchannel> c,
+                std::string health_check_service_name)
+      : subchannel_(std::move(c)),
         health_check_service_name_(std::move(health_check_service_name)),
-        state_(subchannel_state == GRPC_CHANNEL_READY ? GRPC_CHANNEL_CONNECTING
-                                                      : subchannel_state) {
-    GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "health_watcher");
+        state_(subchannel_->state_ == GRPC_CHANNEL_READY
+                   ? GRPC_CHANNEL_CONNECTING
+                   : subchannel_->state_) {
     // If the subchannel is already connected, start health checking.
-    if (subchannel_state == GRPC_CHANNEL_READY) StartHealthCheckingLocked();
+    if (subchannel_->state_ == GRPC_CHANNEL_READY) StartHealthCheckingLocked();
   }
 
   ~HealthWatcher() override {
-    GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "health_watcher");
+    subchannel_.reset(DEBUG_LOCATION, "health_watcher");
   }
 
   const std::string& health_check_service_name() const {
@@ -449,7 +446,8 @@
       grpc_connectivity_state initial_state,
       RefCountedPtr<Subchannel::ConnectivityStateWatcherInterface> watcher) {
     if (state_ != initial_state) {
-      new AsyncWatcherNotifierLocked(watcher, subchannel_, state_, status_);
+      new AsyncWatcherNotifierLocked(watcher, subchannel_.get(), state_,
+                                     status_);
     }
     watcher_list_.AddWatcherLocked(std::move(watcher));
   }
@@ -461,7 +459,8 @@
 
   bool HasWatchers() const { return !watcher_list_.empty(); }
 
-  void NotifyLocked(grpc_connectivity_state state, const absl::Status& status) {
+  void NotifyLocked(grpc_connectivity_state state, const absl::Status& status)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(subchannel_->mu_) {
     if (state == GRPC_CHANNEL_READY) {
       // If we had not already notified for CONNECTING state, do so now.
       // (We may have missed this earlier, because if the transition
@@ -470,14 +469,14 @@
       if (state_ != GRPC_CHANNEL_CONNECTING) {
         state_ = GRPC_CHANNEL_CONNECTING;
         status_ = status;
-        watcher_list_.NotifyLocked(subchannel_, state_, status);
+        watcher_list_.NotifyLocked(subchannel_.get(), state_, status);
       }
       // If we've become connected, start health checking.
       StartHealthCheckingLocked();
     } else {
       state_ = state;
       status_ = status;
-      watcher_list_.NotifyLocked(subchannel_, state_, status);
+      watcher_list_.NotifyLocked(subchannel_.get(), state_, status);
       // We're not connected, so stop health checking.
       health_check_client_.reset();
     }
@@ -496,18 +495,19 @@
     if (new_state != GRPC_CHANNEL_SHUTDOWN && health_check_client_ != nullptr) {
       state_ = new_state;
       status_ = status;
-      watcher_list_.NotifyLocked(subchannel_, new_state, status);
+      watcher_list_.NotifyLocked(subchannel_.get(), new_state, status);
     }
   }
 
-  void StartHealthCheckingLocked() {
+  void StartHealthCheckingLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(subchannel_->mu_) {
     GPR_ASSERT(health_check_client_ == nullptr);
     health_check_client_ = MakeOrphanable<HealthCheckClient>(
         health_check_service_name_, subchannel_->connected_subchannel_,
         subchannel_->pollset_set_, subchannel_->channelz_node_, Ref());
   }
 
-  Subchannel* subchannel_;
+  WeakRefCountedPtr<Subchannel> subchannel_;
   std::string health_check_service_name_;
   OrphanablePtr<HealthCheckClient> health_check_client_;
   grpc_connectivity_state state_;
@@ -520,7 +520,8 @@
 //
 
 void Subchannel::HealthWatcherMap::AddWatcherLocked(
-    Subchannel* subchannel, grpc_connectivity_state initial_state,
+    WeakRefCountedPtr<Subchannel> subchannel,
+    grpc_connectivity_state initial_state,
     const std::string& health_check_service_name,
     RefCountedPtr<ConnectivityStateWatcherInterface> watcher) {
   // If the health check service name is not already present in the map,
@@ -528,8 +529,8 @@
   auto it = map_.find(health_check_service_name);
   HealthWatcher* health_watcher;
   if (it == map_.end()) {
-    auto w = MakeOrphanable<HealthWatcher>(
-        subchannel, health_check_service_name, subchannel->state_);
+    auto w = MakeOrphanable<HealthWatcher>(std::move(subchannel),
+                                           health_check_service_name);
     health_watcher = w.get();
     map_.emplace(health_check_service_name, std::move(w));
   } else {
@@ -647,14 +648,16 @@
   return state_change;
 }
 
-Subchannel::Subchannel(SubchannelKey* key,
+Subchannel::Subchannel(SubchannelKey key,
                        OrphanablePtr<SubchannelConnector> connector,
                        const grpc_channel_args* args)
-    : key_(key),
+    : DualRefCounted<Subchannel>(
+          GRPC_TRACE_FLAG_ENABLED(grpc_trace_subchannel_refcount) ? "Subchannel"
+                                                                  : nullptr),
+      key_(std::move(key)),
       connector_(std::move(connector)),
       backoff_(ParseArgsForBackoffValues(args, &min_connect_timeout_ms_)) {
   GRPC_STATS_INC_CLIENT_SUBCHANNELS_CREATED();
-  gpr_atm_no_barrier_store(&ref_pair_, 1 << INTERNAL_REF_BITS);
   pollset_set_ = grpc_pollset_set_create();
   grpc_resolved_address* addr =
       static_cast<grpc_resolved_address*>(gpr_malloc(sizeof(*addr)));
@@ -704,26 +707,26 @@
   grpc_channel_args_destroy(args_);
   connector_.reset();
   grpc_pollset_set_destroy(pollset_set_);
-  delete key_;
 }
 
-Subchannel* Subchannel::Create(OrphanablePtr<SubchannelConnector> connector,
-                               const grpc_channel_args* args) {
-  SubchannelKey* key = new SubchannelKey(args);
+RefCountedPtr<Subchannel> Subchannel::Create(
+    OrphanablePtr<SubchannelConnector> connector,
+    const grpc_channel_args* args) {
+  SubchannelKey key(args);
   SubchannelPoolInterface* subchannel_pool =
       SubchannelPoolInterface::GetSubchannelPoolFromChannelArgs(args);
   GPR_ASSERT(subchannel_pool != nullptr);
-  Subchannel* c = subchannel_pool->FindSubchannel(key);
+  RefCountedPtr<Subchannel> c = subchannel_pool->FindSubchannel(key);
   if (c != nullptr) {
-    delete key;
     return c;
   }
-  c = new Subchannel(key, std::move(connector), args);
+  c = MakeRefCounted<Subchannel>(std::move(key), std::move(connector), args);
   // Try to register the subchannel before setting the subchannel pool.
   // Otherwise, in case of a registration race, unreffing c in
   // RegisterSubchannel() will cause c to be tried to be unregistered, while
   // its key maps to a different subchannel.
-  Subchannel* registered = subchannel_pool->RegisterSubchannel(key, c);
+  RefCountedPtr<Subchannel> registered =
+      subchannel_pool->RegisterSubchannel(c->key_, c);
   if (registered == c) c->subchannel_pool_ = subchannel_pool->Ref();
   return registered;
 }
@@ -747,68 +750,6 @@
   }
 }
 
-Subchannel* Subchannel::Ref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  gpr_atm old_refs;
-  old_refs = RefMutate((1 << INTERNAL_REF_BITS),
-                       0 GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE("STRONG_REF"));
-  GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0);
-  return this;
-}
-
-void Subchannel::Unref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  gpr_atm old_refs;
-  // add a weak ref and subtract a strong ref (atomically)
-  old_refs = RefMutate(
-      static_cast<gpr_atm>(1) - static_cast<gpr_atm>(1 << INTERNAL_REF_BITS),
-      1 GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE("STRONG_UNREF"));
-  if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) {
-    Disconnect();
-  }
-  GRPC_SUBCHANNEL_WEAK_UNREF(this, "strong-unref");
-}
-
-Subchannel* Subchannel::WeakRef(GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  gpr_atm old_refs;
-  old_refs = RefMutate(1, 0 GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE("WEAK_REF"));
-  GPR_ASSERT(old_refs != 0);
-  return this;
-}
-
-namespace {
-
-void subchannel_destroy(void* arg, grpc_error* /*error*/) {
-  Subchannel* self = static_cast<Subchannel*>(arg);
-  delete self;
-}
-
-}  // namespace
-
-void Subchannel::WeakUnref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  gpr_atm old_refs;
-  old_refs = RefMutate(-static_cast<gpr_atm>(1),
-                       1 GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE("WEAK_UNREF"));
-  if (old_refs == 1) {
-    ExecCtx::Run(DEBUG_LOCATION,
-                 GRPC_CLOSURE_CREATE(subchannel_destroy, this,
-                                     grpc_schedule_on_exec_ctx),
-                 GRPC_ERROR_NONE);
-  }
-}
-
-Subchannel* Subchannel::RefFromWeakRef() {
-  for (;;) {
-    gpr_atm old_refs = gpr_atm_acq_load(&ref_pair_);
-    if (old_refs >= (1 << INTERNAL_REF_BITS)) {
-      gpr_atm new_refs = old_refs + (1 << INTERNAL_REF_BITS);
-      if (gpr_atm_rel_cas(&ref_pair_, old_refs, new_refs)) {
-        return this;
-      }
-    } else {
-      return nullptr;
-    }
-  }
-}
-
 const char* Subchannel::GetTargetAddress() {
   const grpc_arg* addr_arg =
       grpc_channel_args_find(args_, GRPC_ARG_SUBCHANNEL_ADDRESS);
@@ -854,7 +795,8 @@
     watcher_list_.AddWatcherLocked(std::move(watcher));
   } else {
     health_watcher_map_.AddWatcherLocked(
-        this, initial_state, *health_check_service_name, std::move(watcher));
+        WeakRef(DEBUG_LOCATION, "health_watcher"), initial_state,
+        *health_check_service_name, std::move(watcher));
   }
 }
 
@@ -891,6 +833,21 @@
   }
 }
 
+void Subchannel::Orphan() {
+  // The subchannel_pool is only used once here in this subchannel, so the
+  // access can be outside of the lock.
+  if (subchannel_pool_ != nullptr) {
+    subchannel_pool_->UnregisterSubchannel(key_, this);
+    subchannel_pool_.reset();
+  }
+  MutexLock lock(&mu_);
+  GPR_ASSERT(!disconnected_);
+  disconnected_ = true;
+  connector_.reset();
+  connected_subchannel_.reset();
+  health_watcher_map_.ShutdownLocked();
+}
+
 grpc_arg Subchannel::CreateSubchannelAddressArg(
     const grpc_resolved_address* addr) {
   return grpc_channel_arg_string_create(
@@ -984,7 +941,8 @@
     return;
   }
   connecting_ = true;
-  GRPC_SUBCHANNEL_WEAK_REF(this, "connecting");
+  WeakRef(DEBUG_LOCATION, "connecting")
+      .release();  // ref held by pending connect
   if (!backoff_begun_) {
     backoff_begun_ = true;
     ContinueConnectingLocked();
@@ -1005,11 +963,9 @@
   }
 }
 
-void Subchannel::OnRetryAlarm(void* arg, grpc_error* error) {
-  Subchannel* c = static_cast<Subchannel*>(arg);
-  // TODO(soheilhy): Once subchannel refcounting is simplified, we can get use
-  //                 MutexLock instead of ReleasableMutexLock, here.
-  ReleasableMutexLock lock(&c->mu_);
+void Subchannel::OnRetryAlarm(void* arg, grpc_error_handle error) {
+  WeakRefCountedPtr<Subchannel> c(static_cast<Subchannel*>(arg));
+  MutexLock lock(&c->mu_);
   c->have_retry_alarm_ = false;
   if (c->disconnected_) {
     error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Disconnected",
@@ -1023,10 +979,9 @@
   if (error == GRPC_ERROR_NONE) {
     gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
     c->ContinueConnectingLocked();
-    lock.Unlock();
-  } else {
-    lock.Unlock();
-    GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
+    // Still connecting, keep ref around. Note that this stolen ref won't
+    // be dropped without first acquiring c->mu_.
+    c.release();
   }
   GRPC_ERROR_UNREF(error);
 }
@@ -1043,33 +998,30 @@
   connector_->Connect(args, &connecting_result_, &on_connecting_finished_);
 }
 
-void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) {
-  auto* c = static_cast<Subchannel*>(arg);
+void Subchannel::OnConnectingFinished(void* arg, grpc_error_handle error) {
+  WeakRefCountedPtr<Subchannel> c(static_cast<Subchannel*>(arg));
   const grpc_channel_args* delete_channel_args =
       c->connecting_result_.channel_args;
-  GRPC_SUBCHANNEL_WEAK_REF(c, "on_connecting_finished");
   {
     MutexLock lock(&c->mu_);
     c->connecting_ = false;
     if (c->connecting_result_.transport != nullptr &&
         c->PublishTransportLocked()) {
       // Do nothing, transport was published.
-    } else if (c->disconnected_) {
-      GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
-    } else {
-      gpr_log(GPR_INFO, "Connect failed: %s", grpc_error_string(error));
+    } else if (!c->disconnected_) {
+      gpr_log(GPR_INFO, "Connect failed: %s",
+              grpc_error_std_string(error).c_str());
       c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE,
                                     grpc_error_to_absl_status(error));
-      GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
     }
   }
-  GRPC_SUBCHANNEL_WEAK_UNREF(c, "on_connecting_finished");
   grpc_channel_args_destroy(delete_channel_args);
+  c.reset(DEBUG_LOCATION, "connecting");
 }
 
 namespace {
 
-void ConnectionDestroy(void* arg, grpc_error* /*error*/) {
+void ConnectionDestroy(void* arg, grpc_error_handle /*error*/) {
   grpc_channel_stack* stk = static_cast<grpc_channel_stack*>(arg);
   grpc_channel_stack_destroy(stk);
   gpr_free(stk);
@@ -1089,13 +1041,13 @@
     return false;
   }
   grpc_channel_stack* stk;
-  grpc_error* error = grpc_channel_stack_builder_finish(
+  grpc_error_handle error = grpc_channel_stack_builder_finish(
       builder, 0, 1, ConnectionDestroy, nullptr,
       reinterpret_cast<void**>(&stk));
   if (error != GRPC_ERROR_NONE) {
     grpc_transport_destroy(connecting_result_.transport);
     gpr_log(GPR_ERROR, "error initializing subchannel stack: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return false;
   }
@@ -1117,39 +1069,11 @@
   }
   // Start watching connected subchannel.
   connected_subchannel_->StartWatch(
-      pollset_set_, MakeOrphanable<ConnectedSubchannelStateWatcher>(this));
+      pollset_set_, MakeOrphanable<ConnectedSubchannelStateWatcher>(
+                        WeakRef(DEBUG_LOCATION, "state_watcher")));
   // Report initial state.
   SetConnectivityStateLocked(GRPC_CHANNEL_READY, absl::Status());
   return true;
 }
 
-void Subchannel::Disconnect() {
-  // The subchannel_pool is only used once here in this subchannel, so the
-  // access can be outside of the lock.
-  if (subchannel_pool_ != nullptr) {
-    subchannel_pool_->UnregisterSubchannel(key_);
-    subchannel_pool_.reset();
-  }
-  MutexLock lock(&mu_);
-  GPR_ASSERT(!disconnected_);
-  disconnected_ = true;
-  connector_.reset();
-  connected_subchannel_.reset();
-  health_watcher_map_.ShutdownLocked();
-}
-
-gpr_atm Subchannel::RefMutate(
-    gpr_atm delta, int barrier GRPC_SUBCHANNEL_REF_MUTATE_EXTRA_ARGS) {
-  gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&ref_pair_, delta)
-                            : gpr_atm_no_barrier_fetch_add(&ref_pair_, delta);
-#ifndef NDEBUG
-  if (grpc_trace_subchannel_refcount.enabled()) {
-    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-            "SUBCHANNEL: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", this,
-            purpose, old_val, old_val + delta, reason);
-  }
-#endif
-  return old_val;
-}
-
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/subchannel.h b/grpc/src/core/ext/filters/client_channel/subchannel.h
index 952a02a..9667fe7 100644
--- a/grpc/src/core/ext/filters/client_channel/subchannel.h
+++ b/grpc/src/core/ext/filters/client_channel/subchannel.h
@@ -30,6 +30,7 @@
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/gpr/time_precise.h"
 #include "src/core/lib/gprpp/arena.h"
+#include "src/core/lib/gprpp/dual_ref_counted.h"
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
@@ -41,31 +42,6 @@
 // Channel arg containing a URI indicating the address to connect to.
 #define GRPC_ARG_SUBCHANNEL_ADDRESS "grpc.subchannel_address"
 
-// For debugging refcounting.
-#ifndef NDEBUG
-#define GRPC_SUBCHANNEL_REF(p, r) (p)->Ref(__FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) (p)->RefFromWeakRef()
-#define GRPC_SUBCHANNEL_UNREF(p, r) (p)->Unref(__FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_WEAK_REF(p, r) (p)->WeakRef(__FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_WEAK_UNREF(p, r) (p)->WeakUnref(__FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS \
-  const char *file, int line, const char *reason
-#define GRPC_SUBCHANNEL_REF_REASON reason
-#define GRPC_SUBCHANNEL_REF_MUTATE_EXTRA_ARGS \
-  , GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char* purpose
-#define GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE(x) , file, line, reason, x
-#else
-#define GRPC_SUBCHANNEL_REF(p, r) (p)->Ref()
-#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) (p)->RefFromWeakRef()
-#define GRPC_SUBCHANNEL_UNREF(p, r) (p)->Unref()
-#define GRPC_SUBCHANNEL_WEAK_REF(p, r) (p)->WeakRef()
-#define GRPC_SUBCHANNEL_WEAK_UNREF(p, r) (p)->WeakUnref()
-#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS
-#define GRPC_SUBCHANNEL_REF_REASON ""
-#define GRPC_SUBCHANNEL_REF_MUTATE_EXTRA_ARGS
-#define GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE(x)
-#endif
-
 namespace grpc_core {
 
 class SubchannelCall;
@@ -111,7 +87,8 @@
     grpc_call_context_element* context;
     CallCombiner* call_combiner;
   };
-  static RefCountedPtr<SubchannelCall> Create(Args args, grpc_error** error);
+  static RefCountedPtr<SubchannelCall> Create(Args args,
+                                              grpc_error_handle* error);
 
   // Continues processing a transport stream op batch.
   void StartTransportStreamOpBatch(grpc_transport_stream_op_batch* batch);
@@ -137,20 +114,20 @@
   template <typename T>
   friend class RefCountedPtr;
 
-  SubchannelCall(Args args, grpc_error** error);
+  SubchannelCall(Args args, grpc_error_handle* error);
 
   // If channelz is enabled, intercepts recv_trailing so that we may check the
   // status and associate it to a subchannel.
   void MaybeInterceptRecvTrailingMetadata(
       grpc_transport_stream_op_batch* batch);
 
-  static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
+  static void RecvTrailingMetadataReady(void* arg, grpc_error_handle error);
 
   // Interface of RefCounted<>.
   void IncrementRefCount();
   void IncrementRefCount(const DebugLocation& location, const char* reason);
 
-  static void Destroy(void* arg, grpc_error* error);
+  static void Destroy(void* arg, grpc_error_handle error);
 
   RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
   grpc_closure* after_call_stack_destroy_ = nullptr;
@@ -168,7 +145,7 @@
 // different from the SubchannelInterface that is exposed to LB policy
 // implementations.  The client channel provides an adaptor class
 // (SubchannelWrapper) that "converts" between the two.
-class Subchannel {
+class Subchannel : public DualRefCounted<Subchannel> {
  public:
   class ConnectivityStateWatcherInterface
       : public RefCounted<ConnectivityStateWatcherInterface> {
@@ -204,37 +181,29 @@
     ConnectivityStateChange PopConnectivityStateChange();
 
    private:
+    Mutex mu_;  // protects the queue
     // Keeps track of the updates that the watcher instance must be notified of.
     // TODO(yashkt): This is currently needed to send the state updates in the
     // right order when asynchronously notifying. This will no longer be
     // necessary when we have access to EventManager.
-    std::deque<ConnectivityStateChange> connectivity_state_queue_;
-    Mutex mu_;  // protects the queue
+    std::deque<ConnectivityStateChange> connectivity_state_queue_
+        ABSL_GUARDED_BY(&mu_);
   };
 
-  // The ctor and dtor are not intended to use directly.
-  Subchannel(SubchannelKey* key, OrphanablePtr<SubchannelConnector> connector,
-             const grpc_channel_args* args);
-  ~Subchannel();
-
   // Creates a subchannel given \a connector and \a args.
-  static Subchannel* Create(OrphanablePtr<SubchannelConnector> connector,
-                            const grpc_channel_args* args);
+  static RefCountedPtr<Subchannel> Create(
+      OrphanablePtr<SubchannelConnector> connector,
+      const grpc_channel_args* args);
+
+  // The ctor and dtor are not intended to use directly.
+  Subchannel(SubchannelKey key, OrphanablePtr<SubchannelConnector> connector,
+             const grpc_channel_args* args);
+  ~Subchannel() override;
 
   // Throttles keepalive time to \a new_keepalive_time iff \a new_keepalive_time
   // is larger than the subchannel's current keepalive time. The updated value
   // will have an affect when the subchannel creates a new ConnectedSubchannel.
-  void ThrottleKeepaliveTime(int new_keepalive_time);
-
-  // Strong and weak refcounting.
-  Subchannel* Ref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-  void Unref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-  Subchannel* WeakRef(GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-  void WeakUnref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-  // Attempts to return a strong ref when only the weak refcount is guaranteed
-  // non-zero. If the strong refcount is zero, does not alter the refcount and
-  // returns null.
-  Subchannel* RefFromWeakRef();
+  void ThrottleKeepaliveTime(int new_keepalive_time) ABSL_LOCKS_EXCLUDED(mu_);
 
   // Gets the string representing the subchannel address.
   // Caller doesn't take ownership.
@@ -251,7 +220,8 @@
   // If the return value is GRPC_CHANNEL_READY, also sets *connected_subchannel.
   grpc_connectivity_state CheckConnectivityState(
       const absl::optional<std::string>& health_check_service_name,
-      RefCountedPtr<ConnectedSubchannel>* connected_subchannel);
+      RefCountedPtr<ConnectedSubchannel>* connected_subchannel)
+      ABSL_LOCKS_EXCLUDED(mu_);
 
   // Starts watching the subchannel's connectivity state.
   // The first callback to the watcher will be delivered when the
@@ -264,23 +234,27 @@
   void WatchConnectivityState(
       grpc_connectivity_state initial_state,
       const absl::optional<std::string>& health_check_service_name,
-      RefCountedPtr<ConnectivityStateWatcherInterface> watcher);
+      RefCountedPtr<ConnectivityStateWatcherInterface> watcher)
+      ABSL_LOCKS_EXCLUDED(mu_);
 
   // Cancels a connectivity state watch.
   // If the watcher has already been destroyed, this is a no-op.
   void CancelConnectivityStateWatch(
       const absl::optional<std::string>& health_check_service_name,
-      ConnectivityStateWatcherInterface* watcher);
+      ConnectivityStateWatcherInterface* watcher) ABSL_LOCKS_EXCLUDED(mu_);
 
   // Attempt to connect to the backend.  Has no effect if already connected.
-  void AttemptToConnect();
+  void AttemptToConnect() ABSL_LOCKS_EXCLUDED(mu_);
 
   // Resets the connection backoff of the subchannel.
   // TODO(roth): Move connection backoff out of subchannels and up into LB
   // policy code (probably by adding a SubchannelGroup between
   // SubchannelList and SubchannelData), at which point this method can
   // go away.
-  void ResetBackoff();
+  void ResetBackoff() ABSL_LOCKS_EXCLUDED(mu_);
+
+  // Tears down any existing connection, and arranges for destruction
+  void Orphan() override ABSL_LOCKS_EXCLUDED(mu_);
 
   // Returns a new channel arg encoding the subchannel address as a URI
   // string. Caller is responsible for freeing the string.
@@ -333,18 +307,20 @@
   class HealthWatcherMap {
    public:
     void AddWatcherLocked(
-        Subchannel* subchannel, grpc_connectivity_state initial_state,
+        WeakRefCountedPtr<Subchannel> subchannel,
+        grpc_connectivity_state initial_state,
         const std::string& health_check_service_name,
         RefCountedPtr<ConnectivityStateWatcherInterface> watcher);
     void RemoveWatcherLocked(const std::string& health_check_service_name,
                              ConnectivityStateWatcherInterface* watcher);
 
     // Notifies the watcher when the subchannel's state changes.
-    void NotifyLocked(grpc_connectivity_state state,
-                      const absl::Status& status);
+    void NotifyLocked(grpc_connectivity_state state, const absl::Status& status)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&Subchannel::mu_);
 
     grpc_connectivity_state CheckConnectivityStateLocked(
-        Subchannel* subchannel, const std::string& health_check_service_name);
+        Subchannel* subchannel, const std::string& health_check_service_name)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&Subchannel::mu_);
 
     void ShutdownLocked();
 
@@ -360,72 +336,65 @@
 
   // Sets the subchannel's connectivity state to \a state.
   void SetConnectivityStateLocked(grpc_connectivity_state state,
-                                  const absl::Status& status);
+                                  const absl::Status& status)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   // Methods for connection.
-  void MaybeStartConnectingLocked();
-  static void OnRetryAlarm(void* arg, grpc_error* error);
-  void ContinueConnectingLocked();
-  static void OnConnectingFinished(void* arg, grpc_error* error);
-  bool PublishTransportLocked();
-  void Disconnect();
-
-  gpr_atm RefMutate(gpr_atm delta,
-                    int barrier GRPC_SUBCHANNEL_REF_MUTATE_EXTRA_ARGS);
+  void MaybeStartConnectingLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+  static void OnRetryAlarm(void* arg, grpc_error_handle error)
+      ABSL_LOCKS_EXCLUDED(mu_);
+  void ContinueConnectingLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+  static void OnConnectingFinished(void* arg, grpc_error_handle error)
+      ABSL_LOCKS_EXCLUDED(mu_);
+  bool PublishTransportLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   // The subchannel pool this subchannel is in.
   RefCountedPtr<SubchannelPoolInterface> subchannel_pool_;
   // TODO(juanlishen): Consider using args_ as key_ directly.
   // Subchannel key that identifies this subchannel in the subchannel pool.
-  SubchannelKey* key_;
+  const SubchannelKey key_;
   // Channel args.
   grpc_channel_args* args_;
   // pollset_set tracking who's interested in a connection being setup.
   grpc_pollset_set* pollset_set_;
-  // Protects the other members.
-  Mutex mu_;
-  // Refcount
-  //    - lower INTERNAL_REF_BITS bits are for internal references:
-  //      these do not keep the subchannel open.
-  //    - upper remaining bits are for public references: these do
-  //      keep the subchannel open
-  gpr_atm ref_pair_;
-
-  // Connection states.
-  OrphanablePtr<SubchannelConnector> connector_;
-  // Set during connection.
-  SubchannelConnector::Result connecting_result_;
-  grpc_closure on_connecting_finished_;
-  // Active connection, or null.
-  RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
-  bool connecting_ = false;
-  bool disconnected_ = false;
-
-  // Connectivity state tracking.
-  grpc_connectivity_state state_ = GRPC_CHANNEL_IDLE;
-  absl::Status status_;
-  // The list of watchers without a health check service name.
-  ConnectivityStateWatcherList watcher_list_;
-  // The map of watchers with health check service names.
-  HealthWatcherMap health_watcher_map_;
-
-  // Backoff state.
-  BackOff backoff_;
-  grpc_millis next_attempt_deadline_;
-  grpc_millis min_connect_timeout_ms_;
-  bool backoff_begun_ = false;
-
-  // Retry alarm.
-  grpc_timer retry_alarm_;
-  grpc_closure on_retry_alarm_;
-  bool have_retry_alarm_ = false;
-  // reset_backoff() was called while alarm was pending.
-  bool retry_immediately_ = false;
-  // Keepalive time period (-1 for unset)
-  int keepalive_time_ = -1;
-
   // Channelz tracking.
   RefCountedPtr<channelz::SubchannelNode> channelz_node_;
+
+  // Connection state.
+  OrphanablePtr<SubchannelConnector> connector_;
+  SubchannelConnector::Result connecting_result_;
+  grpc_closure on_connecting_finished_;
+
+  // Protects the other members.
+  Mutex mu_;
+
+  // Active connection, or null.
+  RefCountedPtr<ConnectedSubchannel> connected_subchannel_ ABSL_GUARDED_BY(mu_);
+  bool connecting_ ABSL_GUARDED_BY(mu_) = false;
+  bool disconnected_ ABSL_GUARDED_BY(mu_) = false;
+
+  // Connectivity state tracking.
+  grpc_connectivity_state state_ ABSL_GUARDED_BY(mu_) = GRPC_CHANNEL_IDLE;
+  absl::Status status_ ABSL_GUARDED_BY(mu_);
+  // The list of watchers without a health check service name.
+  ConnectivityStateWatcherList watcher_list_ ABSL_GUARDED_BY(mu_);
+  // The map of watchers with health check service names.
+  HealthWatcherMap health_watcher_map_ ABSL_GUARDED_BY(mu_);
+
+  // Backoff state.
+  BackOff backoff_ ABSL_GUARDED_BY(mu_);
+  grpc_millis next_attempt_deadline_ ABSL_GUARDED_BY(mu_);
+  grpc_millis min_connect_timeout_ms_ ABSL_GUARDED_BY(mu_);
+  bool backoff_begun_ ABSL_GUARDED_BY(mu_) = false;
+
+  // Retry alarm.
+  grpc_timer retry_alarm_ ABSL_GUARDED_BY(mu_);
+  grpc_closure on_retry_alarm_ ABSL_GUARDED_BY(mu_);
+  bool have_retry_alarm_ ABSL_GUARDED_BY(mu_) = false;
+  // reset_backoff() was called while alarm was pending.
+  bool retry_immediately_ ABSL_GUARDED_BY(mu_) = false;
+  // Keepalive time period (-1 for unset)
+  int keepalive_time_ ABSL_GUARDED_BY(mu_) = -1;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.cc b/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.cc
index bb35f22..308541c 100644
--- a/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.cc
+++ b/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.cc
@@ -44,13 +44,27 @@
 }
 
 SubchannelKey& SubchannelKey::operator=(const SubchannelKey& other) {
+  if (&other == this) {
+    return *this;
+  }
   grpc_channel_args_destroy(const_cast<grpc_channel_args*>(args_));
   Init(other.args_, grpc_channel_args_copy);
   return *this;
 }
 
-int SubchannelKey::Cmp(const SubchannelKey& other) const {
-  return grpc_channel_args_compare(args_, other.args_);
+SubchannelKey::SubchannelKey(SubchannelKey&& other) noexcept {
+  args_ = other.args_;
+  other.args_ = nullptr;
+}
+
+SubchannelKey& SubchannelKey::operator=(SubchannelKey&& other) noexcept {
+  args_ = other.args_;
+  other.args_ = nullptr;
+  return *this;
+}
+
+bool SubchannelKey::operator<(const SubchannelKey& other) const {
+  return grpc_channel_args_compare(args_, other.args_) < 0;
 }
 
 void SubchannelKey::Init(
diff --git a/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.h b/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.h
index f320ab6..8a8a0cb 100644
--- a/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.h
+++ b/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.h
@@ -41,11 +41,11 @@
   // Copyable.
   SubchannelKey(const SubchannelKey& other);
   SubchannelKey& operator=(const SubchannelKey& other);
-  // Not movable.
-  SubchannelKey(SubchannelKey&&) = delete;
-  SubchannelKey& operator=(SubchannelKey&&) = delete;
+  // Movable
+  SubchannelKey(SubchannelKey&&) noexcept;
+  SubchannelKey& operator=(SubchannelKey&&) noexcept;
 
-  int Cmp(const SubchannelKey& other) const;
+  bool operator<(const SubchannelKey& other) const;
 
  private:
   // Initializes the subchannel key with the given \a args and the function to
@@ -72,15 +72,17 @@
   // Registers a subchannel against a key. Returns the subchannel registered
   // with \a key, which may be different from \a constructed because we reuse
   // (instead of update) any existing subchannel already registered with \a key.
-  virtual Subchannel* RegisterSubchannel(SubchannelKey* key,
-                                         Subchannel* constructed) = 0;
+  virtual RefCountedPtr<Subchannel> RegisterSubchannel(
+      const SubchannelKey& key, RefCountedPtr<Subchannel> constructed) = 0;
 
   // Removes the registered subchannel found by \a key.
-  virtual void UnregisterSubchannel(SubchannelKey* key) = 0;
+  virtual void UnregisterSubchannel(const SubchannelKey& key,
+                                    Subchannel* subchannel) = 0;
 
   // Finds the subchannel registered for the given subchannel key. Returns NULL
   // if no such channel exists. Thread-safe.
-  virtual Subchannel* FindSubchannel(SubchannelKey* key) = 0;
+  virtual RefCountedPtr<Subchannel> FindSubchannel(
+      const SubchannelKey& key) = 0;
 
   // Creates a channel arg from \a subchannel pool.
   static grpc_arg CreateChannelArg(SubchannelPoolInterface* subchannel_pool);
diff --git a/grpc/src/core/ext/filters/client_idle/client_idle_filter.cc b/grpc/src/core/ext/filters/client_idle/client_idle_filter.cc
index 2ea3ead..01abaab 100644
--- a/grpc/src/core/ext/filters/client_idle/client_idle_filter.cc
+++ b/grpc/src/core/ext/filters/client_idle/client_idle_filter.cc
@@ -126,8 +126,8 @@
 
 class ChannelData {
  public:
-  static grpc_error* Init(grpc_channel_element* elem,
-                          grpc_channel_element_args* args);
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args);
   static void Destroy(grpc_channel_element* elem);
 
   static void StartTransportOp(grpc_channel_element* elem,
@@ -139,11 +139,12 @@
 
  private:
   ChannelData(grpc_channel_element* elem, grpc_channel_element_args* args,
-              grpc_error** error);
+              grpc_error_handle* error);
   ~ChannelData() = default;
 
-  static void IdleTimerCallback(void* arg, grpc_error* error);
-  static void IdleTransportOpCompleteCallback(void* arg, grpc_error* error);
+  static void IdleTimerCallback(void* arg, grpc_error_handle error);
+  static void IdleTransportOpCompleteCallback(void* arg,
+                                              grpc_error_handle error);
 
   void StartIdleTimer();
 
@@ -170,9 +171,9 @@
   grpc_closure idle_transport_op_complete_callback_;
 };
 
-grpc_error* ChannelData::Init(grpc_channel_element* elem,
-                              grpc_channel_element_args* args) {
-  grpc_error* error = GRPC_ERROR_NONE;
+grpc_error_handle ChannelData::Init(grpc_channel_element* elem,
+                                    grpc_channel_element_args* args) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   new (elem->channel_data) ChannelData(elem, args, &error);
   return error;
 }
@@ -187,7 +188,7 @@
   ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
   // Catch the disconnect_with_error transport op.
   if (op->disconnect_with_error != nullptr) {
-    // IncreaseCallCount() introduces a dummy call and prevent the timer from
+    // IncreaseCallCount() introduces a phony call and prevent the timer from
     // being reset by other threads.
     chand->IncreaseCallCount();
     // If the timer has been set, cancel the timer.
@@ -283,7 +284,7 @@
 
 ChannelData::ChannelData(grpc_channel_element* elem,
                          grpc_channel_element_args* args,
-                         grpc_error** /*error*/)
+                         grpc_error_handle* /*error*/)
     : elem_(elem),
       channel_stack_(args->channel_stack),
       client_idle_timeout_(GetClientIdleTimeout(args->channel_args)) {
@@ -303,7 +304,7 @@
                     grpc_schedule_on_exec_ctx);
 }
 
-void ChannelData::IdleTimerCallback(void* arg, grpc_error* error) {
+void ChannelData::IdleTimerCallback(void* arg, grpc_error_handle error) {
   GRPC_IDLE_FILTER_LOG("timer alarms");
   ChannelData* chand = static_cast<ChannelData*>(arg);
   if (error != GRPC_ERROR_NONE) {
@@ -352,7 +353,7 @@
 }
 
 void ChannelData::IdleTransportOpCompleteCallback(void* arg,
-                                                  grpc_error* /*error*/) {
+                                                  grpc_error_handle /*error*/) {
   ChannelData* chand = static_cast<ChannelData*>(arg);
   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack_, "idle transport op");
 }
@@ -381,15 +382,15 @@
 
 class CallData {
  public:
-  static grpc_error* Init(grpc_call_element* elem,
-                          const grpc_call_element_args* args);
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args);
   static void Destroy(grpc_call_element* elem,
                       const grpc_call_final_info* final_info,
                       grpc_closure* then_schedule_closure);
 };
 
-grpc_error* CallData::Init(grpc_call_element* elem,
-                           const grpc_call_element_args* /*args*/) {
+grpc_error_handle CallData::Init(grpc_call_element* elem,
+                                 const grpc_call_element_args* /*args*/) {
   ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
   chand->IncreaseCallCount();
   return GRPC_ERROR_NONE;
diff --git a/grpc/src/core/ext/filters/deadline/deadline_filter.cc b/grpc/src/core/ext/filters/deadline/deadline_filter.cc
index 837e337..8944f5d 100644
--- a/grpc/src/core/ext/filters/deadline/deadline_filter.cc
+++ b/grpc/src/core/ext/filters/deadline/deadline_filter.cc
@@ -51,7 +51,7 @@
  private:
   // The on_complete callback used when sending a cancel_error batch down the
   // filter stack.  Yields the call combiner when the batch returns.
-  static void YieldCallCombiner(void* arg, grpc_error* /*ignored*/) {
+  static void YieldCallCombiner(void* arg, grpc_error_handle /*ignored*/) {
     TimerState* self = static_cast<TimerState*>(arg);
     grpc_deadline_state* deadline_state =
         static_cast<grpc_deadline_state*>(self->elem_->call_data);
@@ -62,7 +62,7 @@
 
   // This is called via the call combiner, so access to deadline_state is
   // synchronized.
-  static void SendCancelOpInCallCombiner(void* arg, grpc_error* error) {
+  static void SendCancelOpInCallCombiner(void* arg, grpc_error_handle error) {
     TimerState* self = static_cast<TimerState*>(arg);
     grpc_transport_stream_op_batch* batch = grpc_make_transport_stream_op(
         GRPC_CLOSURE_INIT(&self->closure_, YieldCallCombiner, self, nullptr));
@@ -72,7 +72,7 @@
   }
 
   // Timer callback.
-  static void TimerCallback(void* arg, grpc_error* error) {
+  static void TimerCallback(void* arg, grpc_error_handle error) {
     TimerState* self = static_cast<TimerState*>(arg);
     grpc_deadline_state* deadline_state =
         static_cast<grpc_deadline_state*>(self->elem_->call_data);
@@ -135,7 +135,7 @@
 }
 
 // Callback run when we receive trailing metadata.
-static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
+static void recv_trailing_metadata_ready(void* arg, grpc_error_handle error) {
   grpc_deadline_state* deadline_state = static_cast<grpc_deadline_state*>(arg);
   cancel_timer_if_needed(deadline_state);
   // Invoke the original callback.
@@ -168,7 +168,7 @@
   grpc_millis deadline;
   grpc_closure closure;
 };
-static void start_timer_after_init(void* arg, grpc_error* error) {
+static void start_timer_after_init(void* arg, grpc_error_handle error) {
   struct start_timer_after_init_state* state =
       static_cast<struct start_timer_after_init_state*>(arg);
   grpc_deadline_state* deadline_state =
@@ -241,8 +241,8 @@
 //
 
 // Constructor for channel_data.  Used for both client and server filters.
-static grpc_error* deadline_init_channel_elem(grpc_channel_element* /*elem*/,
-                                              grpc_channel_element_args* args) {
+static grpc_error_handle deadline_init_channel_elem(
+    grpc_channel_element* /*elem*/, grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   return GRPC_ERROR_NONE;
 }
@@ -268,8 +268,8 @@
 } server_call_data;
 
 // Constructor for call_data.  Used for both client and server filters.
-static grpc_error* deadline_init_call_elem(grpc_call_element* elem,
-                                           const grpc_call_element_args* args) {
+static grpc_error_handle deadline_init_call_elem(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   new (elem->call_data) grpc_deadline_state(elem, *args, args->deadline);
   return GRPC_ERROR_NONE;
 }
@@ -292,7 +292,7 @@
 }
 
 // Callback for receiving initial metadata on the server.
-static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
+static void recv_initial_metadata_ready(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
   start_timer_if_needed(elem, calld->recv_initial_metadata->deadline);
diff --git a/grpc/src/core/ext/filters/fault_injection/fault_injection_filter.cc b/grpc/src/core/ext/filters/fault_injection/fault_injection_filter.cc
new file mode 100644
index 0000000..5f8d779
--- /dev/null
+++ b/grpc/src/core/ext/filters/fault_injection/fault_injection_filter.cc
@@ -0,0 +1,501 @@
+//
+// Copyright 2021 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>
+
+#include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
+
+#include "absl/strings/numbers.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/ext/filters/client_channel/service_config_call_data.h"
+#include "src/core/ext/filters/fault_injection/service_config_parser.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gprpp/atomic.h"
+#include "src/core/lib/gprpp/sync.h"
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/transport/status_conversion.h"
+
+namespace grpc_core {
+
+TraceFlag grpc_fault_injection_filter_trace(false, "fault_injection_filter");
+
+namespace {
+
+Atomic<uint32_t> g_active_faults{0};
+static_assert(
+    std::is_trivially_destructible<Atomic<uint32_t>>::value,
+    "the active fault counter needs to have a trivially destructible type");
+
+inline int GetLinkedMetadatumValueInt(grpc_linked_mdelem* md) {
+  int res;
+  if (absl::SimpleAtoi(StringViewFromSlice(GRPC_MDVALUE(md->md)), &res)) {
+    return res;
+  } else {
+    return -1;
+  }
+}
+
+inline uint32_t GetLinkedMetadatumValueUnsignedInt(grpc_linked_mdelem* md) {
+  uint32_t res;
+  if (absl::SimpleAtoi(StringViewFromSlice(GRPC_MDVALUE(md->md)), &res)) {
+    return res;
+  } else {
+    return -1;
+  }
+}
+
+inline int64_t GetLinkedMetadatumValueInt64(grpc_linked_mdelem* md) {
+  int64_t res;
+  if (absl::SimpleAtoi(StringViewFromSlice(GRPC_MDVALUE(md->md)), &res)) {
+    return res;
+  } else {
+    return -1;
+  }
+}
+
+inline bool UnderFraction(const uint32_t numerator,
+                          const uint32_t denominator) {
+  if (numerator <= 0) return false;
+  if (numerator >= denominator) return true;
+  // Generate a random number in [0, denominator).
+  const uint32_t random_number = rand() % denominator;
+  return random_number < numerator;
+}
+
+class ChannelData {
+ public:
+  static grpc_error_handle Init(grpc_channel_element* elem,
+                                grpc_channel_element_args* args);
+  static void Destroy(grpc_channel_element* elem);
+
+  int index() const { return index_; }
+
+ private:
+  ChannelData(grpc_channel_element* elem, grpc_channel_element_args* args);
+  ~ChannelData() = default;
+
+  // The relative index of instances of the same filter.
+  int index_;
+};
+
+class CallData {
+ public:
+  static grpc_error_handle Init(grpc_call_element* elem,
+                                const grpc_call_element_args* args);
+
+  static void Destroy(grpc_call_element* elem,
+                      const grpc_call_final_info* /*final_info*/,
+                      grpc_closure* /*then_schedule_closure*/);
+
+  static void StartTransportStreamOpBatch(
+      grpc_call_element* elem, grpc_transport_stream_op_batch* batch);
+
+ private:
+  class ResumeBatchCanceller;
+
+  CallData(grpc_call_element* elem, const grpc_call_element_args* args);
+  ~CallData();
+
+  void DecideWhetherToInjectFaults(grpc_metadata_batch* initial_metadata);
+
+  // Checks if current active faults exceed the allowed max faults.
+  bool HaveActiveFaultsQuota(bool increment);
+
+  // Returns true if this RPC needs to be delayed. If so, this call will be
+  // counted as an active fault.
+  bool MaybeDelay();
+
+  // Returns the aborted RPC status if this RPC needs to be aborted. If so,
+  // this call will be counted as an active fault. Otherwise, it returns
+  // GRPC_ERROR_NONE.
+  // If this call is already been delay injected, skip the active faults
+  // quota check.
+  grpc_error_handle MaybeAbort();
+
+  // Delays the stream operations batch.
+  void DelayBatch(grpc_call_element* elem,
+                  grpc_transport_stream_op_batch* batch);
+
+  // Cancels the delay timer.
+  void CancelDelayTimer() { grpc_timer_cancel(&delay_timer_); }
+
+  // Finishes the fault injection, should only be called once.
+  void FaultInjectionFinished() {
+    g_active_faults.FetchSub(1, MemoryOrder::RELAXED);
+  }
+
+  // This is a callback that will be invoked after the delay timer is up.
+  static void ResumeBatch(void* arg, grpc_error_handle error);
+
+  // This is a callback invoked upon completion of recv_trailing_metadata.
+  // Injects the abort_error_ to the recv_trailing_metadata batch if needed.
+  static void HijackedRecvTrailingMetadataReady(void* arg, grpc_error_handle);
+
+  // Used to track the policy structs that needs to be destroyed in dtor.
+  bool fi_policy_owned_ = false;
+  const FaultInjectionMethodParsedConfig::FaultInjectionPolicy* fi_policy_;
+  grpc_call_stack* owning_call_;
+  Arena* arena_;
+  CallCombiner* call_combiner_;
+
+  // Indicates whether we are doing a delay and/or an abort for this call.
+  bool delay_request_ = false;
+  bool abort_request_ = false;
+
+  // Delay states
+  grpc_timer delay_timer_ ABSL_GUARDED_BY(delay_mu_);
+  ResumeBatchCanceller* resume_batch_canceller_ ABSL_GUARDED_BY(delay_mu_);
+  grpc_transport_stream_op_batch* delayed_batch_ ABSL_GUARDED_BY(delay_mu_);
+  // Abort states
+  grpc_error_handle abort_error_ = GRPC_ERROR_NONE;
+  grpc_closure recv_trailing_metadata_ready_;
+  grpc_closure* original_recv_trailing_metadata_ready_;
+  // Protects the asynchronous delay, resume, and cancellation.
+  Mutex delay_mu_;
+};
+
+// ChannelData
+
+grpc_error_handle ChannelData::Init(grpc_channel_element* elem,
+                                    grpc_channel_element_args* args) {
+  GPR_ASSERT(elem->filter == &FaultInjectionFilterVtable);
+  new (elem->channel_data) ChannelData(elem, args);
+  return GRPC_ERROR_NONE;
+}
+
+void ChannelData::Destroy(grpc_channel_element* elem) {
+  auto* chand = static_cast<ChannelData*>(elem->channel_data);
+  chand->~ChannelData();
+}
+
+ChannelData::ChannelData(grpc_channel_element* elem,
+                         grpc_channel_element_args* args)
+    : index_(grpc_channel_stack_filter_instance_number(args->channel_stack,
+                                                       elem)) {}
+
+// CallData::ResumeBatchCanceller
+
+class CallData::ResumeBatchCanceller {
+ public:
+  explicit ResumeBatchCanceller(grpc_call_element* elem) : elem_(elem) {
+    auto* calld = static_cast<CallData*>(elem->call_data);
+    GRPC_CALL_STACK_REF(calld->owning_call_, "ResumeBatchCanceller");
+    GRPC_CLOSURE_INIT(&closure_, &Cancel, this, grpc_schedule_on_exec_ctx);
+    calld->call_combiner_->SetNotifyOnCancel(&closure_);
+  }
+
+ private:
+  static void Cancel(void* arg, grpc_error_handle error) {
+    auto* self = static_cast<ResumeBatchCanceller*>(arg);
+    auto* chand = static_cast<ChannelData*>(self->elem_->channel_data);
+    auto* calld = static_cast<CallData*>(self->elem_->call_data);
+    {
+      MutexLock lock(&calld->delay_mu_);
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_fault_injection_filter_trace)) {
+        gpr_log(GPR_INFO,
+                "chand=%p calld=%p: cancelling schdueled pick: "
+                "error=%s self=%p calld->resume_batch_canceller_=%p",
+                chand, calld, grpc_error_std_string(error).c_str(), self,
+                calld->resume_batch_canceller_);
+      }
+      if (error != GRPC_ERROR_NONE && calld->resume_batch_canceller_ == self) {
+        // Cancel the delayed pick.
+        calld->CancelDelayTimer();
+        calld->FaultInjectionFinished();
+        // Fail pending batches on the call.
+        grpc_transport_stream_op_batch_finish_with_failure(
+            calld->delayed_batch_, GRPC_ERROR_REF(error),
+            calld->call_combiner_);
+      }
+    }
+    GRPC_CALL_STACK_UNREF(calld->owning_call_, "ResumeBatchCanceller");
+    delete self;
+  }
+
+  grpc_call_element* elem_;
+  grpc_closure closure_;
+};
+
+// CallData
+
+grpc_error_handle CallData::Init(grpc_call_element* elem,
+                                 const grpc_call_element_args* args) {
+  auto* calld = new (elem->call_data) CallData(elem, args);
+  if (calld->fi_policy_ == nullptr) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "failed to find fault injection policy");
+  }
+  return GRPC_ERROR_NONE;
+}
+
+void CallData::Destroy(grpc_call_element* elem,
+                       const grpc_call_final_info* /*final_info*/,
+                       grpc_closure* /*then_schedule_closure*/) {
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  calld->~CallData();
+}
+
+void CallData::StartTransportStreamOpBatch(
+    grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  // There should only be one send_initial_metdata op, and fault injection also
+  // only need to be enforced once.
+  if (batch->send_initial_metadata) {
+    calld->DecideWhetherToInjectFaults(
+        batch->payload->send_initial_metadata.send_initial_metadata);
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_fault_injection_filter_trace)) {
+      gpr_log(GPR_INFO,
+              "chand=%p calld=%p: Fault injection triggered delay=%d abort=%d",
+              elem->channel_data, calld, calld->delay_request_,
+              calld->abort_request_);
+    }
+    if (calld->MaybeDelay()) {
+      // Delay the batch, and pass down the batch in the scheduled closure.
+      calld->DelayBatch(elem, batch);
+      return;
+    }
+    grpc_error_handle abort_error = calld->MaybeAbort();
+    if (abort_error != GRPC_ERROR_NONE) {
+      calld->abort_error_ = abort_error;
+      grpc_transport_stream_op_batch_finish_with_failure(
+          batch, GRPC_ERROR_REF(calld->abort_error_), calld->call_combiner_);
+      return;
+    }
+  } else {
+    if (batch->recv_trailing_metadata) {
+      // Intercept recv_trailing_metadata callback so that we can inject the
+      // failure when aborting streaming calls, because their
+      // recv_trailing_metatdata op may not be on the same batch as the
+      // send_initial_metadata op.
+      calld->original_recv_trailing_metadata_ready_ =
+          batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
+      batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+          &calld->recv_trailing_metadata_ready_;
+    }
+    if (calld->abort_error_ != GRPC_ERROR_NONE) {
+      // If we already decided to abort, then immediately fail this batch.
+      grpc_transport_stream_op_batch_finish_with_failure(
+          batch, GRPC_ERROR_REF(calld->abort_error_), calld->call_combiner_);
+      return;
+    }
+  }
+  // Chain to the next filter.
+  grpc_call_next_op(elem, batch);
+}
+
+CallData::CallData(grpc_call_element* elem, const grpc_call_element_args* args)
+    : owning_call_(args->call_stack),
+      arena_(args->arena),
+      call_combiner_(args->call_combiner) {
+  auto* chand = static_cast<ChannelData*>(elem->channel_data);
+  // Fetch the fault injection policy from the service config, based on the
+  // relative index for which policy should this CallData use.
+  auto* service_config_call_data = static_cast<ServiceConfigCallData*>(
+      args->context[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value);
+  auto* method_params = static_cast<FaultInjectionMethodParsedConfig*>(
+      service_config_call_data->GetMethodParsedConfig(
+          FaultInjectionServiceConfigParser::ParserIndex()));
+  if (method_params != nullptr) {
+    fi_policy_ = method_params->fault_injection_policy(chand->index());
+  }
+  GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready_,
+                    HijackedRecvTrailingMetadataReady, elem,
+                    grpc_schedule_on_exec_ctx);
+}
+
+CallData::~CallData() {
+  if (fi_policy_owned_) {
+    fi_policy_->~FaultInjectionPolicy();
+  }
+  GRPC_ERROR_UNREF(abort_error_);
+}
+
+void CallData::DecideWhetherToInjectFaults(
+    grpc_metadata_batch* initial_metadata) {
+  FaultInjectionMethodParsedConfig::FaultInjectionPolicy* copied_policy =
+      nullptr;
+  // Update the policy with values in initial metadata.
+  if (!fi_policy_->abort_code_header.empty() ||
+      !fi_policy_->abort_percentage_header.empty() ||
+      !fi_policy_->delay_header.empty() ||
+      !fi_policy_->delay_percentage_header.empty()) {
+    // Defer the actual copy until the first matched header.
+    auto maybe_copy_policy_func = [this, &copied_policy]() {
+      if (copied_policy == nullptr) {
+        copied_policy =
+            arena_->New<FaultInjectionMethodParsedConfig::FaultInjectionPolicy>(
+                *fi_policy_);
+      }
+    };
+    for (grpc_linked_mdelem* md = initial_metadata->list.head; md != nullptr;
+         md = md->next) {
+      absl::string_view key = StringViewFromSlice(GRPC_MDKEY(md->md));
+      // Only perform string comparison if:
+      //   1. Needs to check this header;
+      //   2. The value is not been filled before.
+      if (!fi_policy_->abort_code_header.empty() &&
+          (copied_policy == nullptr ||
+           copied_policy->abort_code == GRPC_STATUS_OK) &&
+          key == fi_policy_->abort_code_header) {
+        maybe_copy_policy_func();
+        grpc_status_code_from_int(GetLinkedMetadatumValueInt(md),
+                                  &copied_policy->abort_code);
+      }
+      if (!fi_policy_->abort_percentage_header.empty() &&
+          key == fi_policy_->abort_percentage_header) {
+        maybe_copy_policy_func();
+        copied_policy->abort_percentage_numerator =
+            GPR_MIN(GetLinkedMetadatumValueUnsignedInt(md),
+                    fi_policy_->abort_percentage_numerator);
+      }
+      if (!fi_policy_->delay_header.empty() &&
+          (copied_policy == nullptr || copied_policy->delay == 0) &&
+          key == fi_policy_->delay_header) {
+        maybe_copy_policy_func();
+        copied_policy->delay = static_cast<grpc_millis>(
+            GPR_MAX(GetLinkedMetadatumValueInt64(md), 0));
+      }
+      if (!fi_policy_->delay_percentage_header.empty() &&
+          key == fi_policy_->delay_percentage_header) {
+        maybe_copy_policy_func();
+        copied_policy->delay_percentage_numerator =
+            GPR_MIN(GetLinkedMetadatumValueUnsignedInt(md),
+                    fi_policy_->delay_percentage_numerator);
+      }
+    }
+    if (copied_policy != nullptr) fi_policy_ = copied_policy;
+  }
+  // Roll the dice
+  delay_request_ = fi_policy_->delay != 0 &&
+                   UnderFraction(fi_policy_->delay_percentage_numerator,
+                                 fi_policy_->delay_percentage_denominator);
+  abort_request_ = fi_policy_->abort_code != GRPC_STATUS_OK &&
+                   UnderFraction(fi_policy_->abort_percentage_numerator,
+                                 fi_policy_->abort_percentage_denominator);
+  if (!delay_request_ && !abort_request_) {
+    if (copied_policy != nullptr) copied_policy->~FaultInjectionPolicy();
+    // No fault injection for this call
+  } else {
+    fi_policy_owned_ = copied_policy != nullptr;
+  }
+}
+
+bool CallData::HaveActiveFaultsQuota(bool increment) {
+  if (g_active_faults.Load(MemoryOrder::ACQUIRE) >= fi_policy_->max_faults) {
+    return false;
+  }
+  if (increment) g_active_faults.FetchAdd(1, MemoryOrder::RELAXED);
+  return true;
+}
+
+bool CallData::MaybeDelay() {
+  if (delay_request_) {
+    return HaveActiveFaultsQuota(true);
+  }
+  return false;
+}
+
+grpc_error_handle CallData::MaybeAbort() {
+  if (abort_request_ && (delay_request_ || HaveActiveFaultsQuota(false))) {
+    return grpc_error_set_int(
+        GRPC_ERROR_CREATE_FROM_COPIED_STRING(fi_policy_->abort_message.c_str()),
+        GRPC_ERROR_INT_GRPC_STATUS, fi_policy_->abort_code);
+  }
+  return GRPC_ERROR_NONE;
+}
+
+void CallData::DelayBatch(grpc_call_element* elem,
+                          grpc_transport_stream_op_batch* batch) {
+  MutexLock lock(&delay_mu_);
+  delayed_batch_ = batch;
+  resume_batch_canceller_ = new ResumeBatchCanceller(elem);
+  grpc_millis resume_time = ExecCtx::Get()->Now() + fi_policy_->delay;
+  GRPC_CLOSURE_INIT(&batch->handler_private.closure, ResumeBatch, elem,
+                    grpc_schedule_on_exec_ctx);
+  grpc_timer_init(&delay_timer_, resume_time, &batch->handler_private.closure);
+}
+
+void CallData::ResumeBatch(void* arg, grpc_error_handle error) {
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  MutexLock lock(&calld->delay_mu_);
+  // Cancelled or canceller has already run
+  if (error == GRPC_ERROR_CANCELLED ||
+      calld->resume_batch_canceller_ == nullptr) {
+    return;
+  }
+  if (GRPC_TRACE_FLAG_ENABLED(grpc_fault_injection_filter_trace)) {
+    gpr_log(GPR_INFO, "chand=%p calld=%p: Resuming delayed stream op batch %p",
+            elem->channel_data, calld, calld->delayed_batch_);
+  }
+  // Lame the canceller
+  calld->resume_batch_canceller_ = nullptr;
+  // Finish fault injection.
+  calld->FaultInjectionFinished();
+  // Abort if needed.
+  error = calld->MaybeAbort();
+  if (error != GRPC_ERROR_NONE) {
+    grpc_transport_stream_op_batch_finish_with_failure(
+        calld->delayed_batch_, error, calld->call_combiner_);
+    return;
+  }
+  // Chain to the next filter.
+  grpc_call_next_op(elem, calld->delayed_batch_);
+}
+
+void CallData::HijackedRecvTrailingMetadataReady(void* arg,
+                                                 grpc_error_handle error) {
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  auto* calld = static_cast<CallData*>(elem->call_data);
+  if (calld->abort_error_ != GRPC_ERROR_NONE) {
+    error = grpc_error_add_child(GRPC_ERROR_REF(error),
+                                 GRPC_ERROR_REF(calld->abort_error_));
+  } else {
+    error = GRPC_ERROR_REF(error);
+  }
+  Closure::Run(DEBUG_LOCATION, calld->original_recv_trailing_metadata_ready_,
+               error);
+}
+
+}  // namespace
+
+extern const grpc_channel_filter FaultInjectionFilterVtable = {
+    CallData::StartTransportStreamOpBatch,
+    grpc_channel_next_op,
+    sizeof(CallData),
+    CallData::Init,
+    grpc_call_stack_ignore_set_pollset_or_pollset_set,
+    CallData::Destroy,
+    sizeof(ChannelData),
+    ChannelData::Init,
+    ChannelData::Destroy,
+    grpc_channel_next_get_info,
+    "fault_injection_filter",
+};
+
+void FaultInjectionFilterInit(void) {
+  grpc_core::FaultInjectionServiceConfigParser::Register();
+}
+
+void FaultInjectionFilterShutdown(void) {}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/fault_injection/fault_injection_filter.h b/grpc/src/core/ext/filters/fault_injection/fault_injection_filter.h
new file mode 100644
index 0000000..fbc1eb0
--- /dev/null
+++ b/grpc/src/core/ext/filters/fault_injection/fault_injection_filter.h
@@ -0,0 +1,39 @@
+//
+// Copyright 2021 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_FAULT_INJECTION_FAULT_INJECTION_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_FAULT_INJECTION_FILTER_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/filters/fault_injection/service_config_parser.h"
+#include "src/core/lib/channel/channel_stack.h"
+
+// Channel arg key for enabling parsing fault injection via method config.
+#define GRPC_ARG_PARSE_FAULT_INJECTION_METHOD_CONFIG \
+  "grpc.parse_fault_injection_method_config"
+
+namespace grpc_core {
+
+// This channel filter is intended to be used by the dynamic filters, instead
+// of the ordinary channel stack. The fault injection filter fetches fault
+// injection policy from the method config of service config returned by the
+// resolver, and enforces the fault injection policy.
+extern const grpc_channel_filter FaultInjectionFilterVtable;
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_FAULT_INJECTION_FILTER_H
diff --git a/grpc/src/core/ext/filters/fault_injection/service_config_parser.cc b/grpc/src/core/ext/filters/fault_injection/service_config_parser.cc
new file mode 100644
index 0000000..e8c23e1
--- /dev/null
+++ b/grpc/src/core/ext/filters/fault_injection/service_config_parser.cc
@@ -0,0 +1,189 @@
+//
+// Copyright 2021 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>
+
+#include "src/core/ext/filters/fault_injection/service_config_parser.h"
+
+#include <vector>
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/json/json_util.h"
+
+namespace grpc_core {
+
+namespace {
+
+size_t g_fault_injection_parser_index;
+
+std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy>
+ParseFaultInjectionPolicy(const Json::Array& policies_json_array,
+                          std::vector<grpc_error_handle>* error_list) {
+  std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy> policies;
+  for (size_t i = 0; i < policies_json_array.size(); i++) {
+    FaultInjectionMethodParsedConfig::FaultInjectionPolicy
+        fault_injection_policy;
+    std::vector<grpc_error_handle> sub_error_list;
+    if (policies_json_array[i].type() != Json::Type::OBJECT) {
+      error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("faultInjectionPolicy index ", i,
+                       " is not a JSON object")
+              .c_str()));
+      continue;
+    }
+    const Json::Object& json_object = policies_json_array[i].object_value();
+    // Parse abort_code
+    std::string abort_code_string;
+    if (ParseJsonObjectField(json_object, "abortCode", &abort_code_string,
+                             &sub_error_list, false)) {
+      if (!grpc_status_code_from_string(abort_code_string.c_str(),
+                                        &(fault_injection_policy.abort_code))) {
+        sub_error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:abortCode error:failed to parse status code"));
+      }
+    }
+    // Parse abort_message
+    if (!ParseJsonObjectField(json_object, "abortMessage",
+                              &fault_injection_policy.abort_message,
+                              &sub_error_list, false)) {
+      fault_injection_policy.abort_message = "Fault injected";
+    }
+    // Parse abort_code_header
+    ParseJsonObjectField(json_object, "abortCodeHeader",
+                         &fault_injection_policy.abort_code_header,
+                         &sub_error_list, false);
+    // Parse abort_percentage_header
+    ParseJsonObjectField(json_object, "abortPercentageHeader",
+                         &fault_injection_policy.abort_percentage_header,
+                         &sub_error_list, false);
+    // Parse abort_percentage_numerator
+    ParseJsonObjectField(json_object, "abortPercentageNumerator",
+                         &fault_injection_policy.abort_percentage_numerator,
+                         &sub_error_list, false);
+    // Parse abort_percentage_denominator
+    if (ParseJsonObjectField(
+            json_object, "abortPercentageDenominator",
+            &fault_injection_policy.abort_percentage_denominator,
+            &sub_error_list, false)) {
+      if (fault_injection_policy.abort_percentage_denominator != 100 &&
+          fault_injection_policy.abort_percentage_denominator != 10000 &&
+          fault_injection_policy.abort_percentage_denominator != 1000000) {
+        sub_error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:abortPercentageDenominator error:Denominator can only be "
+            "one of "
+            "100, 10000, 1000000"));
+      }
+    }
+    // Parse delay
+    ParseJsonObjectFieldAsDuration(json_object, "delay",
+                                   &fault_injection_policy.delay,
+                                   &sub_error_list, false);
+    // Parse delay_header
+    ParseJsonObjectField(json_object, "delayHeader",
+                         &fault_injection_policy.delay_header, &sub_error_list,
+                         false);
+    // Parse delay_percentage_header
+    ParseJsonObjectField(json_object, "delayPercentageHeader",
+                         &fault_injection_policy.delay_percentage_header,
+                         &sub_error_list, false);
+    // Parse delay_percentage_numerator
+    ParseJsonObjectField(json_object, "delayPercentageNumerator",
+                         &fault_injection_policy.delay_percentage_numerator,
+                         &sub_error_list, false);
+    // Parse delay_percentage_denominator
+    if (ParseJsonObjectField(
+            json_object, "delayPercentageDenominator",
+            &fault_injection_policy.delay_percentage_denominator,
+            &sub_error_list, false)) {
+      if (fault_injection_policy.delay_percentage_denominator != 100 &&
+          fault_injection_policy.delay_percentage_denominator != 10000 &&
+          fault_injection_policy.delay_percentage_denominator != 1000000) {
+        sub_error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:delayPercentageDenominator error:Denominator can only be "
+            "one of "
+            "100, 10000, 1000000"));
+      }
+    }
+    // Parse max_faults
+    if (ParseJsonObjectField(json_object, "maxFaults",
+                             &fault_injection_policy.max_faults,
+                             &sub_error_list, false)) {
+      if (fault_injection_policy.max_faults < 0) {
+        sub_error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "field:maxFaults error:should be zero or positive"));
+      }
+    }
+    if (!sub_error_list.empty()) {
+      // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
+      // string is not static in this case.
+      grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("failed to parse faultInjectionPolicy index ", i)
+              .c_str());
+      for (size_t i = 0; i < sub_error_list.size(); ++i) {
+        error = grpc_error_add_child(error, sub_error_list[i]);
+      }
+      error_list->push_back(error);
+    }
+    policies.push_back(std::move(fault_injection_policy));
+  }
+  return policies;
+}
+
+}  // namespace
+
+std::unique_ptr<ServiceConfigParser::ParsedConfig>
+FaultInjectionServiceConfigParser::ParsePerMethodParams(
+    const grpc_channel_args* args, const Json& json, grpc_error_handle* error) {
+  GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
+  // Only parse fault injection policy if the following channel arg is present.
+  if (!grpc_channel_args_find_bool(
+          args, GRPC_ARG_PARSE_FAULT_INJECTION_METHOD_CONFIG, false)) {
+    return nullptr;
+  }
+  // Parse fault injection policy from given Json
+  std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy>
+      fault_injection_policies;
+  std::vector<grpc_error_handle> error_list;
+  const Json::Array* policies_json_array;
+  if (ParseJsonObjectField(json.object_value(), "faultInjectionPolicy",
+                           &policies_json_array, &error_list)) {
+    fault_injection_policies =
+        ParseFaultInjectionPolicy(*policies_json_array, &error_list);
+  }
+  *error = GRPC_ERROR_CREATE_FROM_VECTOR("Fault injection parser", &error_list);
+  if (*error != GRPC_ERROR_NONE || fault_injection_policies.empty()) {
+    return nullptr;
+  }
+  return absl::make_unique<FaultInjectionMethodParsedConfig>(
+      std::move(fault_injection_policies));
+}
+
+void FaultInjectionServiceConfigParser::Register() {
+  g_fault_injection_parser_index = ServiceConfigParser::RegisterParser(
+      absl::make_unique<FaultInjectionServiceConfigParser>());
+}
+
+size_t FaultInjectionServiceConfigParser::ParserIndex() {
+  return g_fault_injection_parser_index;
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/ext/filters/fault_injection/service_config_parser.h b/grpc/src/core/ext/filters/fault_injection/service_config_parser.h
new file mode 100644
index 0000000..a885539
--- /dev/null
+++ b/grpc/src/core/ext/filters/fault_injection/service_config_parser.h
@@ -0,0 +1,85 @@
+//
+// Copyright 2021 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_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H
+#define GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H
+
+#include <grpc/support/port_platform.h>
+
+#include <vector>
+
+#include "src/core/ext/filters/client_channel/service_config.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+namespace grpc_core {
+
+class FaultInjectionMethodParsedConfig
+    : public ServiceConfigParser::ParsedConfig {
+ public:
+  struct FaultInjectionPolicy {
+    grpc_status_code abort_code = GRPC_STATUS_OK;
+    std::string abort_message;
+    std::string abort_code_header;
+    std::string abort_percentage_header;
+    uint32_t abort_percentage_numerator = 0;
+    uint32_t abort_percentage_denominator = 100;
+
+    grpc_millis delay = 0;
+    std::string delay_header;
+    std::string delay_percentage_header;
+    uint32_t delay_percentage_numerator = 0;
+    uint32_t delay_percentage_denominator = 100;
+
+    // By default, the max allowed active faults are unlimited.
+    uint32_t max_faults = std::numeric_limits<uint32_t>::max();
+  };
+
+  explicit FaultInjectionMethodParsedConfig(
+      std::vector<FaultInjectionPolicy> fault_injection_policies)
+      : fault_injection_policies_(std::move(fault_injection_policies)) {}
+
+  // Returns the fault injection policy at certain index.
+  // There might be multiple fault injection policies functioning at the same
+  // time. The order between the policies are stable, and an index is used to
+  // keep track of their relative positions. The FaultInjectionFilter uses this
+  // method to access the parsed fault injection policy in service config,
+  // whether it came from xDS resolver or directly from service config
+  const FaultInjectionPolicy* fault_injection_policy(int index) const {
+    if (static_cast<size_t>(index) >= fault_injection_policies_.size()) {
+      return nullptr;
+    }
+    return &fault_injection_policies_[index];
+  }
+
+ private:
+  std::vector<FaultInjectionPolicy> fault_injection_policies_;
+};
+
+class FaultInjectionServiceConfigParser : public ServiceConfigParser::Parser {
+ public:
+  // Parses the per-method service config for fault injection filter.
+  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
+      const grpc_channel_args* args, const Json& json,
+      grpc_error_handle* error) override;
+  // Returns the parser index for FaultInjectionServiceConfigParser.
+  static size_t ParserIndex();
+  // Registers FaultInjectionServiceConfigParser to ServiceConfigParser.
+  static void Register();
+};
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H
diff --git a/grpc/src/core/ext/filters/http/client/http_client_filter.cc b/grpc/src/core/ext/filters/http/client/http_client_filter.cc
index 3a4825f..ef737f0 100644
--- a/grpc/src/core/ext/filters/http/client/http_client_filter.cc
+++ b/grpc/src/core/ext/filters/http/client/http_client_filter.cc
@@ -48,10 +48,12 @@
 /* default maximum size of payload eligible for GET request */
 static constexpr size_t kMaxPayloadSizeForGet = 2048;
 
-static void recv_initial_metadata_ready(void* user_data, grpc_error* error);
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
-static void on_send_message_next_done(void* arg, grpc_error* error);
-static void send_message_on_complete(void* arg, grpc_error* error);
+static void recv_initial_metadata_ready(void* user_data,
+                                        grpc_error_handle error);
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error);
+static void on_send_message_next_done(void* arg, grpc_error_handle error);
+static void send_message_on_complete(void* arg, grpc_error_handle error);
 
 namespace {
 struct call_data {
@@ -81,14 +83,14 @@
   grpc_linked_mdelem user_agent;
   // State for handling recv_initial_metadata ops.
   grpc_metadata_batch* recv_initial_metadata;
-  grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
+  grpc_error_handle recv_initial_metadata_error = GRPC_ERROR_NONE;
   grpc_closure* original_recv_initial_metadata_ready = nullptr;
   grpc_closure recv_initial_metadata_ready;
   // State for handling recv_trailing_metadata ops.
   grpc_metadata_batch* recv_trailing_metadata;
   grpc_closure* original_recv_trailing_metadata_ready;
   grpc_closure recv_trailing_metadata_ready;
-  grpc_error* recv_trailing_metadata_error = GRPC_ERROR_NONE;
+  grpc_error_handle recv_trailing_metadata_error = GRPC_ERROR_NONE;
   bool seen_recv_trailing_metadata_ready = false;
   // State for handling send_message ops.
   grpc_transport_stream_op_batch* send_message_batch;
@@ -108,7 +110,8 @@
 };
 }  // namespace
 
-static grpc_error* client_filter_incoming_metadata(grpc_metadata_batch* b) {
+static grpc_error_handle client_filter_incoming_metadata(
+    grpc_metadata_batch* b) {
   if (b->idx.named.status != nullptr) {
     /* If both gRPC status and HTTP status are provided in the response, we
      * should prefer the gRPC status code, as mentioned in
@@ -123,7 +126,7 @@
                                   GPR_DUMP_ASCII);
       std::string msg =
           absl::StrCat("Received http2 header with status: ", val);
-      grpc_error* e = grpc_error_set_str(
+      grpc_error_handle e = grpc_error_set_str(
           grpc_error_set_int(
               grpc_error_set_str(
                   GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -182,7 +185,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
+static void recv_initial_metadata_ready(void* user_data,
+                                        grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error == GRPC_ERROR_NONE) {
@@ -201,7 +205,8 @@
   grpc_core::Closure::Run(DEBUG_LOCATION, closure, error);
 }
 
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->original_recv_initial_metadata_ready != nullptr) {
@@ -223,7 +228,7 @@
                           calld->original_recv_trailing_metadata_ready, error);
 }
 
-static void send_message_on_complete(void* arg, grpc_error* error) {
+static void send_message_on_complete(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->send_message_cache.Destroy();
@@ -234,9 +239,10 @@
 
 // Pulls a slice from the send_message byte stream, updating
 // calld->send_message_bytes_read.
-static grpc_error* pull_slice_from_send_message(call_data* calld) {
+static grpc_error_handle pull_slice_from_send_message(call_data* calld) {
   grpc_slice incoming_slice;
-  grpc_error* error = calld->send_message_caching_stream->Pull(&incoming_slice);
+  grpc_error_handle error =
+      calld->send_message_caching_stream->Pull(&incoming_slice);
   if (error == GRPC_ERROR_NONE) {
     calld->send_message_bytes_read += GRPC_SLICE_LENGTH(incoming_slice);
     grpc_slice_unref_internal(incoming_slice);
@@ -249,10 +255,11 @@
 // calld->send_message_caching_stream->length(), then we have completed
 // reading from the byte stream; otherwise, an async read has been dispatched
 // and on_send_message_next_done() will be invoked when it is complete.
-static grpc_error* read_all_available_send_message_data(call_data* calld) {
+static grpc_error_handle read_all_available_send_message_data(
+    call_data* calld) {
   while (calld->send_message_caching_stream->Next(
       SIZE_MAX, &calld->on_send_message_next_done)) {
-    grpc_error* error = pull_slice_from_send_message(calld);
+    grpc_error_handle error = pull_slice_from_send_message(calld);
     if (error != GRPC_ERROR_NONE) return error;
     if (calld->send_message_bytes_read ==
         calld->send_message_caching_stream->length()) {
@@ -263,7 +270,7 @@
 }
 
 // Async callback for ByteStream::Next().
-static void on_send_message_next_done(void* arg, grpc_error* error) {
+static void on_send_message_next_done(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
@@ -301,8 +308,8 @@
 
 // Modifies the path entry in the batch's send_initial_metadata to
 // append the base64-encoded query for a GET request.
-static grpc_error* update_path_for_get(grpc_call_element* elem,
-                                       grpc_transport_stream_op_batch* batch) {
+static grpc_error_handle update_path_for_get(
+    grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_slice path_slice =
       GRPC_MDVALUE(batch->payload->send_initial_metadata.send_initial_metadata
@@ -376,7 +383,7 @@
         &calld->recv_trailing_metadata_ready;
   }
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   bool batch_will_be_handled_asynchronously = false;
   if (batch->send_initial_metadata) {
     // Decide which HTTP VERB to use. We use GET if the request is marked
@@ -475,7 +482,7 @@
 }
 
 /* Constructor for call_data */
-static grpc_error* http_client_init_call_elem(
+static grpc_error_handle http_client_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   new (elem->call_data) call_data(elem, *args);
   return GRPC_ERROR_NONE;
@@ -561,7 +568,7 @@
 }
 
 /* Constructor for channel_data */
-static grpc_error* http_client_init_channel_elem(
+static grpc_error_handle http_client_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(!args->is_last);
diff --git a/grpc/src/core/ext/filters/http/client_authority_filter.cc b/grpc/src/core/ext/filters/http/client_authority_filter.cc
index 9511d25..f44ef85 100644
--- a/grpc/src/core/ext/filters/http/client_authority_filter.cc
+++ b/grpc/src/core/ext/filters/http/client_authority_filter.cc
@@ -57,7 +57,7 @@
   if (batch->send_initial_metadata &&
       batch->payload->send_initial_metadata.send_initial_metadata->idx.named
               .authority == nullptr) {
-    grpc_error* error = grpc_metadata_batch_add_head(
+    grpc_error_handle error = grpc_metadata_batch_add_head(
         batch->payload->send_initial_metadata.send_initial_metadata,
         &calld->authority_storage,
         GRPC_MDELEM_REF(chand->default_authority_mdelem), GRPC_BATCH_AUTHORITY);
@@ -72,7 +72,7 @@
 }
 
 /* Constructor for call_data */
-grpc_error* client_authority_init_call_elem(
+grpc_error_handle client_authority_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
@@ -85,7 +85,7 @@
     grpc_closure* /*ignored*/) {}
 
 /* Constructor for channel_data */
-grpc_error* client_authority_init_channel_elem(
+grpc_error_handle client_authority_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   const grpc_arg* default_authority_arg =
diff --git a/grpc/src/core/ext/filters/http/message_compress/message_compress_filter.cc b/grpc/src/core/ext/filters/http/message_compress/message_compress_filter.cc
index 09c914f..0fc85b1 100644
--- a/grpc/src/core/ext/filters/http/message_compress/message_compress_filter.cc
+++ b/grpc/src/core/ext/filters/http/message_compress/message_compress_filter.cc
@@ -131,25 +131,25 @@
   bool SkipMessageCompression();
   void InitializeState(grpc_call_element* elem);
 
-  grpc_error* ProcessSendInitialMetadata(grpc_call_element* elem,
-                                         grpc_metadata_batch* initial_metadata);
+  grpc_error_handle ProcessSendInitialMetadata(
+      grpc_call_element* elem, grpc_metadata_batch* initial_metadata);
 
   // Methods for processing a send_message batch
-  static void StartSendMessageBatch(void* elem_arg, grpc_error* unused);
-  static void OnSendMessageNextDone(void* elem_arg, grpc_error* error);
-  grpc_error* PullSliceFromSendMessage();
+  static void StartSendMessageBatch(void* elem_arg, grpc_error_handle unused);
+  static void OnSendMessageNextDone(void* elem_arg, grpc_error_handle error);
+  grpc_error_handle PullSliceFromSendMessage();
   void ContinueReadingSendMessage(grpc_call_element* elem);
   void FinishSendMessage(grpc_call_element* elem);
   void SendMessageBatchContinue(grpc_call_element* elem);
   static void FailSendMessageBatchInCallCombiner(void* calld_arg,
-                                                 grpc_error* error);
+                                                 grpc_error_handle error);
 
-  static void SendMessageOnComplete(void* calld_arg, grpc_error* error);
+  static void SendMessageOnComplete(void* calld_arg, grpc_error_handle error);
 
   grpc_core::CallCombiner* call_combiner_;
   grpc_message_compression_algorithm message_compression_algorithm_ =
       GRPC_MESSAGE_COMPRESS_NONE;
-  grpc_error* cancel_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_error_ = GRPC_ERROR_NONE;
   grpc_transport_stream_op_batch* send_message_batch_ = nullptr;
   bool seen_initial_metadata_ = false;
   /* Set to true, if the fields below are initialized. */
@@ -232,7 +232,7 @@
                     grpc_schedule_on_exec_ctx);
 }
 
-grpc_error* CallData::ProcessSendInitialMetadata(
+grpc_error_handle CallData::ProcessSendInitialMetadata(
     grpc_call_element* elem, grpc_metadata_batch* initial_metadata) {
   ChannelData* channeld = static_cast<ChannelData*>(elem->channel_data);
   // Find the compression algorithm.
@@ -246,7 +246,7 @@
       grpc_compression_algorithm_to_stream_compression_algorithm(
           compression_algorithm);
   // Hint compression algorithm.
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (message_compression_algorithm_ != GRPC_MESSAGE_COMPRESS_NONE) {
     InitializeState(elem);
     error = grpc_metadata_batch_add_tail(
@@ -281,7 +281,7 @@
   return error;
 }
 
-void CallData::SendMessageOnComplete(void* calld_arg, grpc_error* error) {
+void CallData::SendMessageOnComplete(void* calld_arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(calld_arg);
   grpc_slice_buffer_reset_and_unref_internal(&calld->slices_);
   grpc_core::Closure::Run(DEBUG_LOCATION,
@@ -348,7 +348,7 @@
 }
 
 void CallData::FailSendMessageBatchInCallCombiner(void* calld_arg,
-                                                  grpc_error* error) {
+                                                  grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(calld_arg);
   if (calld->send_message_batch_ != nullptr) {
     grpc_transport_stream_op_batch_finish_with_failure(
@@ -359,9 +359,9 @@
 }
 
 // Pulls a slice from the send_message byte stream and adds it to slices_.
-grpc_error* CallData::PullSliceFromSendMessage() {
+grpc_error_handle CallData::PullSliceFromSendMessage() {
   grpc_slice incoming_slice;
-  grpc_error* error =
+  grpc_error_handle error =
       send_message_batch_->payload->send_message.send_message->Pull(
           &incoming_slice);
   if (error == GRPC_ERROR_NONE) {
@@ -382,7 +382,7 @@
   }
   while (send_message_batch_->payload->send_message.send_message->Next(
       ~static_cast<size_t>(0), &on_send_message_next_done_)) {
-    grpc_error* error = PullSliceFromSendMessage();
+    grpc_error_handle error = PullSliceFromSendMessage();
     if (error != GRPC_ERROR_NONE) {
       // Closure callback; does not take ownership of error.
       FailSendMessageBatchInCallCombiner(this, error);
@@ -398,7 +398,7 @@
 }
 
 // Async callback for ByteStream::Next().
-void CallData::OnSendMessageNextDone(void* elem_arg, grpc_error* error) {
+void CallData::OnSendMessageNextDone(void* elem_arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(elem_arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
@@ -421,7 +421,8 @@
   }
 }
 
-void CallData::StartSendMessageBatch(void* elem_arg, grpc_error* /*unused*/) {
+void CallData::StartSendMessageBatch(void* elem_arg,
+                                     grpc_error_handle /*unused*/) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(elem_arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   if (calld->SkipMessageCompression()) {
@@ -458,7 +459,7 @@
   // Handle send_initial_metadata.
   if (batch->send_initial_metadata) {
     GPR_ASSERT(!seen_initial_metadata_);
-    grpc_error* error = ProcessSendInitialMetadata(
+    grpc_error_handle error = ProcessSendInitialMetadata(
         elem, batch->payload->send_initial_metadata.send_initial_metadata);
     if (error != GRPC_ERROR_NONE) {
       grpc_transport_stream_op_batch_finish_with_failure(batch, error,
@@ -503,8 +504,8 @@
 }
 
 /* Constructor for call_data */
-grpc_error* CompressInitCallElem(grpc_call_element* elem,
-                                 const grpc_call_element_args* args) {
+grpc_error_handle CompressInitCallElem(grpc_call_element* elem,
+                                       const grpc_call_element_args* args) {
   new (elem->call_data) CallData(elem, *args);
   return GRPC_ERROR_NONE;
 }
@@ -518,8 +519,8 @@
 }
 
 /* Constructor for ChannelData */
-grpc_error* CompressInitChannelElem(grpc_channel_element* elem,
-                                    grpc_channel_element_args* args) {
+grpc_error_handle CompressInitChannelElem(grpc_channel_element* elem,
+                                          grpc_channel_element_args* args) {
   new (elem->channel_data) ChannelData(args);
   return GRPC_ERROR_NONE;
 }
diff --git a/grpc/src/core/ext/filters/http/message_compress/message_decompress_filter.cc b/grpc/src/core/ext/filters/http/message_compress/message_decompress_filter.cc
index 4ab8a56..426dd90 100644
--- a/grpc/src/core/ext/filters/http/message_compress/message_decompress_filter.cc
+++ b/grpc/src/core/ext/filters/http/message_compress/message_decompress_filter.cc
@@ -89,24 +89,24 @@
       grpc_call_element* elem, grpc_transport_stream_op_batch* batch);
 
  private:
-  static void OnRecvInitialMetadataReady(void* arg, grpc_error* error);
+  static void OnRecvInitialMetadataReady(void* arg, grpc_error_handle error);
 
   // Methods for processing a receive message event
   void MaybeResumeOnRecvMessageReady();
-  static void OnRecvMessageReady(void* arg, grpc_error* error);
-  static void OnRecvMessageNextDone(void* arg, grpc_error* error);
-  grpc_error* PullSliceFromRecvMessage();
+  static void OnRecvMessageReady(void* arg, grpc_error_handle error);
+  static void OnRecvMessageNextDone(void* arg, grpc_error_handle error);
+  grpc_error_handle PullSliceFromRecvMessage();
   void ContinueReadingRecvMessage();
   void FinishRecvMessage();
-  void ContinueRecvMessageReadyCallback(grpc_error* error);
+  void ContinueRecvMessageReadyCallback(grpc_error_handle error);
 
   // Methods for processing a recv_trailing_metadata event
   void MaybeResumeOnRecvTrailingMetadataReady();
-  static void OnRecvTrailingMetadataReady(void* arg, grpc_error* error);
+  static void OnRecvTrailingMetadataReady(void* arg, grpc_error_handle error);
 
   CallCombiner* call_combiner_;
   // Overall error for the call
-  grpc_error* error_ = GRPC_ERROR_NONE;
+  grpc_error_handle error_ = GRPC_ERROR_NONE;
   // Fields for handling recv_initial_metadata_ready callback
   grpc_closure on_recv_initial_metadata_ready_;
   grpc_closure* original_recv_initial_metadata_ready_ = nullptr;
@@ -130,7 +130,7 @@
   bool seen_recv_trailing_metadata_ready_ = false;
   grpc_closure on_recv_trailing_metadata_ready_;
   grpc_closure* original_recv_trailing_metadata_ready_ = nullptr;
-  grpc_error* on_recv_trailing_metadata_ready_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle on_recv_trailing_metadata_ready_error_ = GRPC_ERROR_NONE;
 };
 
 grpc_message_compression_algorithm DecodeMessageCompressionAlgorithm(
@@ -149,7 +149,7 @@
   return algorithm;
 }
 
-void CallData::OnRecvInitialMetadataReady(void* arg, grpc_error* error) {
+void CallData::OnRecvInitialMetadataReady(void* arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(arg);
   if (error == GRPC_ERROR_NONE) {
     grpc_linked_mdelem* grpc_encoding =
@@ -174,7 +174,7 @@
   }
 }
 
-void CallData::OnRecvMessageReady(void* arg, grpc_error* error) {
+void CallData::OnRecvMessageReady(void* arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(arg);
   if (error == GRPC_ERROR_NONE) {
     if (calld->original_recv_initial_metadata_ready_ != nullptr) {
@@ -218,7 +218,7 @@
   while ((*recv_message_)
              ->Next((*recv_message_)->length() - recv_slices_.length,
                     &on_recv_message_next_done_)) {
-    grpc_error* error = PullSliceFromRecvMessage();
+    grpc_error_handle error = PullSliceFromRecvMessage();
     if (error != GRPC_ERROR_NONE) {
       return ContinueRecvMessageReadyCallback(error);
     }
@@ -229,16 +229,16 @@
   }
 }
 
-grpc_error* CallData::PullSliceFromRecvMessage() {
+grpc_error_handle CallData::PullSliceFromRecvMessage() {
   grpc_slice incoming_slice;
-  grpc_error* error = (*recv_message_)->Pull(&incoming_slice);
+  grpc_error_handle error = (*recv_message_)->Pull(&incoming_slice);
   if (error == GRPC_ERROR_NONE) {
     grpc_slice_buffer_add(&recv_slices_, incoming_slice);
   }
   return error;
 }
 
-void CallData::OnRecvMessageNextDone(void* arg, grpc_error* error) {
+void CallData::OnRecvMessageNextDone(void* arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(arg);
   if (error != GRPC_ERROR_NONE) {
     return calld->ContinueRecvMessageReadyCallback(GRPC_ERROR_REF(error));
@@ -283,7 +283,7 @@
   ContinueRecvMessageReadyCallback(GRPC_ERROR_REF(error_));
 }
 
-void CallData::ContinueRecvMessageReadyCallback(grpc_error* error) {
+void CallData::ContinueRecvMessageReadyCallback(grpc_error_handle error) {
   MaybeResumeOnRecvTrailingMetadataReady();
   // The surface will clean up the receiving stream if there is an error.
   grpc_closure* closure = original_recv_message_ready_;
@@ -294,14 +294,14 @@
 void CallData::MaybeResumeOnRecvTrailingMetadataReady() {
   if (seen_recv_trailing_metadata_ready_) {
     seen_recv_trailing_metadata_ready_ = false;
-    grpc_error* error = on_recv_trailing_metadata_ready_error_;
+    grpc_error_handle error = on_recv_trailing_metadata_ready_error_;
     on_recv_trailing_metadata_ready_error_ = GRPC_ERROR_NONE;
     GRPC_CALL_COMBINER_START(call_combiner_, &on_recv_trailing_metadata_ready_,
                              error, "Continuing OnRecvTrailingMetadataReady");
   }
 }
 
-void CallData::OnRecvTrailingMetadataReady(void* arg, grpc_error* error) {
+void CallData::OnRecvTrailingMetadataReady(void* arg, grpc_error_handle error) {
   CallData* calld = static_cast<CallData*>(arg);
   if (calld->original_recv_initial_metadata_ready_ != nullptr ||
       calld->original_recv_message_ready_ != nullptr) {
@@ -356,8 +356,8 @@
   calld->DecompressStartTransportStreamOpBatch(elem, batch);
 }
 
-grpc_error* DecompressInitCallElem(grpc_call_element* elem,
-                                   const grpc_call_element_args* args) {
+grpc_error_handle DecompressInitCallElem(grpc_call_element* elem,
+                                         const grpc_call_element_args* args) {
   ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
   new (elem->call_data) CallData(*args, chand);
   return GRPC_ERROR_NONE;
@@ -370,8 +370,8 @@
   calld->~CallData();
 }
 
-grpc_error* DecompressInitChannelElem(grpc_channel_element* elem,
-                                      grpc_channel_element_args* args) {
+grpc_error_handle DecompressInitChannelElem(grpc_channel_element* elem,
+                                            grpc_channel_element_args* args) {
   ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
   new (chand) ChannelData(args);
   return GRPC_ERROR_NONE;
diff --git a/grpc/src/core/ext/filters/http/server/http_server_filter.cc b/grpc/src/core/ext/filters/http/server/http_server_filter.cc
index e4ece54..226ba02 100644
--- a/grpc/src/core/ext/filters/http/server/http_server_filter.cc
+++ b/grpc/src/core/ext/filters/http/server/http_server_filter.cc
@@ -35,9 +35,11 @@
 #define EXPECTED_CONTENT_TYPE "application/grpc"
 #define EXPECTED_CONTENT_TYPE_LENGTH (sizeof(EXPECTED_CONTENT_TYPE) - 1)
 
-static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err);
-static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err);
-static void hs_recv_message_ready(void* user_data, grpc_error* err);
+static void hs_recv_initial_metadata_ready(void* user_data,
+                                           grpc_error_handle err);
+static void hs_recv_trailing_metadata_ready(void* user_data,
+                                            grpc_error_handle err);
+static void hs_recv_message_ready(void* user_data, grpc_error_handle err);
 
 namespace {
 
@@ -74,7 +76,7 @@
 
   // State for intercepting recv_initial_metadata.
   grpc_closure recv_initial_metadata_ready;
-  grpc_error* recv_initial_metadata_ready_error = GRPC_ERROR_NONE;
+  grpc_error_handle recv_initial_metadata_ready_error = GRPC_ERROR_NONE;
   grpc_closure* original_recv_initial_metadata_ready;
   grpc_metadata_batch* recv_initial_metadata = nullptr;
   uint32_t* recv_initial_metadata_flags;
@@ -89,7 +91,7 @@
   // State for intercepting recv_trailing_metadata
   grpc_closure recv_trailing_metadata_ready;
   grpc_closure* original_recv_trailing_metadata_ready;
-  grpc_error* recv_trailing_metadata_ready_error;
+  grpc_error_handle recv_trailing_metadata_ready_error;
   bool seen_recv_trailing_metadata_ready = false;
 };
 
@@ -99,7 +101,7 @@
 
 }  // namespace
 
-static grpc_error* hs_filter_outgoing_metadata(grpc_metadata_batch* b) {
+static grpc_error_handle hs_filter_outgoing_metadata(grpc_metadata_batch* b) {
   if (b->idx.named.grpc_message != nullptr) {
     grpc_slice pct_encoded_msg = grpc_percent_encode_slice(
         GRPC_MDVALUE(b->idx.named.grpc_message->md),
@@ -114,8 +116,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static void hs_add_error(const char* error_name, grpc_error** cumulative,
-                         grpc_error* new_err) {
+static void hs_add_error(const char* error_name, grpc_error_handle* cumulative,
+                         grpc_error_handle new_err) {
   if (new_err == GRPC_ERROR_NONE) return;
   if (*cumulative == GRPC_ERROR_NONE) {
     *cumulative = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_name);
@@ -149,10 +151,10 @@
   }
 }
 
-static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem,
-                                               grpc_metadata_batch* b) {
+static grpc_error_handle hs_filter_incoming_metadata(grpc_call_element* elem,
+                                                     grpc_metadata_batch* b) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* error_name = "Failed processing incoming headers";
 
   if (b->idx.named.method != nullptr) {
@@ -330,7 +332,8 @@
   return error;
 }
 
-static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err) {
+static void hs_recv_initial_metadata_ready(void* user_data,
+                                           grpc_error_handle err) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->seen_recv_initial_metadata_ready = true;
@@ -367,7 +370,7 @@
                           calld->original_recv_initial_metadata_ready, err);
 }
 
-static void hs_recv_message_ready(void* user_data, grpc_error* err) {
+static void hs_recv_message_ready(void* user_data, grpc_error_handle err) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->seen_recv_message_ready = true;
@@ -392,7 +395,8 @@
   }
 }
 
-static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
+static void hs_recv_trailing_metadata_ready(void* user_data,
+                                            grpc_error_handle err) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (!calld->seen_recv_initial_metadata_ready) {
@@ -410,13 +414,13 @@
                           calld->original_recv_trailing_metadata_ready, err);
 }
 
-static grpc_error* hs_mutate_op(grpc_call_element* elem,
-                                grpc_transport_stream_op_batch* op) {
+static grpc_error_handle hs_mutate_op(grpc_call_element* elem,
+                                      grpc_transport_stream_op_batch* op) {
   /* grab pointers to our data from the call element */
   call_data* calld = static_cast<call_data*>(elem->call_data);
 
   if (op->send_initial_metadata) {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     static const char* error_name = "Failed sending initial metadata";
     hs_add_error(
         error_name, &error,
@@ -463,7 +467,7 @@
   }
 
   if (op->send_trailing_metadata) {
-    grpc_error* error = hs_filter_outgoing_metadata(
+    grpc_error_handle error = hs_filter_outgoing_metadata(
         op->payload->send_trailing_metadata.send_trailing_metadata);
     if (error != GRPC_ERROR_NONE) return error;
   }
@@ -475,7 +479,7 @@
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
   GPR_TIMER_SCOPE("hs_start_transport_stream_op_batch", 0);
   call_data* calld = static_cast<call_data*>(elem->call_data);
-  grpc_error* error = hs_mutate_op(elem, op);
+  grpc_error_handle error = hs_mutate_op(elem, op);
   if (error != GRPC_ERROR_NONE) {
     grpc_transport_stream_op_batch_finish_with_failure(op, error,
                                                        calld->call_combiner);
@@ -485,8 +489,8 @@
 }
 
 /* Constructor for call_data */
-static grpc_error* hs_init_call_elem(grpc_call_element* elem,
-                                     const grpc_call_element_args* args) {
+static grpc_error_handle hs_init_call_elem(grpc_call_element* elem,
+                                           const grpc_call_element_args* args) {
   new (elem->call_data) call_data(elem, *args);
   return GRPC_ERROR_NONE;
 }
@@ -500,8 +504,8 @@
 }
 
 /* Constructor for channel_data */
-static grpc_error* hs_init_channel_elem(grpc_channel_element* elem,
-                                        grpc_channel_element_args* args) {
+static grpc_error_handle hs_init_channel_elem(grpc_channel_element* elem,
+                                              grpc_channel_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(!args->is_last);
   chand->surface_user_agent = grpc_channel_arg_get_bool(
diff --git a/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc b/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
index 5d57830..46af805 100644
--- a/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
+++ b/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
@@ -32,9 +32,9 @@
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h"
 #include "src/core/ext/filters/load_reporting/registered_opencensus_objects.h"
 #include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/context.h"
-#include "src/core/lib/iomgr/parse_address.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/socket_utils.h"
@@ -50,7 +50,7 @@
 constexpr char kEmptyAddressLengthString[] = "00";
 constexpr size_t kLengthPrefixSize = 2;
 
-grpc_error* ServerLoadReportingChannelData::Init(
+grpc_error_handle ServerLoadReportingChannelData::Init(
     grpc_channel_element* /* elem */, grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   // Find and record the peer_identity.
@@ -72,7 +72,7 @@
 
 void ServerLoadReportingCallData::Destroy(
     grpc_call_element* elem, const grpc_call_final_info* final_info,
-    grpc_closure* then_call_closure) {
+    grpc_closure* /*then_call_closure*/) {
   ServerLoadReportingChannelData* chand =
       reinterpret_cast<ServerLoadReportingChannelData*>(elem->channel_data);
   // Only record an end if we've recorded its corresponding start, which is
@@ -200,7 +200,7 @@
     strncpy(cur_pos, lr_token, lr_token_len);
   }
   GPR_ASSERT(cur_pos + lr_token_len - client_ip_and_lr_token_ ==
-             client_ip_and_lr_token_len_);
+             long(client_ip_and_lr_token_len_));
 }
 
 grpc_filtered_mdelem ServerLoadReportingCallData::RecvInitialMetadataFilter(
@@ -232,8 +232,8 @@
   return GRPC_FILTERED_MDELEM(md);
 }
 
-void ServerLoadReportingCallData::RecvInitialMetadataReady(void* arg,
-                                                           grpc_error* err) {
+void ServerLoadReportingCallData::RecvInitialMetadataReady(
+    void* arg, grpc_error_handle err) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(arg);
   ServerLoadReportingCallData* calld =
       reinterpret_cast<ServerLoadReportingCallData*>(elem->call_data);
@@ -264,8 +264,8 @@
                           GRPC_ERROR_REF(err));
 }
 
-grpc_error* ServerLoadReportingCallData::Init(
-    grpc_call_element* elem, const grpc_call_element_args* args) {
+grpc_error_handle ServerLoadReportingCallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* /*args*/) {
   service_method_ = grpc_empty_slice();
   GRPC_CLOSURE_INIT(&recv_initial_metadata_ready_, RecvInitialMetadataReady,
                     elem, grpc_schedule_on_exec_ctx);
diff --git a/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.h b/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
index 3bfdc98..47390fa 100644
--- a/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
+++ b/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
@@ -30,8 +30,8 @@
 
 class ServerLoadReportingChannelData : public ChannelData {
  public:
-  grpc_error* Init(grpc_channel_element* elem,
-                   grpc_channel_element_args* args) override;
+  grpc_error_handle Init(grpc_channel_element* elem,
+                         grpc_channel_element_args* args) override;
 
   // Getters.
   const char* peer_identity() { return peer_identity_; }
@@ -45,8 +45,8 @@
 
 class ServerLoadReportingCallData : public CallData {
  public:
-  grpc_error* Init(grpc_call_element* elem,
-                   const grpc_call_element_args* args) override;
+  grpc_error_handle Init(grpc_call_element* elem,
+                         const grpc_call_element_args* args) override;
 
   void Destroy(grpc_call_element* elem, const grpc_call_final_info* final_info,
                grpc_closure* then_call_closure) override;
@@ -68,7 +68,7 @@
   static const char* GetStatusTagForStatus(grpc_status_code status);
 
   // Records the call start.
-  static void RecvInitialMetadataReady(void* arg, grpc_error* err);
+  static void RecvInitialMetadataReady(void* arg, grpc_error_handle err);
 
   // From the initial metadata, extracts the service_method_, target_host_, and
   // client_ip_and_lr_token_.
diff --git a/grpc/src/core/ext/filters/max_age/max_age_filter.cc b/grpc/src/core/ext/filters/max_age/max_age_filter.cc
index b417db5..97a4dc2 100644
--- a/grpc/src/core/ext/filters/max_age/max_age_filter.cc
+++ b/grpc/src/core/ext/filters/max_age/max_age_filter.cc
@@ -54,16 +54,16 @@
   grpc_channel_stack* channel_stack;
   /* Guards access to max_age_timer, max_age_timer_pending, max_age_grace_timer
      and max_age_grace_timer_pending */
-  gpr_mu max_age_timer_mu;
+  grpc_core::Mutex max_age_timer_mu;
   /* True if the max_age timer callback is currently pending */
-  bool max_age_timer_pending;
+  bool max_age_timer_pending ABSL_GUARDED_BY(max_age_timer_mu) = false;
   /* True if the max_age_grace timer callback is currently pending */
-  bool max_age_grace_timer_pending;
+  bool max_age_grace_timer_pending ABSL_GUARDED_BY(max_age_timer_mu) = false;
   /* The timer for checking if the channel has reached its max age */
-  grpc_timer max_age_timer;
+  grpc_timer max_age_timer ABSL_GUARDED_BY(max_age_timer_mu);
   /* The timer for checking if the max-aged channel has uesed up the grace
      period */
-  grpc_timer max_age_grace_timer;
+  grpc_timer max_age_grace_timer ABSL_GUARDED_BY(max_age_timer_mu);
   /* The timer for checking if the channel's idle duration reaches
      max_connection_idle */
   grpc_timer max_idle_timer;
@@ -206,7 +206,8 @@
   }
 }
 
-static void start_max_idle_timer_after_init(void* arg, grpc_error* /*error*/) {
+static void start_max_idle_timer_after_init(void* arg,
+                                            grpc_error_handle /*error*/) {
   channel_data* chand = static_cast<channel_data*>(arg);
   /* Decrease call_count. If there are no active calls at this time,
      max_idle_timer will start here. If the number of active calls is not 0,
@@ -258,15 +259,18 @@
 
 }  // namespace grpc_core
 
-static void start_max_age_timer_after_init(void* arg, grpc_error* /*error*/) {
+static void start_max_age_timer_after_init(void* arg,
+                                           grpc_error_handle /*error*/) {
   channel_data* chand = static_cast<channel_data*>(arg);
-  gpr_mu_lock(&chand->max_age_timer_mu);
-  chand->max_age_timer_pending = true;
-  GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_timer");
-  grpc_timer_init(&chand->max_age_timer,
-                  grpc_core::ExecCtx::Get()->Now() + chand->max_connection_age,
-                  &chand->close_max_age_channel);
-  gpr_mu_unlock(&chand->max_age_timer_mu);
+  {
+    grpc_core::MutexLock lock(&chand->max_age_timer_mu);
+    chand->max_age_timer_pending = true;
+    GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_timer");
+    grpc_timer_init(
+        &chand->max_age_timer,
+        grpc_core::ExecCtx::Get()->Now() + chand->max_connection_age,
+        &chand->close_max_age_channel);
+  }
   grpc_transport_op* op = grpc_make_transport_op(nullptr);
   op->start_connectivity_watch.reset(new grpc_core::ConnectivityWatcher(chand));
   op->start_connectivity_watch_state = GRPC_CHANNEL_IDLE;
@@ -275,19 +279,20 @@
                            "max_age start_max_age_timer_after_init");
 }
 
-static void start_max_age_grace_timer_after_goaway_op(void* arg,
-                                                      grpc_error* /*error*/) {
+static void start_max_age_grace_timer_after_goaway_op(
+    void* arg, grpc_error_handle /*error*/) {
   channel_data* chand = static_cast<channel_data*>(arg);
-  gpr_mu_lock(&chand->max_age_timer_mu);
-  chand->max_age_grace_timer_pending = true;
-  GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_grace_timer");
-  grpc_timer_init(
-      &chand->max_age_grace_timer,
-      chand->max_connection_age_grace == GRPC_MILLIS_INF_FUTURE
-          ? GRPC_MILLIS_INF_FUTURE
-          : grpc_core::ExecCtx::Get()->Now() + chand->max_connection_age_grace,
-      &chand->force_close_max_age_channel);
-  gpr_mu_unlock(&chand->max_age_timer_mu);
+  {
+    grpc_core::MutexLock lock(&chand->max_age_timer_mu);
+    chand->max_age_grace_timer_pending = true;
+    GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_grace_timer");
+    grpc_timer_init(&chand->max_age_grace_timer,
+                    chand->max_connection_age_grace == GRPC_MILLIS_INF_FUTURE
+                        ? GRPC_MILLIS_INF_FUTURE
+                        : grpc_core::ExecCtx::Get()->Now() +
+                              chand->max_connection_age_grace,
+                    &chand->force_close_max_age_channel);
+  }
   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack,
                            "max_age start_max_age_grace_timer_after_goaway_op");
 }
@@ -304,7 +309,7 @@
   elem->filter->start_transport_op(elem, op);
 }
 
-static void max_idle_timer_cb(void* arg, grpc_error* error) {
+static void max_idle_timer_cb(void* arg, grpc_error_handle error) {
   channel_data* chand = static_cast<channel_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
     bool try_again = true;
@@ -348,11 +353,12 @@
   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack, "max_age max_idle_timer");
 }
 
-static void close_max_age_channel(void* arg, grpc_error* error) {
+static void close_max_age_channel(void* arg, grpc_error_handle error) {
   channel_data* chand = static_cast<channel_data*>(arg);
-  gpr_mu_lock(&chand->max_age_timer_mu);
-  chand->max_age_timer_pending = false;
-  gpr_mu_unlock(&chand->max_age_timer_mu);
+  {
+    grpc_core::MutexLock lock(&chand->max_age_timer_mu);
+    chand->max_age_timer_pending = false;
+  }
   if (error == GRPC_ERROR_NONE) {
     GRPC_CHANNEL_STACK_REF(chand->channel_stack,
                            "max_age start_max_age_grace_timer_after_goaway_op");
@@ -370,11 +376,12 @@
   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack, "max_age max_age_timer");
 }
 
-static void force_close_max_age_channel(void* arg, grpc_error* error) {
+static void force_close_max_age_channel(void* arg, grpc_error_handle error) {
   channel_data* chand = static_cast<channel_data*>(arg);
-  gpr_mu_lock(&chand->max_age_timer_mu);
-  chand->max_age_grace_timer_pending = false;
-  gpr_mu_unlock(&chand->max_age_timer_mu);
+  {
+    grpc_core::MutexLock lock(&chand->max_age_timer_mu);
+    chand->max_age_grace_timer_pending = false;
+  }
   if (error == GRPC_ERROR_NONE) {
     grpc_transport_op* op = grpc_make_transport_op(nullptr);
     op->disconnect_with_error =
@@ -407,7 +414,7 @@
 }
 
 /* Constructor for call_data. */
-static grpc_error* max_age_init_call_elem(
+static grpc_error_handle max_age_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* /*args*/) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   increase_call_count(chand);
@@ -423,12 +430,10 @@
 }
 
 /* Constructor for channel_data. */
-static grpc_error* max_age_init_channel_elem(grpc_channel_element* elem,
-                                             grpc_channel_element_args* args) {
+static grpc_error_handle max_age_init_channel_elem(
+    grpc_channel_element* elem, grpc_channel_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
-  gpr_mu_init(&chand->max_age_timer_mu);
-  chand->max_age_timer_pending = false;
-  chand->max_age_grace_timer_pending = false;
+  new (chand) channel_data();
   chand->channel_stack = args->channel_stack;
   chand->max_connection_age =
       add_random_max_connection_age_jitter_and_convert_to_grpc_millis(
@@ -513,7 +518,7 @@
 /* Destructor for channel_data. */
 static void max_age_destroy_channel_elem(grpc_channel_element* elem) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
-  gpr_mu_destroy(&chand->max_age_timer_mu);
+  chand->~channel_data();
 }
 
 const grpc_channel_filter grpc_max_age_filter = {
diff --git a/grpc/src/core/ext/filters/message_size/message_size_filter.cc b/grpc/src/core/ext/filters/message_size/message_size_filter.cc
index 10a58d9..3c921e2 100644
--- a/grpc/src/core/ext/filters/message_size/message_size_filter.cc
+++ b/grpc/src/core/ext/filters/message_size/message_size_filter.cc
@@ -37,8 +37,9 @@
 #include "src/core/lib/surface/call.h"
 #include "src/core/lib/surface/channel_init.h"
 
-static void recv_message_ready(void* user_data, grpc_error* error);
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
+static void recv_message_ready(void* user_data, grpc_error_handle error);
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error);
 
 namespace grpc_core {
 
@@ -67,9 +68,10 @@
 
 std::unique_ptr<ServiceConfigParser::ParsedConfig>
 MessageSizeParser::ParsePerMethodParams(const grpc_channel_args* /*args*/,
-                                        const Json& json, grpc_error** error) {
+                                        const Json& json,
+                                        grpc_error_handle* error) {
   GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   // Max request size.
   int max_request_message_bytes = -1;
   auto it = json.object_value().find("maxRequestMessageBytes");
@@ -179,7 +181,7 @@
   grpc_closure recv_message_ready;
   grpc_closure recv_trailing_metadata_ready;
   // The error caused by a message that is too large, or GRPC_ERROR_NONE
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   // Used by recv_message_ready.
   grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message = nullptr;
   // Original recv_message_ready callback, invoked after our own.
@@ -187,20 +189,20 @@
   // Original recv_trailing_metadata callback, invoked after our own.
   grpc_closure* original_recv_trailing_metadata_ready;
   bool seen_recv_trailing_metadata = false;
-  grpc_error* recv_trailing_metadata_error;
+  grpc_error_handle recv_trailing_metadata_error;
 };
 
 }  // namespace
 
 // Callback invoked when we receive a message.  Here we check the max
 // receive message size.
-static void recv_message_ready(void* user_data, grpc_error* error) {
+static void recv_message_ready(void* user_data, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (*calld->recv_message != nullptr && calld->limits.max_recv_size >= 0 &&
       (*calld->recv_message)->length() >
           static_cast<size_t>(calld->limits.max_recv_size)) {
-    grpc_error* new_error = grpc_error_set_int(
+    grpc_error_handle new_error = grpc_error_set_int(
         GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrFormat("Received message larger than max (%u vs. %d)",
                             (*calld->recv_message)->length(),
@@ -233,7 +235,8 @@
 
 // Callback invoked on completion of recv_trailing_metadata
 // Notifies the recv_trailing_metadata batch of any message size failures
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->next_recv_message_ready != nullptr) {
@@ -291,7 +294,7 @@
 }
 
 // Constructor for call_data.
-static grpc_error* message_size_init_call_elem(
+static grpc_error_handle message_size_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   new (elem->call_data) call_data(elem, *chand, *args);
@@ -315,7 +318,7 @@
 }
 
 // Constructor for channel_data.
-static grpc_error* message_size_init_channel_elem(
+static grpc_error_handle message_size_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
diff --git a/grpc/src/core/ext/filters/message_size/message_size_filter.h b/grpc/src/core/ext/filters/message_size/message_size_filter.h
index 0583a78..6629803 100644
--- a/grpc/src/core/ext/filters/message_size/message_size_filter.h
+++ b/grpc/src/core/ext/filters/message_size/message_size_filter.h
@@ -51,7 +51,7 @@
  public:
   std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
       const grpc_channel_args* /*args*/, const Json& json,
-      grpc_error** error) override;
+      grpc_error_handle* error) override;
 
   static void Register();
 
diff --git a/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc b/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
index 7f9a4fc..b2e8f3f 100644
--- a/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
+++ b/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
@@ -54,7 +54,8 @@
 }
 
 // Callback invoked when we receive an initial metadata.
-static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
+static void recv_initial_metadata_ready(void* user_data,
+                                        grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
 
@@ -105,7 +106,7 @@
 }
 
 // Constructor for call_data.
-static grpc_error* cronet_compression_init_call_elem(
+static grpc_error_handle cronet_compression_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* /*args*/) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->next_recv_initial_metadata_ready = nullptr;
@@ -122,7 +123,7 @@
     grpc_closure* /*ignored*/) {}
 
 // Constructor for channel_data.
-static grpc_error* cronet_compression_init_channel_elem(
+static grpc_error_handle cronet_compression_init_channel_elem(
     grpc_channel_element* /*elem*/, grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
@@ -192,7 +193,7 @@
   if (a == nullptr) {
     return true;
   }
-  if (grpc_channel_arg_get_bool(a, false) == false) {
+  if (!grpc_channel_arg_get_bool(a, false)) {
     return true;
   }
   return grpc_channel_stack_builder_prepend_filter(
diff --git a/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc
index 3408ed9..8b3d5d7 100644
--- a/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc
+++ b/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc
@@ -75,7 +75,7 @@
                           args.channel_args, &addr, args.deadline);
 }
 
-void Chttp2Connector::Shutdown(grpc_error* error) {
+void Chttp2Connector::Shutdown(grpc_error_handle error) {
   MutexLock lock(&mu_);
   shutdown_ = true;
   if (handshake_mgr_ != nullptr) {
@@ -89,7 +89,7 @@
   GRPC_ERROR_UNREF(error);
 }
 
-void Chttp2Connector::Connected(void* arg, grpc_error* error) {
+void Chttp2Connector::Connected(void* arg, grpc_error_handle error) {
   Chttp2Connector* self = static_cast<Chttp2Connector*>(arg);
   bool unref = false;
   {
@@ -131,14 +131,14 @@
 
 namespace {
 void NullThenSchedClosure(const DebugLocation& location, grpc_closure** closure,
-                          grpc_error* error) {
+                          grpc_error_handle error) {
   grpc_closure* c = *closure;
   *closure = nullptr;
   ExecCtx::Run(location, c, error);
 }
 }  // namespace
 
-void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error* error) {
+void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error_handle error) {
   auto* args = static_cast<HandshakerArgs*>(arg);
   Chttp2Connector* self = static_cast<Chttp2Connector*>(args->user_data);
   {
@@ -178,7 +178,7 @@
       self->Ref().release();  // Ref held by OnTimeout()
       grpc_chttp2_transport_start_reading(self->result_->transport,
                                           args->read_buffer,
-                                          &self->on_receive_settings_);
+                                          &self->on_receive_settings_, nullptr);
       GRPC_CLOSURE_INIT(&self->on_timeout_, OnTimeout, self,
                         grpc_schedule_on_exec_ctx);
       grpc_timer_init(&self->timer_, self->args_.deadline, &self->on_timeout_);
@@ -194,7 +194,7 @@
   self->Unref();
 }
 
-void Chttp2Connector::OnReceiveSettings(void* arg, grpc_error* error) {
+void Chttp2Connector::OnReceiveSettings(void* arg, grpc_error_handle error) {
   Chttp2Connector* self = static_cast<Chttp2Connector*>(arg);
   {
     MutexLock lock(&self->mu_);
@@ -220,7 +220,7 @@
   self->Unref();
 }
 
-void Chttp2Connector::OnTimeout(void* arg, grpc_error* error) {
+void Chttp2Connector::OnTimeout(void* arg, grpc_error_handle /*error*/) {
   Chttp2Connector* self = static_cast<Chttp2Connector*>(arg);
   {
     MutexLock lock(&self->mu_);
@@ -245,7 +245,7 @@
   self->Unref();
 }
 
-void Chttp2Connector::MaybeNotify(grpc_error* error) {
+void Chttp2Connector::MaybeNotify(grpc_error_handle error) {
   if (notify_error_.has_value()) {
     GRPC_ERROR_UNREF(error);
     NullThenSchedClosure(DEBUG_LOCATION, &notify_, notify_error_.value());
diff --git a/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.h b/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.h
index 7624b7f..59db078 100644
--- a/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.h
+++ b/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.h
@@ -33,14 +33,14 @@
   ~Chttp2Connector() override;
 
   void Connect(const Args& args, Result* result, grpc_closure* notify) override;
-  void Shutdown(grpc_error* error) override;
+  void Shutdown(grpc_error_handle error) override;
 
  private:
-  static void Connected(void* arg, grpc_error* error);
+  static void Connected(void* arg, grpc_error_handle error);
   void StartHandshakeLocked();
-  static void OnHandshakeDone(void* arg, grpc_error* error);
-  static void OnReceiveSettings(void* arg, grpc_error* error);
-  static void OnTimeout(void* arg, grpc_error* error);
+  static void OnHandshakeDone(void* arg, grpc_error_handle error);
+  static void OnReceiveSettings(void* arg, grpc_error_handle error);
+  static void OnTimeout(void* arg, grpc_error_handle error);
 
   // We cannot invoke notify_ until both OnTimeout() and OnReceiveSettings()
   // have been called since that is an indicator to the upper layer that we are
@@ -51,7 +51,7 @@
   // invoked, we call MaybeNotify() again to actually invoke the notify_
   // callback. Note that this only happens if the handshake is done and the
   // connector is waiting on the SETTINGS frame.
-  void MaybeNotify(grpc_error* error);
+  void MaybeNotify(grpc_error_handle error);
 
   Mutex mu_;
   Args args_;
@@ -66,7 +66,7 @@
   grpc_closure on_receive_settings_;
   grpc_timer timer_;
   grpc_closure on_timeout_;
-  absl::optional<grpc_error*> notify_error_;
+  absl::optional<grpc_error_handle> notify_error_;
   RefCountedPtr<HandshakeManager> handshake_mgr_;
 };
 
diff --git a/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc b/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc
index a325533..58f2742 100644
--- a/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc
+++ b/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc
@@ -37,10 +37,11 @@
 
 class Chttp2InsecureClientChannelFactory : public ClientChannelFactory {
  public:
-  Subchannel* CreateSubchannel(const grpc_channel_args* args) override {
+  RefCountedPtr<Subchannel> CreateSubchannel(
+      const grpc_channel_args* args) override {
     grpc_channel_args* new_args =
         grpc_default_authority_add_if_not_present(args);
-    Subchannel* s =
+    RefCountedPtr<Subchannel> s =
         Subchannel::Create(MakeOrphanable<Chttp2Connector>(), new_args);
     grpc_channel_args_destroy(new_args);
     return s;
@@ -50,7 +51,7 @@
 namespace {
 
 grpc_channel* CreateChannel(const char* target, const grpc_channel_args* args,
-                            grpc_error** error) {
+                            grpc_error_handle* error) {
   if (target == nullptr) {
     gpr_log(GPR_ERROR, "cannot create channel with NULL target name");
     if (error != nullptr) {
@@ -105,7 +106,7 @@
   const char* arg_to_remove = arg.key;
   grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
       args, &arg_to_remove, 1, &arg, 1);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   // Create channel.
   grpc_channel* channel = grpc_core::CreateChannel(target, new_args, &error);
   // Clean up.
diff --git a/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc b/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
index 27e64fb..4700093 100644
--- a/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
+++ b/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
@@ -56,13 +56,13 @@
   grpc_transport* transport =
       grpc_create_chttp2_transport(final_args, client, true);
   GPR_ASSERT(transport);
-  grpc_error* error = nullptr;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_channel* channel =
       grpc_channel_create(target, final_args, GRPC_CLIENT_DIRECT_CHANNEL,
                           transport, nullptr, &error);
   grpc_channel_args_destroy(final_args);
   if (channel != nullptr) {
-    grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
+    grpc_chttp2_transport_start_reading(transport, nullptr, nullptr, nullptr);
     grpc_core::ExecCtx::Get()->Flush();
   } else {
     intptr_t integer;
diff --git a/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc b/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
index 7edf6aa..5b00098 100644
--- a/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
+++ b/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
@@ -28,9 +28,9 @@
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/memory.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/security_connector/security_connector.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -43,14 +43,15 @@
 
 class Chttp2SecureClientChannelFactory : public ClientChannelFactory {
  public:
-  Subchannel* CreateSubchannel(const grpc_channel_args* args) override {
+  RefCountedPtr<Subchannel> CreateSubchannel(
+      const grpc_channel_args* args) override {
     grpc_channel_args* new_args = GetSecureNamingChannelArgs(args);
     if (new_args == nullptr) {
       gpr_log(GPR_ERROR,
               "Failed to create channel args during subchannel creation.");
       return nullptr;
     }
-    Subchannel* s =
+    RefCountedPtr<Subchannel> s =
         Subchannel::Create(MakeOrphanable<Chttp2Connector>(), new_args);
     grpc_channel_args_destroy(new_args);
     return s;
@@ -128,7 +129,7 @@
 namespace {
 
 grpc_channel* CreateChannel(const char* target, const grpc_channel_args* args,
-                            grpc_error** error) {
+                            grpc_error_handle* error) {
   if (target == nullptr) {
     gpr_log(GPR_ERROR, "cannot create channel with NULL target name");
     if (error != nullptr) {
@@ -180,7 +181,7 @@
       4, ((void*)creds, target, (void*)args, (void*)reserved));
   GPR_ASSERT(reserved == nullptr);
   grpc_channel* channel = nullptr;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (creds != nullptr) {
     // Add channel args containing the client channel factory and channel
     // credentials.
diff --git a/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc b/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc
index 8446a9f..911af03 100644
--- a/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc
+++ b/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc
@@ -38,6 +38,7 @@
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
 #include "src/core/lib/channel/handshaker_registry.h"
@@ -46,7 +47,6 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/resource_quota.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -61,14 +61,18 @@
 
 class Chttp2ServerListener : public Server::ListenerInterface {
  public:
-  static grpc_error* Create(Server* server, grpc_resolved_address* addr,
-                            grpc_channel_args* args, int* port_num);
+  static grpc_error_handle Create(Server* server, grpc_resolved_address* addr,
+                                  grpc_channel_args* args,
+                                  Chttp2ServerArgsModifier args_modifier,
+                                  int* port_num);
 
-  static grpc_error* CreateWithAcceptor(Server* server, const char* name,
-                                        grpc_channel_args* args);
+  static grpc_error_handle CreateWithAcceptor(
+      Server* server, const char* name, grpc_channel_args* args,
+      Chttp2ServerArgsModifier args_modifier);
 
   // Do not instantiate directly.  Use one of the factory methods above.
-  Chttp2ServerListener(Server* server, grpc_channel_args* args);
+  Chttp2ServerListener(Server* server, grpc_channel_args* args,
+                       Chttp2ServerArgsModifier args_modifier);
   ~Chttp2ServerListener() override;
 
   void Start(Server* server,
@@ -86,91 +90,209 @@
   class ConfigFetcherWatcher
       : public grpc_server_config_fetcher::WatcherInterface {
    public:
-    explicit ConfigFetcherWatcher(Chttp2ServerListener* listener)
-        : listener_(listener) {}
+    explicit ConfigFetcherWatcher(RefCountedPtr<Chttp2ServerListener> listener)
+        : listener_(std::move(listener)) {}
 
-    void UpdateConfig(grpc_channel_args* args) override {
-      {
-        MutexLock lock(&listener_->mu_);
-        // TODO(yashykt): Fix this
-        // grpc_channel_args_destroy(listener_->args_);
-        // listener_->args_ = args;
-        if (!listener_->shutdown_) return;  // Already started listening.
-      }
-      int port_temp;
-      grpc_error* error = grpc_tcp_server_add_port(
-          listener_->tcp_server_, &listener_->resolved_address_, &port_temp);
-      if (error != GRPC_ERROR_NONE) {
-        GRPC_ERROR_UNREF(error);
-        gpr_log(GPR_ERROR, "Error adding port to server: %s",
-                grpc_error_string(error));
-        // TODO(yashykt): We wouldn't need to assert here if we bound to the
-        // port earlier during AddPort.
-        GPR_ASSERT(0);
-      }
-      listener_->StartListening();
-    }
+    void UpdateConnectionManager(
+        RefCountedPtr<grpc_server_config_fetcher::ConnectionManager>
+            connection_manager) override;
+
+    void StopServing() override;
 
    private:
-    Chttp2ServerListener* listener_;
+    RefCountedPtr<Chttp2ServerListener> listener_;
   };
 
-  class ConnectionState : public RefCounted<ConnectionState> {
+  class ActiveConnection : public InternallyRefCounted<ActiveConnection> {
    public:
-    ConnectionState(Chttp2ServerListener* listener,
-                    grpc_pollset* accepting_pollset,
-                    grpc_tcp_server_acceptor* acceptor,
-                    RefCountedPtr<HandshakeManager> handshake_mgr,
-                    grpc_channel_args* args, grpc_endpoint* endpoint);
+    class HandshakingState : public InternallyRefCounted<HandshakingState> {
+     public:
+      HandshakingState(RefCountedPtr<ActiveConnection> connection_ref,
+                       grpc_pollset* accepting_pollset,
+                       grpc_tcp_server_acceptor* acceptor,
+                       grpc_channel_args* args);
 
-    ~ConnectionState() override;
+      ~HandshakingState() override;
+
+      void Orphan() override;
+
+      void Start(grpc_endpoint* endpoint, grpc_channel_args* args);
+
+      // Needed to be able to grab an external ref in ActiveConnection::Start()
+      using InternallyRefCounted<HandshakingState>::Ref;
+
+     private:
+      static void OnTimeout(void* arg, grpc_error_handle error);
+      static void OnReceiveSettings(void* arg, grpc_error_handle /* error */);
+      static void OnHandshakeDone(void* arg, grpc_error_handle error);
+      RefCountedPtr<ActiveConnection> const connection_;
+      grpc_pollset* const accepting_pollset_;
+      grpc_tcp_server_acceptor* const acceptor_;
+      RefCountedPtr<HandshakeManager> handshake_mgr_
+          ABSL_GUARDED_BY(&connection_->mu_);
+      // State for enforcing handshake timeout on receiving HTTP/2 settings.
+      grpc_millis const deadline_;
+      grpc_timer timer_ ABSL_GUARDED_BY(&connection_->mu_);
+      grpc_closure on_timeout_ ABSL_GUARDED_BY(&connection_->mu_);
+      grpc_closure on_receive_settings_ ABSL_GUARDED_BY(&connection_->mu_);
+      grpc_pollset_set* const interested_parties_;
+    };
+
+    ActiveConnection(grpc_pollset* accepting_pollset,
+                     grpc_tcp_server_acceptor* acceptor,
+                     grpc_channel_args* args);
+    ~ActiveConnection() override;
+
+    void Orphan() override;
+
+    void SendGoAway();
+
+    void Start(RefCountedPtr<Chttp2ServerListener> listener,
+               grpc_endpoint* endpoint, grpc_channel_args* args);
+
+    // Needed to be able to grab an external ref in
+    // Chttp2ServerListener::OnAccept()
+    using InternallyRefCounted<ActiveConnection>::Ref;
 
    private:
-    static void OnTimeout(void* arg, grpc_error* error);
-    static void OnReceiveSettings(void* arg, grpc_error* error);
-    static void OnHandshakeDone(void* arg, grpc_error* error);
+    static void OnClose(void* arg, grpc_error_handle error);
 
-    Chttp2ServerListener* const listener_;
-    grpc_pollset* const accepting_pollset_;
-    grpc_tcp_server_acceptor* const acceptor_;
-    RefCountedPtr<HandshakeManager> handshake_mgr_;
-    // State for enforcing handshake timeout on receiving HTTP/2 settings.
-    grpc_chttp2_transport* transport_ = nullptr;
-    grpc_millis deadline_;
-    grpc_timer timer_;
-    grpc_closure on_timeout_;
-    grpc_closure on_receive_settings_;
-    grpc_pollset_set* const interested_parties_;
+    RefCountedPtr<Chttp2ServerListener> listener_;
+    Mutex mu_ ABSL_ACQUIRED_AFTER(&listener_->mu_);
+    // Set by HandshakingState before the handshaking begins and reset when
+    // handshaking is done.
+    OrphanablePtr<HandshakingState> handshaking_state_ ABSL_GUARDED_BY(&mu_);
+    // Set by HandshakingState when handshaking is done and a valid transport is
+    // created.
+    grpc_chttp2_transport* transport_ ABSL_GUARDED_BY(&mu_) = nullptr;
+    grpc_closure on_close_;
+    bool shutdown_ ABSL_GUARDED_BY(&mu_) = false;
   };
 
+  // To allow access to RefCounted<> like interface.
+  friend class RefCountedPtr<Chttp2ServerListener>;
+
+  // Should only be called once so as to start the TCP server.
   void StartListening();
 
   static void OnAccept(void* arg, grpc_endpoint* tcp,
                        grpc_pollset* accepting_pollset,
                        grpc_tcp_server_acceptor* acceptor);
 
-  RefCountedPtr<HandshakeManager> CreateHandshakeManager();
-
-  static void TcpServerShutdownComplete(void* arg, grpc_error* error);
+  static void TcpServerShutdownComplete(void* arg, grpc_error_handle error);
 
   static void DestroyListener(Server* /*server*/, void* arg,
                               grpc_closure* destroy_done);
 
+  // The interface required by RefCountedPtr<> has been manually implemented
+  // here to take a ref on tcp_server_ instead. Note that, the handshaker needs
+  // tcp_server_ to exist for the lifetime of the handshake since it's needed by
+  // acceptor. Sharing refs between the listener and tcp_server_ is just an
+  // optimization to avoid taking additional refs on the listener, since
+  // TcpServerShutdownComplete already holds a ref to the listener.
+  void IncrementRefCount() { grpc_tcp_server_ref(tcp_server_); }
+  void IncrementRefCount(const DebugLocation& /* location */,
+                         const char* /* reason */) {
+    IncrementRefCount();
+  }
+
+  RefCountedPtr<Chttp2ServerListener> Ref() GRPC_MUST_USE_RESULT {
+    IncrementRefCount();
+    return RefCountedPtr<Chttp2ServerListener>(this);
+  }
+  RefCountedPtr<Chttp2ServerListener> Ref(const DebugLocation& /* location */,
+                                          const char* /* reason */)
+      GRPC_MUST_USE_RESULT {
+    return Ref();
+  }
+
+  void Unref() { grpc_tcp_server_unref(tcp_server_); }
+  void Unref(const DebugLocation& /* location */, const char* /* reason */) {
+    Unref();
+  }
+
   Server* const server_;
-  grpc_channel_args* const args_;
   grpc_tcp_server* tcp_server_;
   grpc_resolved_address resolved_address_;
-  Mutex mu_;
+  Chttp2ServerArgsModifier const args_modifier_;
   ConfigFetcherWatcher* config_fetcher_watcher_ = nullptr;
-  bool shutdown_ = true;
-  grpc_closure tcp_server_shutdown_complete_;
-  grpc_closure* on_destroy_done_ = nullptr;
-  HandshakeManager* pending_handshake_mgrs_ = nullptr;
+  Mutex channel_args_mu_;
+  grpc_channel_args* args_ ABSL_GUARDED_BY(channel_args_mu_);
+  RefCountedPtr<grpc_server_config_fetcher::ConnectionManager>
+      connection_manager_ ABSL_GUARDED_BY(channel_args_mu_);
+  Mutex mu_;
+  // Signals whether grpc_tcp_server_start() has been called.
+  bool started_ ABSL_GUARDED_BY(mu_) = false;
+  // Signals whether grpc_tcp_server_start() has completed.
+  CondVar started_cv_ ABSL_GUARDED_BY(mu_);
+  // Signals whether new requests/connections are to be accepted.
+  bool is_serving_ ABSL_GUARDED_BY(mu_) = false;
+  // Signals whether the application has triggered shutdown.
+  bool shutdown_ ABSL_GUARDED_BY(mu_) = false;
+  std::map<ActiveConnection*, OrphanablePtr<ActiveConnection>> connections_
+      ABSL_GUARDED_BY(mu_);
+  grpc_closure tcp_server_shutdown_complete_ ABSL_GUARDED_BY(mu_);
+  grpc_closure* on_destroy_done_ ABSL_GUARDED_BY(mu_) = nullptr;
   RefCountedPtr<channelz::ListenSocketNode> channelz_listen_socket_;
 };
 
 //
-// Chttp2ServerListener::ConnectionState
+// Chttp2ServerListener::ConfigFetcherWatcher
+//
+
+void Chttp2ServerListener::ConfigFetcherWatcher::UpdateConnectionManager(
+    RefCountedPtr<grpc_server_config_fetcher::ConnectionManager>
+        connection_manager) {
+  RefCountedPtr<grpc_server_config_fetcher::ConnectionManager>
+      connection_manager_to_destroy;
+  {
+    MutexLock lock(&listener_->channel_args_mu_);
+    connection_manager_to_destroy = listener_->connection_manager_;
+    listener_->connection_manager_ = std::move(connection_manager);
+  }
+  {
+    MutexLock lock(&listener_->mu_);
+    if (listener_->shutdown_) {
+      return;
+    }
+    listener_->is_serving_ = true;
+    if (listener_->started_) return;
+  }
+  int port_temp;
+  grpc_error_handle error = grpc_tcp_server_add_port(
+      listener_->tcp_server_, &listener_->resolved_address_, &port_temp);
+  if (error != GRPC_ERROR_NONE) {
+    GRPC_ERROR_UNREF(error);
+    gpr_log(GPR_ERROR, "Error adding port to server: %s",
+            grpc_error_std_string(error).c_str());
+    // TODO(yashykt): We wouldn't need to assert here if we bound to the
+    // port earlier during AddPort.
+    GPR_ASSERT(0);
+  }
+  listener_->StartListening();
+  {
+    MutexLock lock(&listener_->mu_);
+    listener_->started_ = true;
+    listener_->started_cv_.SignalAll();
+  }
+}
+
+void Chttp2ServerListener::ConfigFetcherWatcher::StopServing() {
+  std::map<ActiveConnection*, OrphanablePtr<ActiveConnection>> connections;
+  {
+    MutexLock lock(&listener_->mu_);
+    listener_->is_serving_ = false;
+    connections = std::move(listener_->connections_);
+  }
+  // Send GOAWAYs on the transports so that they disconnected when existing RPCs
+  // finish.
+  for (auto& connection : connections) {
+    connection.first->SendGoAway();
+  }
+}
+
+//
+// Chttp2ServerListener::ActiveConnection::HandshakingState
 //
 
 grpc_millis GetConnectionDeadline(const grpc_channel_args* args) {
@@ -180,73 +302,96 @@
   return ExecCtx::Get()->Now() + timeout_ms;
 }
 
-Chttp2ServerListener::ConnectionState::ConnectionState(
-    Chttp2ServerListener* listener, grpc_pollset* accepting_pollset,
-    grpc_tcp_server_acceptor* acceptor,
-    RefCountedPtr<HandshakeManager> handshake_mgr, grpc_channel_args* args,
-    grpc_endpoint* endpoint)
-    : listener_(listener),
+Chttp2ServerListener::ActiveConnection::HandshakingState::HandshakingState(
+    RefCountedPtr<ActiveConnection> connection_ref,
+    grpc_pollset* accepting_pollset, grpc_tcp_server_acceptor* acceptor,
+    grpc_channel_args* args)
+    : connection_(std::move(connection_ref)),
       accepting_pollset_(accepting_pollset),
       acceptor_(acceptor),
-      handshake_mgr_(std::move(handshake_mgr)),
+      handshake_mgr_(MakeRefCounted<HandshakeManager>()),
       deadline_(GetConnectionDeadline(args)),
       interested_parties_(grpc_pollset_set_create()) {
   grpc_pollset_set_add_pollset(interested_parties_, accepting_pollset_);
   HandshakerRegistry::AddHandshakers(HANDSHAKER_SERVER, args,
                                      interested_parties_, handshake_mgr_.get());
-  handshake_mgr_->DoHandshake(endpoint, args, deadline_, acceptor_,
-                              OnHandshakeDone, this);
 }
 
-Chttp2ServerListener::ConnectionState::~ConnectionState() {
-  if (transport_ != nullptr) {
-    GRPC_CHTTP2_UNREF_TRANSPORT(transport_, "receive settings timeout");
-  }
+Chttp2ServerListener::ActiveConnection::HandshakingState::~HandshakingState() {
   grpc_pollset_set_del_pollset(interested_parties_, accepting_pollset_);
   grpc_pollset_set_destroy(interested_parties_);
 }
 
-void Chttp2ServerListener::ConnectionState::OnTimeout(void* arg,
-                                                      grpc_error* error) {
-  ConnectionState* self = static_cast<ConnectionState*>(arg);
+void Chttp2ServerListener::ActiveConnection::HandshakingState::Orphan() {
+  {
+    MutexLock lock(&connection_->mu_);
+    if (handshake_mgr_ != nullptr) {
+      handshake_mgr_->Shutdown(
+          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Listener stopped serving."));
+    }
+  }
+  Unref();
+}
+
+void Chttp2ServerListener::ActiveConnection::HandshakingState::Start(
+    grpc_endpoint* endpoint, grpc_channel_args* args) {
+  Ref().release();  // Held by OnHandshakeDone
+  RefCountedPtr<HandshakeManager> handshake_mgr;
+  {
+    MutexLock lock(&connection_->mu_);
+    if (handshake_mgr_ == nullptr) return;
+    handshake_mgr = handshake_mgr_;
+  }
+  handshake_mgr->DoHandshake(endpoint, args, deadline_, acceptor_,
+                             OnHandshakeDone, this);
+}
+
+void Chttp2ServerListener::ActiveConnection::HandshakingState::OnTimeout(
+    void* arg, grpc_error_handle error) {
+  HandshakingState* self = static_cast<HandshakingState*>(arg);
   // Note that we may be called with GRPC_ERROR_NONE when the timer fires
   // or with an error indicating that the timer system is being shut down.
   if (error != GRPC_ERROR_CANCELLED) {
     grpc_transport_op* op = grpc_make_transport_op(nullptr);
     op->disconnect_with_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Did not receive HTTP/2 settings before handshake timeout");
-    grpc_transport_perform_op(&self->transport_->base, op);
+    grpc_chttp2_transport* transport = nullptr;
+    {
+      MutexLock lock(&self->connection_->mu_);
+      transport = self->connection_->transport_;
+    }
+    grpc_transport_perform_op(&transport->base, op);
   }
   self->Unref();
 }
 
-void Chttp2ServerListener::ConnectionState::OnReceiveSettings(
-    void* arg, grpc_error* error) {
-  ConnectionState* self = static_cast<ConnectionState*>(arg);
-  if (error == GRPC_ERROR_NONE) {
-    grpc_timer_cancel(&self->timer_);
-  }
+void Chttp2ServerListener::ActiveConnection::HandshakingState::
+    OnReceiveSettings(void* arg, grpc_error_handle /* error */) {
+  HandshakingState* self = static_cast<HandshakingState*>(arg);
+  grpc_timer_cancel(&self->timer_);
   self->Unref();
 }
 
-void Chttp2ServerListener::ConnectionState::OnHandshakeDone(void* arg,
-                                                            grpc_error* error) {
+void Chttp2ServerListener::ActiveConnection::HandshakingState::OnHandshakeDone(
+    void* arg, grpc_error_handle error) {
   auto* args = static_cast<HandshakerArgs*>(arg);
-  ConnectionState* self = static_cast<ConnectionState*>(args->user_data);
+  HandshakingState* self = static_cast<HandshakingState*>(args->user_data);
+  OrphanablePtr<HandshakingState> handshaking_state_ref;
+  RefCountedPtr<HandshakeManager> handshake_mgr;
+  bool cleanup_connection = false;
+  bool free_resource_quota = false;
+  grpc_resource_user* resource_user =
+      self->connection_->listener_->server_->default_resource_user();
   {
-    MutexLock lock(&self->listener_->mu_);
-    grpc_resource_user* resource_user =
-        self->listener_->server_->default_resource_user();
-    if (error != GRPC_ERROR_NONE || self->listener_->shutdown_) {
-      const char* error_str = grpc_error_string(error);
-      gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str);
-      if (resource_user != nullptr) {
-        grpc_resource_user_free(resource_user,
-                                GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
-      }
+    MutexLock connection_lock(&self->connection_->mu_);
+    if (error != GRPC_ERROR_NONE || self->connection_->shutdown_) {
+      std::string error_str = grpc_error_std_string(error);
+      gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str.c_str());
+      cleanup_connection = true;
+      free_resource_quota = true;
       if (error == GRPC_ERROR_NONE && args->endpoint != nullptr) {
-        // We were shut down after handshaking completed successfully, so
-        // destroy the endpoint here.
+        // We were shut down or stopped serving after handshaking completed
+        // successfully, so destroy the endpoint here.
         // TODO(ctiller): It is currently necessary to shutdown endpoints
         // before destroying them, even if we know that there are no
         // pending read/write callbacks.  This should be fixed, at which
@@ -264,9 +409,11 @@
       if (args->endpoint != nullptr) {
         grpc_transport* transport = grpc_create_chttp2_transport(
             args->args, args->endpoint, false, resource_user);
-        grpc_error* channel_init_err = self->listener_->server_->SetupTransport(
-            transport, self->accepting_pollset_, args->args,
-            grpc_chttp2_transport_get_socket_node(transport), resource_user);
+        grpc_error_handle channel_init_err =
+            self->connection_->listener_->server_->SetupTransport(
+                transport, self->accepting_pollset_, args->args,
+                grpc_chttp2_transport_get_socket_node(transport),
+                resource_user);
         if (channel_init_err == GRPC_ERROR_NONE) {
           // Use notify_on_receive_settings callback to enforce the
           // handshake deadline.
@@ -276,48 +423,153 @@
           // static_cast<> to a derived class.
           // TODO(roth): Change to static_cast<> when we C++-ify the
           // transport API.
-          self->transport_ =
+          self->connection_->transport_ =
               reinterpret_cast<grpc_chttp2_transport*>(transport);
+          GRPC_CHTTP2_REF_TRANSPORT(self->connection_->transport_,
+                                    "ActiveConnection");  // Held by connection_
           self->Ref().release();  // Held by OnReceiveSettings().
           GRPC_CLOSURE_INIT(&self->on_receive_settings_, OnReceiveSettings,
                             self, grpc_schedule_on_exec_ctx);
+          // If the listener has been configured with a config fetcher, we need
+          // to watch on the transport being closed so that we can an updated
+          // list of active connections.
+          grpc_closure* on_close = nullptr;
+          if (self->connection_->listener_->config_fetcher_watcher_ !=
+              nullptr) {
+            // Refs helds by OnClose()
+            self->connection_->Ref().release();
+            on_close = &self->connection_->on_close_;
+          } else {
+            // Remove the connection from the connections_ map since OnClose()
+            // will not be invoked when a config fetcher is set.
+            cleanup_connection = true;
+          }
           grpc_chttp2_transport_start_reading(transport, args->read_buffer,
-                                              &self->on_receive_settings_);
+                                              &self->on_receive_settings_,
+                                              on_close);
           grpc_channel_args_destroy(args->args);
           self->Ref().release();  // Held by OnTimeout().
-          GRPC_CHTTP2_REF_TRANSPORT(
-              reinterpret_cast<grpc_chttp2_transport*>(transport),
-              "receive settings timeout");
           GRPC_CLOSURE_INIT(&self->on_timeout_, OnTimeout, self,
                             grpc_schedule_on_exec_ctx);
           grpc_timer_init(&self->timer_, self->deadline_, &self->on_timeout_);
         } else {
           // Failed to create channel from transport. Clean up.
           gpr_log(GPR_ERROR, "Failed to create channel: %s",
-                  grpc_error_string(channel_init_err));
+                  grpc_error_std_string(channel_init_err).c_str());
           GRPC_ERROR_UNREF(channel_init_err);
           grpc_transport_destroy(transport);
           grpc_slice_buffer_destroy_internal(args->read_buffer);
           gpr_free(args->read_buffer);
-          if (resource_user != nullptr) {
-            grpc_resource_user_free(resource_user,
-                                    GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
-          }
+          cleanup_connection = true;
+          free_resource_quota = true;
           grpc_channel_args_destroy(args->args);
         }
       } else {
-        if (resource_user != nullptr) {
-          grpc_resource_user_free(resource_user,
-                                  GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
-        }
+        cleanup_connection = true;
+        free_resource_quota = true;
       }
     }
-    self->handshake_mgr_->RemoveFromPendingMgrList(
-        &self->listener_->pending_handshake_mgrs_);
+    // Since the handshake manager is done, the connection no longer needs to
+    // shutdown the handshake when the listener needs to stop serving.
+    // Avoid calling the destructor of HandshakeManager and HandshakingState
+    // from within the critical region.
+    handshake_mgr = std::move(self->handshake_mgr_);
+    handshaking_state_ref = std::move(self->connection_->handshaking_state_);
   }
-  self->handshake_mgr_.reset();
   gpr_free(self->acceptor_);
-  grpc_tcp_server_unref(self->listener_->tcp_server_);
+  OrphanablePtr<ActiveConnection> connection;
+  if (free_resource_quota && resource_user != nullptr) {
+    grpc_resource_user_free(resource_user, GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+  }
+  if (cleanup_connection) {
+    MutexLock listener_lock(&self->connection_->listener_->mu_);
+    auto it = self->connection_->listener_->connections_.find(
+        self->connection_.get());
+    if (it != self->connection_->listener_->connections_.end()) {
+      connection = std::move(it->second);
+      self->connection_->listener_->connections_.erase(it);
+    }
+  }
+  self->Unref();
+}
+
+//
+// Chttp2ServerListener::ActiveConnection
+//
+
+Chttp2ServerListener::ActiveConnection::ActiveConnection(
+    grpc_pollset* accepting_pollset, grpc_tcp_server_acceptor* acceptor,
+    grpc_channel_args* args)
+    : handshaking_state_(MakeOrphanable<HandshakingState>(
+          Ref(), accepting_pollset, acceptor, args)) {
+  GRPC_CLOSURE_INIT(&on_close_, ActiveConnection::OnClose, this,
+                    grpc_schedule_on_exec_ctx);
+}
+
+Chttp2ServerListener::ActiveConnection::~ActiveConnection() {
+  if (transport_ != nullptr) {
+    GRPC_CHTTP2_UNREF_TRANSPORT(transport_, "ActiveConnection");
+  }
+}
+
+void Chttp2ServerListener::ActiveConnection::Orphan() {
+  OrphanablePtr<HandshakingState> handshaking_state;
+  {
+    MutexLock lock(&mu_);
+    shutdown_ = true;
+    // Reset handshaking_state_ since we have been orphaned by the listener
+    // signaling that the listener has stopped serving.
+    handshaking_state = std::move(handshaking_state_);
+  }
+  Unref();
+}
+
+void Chttp2ServerListener::ActiveConnection::SendGoAway() {
+  grpc_chttp2_transport* transport = nullptr;
+  {
+    MutexLock lock(&mu_);
+    transport = transport_;
+  }
+  if (transport != nullptr) {
+    grpc_transport_op* op = grpc_make_transport_op(nullptr);
+    op->goaway_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Server is stopping to serve requests.");
+    grpc_transport_perform_op(&transport->base, op);
+  }
+}
+
+void Chttp2ServerListener::ActiveConnection::Start(
+    RefCountedPtr<Chttp2ServerListener> listener, grpc_endpoint* endpoint,
+    grpc_channel_args* args) {
+  RefCountedPtr<HandshakingState> handshaking_state_ref;
+  listener_ = std::move(listener);
+  {
+    MutexLock lock(&mu_);
+    if (shutdown_) return;
+    // Hold a ref to HandshakingState to allow starting the handshake outside
+    // the critical region.
+    handshaking_state_ref = handshaking_state_->Ref();
+  }
+  handshaking_state_ref->Start(endpoint, args);
+}
+
+void Chttp2ServerListener::ActiveConnection::OnClose(
+    void* arg, grpc_error_handle /* error */) {
+  ActiveConnection* self = static_cast<ActiveConnection*>(arg);
+  OrphanablePtr<ActiveConnection> connection;
+  {
+    MutexLock listener_lock(&self->listener_->mu_);
+    MutexLock connection_lock(&self->mu_);
+    // The node was already deleted from the connections_ list if the connection
+    // is shutdown.
+    if (!self->shutdown_) {
+      auto it = self->listener_->connections_.find(self);
+      if (it != self->listener_->connections_.end()) {
+        connection = std::move(it->second);
+        self->listener_->connections_.erase(it);
+      }
+    }
+  }
   self->Unref();
 }
 
@@ -325,16 +577,15 @@
 // Chttp2ServerListener
 //
 
-grpc_error* Chttp2ServerListener::Create(Server* server,
-                                         grpc_resolved_address* addr,
-                                         grpc_channel_args* args,
-                                         int* port_num) {
+grpc_error_handle Chttp2ServerListener::Create(
+    Server* server, grpc_resolved_address* addr, grpc_channel_args* args,
+    Chttp2ServerArgsModifier args_modifier, int* port_num) {
   Chttp2ServerListener* listener = nullptr;
   // The bulk of this method is inside of a lambda to make cleanup
   // easier without using goto.
-  grpc_error* error = [&]() {
+  grpc_error_handle error = [&]() {
     // Create Chttp2ServerListener.
-    listener = new Chttp2ServerListener(server, args);
+    listener = new Chttp2ServerListener(server, args, args_modifier);
     error = grpc_tcp_server_create(&listener->tcp_server_shutdown_complete_,
                                    args, &listener->tcp_server_);
     if (error != GRPC_ERROR_NONE) return error;
@@ -349,7 +600,7 @@
     // Create channelz node.
     if (grpc_channel_args_find_bool(args, GRPC_ARG_ENABLE_CHANNELZ,
                                     GRPC_ENABLE_CHANNELZ_DEFAULT)) {
-      std::string string_address = grpc_sockaddr_to_string(addr, false);
+      std::string string_address = grpc_sockaddr_to_uri(addr);
       listener->channelz_listen_socket_ =
           MakeRefCounted<channelz::ListenSocketNode>(
               string_address.c_str(),
@@ -374,11 +625,12 @@
   return error;
 }
 
-grpc_error* Chttp2ServerListener::CreateWithAcceptor(Server* server,
-                                                     const char* name,
-                                                     grpc_channel_args* args) {
-  Chttp2ServerListener* listener = new Chttp2ServerListener(server, args);
-  grpc_error* error = grpc_tcp_server_create(
+grpc_error_handle Chttp2ServerListener::CreateWithAcceptor(
+    Server* server, const char* name, grpc_channel_args* args,
+    Chttp2ServerArgsModifier args_modifier) {
+  Chttp2ServerListener* listener =
+      new Chttp2ServerListener(server, args, args_modifier);
+  grpc_error_handle error = grpc_tcp_server_create(
       &listener->tcp_server_shutdown_complete_, args, &listener->tcp_server_);
   if (error != GRPC_ERROR_NONE) {
     delete listener;
@@ -392,14 +644,22 @@
   return GRPC_ERROR_NONE;
 }
 
-Chttp2ServerListener::Chttp2ServerListener(Server* server,
-                                           grpc_channel_args* args)
-    : server_(server), args_(args) {
+Chttp2ServerListener::Chttp2ServerListener(
+    Server* server, grpc_channel_args* args,
+    Chttp2ServerArgsModifier args_modifier)
+    : server_(server), args_modifier_(args_modifier), args_(args) {
   GRPC_CLOSURE_INIT(&tcp_server_shutdown_complete_, TcpServerShutdownComplete,
                     this, grpc_schedule_on_exec_ctx);
 }
 
 Chttp2ServerListener::~Chttp2ServerListener() {
+  // Flush queued work before destroying handshaker factory, since that
+  // may do a synchronous unref.
+  ExecCtx::Get()->Flush();
+  if (on_destroy_done_ != nullptr) {
+    ExecCtx::Run(DEBUG_LOCATION, on_destroy_done_, GRPC_ERROR_NONE);
+    ExecCtx::Get()->Flush();
+  }
   grpc_channel_args_destroy(args_);
 }
 
@@ -407,22 +667,28 @@
 void Chttp2ServerListener::Start(
     Server* /*server*/, const std::vector<grpc_pollset*>* /* pollsets */) {
   if (server_->config_fetcher() != nullptr) {
-    auto watcher = absl::make_unique<ConfigFetcherWatcher>(this);
+    grpc_channel_args* args = nullptr;
+    auto watcher = absl::make_unique<ConfigFetcherWatcher>(Ref());
+    config_fetcher_watcher_ = watcher.get();
     {
-      MutexLock lock(&mu_);
-      config_fetcher_watcher_ = watcher.get();
+      MutexLock lock(&channel_args_mu_);
+      args = grpc_channel_args_copy(args_);
     }
     server_->config_fetcher()->StartWatch(
-        grpc_sockaddr_to_string(&resolved_address_, false), std::move(watcher));
+        grpc_sockaddr_to_string(&resolved_address_, false), args,
+        std::move(watcher));
   } else {
+    {
+      MutexLock lock(&mu_);
+      started_ = true;
+      is_serving_ = true;
+    }
     StartListening();
   }
 }
 
 void Chttp2ServerListener::StartListening() {
   grpc_tcp_server_start(tcp_server_, &server_->pollsets(), OnAccept, this);
-  MutexLock lock(&mu_);
-  shutdown_ = false;
 }
 
 void Chttp2ServerListener::SetOnDestroyDone(grpc_closure* on_destroy_done) {
@@ -430,61 +696,94 @@
   on_destroy_done_ = on_destroy_done;
 }
 
-RefCountedPtr<HandshakeManager> Chttp2ServerListener::CreateHandshakeManager() {
-  MutexLock lock(&mu_);
-  if (shutdown_) return nullptr;
-  grpc_resource_user* resource_user = server_->default_resource_user();
-  if (resource_user != nullptr &&
-      !grpc_resource_user_safe_alloc(resource_user,
-                                     GRPC_RESOURCE_QUOTA_CHANNEL_SIZE)) {
-    gpr_log(GPR_ERROR,
-            "Memory quota exhausted, rejecting connection, no handshaking.");
-    return nullptr;
-  }
-  auto handshake_mgr = MakeRefCounted<HandshakeManager>();
-  handshake_mgr->AddToPendingMgrList(&pending_handshake_mgrs_);
-  grpc_tcp_server_ref(tcp_server_);  // Ref held by ConnectionState.
-  return handshake_mgr;
-}
-
 void Chttp2ServerListener::OnAccept(void* arg, grpc_endpoint* tcp,
                                     grpc_pollset* accepting_pollset,
                                     grpc_tcp_server_acceptor* acceptor) {
   Chttp2ServerListener* self = static_cast<Chttp2ServerListener*>(arg);
-  RefCountedPtr<HandshakeManager> handshake_mgr =
-      self->CreateHandshakeManager();
-  if (handshake_mgr == nullptr) {
-    grpc_endpoint_shutdown(tcp, GRPC_ERROR_NONE);
+  grpc_channel_args* args = nullptr;
+  RefCountedPtr<grpc_server_config_fetcher::ConnectionManager>
+      connection_manager;
+  {
+    MutexLock lock(&self->channel_args_mu_);
+    args = grpc_channel_args_copy(self->args_);
+    connection_manager = self->connection_manager_;
+  }
+  auto endpoint_cleanup = [&](grpc_error_handle error) {
+    grpc_endpoint_shutdown(tcp, error);
     grpc_endpoint_destroy(tcp);
     gpr_free(acceptor);
-    return;
+  };
+  if (self->server_->config_fetcher() != nullptr) {
+    if (connection_manager == nullptr) {
+      grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "No ConnectionManager configured. Closing connection.");
+      endpoint_cleanup(error);
+      grpc_channel_args_destroy(args);
+      return;
+    }
+    // TODO(yashykt): Maybe combine the following two arg modifiers into a
+    // single one.
+    absl::StatusOr<grpc_channel_args*> args_result =
+        connection_manager->UpdateChannelArgsForConnection(args, tcp);
+    if (!args_result.ok()) {
+      gpr_log(GPR_DEBUG, "Closing connection: %s",
+              args_result.status().ToString().c_str());
+      endpoint_cleanup(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          args_result.status().ToString().c_str()));
+      return;
+    }
+    grpc_error_handle error = GRPC_ERROR_NONE;
+    args = self->args_modifier_(*args_result, &error);
+    if (error != GRPC_ERROR_NONE) {
+      gpr_log(GPR_DEBUG, "Closing connection: %s",
+              grpc_error_std_string(error).c_str());
+      endpoint_cleanup(error);
+      grpc_channel_args_destroy(args);
+      return;
+    }
   }
-  // Deletes itself when done.
-  new ConnectionState(self, accepting_pollset, acceptor,
-                      std::move(handshake_mgr), self->args_, tcp);
+  auto connection =
+      MakeOrphanable<ActiveConnection>(accepting_pollset, acceptor, args);
+  // Hold a ref to connection to allow starting handshake outside the
+  // critical region
+  RefCountedPtr<ActiveConnection> connection_ref = connection->Ref();
+  RefCountedPtr<Chttp2ServerListener> listener_ref;
+  {
+    MutexLock lock(&self->mu_);
+    // Shutdown the the connection if listener's stopped serving.
+    if (!self->shutdown_ && self->is_serving_) {
+      grpc_resource_user* resource_user =
+          self->server_->default_resource_user();
+      if (resource_user != nullptr &&
+          !grpc_resource_user_safe_alloc(resource_user,
+                                         GRPC_RESOURCE_QUOTA_CHANNEL_SIZE)) {
+        gpr_log(
+            GPR_ERROR,
+            "Memory quota exhausted, rejecting connection, no handshaking.");
+      } else {
+        // This ref needs to be taken in the critical region after having made
+        // sure that the listener has not been Orphaned, so as to avoid
+        // heap-use-after-free issues where `Ref()` is invoked when the ref of
+        // tcp_server_ has already reached 0. (Ref() implementation of
+        // Chttp2ServerListener is grpc_tcp_server_ref().)
+        listener_ref = self->Ref();
+        self->connections_.emplace(connection.get(), std::move(connection));
+      }
+    }
+  }
+  if (connection != nullptr) {
+    endpoint_cleanup(GRPC_ERROR_NONE);
+  } else {
+    connection_ref->Start(std::move(listener_ref), tcp, args);
+  }
+  grpc_channel_args_destroy(args);
 }
 
 void Chttp2ServerListener::TcpServerShutdownComplete(void* arg,
-                                                     grpc_error* error) {
+                                                     grpc_error_handle error) {
   Chttp2ServerListener* self = static_cast<Chttp2ServerListener*>(arg);
-  /* ensure all threads have unlocked */
-  grpc_closure* destroy_done = nullptr;
-  {
-    MutexLock lock(&self->mu_);
-    destroy_done = self->on_destroy_done_;
-    GPR_ASSERT(self->shutdown_);
-    if (self->pending_handshake_mgrs_ != nullptr) {
-      self->pending_handshake_mgrs_->ShutdownAllPending(GRPC_ERROR_REF(error));
-    }
-    self->channelz_listen_socket_.reset();
-  }
-  // Flush queued work before destroying handshaker factory, since that
-  // may do a synchronous unref.
-  ExecCtx::Get()->Flush();
-  if (destroy_done != nullptr) {
-    ExecCtx::Run(DEBUG_LOCATION, destroy_done, GRPC_ERROR_REF(error));
-    ExecCtx::Get()->Flush();
-  }
+  self->channelz_listen_socket_.reset();
+  GRPC_ERROR_UNREF(error);
   delete self;
 }
 
@@ -496,10 +795,20 @@
   if (config_fetcher_watcher_ != nullptr) {
     server_->config_fetcher()->CancelWatch(config_fetcher_watcher_);
   }
+  std::map<ActiveConnection*, OrphanablePtr<ActiveConnection>> connections;
   grpc_tcp_server* tcp_server;
   {
     MutexLock lock(&mu_);
     shutdown_ = true;
+    is_serving_ = false;
+    // Orphan the connections so that they can start cleaning up.
+    connections = std::move(connections_);
+    // If the listener is currently set to be serving but has not been started
+    // yet, it means that `grpc_tcp_server_start` is in progress. Wait for the
+    // operation to finish to avoid causing races.
+    while (is_serving_ && !started_) {
+      started_cv_.Wait(&mu_);
+    }
     tcp_server = tcp_server_;
   }
   grpc_tcp_server_shutdown_listeners(tcp_server);
@@ -512,17 +821,19 @@
 // Chttp2ServerAddPort()
 //
 
-grpc_error* Chttp2ServerAddPort(Server* server, const char* addr,
-                                grpc_channel_args* args, int* port_num) {
+grpc_error_handle Chttp2ServerAddPort(Server* server, const char* addr,
+                                      grpc_channel_args* args,
+                                      Chttp2ServerArgsModifier args_modifier,
+                                      int* port_num) {
   if (strncmp(addr, "external:", 9) == 0) {
-    return grpc_core::Chttp2ServerListener::CreateWithAcceptor(server, addr,
-                                                               args);
+    return grpc_core::Chttp2ServerListener::CreateWithAcceptor(
+        server, addr, args, args_modifier);
   }
   *port_num = -1;
   grpc_resolved_addresses* resolved = nullptr;
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   // Using lambda to avoid use of goto.
-  grpc_error* error = [&]() {
+  grpc_error_handle error = [&]() {
     if (absl::StartsWith(addr, kUnixUriPrefix)) {
       error = grpc_resolve_unix_domain_address(
           addr + sizeof(kUnixUriPrefix) - 1, &resolved);
@@ -540,10 +851,10 @@
       if (*port_num != -1 && grpc_sockaddr_get_port(&resolved->addrs[i]) == 0) {
         grpc_sockaddr_set_port(&resolved->addrs[i], *port_num);
       }
-      int port_temp;
+      int port_temp = -1;
       error = grpc_core::Chttp2ServerListener::Create(
           server, &resolved->addrs[i], grpc_channel_args_copy(args),
-          &port_temp);
+          args_modifier, &port_temp);
       if (error != GRPC_ERROR_NONE) {
         error_list.push_back(error);
       } else {
@@ -567,13 +878,13 @@
           resolved->naddrs - error_list.size(), resolved->naddrs);
       error = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(
           msg.c_str(), error_list.data(), error_list.size());
-      gpr_log(GPR_INFO, "WARNING: %s", grpc_error_string(error));
+      gpr_log(GPR_INFO, "WARNING: %s", grpc_error_std_string(error).c_str());
       GRPC_ERROR_UNREF(error);
       // we managed to bind some addresses: continue without error
     }
     return GRPC_ERROR_NONE;
   }();  // lambda end
-  for (grpc_error* error : error_list) {
+  for (grpc_error_handle error : error_list) {
     GRPC_ERROR_UNREF(error);
   }
   grpc_channel_args_destroy(args);
diff --git a/grpc/src/core/ext/transport/chttp2/server/chttp2_server.h b/grpc/src/core/ext/transport/chttp2/server/chttp2_server.h
index 095cc5e..e4e6b7c 100644
--- a/grpc/src/core/ext/transport/chttp2/server/chttp2_server.h
+++ b/grpc/src/core/ext/transport/chttp2/server/chttp2_server.h
@@ -28,10 +28,19 @@
 
 namespace grpc_core {
 
+// A function to modify channel args for a listening addr:port. Note that this
+// is used to create a security connector for listeners when the servers are
+// configured with a config fetcher. Not invoked if there is no config fetcher
+// added to the server. Takes ownership of the args.  Caller takes ownership of
+// returned args. On failure, the error parameter will be set.
+using Chttp2ServerArgsModifier =
+    std::function<grpc_channel_args*(grpc_channel_args*, grpc_error_handle*)>;
+
 /// Adds a port to \a server.  Sets \a port_num to the port number.
 /// Takes ownership of \a args.
-grpc_error* Chttp2ServerAddPort(Server* server, const char* addr,
-                                grpc_channel_args* args, int* port_num);
+grpc_error_handle Chttp2ServerAddPort(
+    Server* server, const char* addr, grpc_channel_args* args,
+    Chttp2ServerArgsModifier connection_args_modifier, int* port_num);
 
 }  // namespace grpc_core
 
diff --git a/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc b/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
index eebae9e..e00bc92 100644
--- a/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
+++ b/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
@@ -27,17 +27,26 @@
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/server.h"
 
+namespace {
+
+grpc_channel_args* ModifyArgsForConnection(grpc_channel_args* args,
+                                           grpc_error_handle* /*error*/) {
+  return args;
+}
+
+}  // namespace
+
 int grpc_server_add_insecure_http2_port(grpc_server* server, const char* addr) {
   grpc_core::ExecCtx exec_ctx;
   int port_num = 0;
   GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
                  (server, addr));
-  grpc_error* err = grpc_core::Chttp2ServerAddPort(
+  grpc_error_handle err = grpc_core::Chttp2ServerAddPort(
       server->core_server.get(), addr,
-      grpc_channel_args_copy(server->core_server->channel_args()), &port_num);
+      grpc_channel_args_copy(server->core_server->channel_args()),
+      ModifyArgsForConnection, &port_num);
   if (err != GRPC_ERROR_NONE) {
-    const char* msg = grpc_error_string(err);
-    gpr_log(GPR_ERROR, "%s", msg);
+    gpr_log(GPR_ERROR, "%s", grpc_error_std_string(err).c_str());
 
     GRPC_ERROR_UNREF(err);
   }
diff --git a/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc b/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
index e27c907..fd57939 100644
--- a/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
+++ b/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
@@ -51,16 +51,16 @@
   grpc_transport* transport = grpc_create_chttp2_transport(
       server_args, server_endpoint, false /* is_client */);
 
-  grpc_error* error =
+  grpc_error_handle error =
       core_server->SetupTransport(transport, nullptr, server_args, nullptr);
   if (error == GRPC_ERROR_NONE) {
     for (grpc_pollset* pollset : core_server->pollsets()) {
       grpc_endpoint_add_to_pollset(server_endpoint, pollset);
     }
-    grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
+    grpc_chttp2_transport_start_reading(transport, nullptr, nullptr, nullptr);
   } else {
     gpr_log(GPR_ERROR, "Failed to create channel: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     grpc_transport_destroy(transport);
   }
diff --git a/grpc/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc b/grpc/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
index a181db4..f0a0eed 100644
--- a/grpc/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
+++ b/grpc/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
@@ -18,12 +18,11 @@
 
 #include <grpc/support/port_platform.h>
 
-#include <grpc/grpc.h>
-
 #include <string.h>
 
 #include "absl/strings/str_cat.h"
 
+#include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
@@ -38,10 +37,39 @@
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/server.h"
 
+namespace {
+
+grpc_channel_args* ModifyArgsForConnection(grpc_channel_args* args,
+                                           grpc_error_handle* error) {
+  grpc_server_credentials* server_credentials =
+      grpc_find_server_credentials_in_args(args);
+  if (server_credentials == nullptr) {
+    *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Could not find server credentials");
+    return args;
+  }
+  auto security_connector = server_credentials->create_security_connector(args);
+  if (security_connector == nullptr) {
+    *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        absl::StrCat("Unable to create secure server with credentials of type ",
+                     server_credentials->type())
+            .c_str());
+    return args;
+  }
+  grpc_arg arg_to_add =
+      grpc_security_connector_to_arg(security_connector.get());
+  grpc_channel_args* new_args =
+      grpc_channel_args_copy_and_add(args, &arg_to_add, 1);
+  grpc_channel_args_destroy(args);
+  return new_args;
+}
+
+}  // namespace
+
 int grpc_server_add_secure_http2_port(grpc_server* server, const char* addr,
                                       grpc_server_credentials* creds) {
   grpc_core::ExecCtx exec_ctx;
-  grpc_error* err = GRPC_ERROR_NONE;
+  grpc_error_handle err = GRPC_ERROR_NONE;
   grpc_core::RefCountedPtr<grpc_server_security_connector> sc;
   int port_num = 0;
   grpc_channel_args* args = nullptr;
@@ -55,30 +83,45 @@
         "No credentials specified for secure server port (creds==NULL)");
     goto done;
   }
-  sc = creds->create_security_connector();
-  if (sc == nullptr) {
-    err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
-        absl::StrCat("Unable to create secure server with credentials of type ",
-                     creds->type())
-            .c_str());
-    goto done;
+  // TODO(yashykt): Ideally, we would not want to have different behavior here
+  // based on whether a config fetcher is configured or not. Currently, we have
+  // a feature for SSL credentials reloading with an application callback that
+  // assumes that there is a single security connector. If we delay the creation
+  // of the security connector to after the creation of the listener(s), we
+  // would have potentially multiple security connectors which breaks the
+  // assumption for SSL creds reloading. When the API for SSL creds reloading is
+  // rewritten, we would be able to make this workaround go away by removing
+  // that assumption. As an immediate drawback of this workaround, config
+  // fetchers need to be registered before adding ports to the server.
+  if (server->core_server->config_fetcher() != nullptr) {
+    // Create channel args.
+    grpc_arg arg_to_add = grpc_server_credentials_to_arg(creds);
+    args = grpc_channel_args_copy_and_add(server->core_server->channel_args(),
+                                          &arg_to_add, 1);
+  } else {
+    sc = creds->create_security_connector(nullptr);
+    if (sc == nullptr) {
+      err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat(
+              "Unable to create secure server with credentials of type ",
+              creds->type())
+              .c_str());
+      goto done;
+    }
+    grpc_arg args_to_add[2];
+    args_to_add[0] = grpc_server_credentials_to_arg(creds);
+    args_to_add[1] = grpc_security_connector_to_arg(sc.get());
+    args = grpc_channel_args_copy_and_add(server->core_server->channel_args(),
+                                          args_to_add,
+                                          GPR_ARRAY_SIZE(args_to_add));
   }
-  // Create channel args.
-  grpc_arg args_to_add[2];
-  args_to_add[0] = grpc_server_credentials_to_arg(creds);
-  args_to_add[1] = grpc_security_connector_to_arg(sc.get());
-  args =
-      grpc_channel_args_copy_and_add(server->core_server->channel_args(),
-                                     args_to_add, GPR_ARRAY_SIZE(args_to_add));
   // Add server port.
   err = grpc_core::Chttp2ServerAddPort(server->core_server.get(), addr, args,
-                                       &port_num);
+                                       ModifyArgsForConnection, &port_num);
 done:
   sc.reset(DEBUG_LOCATION, "server");
-
   if (err != GRPC_ERROR_NONE) {
-    const char* msg = grpc_error_string(err);
-    gpr_log(GPR_ERROR, "%s", msg);
+    gpr_log(GPR_ERROR, "%s", grpc_error_std_string(err).c_str());
 
     GRPC_ERROR_UNREF(err);
   }
diff --git a/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index 900cd3c..1ff6475 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -100,23 +100,23 @@
                                                          "chttp2_refcount");
 
 // forward declarations of various callbacks that we'll build closures around
-static void write_action_begin_locked(void* t, grpc_error* error);
-static void write_action(void* t, grpc_error* error);
-static void write_action_end(void* t, grpc_error* error);
-static void write_action_end_locked(void* t, grpc_error* error);
+static void write_action_begin_locked(void* t, grpc_error_handle error);
+static void write_action(void* t, grpc_error_handle error);
+static void write_action_end(void* t, grpc_error_handle error);
+static void write_action_end_locked(void* t, grpc_error_handle error);
 
-static void read_action(void* t, grpc_error* error);
-static void read_action_locked(void* t, grpc_error* error);
+static void read_action(void* t, grpc_error_handle error);
+static void read_action_locked(void* t, grpc_error_handle error);
 static void continue_read_action_locked(grpc_chttp2_transport* t);
 
-static void complete_fetch(void* gs, grpc_error* error);
-static void complete_fetch_locked(void* gs, grpc_error* error);
+static void complete_fetch(void* gs, grpc_error_handle error);
+static void complete_fetch_locked(void* gs, grpc_error_handle error);
 // Set a transport level setting, and push it to our peer
 static void queue_setting_update(grpc_chttp2_transport* t,
                                  grpc_chttp2_setting_id id, uint32_t value);
 
 static void close_from_api(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                           grpc_error* error);
+                           grpc_error_handle error);
 
 // Start new streams that have been created if we can
 static void maybe_start_some_streams(grpc_chttp2_transport* t);
@@ -126,45 +126,68 @@
                                    const absl::Status& status,
                                    const char* reason);
 
-static void benign_reclaimer(void* arg, grpc_error* error);
-static void destructive_reclaimer(void* arg, grpc_error* error);
-static void benign_reclaimer_locked(void* arg, grpc_error* error);
-static void destructive_reclaimer_locked(void* arg, grpc_error* error);
+static void benign_reclaimer(void* arg, grpc_error_handle error);
+static void destructive_reclaimer(void* arg, grpc_error_handle error);
+static void benign_reclaimer_locked(void* arg, grpc_error_handle error);
+static void destructive_reclaimer_locked(void* arg, grpc_error_handle error);
 
 static void post_benign_reclaimer(grpc_chttp2_transport* t);
 static void post_destructive_reclaimer(grpc_chttp2_transport* t);
 
-static void close_transport_locked(grpc_chttp2_transport* t, grpc_error* error);
-static void end_all_the_calls(grpc_chttp2_transport* t, grpc_error* error);
+static void close_transport_locked(grpc_chttp2_transport* t,
+                                   grpc_error_handle error);
+static void end_all_the_calls(grpc_chttp2_transport* t,
+                              grpc_error_handle error);
 
-static void start_bdp_ping(void* tp, grpc_error* error);
-static void finish_bdp_ping(void* tp, grpc_error* error);
-static void start_bdp_ping_locked(void* tp, grpc_error* error);
-static void finish_bdp_ping_locked(void* tp, grpc_error* error);
-static void next_bdp_ping_timer_expired(void* tp, grpc_error* error);
-static void next_bdp_ping_timer_expired_locked(void* tp, grpc_error* error);
+static void start_bdp_ping(void* tp, grpc_error_handle error);
+static void finish_bdp_ping(void* tp, grpc_error_handle error);
+static void start_bdp_ping_locked(void* tp, grpc_error_handle error);
+static void finish_bdp_ping_locked(void* tp, grpc_error_handle error);
+static void next_bdp_ping_timer_expired(void* tp, grpc_error_handle error);
+static void next_bdp_ping_timer_expired_locked(void* tp,
+                                               grpc_error_handle error);
 
-static void cancel_pings(grpc_chttp2_transport* t, grpc_error* error);
+static void cancel_pings(grpc_chttp2_transport* t, grpc_error_handle error);
 static void send_ping_locked(grpc_chttp2_transport* t,
                              grpc_closure* on_initiate, grpc_closure* on_ack);
-static void retry_initiate_ping_locked(void* tp, grpc_error* error);
+static void retry_initiate_ping_locked(void* tp, grpc_error_handle error);
 
 // keepalive-relevant functions
-static void init_keepalive_ping(void* arg, grpc_error* error);
-static void init_keepalive_ping_locked(void* arg, grpc_error* error);
-static void start_keepalive_ping(void* arg, grpc_error* error);
-static void finish_keepalive_ping(void* arg, grpc_error* error);
-static void start_keepalive_ping_locked(void* arg, grpc_error* error);
-static void finish_keepalive_ping_locked(void* arg, grpc_error* error);
-static void keepalive_watchdog_fired(void* arg, grpc_error* error);
-static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error);
+static void init_keepalive_ping(void* arg, grpc_error_handle error);
+static void init_keepalive_ping_locked(void* arg, grpc_error_handle error);
+static void start_keepalive_ping(void* arg, grpc_error_handle error);
+static void finish_keepalive_ping(void* arg, grpc_error_handle error);
+static void start_keepalive_ping_locked(void* arg, grpc_error_handle error);
+static void finish_keepalive_ping_locked(void* arg, grpc_error_handle error);
+static void keepalive_watchdog_fired(void* arg, grpc_error_handle error);
+static void keepalive_watchdog_fired_locked(void* arg, grpc_error_handle error);
 
-static void reset_byte_stream(void* arg, grpc_error* error);
+static void reset_byte_stream(void* arg, grpc_error_handle error);
 
 // Flow control default enabled. Can be disabled by setting
 // GRPC_EXPERIMENTAL_DISABLE_FLOW_CONTROL
 bool g_flow_control_enabled = true;
 
+namespace grpc_core {
+
+namespace {
+TestOnlyGlobalHttp2TransportInitCallback test_only_init_callback = nullptr;
+TestOnlyGlobalHttp2TransportDestructCallback test_only_destruct_callback =
+    nullptr;
+}  // namespace
+
+void TestOnlySetGlobalHttp2TransportInitCallback(
+    TestOnlyGlobalHttp2TransportInitCallback callback) {
+  test_only_init_callback = callback;
+}
+
+void TestOnlySetGlobalHttp2TransportDestructCallback(
+    TestOnlyGlobalHttp2TransportDestructCallback callback) {
+  test_only_destruct_callback = callback;
+}
+
+}  // namespace grpc_core
+
 //
 // CONSTRUCTION/DESTRUCTION/REFCOUNTING
 //
@@ -183,7 +206,7 @@
   grpc_slice_buffer_destroy_internal(&outbuf);
   grpc_chttp2_hpack_compressor_destroy(&hpack_compressor);
 
-  grpc_error* error =
+  grpc_error_handle error =
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed");
   // ContextList::Execute follows semantics of a callback function and does not
   // take a ref on error
@@ -221,6 +244,9 @@
 
   GRPC_ERROR_UNREF(closed_with_error);
   gpr_free(ping_acks);
+  if (grpc_core::test_only_destruct_callback != nullptr) {
+    grpc_core::test_only_destruct_callback();
+  }
 }
 
 static const grpc_transport_vtable* get_vtable(void);
@@ -366,7 +392,9 @@
     t->channelz_socket =
         grpc_core::MakeRefCounted<grpc_core::channelz::SocketNode>(
             std::string(grpc_endpoint_get_local_address(t->ep)), t->peer_string,
-            absl::StrFormat("%s %s", get_vtable()->name, t->peer_string));
+            absl::StrFormat("%s %s", get_vtable()->name, t->peer_string),
+            grpc_core::channelz::SocketNode::Security::GetFromChannelArgs(
+                channel_args));
   }
   return enable_bdp;
 }
@@ -504,9 +532,12 @@
 
   grpc_chttp2_initiate_write(this, GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE);
   post_benign_reclaimer(this);
+  if (grpc_core::test_only_init_callback != nullptr) {
+    grpc_core::test_only_init_callback();
+  }
 }
 
-static void destroy_transport_locked(void* tp, grpc_error* /*error*/) {
+static void destroy_transport_locked(void* tp, grpc_error_handle /*error*/) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->destroying = 1;
   close_transport_locked(
@@ -524,7 +555,7 @@
 }
 
 static void close_transport_locked(grpc_chttp2_transport* t,
-                                   grpc_error* error) {
+                                   grpc_error_handle error) {
   end_all_the_calls(t, GRPC_ERROR_REF(error));
   cancel_pings(t, GRPC_ERROR_REF(error));
   if (t->closed_with_error == GRPC_ERROR_NONE) {
@@ -579,6 +610,11 @@
                             GRPC_ERROR_REF(error));
     t->notify_on_receive_settings = nullptr;
   }
+  if (t->notify_on_close != nullptr) {
+    grpc_core::ExecCtx::Run(DEBUG_LOCATION, t->notify_on_close,
+                            GRPC_ERROR_REF(error));
+    t->notify_on_close = nullptr;
+  }
   GRPC_ERROR_UNREF(error);
 }
 
@@ -698,7 +734,7 @@
   return 0;
 }
 
-static void destroy_stream_locked(void* sp, grpc_error* /*error*/) {
+static void destroy_stream_locked(void* sp, grpc_error_handle /*error*/) {
   GPR_TIMER_SCOPE("destroy_stream", 0);
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp);
   s->~grpc_chttp2_stream();
@@ -786,7 +822,7 @@
   if (st == GRPC_CHTTP2_WRITE_STATE_IDLE) {
     grpc_core::ExecCtx::RunList(DEBUG_LOCATION, &t->run_after_write);
     if (t->close_transport_on_writes_finished != nullptr) {
-      grpc_error* err = t->close_transport_on_writes_finished;
+      grpc_error_handle err = t->close_transport_on_writes_finished;
       t->close_transport_on_writes_finished = nullptr;
       close_transport_locked(t, err);
     }
@@ -918,7 +954,8 @@
   }
 }
 
-static void write_action_begin_locked(void* gt, grpc_error* /*error_ignored*/) {
+static void write_action_begin_locked(void* gt,
+                                      grpc_error_handle /*error_ignored*/) {
   GPR_TIMER_SCOPE("write_action_begin_locked", 0);
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(gt);
   GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE);
@@ -957,7 +994,7 @@
   }
 }
 
-static void write_action(void* gt, grpc_error* /*error*/) {
+static void write_action(void* gt, grpc_error_handle /*error*/) {
   GPR_TIMER_SCOPE("write_action", 0);
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(gt);
   void* cl = t->cl;
@@ -969,7 +1006,7 @@
       cl);
 }
 
-static void write_action_end(void* tp, grpc_error* error) {
+static void write_action_end(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->write_action_end_locked,
                                      write_action_end_locked, t, nullptr),
@@ -978,7 +1015,7 @@
 
 // Callback from the grpc_endpoint after bytes have been written by calling
 // sendmsg
-static void write_action_end_locked(void* tp, grpc_error* error) {
+static void write_action_end_locked(void* tp, grpc_error_handle error) {
   GPR_TIMER_SCOPE("terminate_writing_with_lock", 0);
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 
@@ -1067,7 +1104,7 @@
   // received a GOAWAY with a non NO_ERROR code.
   if (goaway_error != GRPC_HTTP2_NO_ERROR) {
     gpr_log(GPR_INFO, "%s: Got goaway [%d] err=%s", t->peer_string.c_str(),
-            goaway_error, grpc_error_string(t->goaway_error));
+            goaway_error, grpc_error_std_string(t->goaway_error).c_str());
   }
   absl::Status status = grpc_error_to_absl_status(t->goaway_error);
   // When a client receives a GOAWAY with error code ENHANCE_YOUR_CALM and debug
@@ -1173,7 +1210,8 @@
 void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
                                        grpc_chttp2_stream* /*s*/,
                                        grpc_closure** pclosure,
-                                       grpc_error* error, const char* desc) {
+                                       grpc_error_handle error,
+                                       const char* desc) {
   grpc_closure* closure = *pclosure;
   *pclosure = nullptr;
   if (closure == nullptr) {
@@ -1182,7 +1220,6 @@
   }
   closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
-    const char* errstr = grpc_error_string(error);
     gpr_log(
         GPR_INFO,
         "complete_closure_step: t=%p %p refs=%d flags=0x%04x desc=%s err=%s "
@@ -1192,7 +1229,8 @@
                          CLOSURE_BARRIER_FIRST_REF_BIT),
         static_cast<int>(closure->next_data.scratch %
                          CLOSURE_BARRIER_FIRST_REF_BIT),
-        desc, errstr, write_state_name(t->write_state));
+        desc, grpc_error_std_string(error).c_str(),
+        write_state_name(t->write_state));
   }
   if (error != GRPC_ERROR_NONE) {
     if (closure->error_data.error == GRPC_ERROR_NONE) {
@@ -1281,7 +1319,8 @@
                    UINT32_MAX, GRPC_CLOSURE_INIT(&s->complete_fetch_locked,
                                                  ::complete_fetch, s,
                                                  grpc_schedule_on_exec_ctx))) {
-      grpc_error* error = s->fetching_send_message->Pull(&s->fetching_slice);
+      grpc_error_handle error =
+          s->fetching_send_message->Pull(&s->fetching_slice);
       if (error != GRPC_ERROR_NONE) {
         s->fetching_send_message.reset();
         grpc_chttp2_cancel_stream(t, s, error);
@@ -1292,14 +1331,14 @@
   }
 }
 
-static void complete_fetch(void* gs, grpc_error* error) {
+static void complete_fetch(void* gs, grpc_error_handle error) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(gs);
   s->t->combiner->Run(GRPC_CLOSURE_INIT(&s->complete_fetch_locked,
                                         ::complete_fetch_locked, s, nullptr),
                       GRPC_ERROR_REF(error));
 }
 
-static void complete_fetch_locked(void* gs, grpc_error* error) {
+static void complete_fetch_locked(void* gs, grpc_error_handle error) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(gs);
   grpc_chttp2_transport* t = s->t;
   if (error == GRPC_ERROR_NONE) {
@@ -1329,7 +1368,7 @@
 }
 
 static void perform_stream_op_locked(void* stream_op,
-                                     grpc_error* /*error_ignored*/) {
+                                     grpc_error_handle /*error_ignored*/) {
   GPR_TIMER_SCOPE("perform_stream_op_locked", 0);
 
   grpc_transport_stream_op_batch* op =
@@ -1613,7 +1652,7 @@
                    GRPC_ERROR_NONE);
 }
 
-static void cancel_pings(grpc_chttp2_transport* t, grpc_error* error) {
+static void cancel_pings(grpc_chttp2_transport* t, grpc_error_handle error) {
   // callback remaining pings: they're not allowed to call into the transport,
   //   and maybe they hold resources that need to be freed
   grpc_chttp2_ping_queue* pq = &t->ping_queue;
@@ -1680,14 +1719,14 @@
       GRPC_ERROR_NONE);
 }
 
-void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error* error) {
+void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->retry_initiate_ping_locked,
                                      retry_initiate_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void retry_initiate_ping_locked(void* tp, grpc_error* error) {
+static void retry_initiate_ping_locked(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->ping_state.is_delayed_ping_timer_set = false;
   if (error == GRPC_ERROR_NONE) {
@@ -1710,10 +1749,10 @@
   }
 }
 
-static void send_goaway(grpc_chttp2_transport* t, grpc_error* error) {
+static void send_goaway(grpc_chttp2_transport* t, grpc_error_handle error) {
   // We want to log this irrespective of whether http tracing is enabled
   gpr_log(GPR_INFO, "%s: Sending goaway err=%s", t->peer_string.c_str(),
-          grpc_error_string(error));
+          grpc_error_std_string(error).c_str());
   t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
   grpc_http2_error_code http_error;
   grpc_slice slice;
@@ -1751,7 +1790,7 @@
 }
 
 static void perform_transport_op_locked(void* stream_op,
-                                        grpc_error* /*error_ignored*/) {
+                                        grpc_error_handle /*error_ignored*/) {
   grpc_transport_op* op = static_cast<grpc_transport_op*>(stream_op);
   grpc_chttp2_transport* t =
       static_cast<grpc_chttp2_transport*>(op->handler_private.extra_arg);
@@ -1831,7 +1870,7 @@
 
 void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* /*t*/,
                                              grpc_chttp2_stream* s) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (s->recv_message_ready != nullptr) {
     *s->recv_message = nullptr;
     if (s->final_metadata_requested && s->seen_error) {
@@ -1981,7 +2020,7 @@
 }
 
 static void remove_stream(grpc_chttp2_transport* t, uint32_t id,
-                          grpc_error* error) {
+                          grpc_error_handle error) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(
       grpc_chttp2_stream_map_delete(&t->stream_map, id));
   GPR_DEBUG_ASSERT(s);
@@ -2024,7 +2063,7 @@
 }
 
 void grpc_chttp2_cancel_stream(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                               grpc_error* due_to_error) {
+                               grpc_error_handle due_to_error) {
   if (!t->is_client && !s->sent_trailing_metadata &&
       grpc_error_has_clear_grpc_status(due_to_error)) {
     close_from_api(t, s, due_to_error);
@@ -2048,7 +2087,7 @@
 }
 
 void grpc_chttp2_fake_status(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                             grpc_error* error) {
+                             grpc_error_handle error) {
   grpc_status_code status;
   grpc_slice slice;
   grpc_error_get_status(error, s->deadline, &status, &slice, nullptr, nullptr);
@@ -2085,7 +2124,8 @@
   GRPC_ERROR_UNREF(error);
 }
 
-static void add_error(grpc_error* error, grpc_error** refs, size_t* nrefs) {
+static void add_error(grpc_error_handle error, grpc_error_handle* refs,
+                      size_t* nrefs) {
   if (error == GRPC_ERROR_NONE) return;
   for (size_t i = 0; i < *nrefs; i++) {
     if (error == refs[i]) {
@@ -2096,16 +2136,17 @@
   ++*nrefs;
 }
 
-static grpc_error* removal_error(grpc_error* extra_error, grpc_chttp2_stream* s,
-                                 const char* master_error_msg) {
-  grpc_error* refs[3];
+static grpc_error_handle removal_error(grpc_error_handle extra_error,
+                                       grpc_chttp2_stream* s,
+                                       const char* main_error_msg) {
+  grpc_error_handle refs[3];
   size_t nrefs = 0;
   add_error(s->read_closed_error, refs, &nrefs);
   add_error(s->write_closed_error, refs, &nrefs);
   add_error(extra_error, refs, &nrefs);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (nrefs > 0) {
-    error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(master_error_msg,
+    error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(main_error_msg,
                                                              refs, nrefs);
   }
   GRPC_ERROR_UNREF(extra_error);
@@ -2113,7 +2154,8 @@
 }
 
 static void flush_write_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                             grpc_chttp2_write_cb** list, grpc_error* error) {
+                             grpc_chttp2_write_cb** list,
+                             grpc_error_handle error) {
   while (*list) {
     grpc_chttp2_write_cb* cb = *list;
     *list = cb->next;
@@ -2126,7 +2168,8 @@
 }
 
 void grpc_chttp2_fail_pending_writes(grpc_chttp2_transport* t,
-                                     grpc_chttp2_stream* s, grpc_error* error) {
+                                     grpc_chttp2_stream* s,
+                                     grpc_error_handle error) {
   error =
       removal_error(error, s, "Pending writes failed due to stream closure");
   s->send_initial_metadata = nullptr;
@@ -2150,10 +2193,10 @@
 
 void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t,
                                     grpc_chttp2_stream* s, int close_reads,
-                                    int close_writes, grpc_error* error) {
+                                    int close_writes, grpc_error_handle error) {
   if (s->read_closed && s->write_closed) {
     // already closed, but we should still fake the status if needed.
-    grpc_error* overall_error = removal_error(error, s, "Stream removed");
+    grpc_error_handle overall_error = removal_error(error, s, "Stream removed");
     if (overall_error != GRPC_ERROR_NONE) {
       grpc_chttp2_fake_status(t, s, overall_error);
     }
@@ -2174,7 +2217,7 @@
   }
   if (s->read_closed && s->write_closed) {
     became_closed = true;
-    grpc_error* overall_error =
+    grpc_error_handle overall_error =
         removal_error(GRPC_ERROR_REF(error), s, "Stream removed");
     if (s->id != 0) {
       remove_stream(t, s->id, GRPC_ERROR_REF(overall_error));
@@ -2203,7 +2246,7 @@
 }
 
 static void close_from_api(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                           grpc_error* error) {
+                           grpc_error_handle error) {
   grpc_slice hdr;
   grpc_slice status_hdr;
   grpc_slice http_status_hdr;
@@ -2361,7 +2404,7 @@
 }
 
 struct cancel_stream_cb_args {
-  grpc_error* error;
+  grpc_error_handle error;
   grpc_chttp2_transport* t;
 };
 
@@ -2371,7 +2414,8 @@
   grpc_chttp2_cancel_stream(args->t, s, GRPC_ERROR_REF(args->error));
 }
 
-static void end_all_the_calls(grpc_chttp2_transport* t, grpc_error* error) {
+static void end_all_the_calls(grpc_chttp2_transport* t,
+                              grpc_error_handle error) {
   intptr_t http2_error;
   // If there is no explicit grpc or HTTP/2 error, set to UNAVAILABLE on server.
   if (!t->is_client && !grpc_error_has_clear_grpc_status(error) &&
@@ -2425,15 +2469,15 @@
               });
 }
 
-static grpc_error* try_http_parsing(grpc_chttp2_transport* t) {
+static grpc_error_handle try_http_parsing(grpc_chttp2_transport* t) {
   grpc_http_parser parser;
   size_t i = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_http_response response;
 
   grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response);
 
-  grpc_error* parse_error = GRPC_ERROR_NONE;
+  grpc_error_handle parse_error = GRPC_ERROR_NONE;
   for (; i < t->read_buffer.count && parse_error == GRPC_ERROR_NONE; i++) {
     parse_error =
         grpc_http_parser_parse(&parser, t->read_buffer.slices[i], nullptr);
@@ -2454,34 +2498,34 @@
   return error;
 }
 
-static void read_action(void* tp, grpc_error* error) {
+static void read_action(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(
       GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t, nullptr),
       GRPC_ERROR_REF(error));
 }
 
-static void read_action_locked(void* tp, grpc_error* error) {
+static void read_action_locked(void* tp, grpc_error_handle error) {
   GPR_TIMER_SCOPE("reading_action_locked", 0);
 
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 
   GRPC_ERROR_REF(error);
 
-  grpc_error* err = error;
+  grpc_error_handle err = error;
   if (err != GRPC_ERROR_NONE) {
     err = grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                                  "Endpoint read failed", &err, 1),
                              GRPC_ERROR_INT_OCCURRED_DURING_WRITE,
                              t->write_state);
   }
-  GPR_SWAP(grpc_error*, err, error);
+  GPR_SWAP(grpc_error_handle, err, error);
   GRPC_ERROR_UNREF(err);
   if (t->closed_with_error == GRPC_ERROR_NONE) {
     GPR_TIMER_SCOPE("reading_action.parse", 0);
     size_t i = 0;
-    grpc_error* errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
-                             GRPC_ERROR_NONE};
+    grpc_error_handle errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
+                                   GRPC_ERROR_NONE};
     for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
       errors[1] = grpc_chttp2_perform_read(t, t->read_buffer.slices[i]);
     }
@@ -2569,23 +2613,21 @@
                         grpc_schedule_on_exec_ctx),
       GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping, t,
                         grpc_schedule_on_exec_ctx));
-  // TODO(yashykt): Enabling this causes internal b/168345569. Re-enable once
-  // fixed.
-  // grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_BDP_PING);
+  grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_BDP_PING);
 }
 
-static void start_bdp_ping(void* tp, grpc_error* error) {
+static void start_bdp_ping(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->start_bdp_ping_locked,
                                      start_bdp_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void start_bdp_ping_locked(void* tp, grpc_error* error) {
+static void start_bdp_ping_locked(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
     gpr_log(GPR_INFO, "%s: Start BDP ping err=%s", t->peer_string.c_str(),
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   if (error != GRPC_ERROR_NONE || t->closed_with_error != GRPC_ERROR_NONE) {
     return;
@@ -2598,18 +2640,18 @@
   t->bdp_ping_started = true;
 }
 
-static void finish_bdp_ping(void* tp, grpc_error* error) {
+static void finish_bdp_ping(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked,
                                      finish_bdp_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void finish_bdp_ping_locked(void* tp, grpc_error* error) {
+static void finish_bdp_ping_locked(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
     gpr_log(GPR_INFO, "%s: Complete BDP ping err=%s", t->peer_string.c_str(),
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   if (error != GRPC_ERROR_NONE || t->closed_with_error != GRPC_ERROR_NONE) {
     GRPC_CHTTP2_UNREF_TRANSPORT(t, "bdp_ping");
@@ -2635,7 +2677,7 @@
                   &t->next_bdp_ping_timer_expired_locked);
 }
 
-static void next_bdp_ping_timer_expired(void* tp, grpc_error* error) {
+static void next_bdp_ping_timer_expired(void* tp, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->combiner->Run(
       GRPC_CLOSURE_INIT(&t->next_bdp_ping_timer_expired_locked,
@@ -2643,7 +2685,8 @@
       GRPC_ERROR_REF(error));
 }
 
-static void next_bdp_ping_timer_expired_locked(void* tp, grpc_error* error) {
+static void next_bdp_ping_timer_expired_locked(void* tp,
+                                               grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   GPR_ASSERT(t->have_next_bdp_ping_timer);
   t->have_next_bdp_ping_timer = false;
@@ -2719,14 +2762,14 @@
   }
 }
 
-static void init_keepalive_ping(void* arg, grpc_error* error) {
+static void init_keepalive_ping(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked,
                                      init_keepalive_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
+static void init_keepalive_ping_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
   if (t->destroying || t->closed_with_error != GRPC_ERROR_NONE) {
@@ -2759,14 +2802,14 @@
   GRPC_CHTTP2_UNREF_TRANSPORT(t, "init keepalive ping");
 }
 
-static void start_keepalive_ping(void* arg, grpc_error* error) {
+static void start_keepalive_ping(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
                                      start_keepalive_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void start_keepalive_ping_locked(void* arg, grpc_error* error) {
+static void start_keepalive_ping_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (error != GRPC_ERROR_NONE) {
     return;
@@ -2787,14 +2830,14 @@
   t->keepalive_ping_started = true;
 }
 
-static void finish_keepalive_ping(void* arg, grpc_error* error) {
+static void finish_keepalive_ping(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->finish_keepalive_ping_locked,
                                      finish_keepalive_ping_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void finish_keepalive_ping_locked(void* arg, grpc_error* error) {
+static void finish_keepalive_ping_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
     if (error == GRPC_ERROR_NONE) {
@@ -2825,7 +2868,7 @@
   GRPC_CHTTP2_UNREF_TRANSPORT(t, "keepalive ping end");
 }
 
-static void keepalive_watchdog_fired(void* arg, grpc_error* error) {
+static void keepalive_watchdog_fired(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(
       GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked,
@@ -2833,7 +2876,8 @@
       GRPC_ERROR_REF(error));
 }
 
-static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error) {
+static void keepalive_watchdog_fired_locked(void* arg,
+                                            grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
     if (error == GRPC_ERROR_NONE) {
@@ -2890,7 +2934,7 @@
 // BYTE STREAM
 //
 
-static void reset_byte_stream(void* arg, grpc_error* error) {
+static void reset_byte_stream(void* arg, grpc_error_handle error) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(arg);
   s->pending_byte_stream = false;
   if (error == GRPC_ERROR_NONE) {
@@ -2921,8 +2965,8 @@
   stream->byte_stream_error = GRPC_ERROR_NONE;
 }
 
-void Chttp2IncomingByteStream::OrphanLocked(void* arg,
-                                            grpc_error* /*error_ignored*/) {
+void Chttp2IncomingByteStream::OrphanLocked(
+    void* arg, grpc_error_handle /*error_ignored*/) {
   Chttp2IncomingByteStream* bs = static_cast<Chttp2IncomingByteStream*>(arg);
   grpc_chttp2_stream* s = bs->stream_;
   grpc_chttp2_transport* t = s->t;
@@ -2941,7 +2985,7 @@
 }
 
 void Chttp2IncomingByteStream::NextLocked(void* arg,
-                                          grpc_error* /*error_ignored*/) {
+                                          grpc_error_handle /*error_ignored*/) {
   Chttp2IncomingByteStream* bs = static_cast<Chttp2IncomingByteStream*>(arg);
   grpc_chttp2_transport* t = bs->transport_;
   grpc_chttp2_stream* s = bs->stream_;
@@ -3011,9 +3055,9 @@
   }
 }
 
-grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
+grpc_error_handle Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
   GPR_TIMER_SCOPE("incoming_byte_stream_pull", 0);
-  grpc_error* error;
+  grpc_error_handle error;
   if (stream_->unprocessed_incoming_frames_buffer.length > 0) {
     if (!stream_->unprocessed_incoming_frames_decompressed &&
         stream_->stream_decompression_method !=
@@ -3056,7 +3100,7 @@
   return GRPC_ERROR_NONE;
 }
 
-void Chttp2IncomingByteStream::PublishError(grpc_error* error) {
+void Chttp2IncomingByteStream::PublishError(grpc_error_handle error) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, stream_->on_next,
                           GRPC_ERROR_REF(error));
@@ -3066,10 +3110,10 @@
   grpc_chttp2_cancel_stream(transport_, stream_, GRPC_ERROR_REF(error));
 }
 
-grpc_error* Chttp2IncomingByteStream::Push(const grpc_slice& slice,
-                                           grpc_slice* slice_out) {
+grpc_error_handle Chttp2IncomingByteStream::Push(const grpc_slice& slice,
+                                                 grpc_slice* slice_out) {
   if (remaining_bytes_ < GRPC_SLICE_LENGTH(slice)) {
-    grpc_error* error =
+    grpc_error_handle error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream");
     transport_->combiner->Run(&stream_->reset_byte_stream,
                               GRPC_ERROR_REF(error));
@@ -3084,8 +3128,8 @@
   }
 }
 
-grpc_error* Chttp2IncomingByteStream::Finished(grpc_error* error,
-                                               bool reset_on_error) {
+grpc_error_handle Chttp2IncomingByteStream::Finished(grpc_error_handle error,
+                                                     bool reset_on_error) {
   if (error == GRPC_ERROR_NONE) {
     if (remaining_bytes_ != 0) {
       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
@@ -3099,7 +3143,7 @@
   return error;
 }
 
-void Chttp2IncomingByteStream::Shutdown(grpc_error* error) {
+void Chttp2IncomingByteStream::Shutdown(grpc_error_handle error) {
   GRPC_ERROR_UNREF(Finished(error, true /* reset_on_error */));
 }
 
@@ -3131,14 +3175,14 @@
   }
 }
 
-static void benign_reclaimer(void* arg, grpc_error* error) {
+static void benign_reclaimer(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->benign_reclaimer_locked,
                                      benign_reclaimer_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void benign_reclaimer_locked(void* arg, grpc_error* error) {
+static void benign_reclaimer_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (error == GRPC_ERROR_NONE &&
       grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
@@ -3168,14 +3212,14 @@
   GRPC_CHTTP2_UNREF_TRANSPORT(t, "benign_reclaimer");
 }
 
-static void destructive_reclaimer(void* arg, grpc_error* error) {
+static void destructive_reclaimer(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   t->combiner->Run(GRPC_CLOSURE_INIT(&t->destructive_reclaimer_locked,
                                      destructive_reclaimer_locked, t, nullptr),
                    GRPC_ERROR_REF(error));
 }
 
-static void destructive_reclaimer_locked(void* arg, grpc_error* error) {
+static void destructive_reclaimer_locked(void* arg, grpc_error_handle error) {
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   size_t n = grpc_chttp2_stream_map_size(&t->stream_map);
   t->destructive_reclaimer_registered = false;
@@ -3293,7 +3337,7 @@
 
 void grpc_chttp2_transport_start_reading(
     grpc_transport* transport, grpc_slice_buffer* read_buffer,
-    grpc_closure* notify_on_receive_settings) {
+    grpc_closure* notify_on_receive_settings, grpc_closure* notify_on_close) {
   grpc_chttp2_transport* t =
       reinterpret_cast<grpc_chttp2_transport*>(transport);
   GRPC_CHTTP2_REF_TRANSPORT(
@@ -3303,6 +3347,7 @@
     gpr_free(read_buffer);
   }
   t->notify_on_receive_settings = notify_on_receive_settings;
+  t->notify_on_close = notify_on_close;
   t->combiner->Run(
       GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t, nullptr),
       GRPC_ERROR_NONE);
diff --git a/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.h
index b04630b..a72d268 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.h
@@ -47,6 +47,17 @@
 /// HTTP/2 settings are received from the peer.
 void grpc_chttp2_transport_start_reading(
     grpc_transport* transport, grpc_slice_buffer* read_buffer,
-    grpc_closure* notify_on_receive_settings);
+    grpc_closure* notify_on_receive_settings, grpc_closure* notify_on_close);
+
+namespace grpc_core {
+typedef void (*TestOnlyGlobalHttp2TransportInitCallback)();
+typedef void (*TestOnlyGlobalHttp2TransportDestructCallback)();
+
+void TestOnlySetGlobalHttp2TransportInitCallback(
+    TestOnlyGlobalHttp2TransportInitCallback callback);
+
+void TestOnlySetGlobalHttp2TransportDestructCallback(
+    TestOnlyGlobalHttp2TransportDestructCallback callback);
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H */
diff --git a/grpc/src/core/ext/transport/chttp2/transport/context_list.cc b/grpc/src/core/ext/transport/chttp2/transport/context_list.cc
index a0473ea..afb18ab 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/context_list.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/context_list.cc
@@ -22,7 +22,7 @@
 
 namespace {
 void (*write_timestamps_callback_g)(void*, grpc_core::Timestamps*,
-                                    grpc_error* error) = nullptr;
+                                    grpc_error_handle error) = nullptr;
 void* (*get_copied_context_fn_g)(void*) = nullptr;
 }  // namespace
 
@@ -41,7 +41,7 @@
 }
 
 void ContextList::Execute(void* arg, grpc_core::Timestamps* ts,
-                          grpc_error* error) {
+                          grpc_error_handle error) {
   ContextList* head = static_cast<ContextList*>(arg);
   ContextList* to_be_freed;
   while (head != nullptr) {
@@ -57,9 +57,8 @@
   }
 }
 
-void grpc_http2_set_write_timestamps_callback(void (*fn)(void*,
-                                                         grpc_core::Timestamps*,
-                                                         grpc_error* error)) {
+void grpc_http2_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error)) {
   write_timestamps_callback_g = fn;
 }
 
diff --git a/grpc/src/core/ext/transport/chttp2/transport/context_list.h b/grpc/src/core/ext/transport/chttp2/transport/context_list.h
index 5b9d2ab..54ec87c 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/context_list.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/context_list.h
@@ -36,7 +36,8 @@
   /* Executes a function \a fn with each context in the list and \a ts. It also
    * frees up the entire list after this operation. It is intended as a callback
    * and hence does not take a ref on \a error */
-  static void Execute(void* arg, grpc_core::Timestamps* ts, grpc_error* error);
+  static void Execute(void* arg, grpc_core::Timestamps* ts,
+                      grpc_error_handle error);
 
  private:
   void* trace_context_ = nullptr;
@@ -44,9 +45,8 @@
   size_t byte_offset_ = 0;
 };
 
-void grpc_http2_set_write_timestamps_callback(void (*fn)(void*,
-                                                         grpc_core::Timestamps*,
-                                                         grpc_error* error));
+void grpc_http2_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error));
 void grpc_http2_set_fn_get_copied_context(void* (*fn)(void*));
 } /* namespace grpc_core */
 
diff --git a/grpc/src/core/ext/transport/chttp2/transport/flow_control.cc b/grpc/src/core/ext/transport/chttp2/transport/flow_control.cc
index 09bd7ab..5f5e551 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/flow_control.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/flow_control.cc
@@ -203,7 +203,7 @@
   return 0;
 }
 
-grpc_error* TransportFlowControl::ValidateRecvData(
+grpc_error_handle TransportFlowControl::ValidateRecvData(
     int64_t incoming_frame_size) {
   if (incoming_frame_size > announced_window_) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -219,10 +219,10 @@
                                      const grpc_chttp2_stream* s)
     : tfc_(tfc), s_(s) {}
 
-grpc_error* StreamFlowControl::RecvData(int64_t incoming_frame_size) {
+grpc_error_handle StreamFlowControl::RecvData(int64_t incoming_frame_size) {
   FlowControlTrace trace("  data recv", tfc_, this);
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   error = tfc_->ValidateRecvData(incoming_frame_size);
   if (error != GRPC_ERROR_NONE) return error;
 
diff --git a/grpc/src/core/ext/transport/chttp2/transport/flow_control.h b/grpc/src/core/ext/transport/chttp2/transport/flow_control.h
index 7e05358..e508896 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/flow_control.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/flow_control.h
@@ -168,7 +168,7 @@
 
   // Called to do bookkeeping when a stream owned by this transport receives
   // data from the wire. Also does error checking for frame size.
-  virtual grpc_error* RecvData(int64_t /* incoming_frame_size */) = 0;
+  virtual grpc_error_handle RecvData(int64_t /* incoming_frame_size */) = 0;
 
   // Called to do bookkeeping when we receive a WINDOW_UPDATE frame.
   virtual void RecvUpdate(uint32_t /* size */) = 0;
@@ -210,7 +210,7 @@
   FlowControlAction MakeAction() override { return FlowControlAction(); }
   FlowControlAction PeriodicUpdate() override { return FlowControlAction(); }
   void StreamSentData(int64_t /* size */) override {}
-  grpc_error* RecvData(int64_t /* incoming_frame_size */) override {
+  grpc_error_handle RecvData(int64_t /* incoming_frame_size */) override {
     return GRPC_ERROR_NONE;
   }
   void RecvUpdate(uint32_t /* size */) override {}
@@ -246,14 +246,14 @@
 
   void StreamSentData(int64_t size) override { remote_window_ -= size; }
 
-  grpc_error* ValidateRecvData(int64_t incoming_frame_size);
+  grpc_error_handle ValidateRecvData(int64_t incoming_frame_size);
   void CommitRecvData(int64_t incoming_frame_size) {
     announced_window_ -= incoming_frame_size;
   }
 
-  grpc_error* RecvData(int64_t incoming_frame_size) override {
+  grpc_error_handle RecvData(int64_t incoming_frame_size) override {
     FlowControlTrace trace("  data recv", this, nullptr);
-    grpc_error* error = ValidateRecvData(incoming_frame_size);
+    grpc_error_handle error = ValidateRecvData(incoming_frame_size);
     if (error != GRPC_ERROR_NONE) return error;
     CommitRecvData(incoming_frame_size);
     return GRPC_ERROR_NONE;
@@ -352,7 +352,7 @@
   virtual void SentData(int64_t /* outgoing_frame_size */) = 0;
 
   // Bookkeeping and error checking for when data is received by this stream.
-  virtual grpc_error* RecvData(int64_t /* incoming_frame_size */) = 0;
+  virtual grpc_error_handle RecvData(int64_t /* incoming_frame_size */) = 0;
 
   // Called to check if this stream needs to send a WINDOW_UPDATE frame.
   virtual uint32_t MaybeSendUpdate() = 0;
@@ -395,7 +395,7 @@
   }
   FlowControlAction MakeAction() override { return FlowControlAction(); }
   void SentData(int64_t /* outgoing_frame_size */) override {}
-  grpc_error* RecvData(int64_t /* incoming_frame_size */) override {
+  grpc_error_handle RecvData(int64_t /* incoming_frame_size */) override {
     return GRPC_ERROR_NONE;
   }
   uint32_t MaybeSendUpdate() override { return 0; }
@@ -427,7 +427,7 @@
   }
 
   // we have received data from the wire
-  grpc_error* RecvData(int64_t incoming_frame_size) override;
+  grpc_error_handle RecvData(int64_t incoming_frame_size) override;
 
   // returns an announce if we should send a stream update to our peer, else
   // returns zero
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_data.cc b/grpc/src/core/ext/transport/chttp2/transport/frame_data.cc
index 0924a4b..745f32a 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_data.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_data.cc
@@ -41,7 +41,7 @@
   GRPC_ERROR_UNREF(error);
 }
 
-grpc_error* grpc_chttp2_data_parser_begin_frame(
+grpc_error_handle grpc_chttp2_data_parser_begin_frame(
     grpc_chttp2_data_parser* /*parser*/, uint8_t flags, uint32_t stream_id,
     grpc_chttp2_stream* s) {
   if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
@@ -89,11 +89,11 @@
   stats->data_bytes += write_bytes;
 }
 
-grpc_error* grpc_deframe_unprocessed_incoming_frames(
+grpc_error_handle grpc_deframe_unprocessed_incoming_frames(
     grpc_chttp2_data_parser* p, grpc_chttp2_stream* s,
     grpc_slice_buffer* slices, grpc_slice* slice_out,
     grpc_core::OrphanablePtr<grpc_core::ByteStream>* stream_out) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_chttp2_transport* t = s->t;
 
   while (slices->count > 0) {
@@ -275,11 +275,11 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_data_parser_parse(void* /*parser*/,
-                                          grpc_chttp2_transport* t,
-                                          grpc_chttp2_stream* s,
-                                          const grpc_slice& slice,
-                                          int is_last) {
+grpc_error_handle grpc_chttp2_data_parser_parse(void* /*parser*/,
+                                                grpc_chttp2_transport* t,
+                                                grpc_chttp2_stream* s,
+                                                const grpc_slice& slice,
+                                                int is_last) {
   if (!s->pending_byte_stream) {
     grpc_slice_ref_internal(slice);
     grpc_slice_buffer_add(&s->frame_storage, slice);
@@ -297,7 +297,11 @@
   }
 
   if (is_last && s->received_last_frame) {
-    grpc_chttp2_mark_stream_closed(t, s, true, false, GRPC_ERROR_NONE);
+    grpc_chttp2_mark_stream_closed(
+        t, s, true, false,
+        t->is_client ? GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                           "Data frame with END_STREAM flag received")
+                     : GRPC_ERROR_NONE);
   }
 
   return GRPC_ERROR_NONE;
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_data.h b/grpc/src/core/ext/transport/chttp2/transport/frame_data.h
index ec38900..5aa4a3e 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -50,31 +50,31 @@
   grpc_chttp2_stream_state state = GRPC_CHTTP2_DATA_FH_0;
   uint8_t frame_type = 0;
   uint32_t frame_size = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   bool is_frame_compressed = false;
   grpc_core::Chttp2IncomingByteStream* parsing_frame = nullptr;
 };
 
 /* start processing a new data frame */
-grpc_error* grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser* parser,
-                                                uint8_t flags,
-                                                uint32_t stream_id,
-                                                grpc_chttp2_stream* s);
+grpc_error_handle grpc_chttp2_data_parser_begin_frame(
+    grpc_chttp2_data_parser* parser, uint8_t flags, uint32_t stream_id,
+    grpc_chttp2_stream* s);
 
 /* handle a slice of a data frame - is_last indicates the last slice of a
    frame */
-grpc_error* grpc_chttp2_data_parser_parse(void* parser,
-                                          grpc_chttp2_transport* t,
-                                          grpc_chttp2_stream* s,
-                                          const grpc_slice& slice, int is_last);
+grpc_error_handle grpc_chttp2_data_parser_parse(void* parser,
+                                                grpc_chttp2_transport* t,
+                                                grpc_chttp2_stream* s,
+                                                const grpc_slice& slice,
+                                                int is_last);
 
 void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer* inbuf,
                              uint32_t write_bytes, int is_eof,
                              grpc_transport_one_way_stats* stats,
                              grpc_slice_buffer* outbuf);
 
-grpc_error* grpc_deframe_unprocessed_incoming_frames(
+grpc_error_handle grpc_deframe_unprocessed_incoming_frames(
     grpc_chttp2_data_parser* p, grpc_chttp2_stream* s,
     grpc_slice_buffer* slices, grpc_slice* slice_out,
     grpc_core::OrphanablePtr<grpc_core::ByteStream>* stream_out);
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.cc b/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.cc
index 3831b80..a139bea 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -36,9 +36,8 @@
   gpr_free(p->debug_data);
 }
 
-grpc_error* grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser* p,
-                                                  uint32_t length,
-                                                  uint8_t /*flags*/) {
+grpc_error_handle grpc_chttp2_goaway_parser_begin_frame(
+    grpc_chttp2_goaway_parser* p, uint32_t length, uint8_t /*flags*/) {
   if (length < 8) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
         absl::StrFormat("goaway frame too short (%d bytes)", length).c_str());
@@ -52,11 +51,11 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_goaway_parser_parse(void* parser,
-                                            grpc_chttp2_transport* t,
-                                            grpc_chttp2_stream* /*s*/,
-                                            const grpc_slice& slice,
-                                            int is_last) {
+grpc_error_handle grpc_chttp2_goaway_parser_parse(void* parser,
+                                                  grpc_chttp2_transport* t,
+                                                  grpc_chttp2_stream* /*s*/,
+                                                  const grpc_slice& slice,
+                                                  int is_last) {
   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.h b/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.h
index df6274d..674f742 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.h
@@ -47,13 +47,13 @@
 };
 void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser* p);
 void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser* p);
-grpc_error* grpc_chttp2_goaway_parser_begin_frame(
+grpc_error_handle grpc_chttp2_goaway_parser_begin_frame(
     grpc_chttp2_goaway_parser* parser, uint32_t length, uint8_t flags);
-grpc_error* grpc_chttp2_goaway_parser_parse(void* parser,
-                                            grpc_chttp2_transport* t,
-                                            grpc_chttp2_stream* s,
-                                            const grpc_slice& slice,
-                                            int is_last);
+grpc_error_handle grpc_chttp2_goaway_parser_parse(void* parser,
+                                                  grpc_chttp2_transport* t,
+                                                  grpc_chttp2_stream* s,
+                                                  const grpc_slice& slice,
+                                                  int is_last);
 
 void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
                                const grpc_slice& debug_data,
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_ping.cc b/grpc/src/core/ext/transport/chttp2/transport/frame_ping.cc
index 9841232..9da4a72 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_ping.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_ping.cc
@@ -55,9 +55,8 @@
   return slice;
 }
 
-grpc_error* grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser* parser,
-                                                uint32_t length,
-                                                uint8_t flags) {
+grpc_error_handle grpc_chttp2_ping_parser_begin_frame(
+    grpc_chttp2_ping_parser* parser, uint32_t length, uint8_t flags) {
   if (flags & 0xfe || length != 8) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
         absl::StrFormat("invalid ping: length=%d, flags=%02x", length, flags)
@@ -69,11 +68,11 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_ping_parser_parse(void* parser,
-                                          grpc_chttp2_transport* t,
-                                          grpc_chttp2_stream* /*s*/,
-                                          const grpc_slice& slice,
-                                          int is_last) {
+grpc_error_handle grpc_chttp2_ping_parser_parse(void* parser,
+                                                grpc_chttp2_transport* t,
+                                                grpc_chttp2_stream* /*s*/,
+                                                const grpc_slice& slice,
+                                                int is_last) {
   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_ping.h b/grpc/src/core/ext/transport/chttp2/transport/frame_ping.h
index e356bf4..6b5318e 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_ping.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -31,12 +31,13 @@
 };
 grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes);
 
-grpc_error* grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser* parser,
-                                                uint32_t length, uint8_t flags);
-grpc_error* grpc_chttp2_ping_parser_parse(void* parser,
-                                          grpc_chttp2_transport* t,
-                                          grpc_chttp2_stream* s,
-                                          const grpc_slice& slice, int is_last);
+grpc_error_handle grpc_chttp2_ping_parser_begin_frame(
+    grpc_chttp2_ping_parser* parser, uint32_t length, uint8_t flags);
+grpc_error_handle grpc_chttp2_ping_parser_parse(void* parser,
+                                                grpc_chttp2_transport* t,
+                                                grpc_chttp2_stream* s,
+                                                const grpc_slice& slice,
+                                                int is_last);
 
 /* Test-only function for disabling ping ack */
 void grpc_set_disable_ping_ack(bool disable_ping_ack);
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc b/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
index bcfcb17..03a7c61 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
@@ -68,7 +68,7 @@
                         grpc_chttp2_rst_stream_create(id, code, stats));
 }
 
-grpc_error* grpc_chttp2_rst_stream_parser_begin_frame(
+grpc_error_handle grpc_chttp2_rst_stream_parser_begin_frame(
     grpc_chttp2_rst_stream_parser* parser, uint32_t length, uint8_t flags) {
   if (length != 4) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -80,11 +80,11 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_rst_stream_parser_parse(void* parser,
-                                                grpc_chttp2_transport* t,
-                                                grpc_chttp2_stream* s,
-                                                const grpc_slice& slice,
-                                                int is_last) {
+grpc_error_handle grpc_chttp2_rst_stream_parser_parse(void* parser,
+                                                      grpc_chttp2_transport* t,
+                                                      grpc_chttp2_stream* s,
+                                                      const grpc_slice& slice,
+                                                      int is_last) {
   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
@@ -104,7 +104,7 @@
                       ((static_cast<uint32_t>(p->reason_bytes[1])) << 16) |
                       ((static_cast<uint32_t>(p->reason_bytes[2])) << 8) |
                       ((static_cast<uint32_t>(p->reason_bytes[3])));
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (reason != GRPC_HTTP2_NO_ERROR || s->metadata_buffer[1].size == 0) {
       error = grpc_error_set_int(
           grpc_error_set_str(
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.h b/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
index e324ee2..865e74d 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
@@ -39,12 +39,12 @@
     grpc_chttp2_transport* t, uint32_t id, uint32_t code,
     grpc_transport_one_way_stats* stats);
 
-grpc_error* grpc_chttp2_rst_stream_parser_begin_frame(
+grpc_error_handle grpc_chttp2_rst_stream_parser_begin_frame(
     grpc_chttp2_rst_stream_parser* parser, uint32_t length, uint8_t flags);
-grpc_error* grpc_chttp2_rst_stream_parser_parse(void* parser,
-                                                grpc_chttp2_transport* t,
-                                                grpc_chttp2_stream* s,
-                                                const grpc_slice& slice,
-                                                int is_last);
+grpc_error_handle grpc_chttp2_rst_stream_parser_parse(void* parser,
+                                                      grpc_chttp2_transport* t,
+                                                      grpc_chttp2_stream* s,
+                                                      const grpc_slice& slice,
+                                                      int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H */
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_settings.cc b/grpc/src/core/ext/transport/chttp2/transport/frame_settings.cc
index 7dbfc69..576f815 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_settings.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_settings.cc
@@ -84,7 +84,7 @@
   return output;
 }
 
-grpc_error* grpc_chttp2_settings_parser_begin_frame(
+grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
     grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
     uint32_t* settings) {
   parser->target_settings = settings;
@@ -110,10 +110,11 @@
   }
 }
 
-grpc_error* grpc_chttp2_settings_parser_parse(void* p, grpc_chttp2_transport* t,
-                                              grpc_chttp2_stream* /*s*/,
-                                              const grpc_slice& slice,
-                                              int is_last) {
+grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
+                                                    grpc_chttp2_transport* t,
+                                                    grpc_chttp2_stream* /*s*/,
+                                                    const grpc_slice& slice,
+                                                    int is_last) {
   grpc_chttp2_settings_parser* parser =
       static_cast<grpc_chttp2_settings_parser*>(p);
   const uint8_t* cur = GRPC_SLICE_START_PTR(slice);
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_settings.h b/grpc/src/core/ext/transport/chttp2/transport/frame_settings.h
index 147d5ea..7268277 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -49,13 +49,13 @@
 /* Create an ack settings frame */
 grpc_slice grpc_chttp2_settings_ack_create(void);
 
-grpc_error* grpc_chttp2_settings_parser_begin_frame(
+grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
     grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
     uint32_t* settings);
-grpc_error* grpc_chttp2_settings_parser_parse(void* parser,
-                                              grpc_chttp2_transport* t,
-                                              grpc_chttp2_stream* s,
-                                              const grpc_slice& slice,
-                                              int is_last);
+grpc_error_handle grpc_chttp2_settings_parser_parse(void* parser,
+                                                    grpc_chttp2_transport* t,
+                                                    grpc_chttp2_stream* s,
+                                                    const grpc_slice& slice,
+                                                    int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H */
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.cc b/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.cc
index 943ea17..37e69ff 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.cc
@@ -53,7 +53,7 @@
   return slice;
 }
 
-grpc_error* grpc_chttp2_window_update_parser_begin_frame(
+grpc_error_handle grpc_chttp2_window_update_parser_begin_frame(
     grpc_chttp2_window_update_parser* parser, uint32_t length, uint8_t flags) {
   if (flags || length != 4) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -66,11 +66,9 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_window_update_parser_parse(void* parser,
-                                                   grpc_chttp2_transport* t,
-                                                   grpc_chttp2_stream* s,
-                                                   const grpc_slice& slice,
-                                                   int is_last) {
+grpc_error_handle grpc_chttp2_window_update_parser_parse(
+    void* parser, grpc_chttp2_transport* t, grpc_chttp2_stream* s,
+    const grpc_slice& slice, int is_last) {
   const uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
diff --git a/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.h b/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.h
index 340445d..5a07b9e 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.h
@@ -33,12 +33,10 @@
 grpc_slice grpc_chttp2_window_update_create(
     uint32_t id, uint32_t window_delta, grpc_transport_one_way_stats* stats);
 
-grpc_error* grpc_chttp2_window_update_parser_begin_frame(
+grpc_error_handle grpc_chttp2_window_update_parser_begin_frame(
     grpc_chttp2_window_update_parser* parser, uint32_t length, uint8_t flags);
-grpc_error* grpc_chttp2_window_update_parser_parse(void* parser,
-                                                   grpc_chttp2_transport* t,
-                                                   grpc_chttp2_stream* s,
-                                                   const grpc_slice& slice,
-                                                   int is_last);
+grpc_error_handle grpc_chttp2_window_update_parser_parse(
+    void* parser, grpc_chttp2_transport* t, grpc_chttp2_stream* s,
+    const grpc_slice& slice, int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H */
diff --git a/grpc/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/grpc/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
index 4ceaec2..cc1eba9 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -104,7 +104,7 @@
 
 struct MetadataComparator {
   typedef grpc_mdelem Type;
-  static const grpc_mdelem Null() { return {0}; }
+  static grpc_mdelem Null() { return {0}; }
   static bool IsNull(const grpc_mdelem md) { return md.payload == 0; }
   static bool Equals(const grpc_mdelem md1, const grpc_mdelem md2) {
     return md1.payload == md2.payload;
diff --git a/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.cc b/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.cc
index 668c2cb..99c308f 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.cc
@@ -67,71 +67,82 @@
    a set of indirect jumps, and so not waste stack space. */
 
 /* forward declarations for parsing states */
-static grpc_error* parse_begin(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                               const uint8_t* end);
-static grpc_error* parse_error(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                               const uint8_t* end, grpc_error* error);
-static grpc_error* still_parse_error(grpc_chttp2_hpack_parser* p,
+static grpc_error_handle parse_begin(grpc_chttp2_hpack_parser* p,
                                      const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_illegal_op(grpc_chttp2_hpack_parser* p,
-                                    const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_error(grpc_chttp2_hpack_parser* p,
+                                     const uint8_t* cur, const uint8_t* end,
+                                     grpc_error_handle error);
+static grpc_error_handle still_parse_error(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end);
+static grpc_error_handle parse_illegal_op(grpc_chttp2_hpack_parser* p,
+                                          const uint8_t* cur,
+                                          const uint8_t* end);
 
-static grpc_error* parse_string_prefix(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_key_string(grpc_chttp2_hpack_parser* p,
-                                    const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_value_string_with_indexed_key(
+static grpc_error_handle parse_string_prefix(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_key_string(grpc_chttp2_hpack_parser* p,
+                                          const uint8_t* cur,
+                                          const uint8_t* end);
+static grpc_error_handle parse_value_string_with_indexed_key(
     grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_value_string_with_literal_key(
+static grpc_error_handle parse_value_string_with_literal_key(
     grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end);
 
-static grpc_error* parse_value0(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value1(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value2(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value3(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value4(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end);
-static grpc_error* parse_value5up(grpc_chttp2_hpack_parser* p,
-                                  const uint8_t* cur, const uint8_t* end);
-
-static grpc_error* parse_indexed_field(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_indexed_field_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end);
-static grpc_error* parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
+static grpc_error_handle parse_value0(grpc_chttp2_hpack_parser* p,
                                       const uint8_t* cur, const uint8_t* end);
-static grpc_error* parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
+static grpc_error_handle parse_value1(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_value2(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_value3(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_value4(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end);
+static grpc_error_handle parse_value5up(grpc_chttp2_hpack_parser* p,
                                         const uint8_t* cur, const uint8_t* end);
 
+static grpc_error_handle parse_indexed_field(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_indexed_field_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end);
+static grpc_error_handle parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end);
+static grpc_error_handle parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
+                                            const uint8_t* cur,
+                                            const uint8_t* end);
+static grpc_error_handle parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end);
+
 /* we translate the first byte of a hpack field into one of these decoding
    cases, then use a lookup table to jump directly to the appropriate parser.
 
@@ -647,14 +658,14 @@
 
 /* emission helpers */
 template <bool do_add>
-static grpc_error* on_hdr(grpc_chttp2_hpack_parser* p, grpc_mdelem md) {
+static grpc_error_handle on_hdr(grpc_chttp2_hpack_parser* p, grpc_mdelem md) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_hpack_parser)) {
     on_hdr_log(md);
   }
   if (do_add) {
     GPR_DEBUG_ASSERT(GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_INTERNED ||
                      GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC);
-    grpc_error* err = grpc_chttp2_hptbl_add(&p->table, md);
+    grpc_error_handle err = grpc_chttp2_hptbl_add(&p->table, md);
     if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) return err;
   }
   return p->on_header(p->on_header_user_data, md);
@@ -693,16 +704,16 @@
 }
 
 /* jump to the next state */
-static grpc_error* parse_next(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                              const uint8_t* end) {
+static grpc_error_handle parse_next(grpc_chttp2_hpack_parser* p,
+                                    const uint8_t* cur, const uint8_t* end) {
   p->state = *p->next_state++;
   return p->state(p, cur, end);
 }
 
 /* begin parsing a header: all functionality is encoded into lookup tables
    above */
-static grpc_error* parse_begin(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                               const uint8_t* end) {
+static grpc_error_handle parse_begin(grpc_chttp2_hpack_parser* p,
+                                     const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_begin;
     return GRPC_ERROR_NONE;
@@ -712,8 +723,9 @@
 }
 
 /* stream dependency and prioritization data: we just skip it */
-static grpc_error* parse_stream_weight(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_weight(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_weight;
     return GRPC_ERROR_NONE;
@@ -722,8 +734,9 @@
   return p->after_prioritization(p, cur + 1, end);
 }
 
-static grpc_error* parse_stream_dep3(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_dep3(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_dep3;
     return GRPC_ERROR_NONE;
@@ -732,8 +745,9 @@
   return parse_stream_weight(p, cur + 1, end);
 }
 
-static grpc_error* parse_stream_dep2(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_dep2(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_dep2;
     return GRPC_ERROR_NONE;
@@ -742,8 +756,9 @@
   return parse_stream_dep3(p, cur + 1, end);
 }
 
-static grpc_error* parse_stream_dep1(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_dep1(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_dep1;
     return GRPC_ERROR_NONE;
@@ -752,8 +767,9 @@
   return parse_stream_dep2(p, cur + 1, end);
 }
 
-static grpc_error* parse_stream_dep0(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_stream_dep0(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* cur,
+                                           const uint8_t* end) {
   if (cur == end) {
     p->state = parse_stream_dep0;
     return GRPC_ERROR_NONE;
@@ -762,7 +778,7 @@
   return parse_stream_dep1(p, cur + 1, end);
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
 on_invalid_hpack_idx(grpc_chttp2_hpack_parser* p) {
   return grpc_error_set_int(
       grpc_error_set_int(
@@ -772,22 +788,23 @@
 }
 
 /* emit an indexed field; jumps to begin the next field on completion */
-static grpc_error* finish_indexed_field(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle finish_indexed_field(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   grpc_mdelem md = grpc_chttp2_hptbl_lookup<true>(&p->table, p->index);
   if (GPR_UNLIKELY(GRPC_MDISNULL(md))) {
     return on_invalid_hpack_idx(p);
   }
   GRPC_STATS_INC_HPACK_RECV_INDEXED();
-  grpc_error* err = on_hdr<false>(p, md);
+  grpc_error_handle err = on_hdr<false>(p, md);
   if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) return err;
   return parse_begin(p, cur, end);
 }
 
 /* parse an indexed field with index < 127 */
-static grpc_error* parse_indexed_field(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_indexed_field(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   p->dynamic_table_update_allowed = 0;
   p->index = (*cur) & 0x7f;
   p->md_for_index.payload = 0; /* Invalidate cached md when index changes. */
@@ -795,9 +812,9 @@
 }
 
 /* parse an indexed field with index >= 127 */
-static grpc_error* parse_indexed_field_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_indexed_field_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       finish_indexed_field};
   p->dynamic_table_update_allowed = 0;
@@ -830,12 +847,12 @@
 }
 
 /* finish a literal header with incremental indexing */
-static grpc_error* finish_lithdr_incidx(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle finish_lithdr_incidx(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_INCIDX();
   grpc_mdelem md = get_precomputed_md_for_idx(p);
-  grpc_error* err = on_hdr<true>(
+  grpc_error_handle err = on_hdr<true>(
       p, grpc_mdelem_from_slices(get_indexed_key(md),
                                  take_string_intern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -843,11 +860,11 @@
 }
 
 /* finish a literal header with incremental indexing with no index */
-static grpc_error* finish_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
-                                          const uint8_t* cur,
-                                          const uint8_t* end) {
+static grpc_error_handle finish_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
+                                                const uint8_t* cur,
+                                                const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_INCIDX_V();
-  grpc_error* err = on_hdr<true>(
+  grpc_error_handle err = on_hdr<true>(
       p, grpc_mdelem_from_slices(take_string_intern(p, &p->key),
                                  take_string_intern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -855,8 +872,9 @@
 }
 
 /* parse a literal header with incremental indexing; index < 63 */
-static grpc_error* parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_lithdr_incidx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_incidx};
   p->dynamic_table_update_allowed = 0;
@@ -867,9 +885,9 @@
 }
 
 /* parse a literal header with incremental indexing; index >= 63 */
-static grpc_error* parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_incidx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_incidx};
@@ -882,9 +900,9 @@
 }
 
 /* parse a literal header with incremental indexing; index = 0 */
-static grpc_error* parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_incidx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_incidx_v};
@@ -894,12 +912,12 @@
 }
 
 /* finish a literal header without incremental indexing */
-static grpc_error* finish_lithdr_notidx(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle finish_lithdr_notidx(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_NOTIDX();
   grpc_mdelem md = get_precomputed_md_for_idx(p);
-  grpc_error* err = on_hdr<false>(
+  grpc_error_handle err = on_hdr<false>(
       p, grpc_mdelem_from_slices(get_indexed_key(md),
                                  take_string_extern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -907,11 +925,11 @@
 }
 
 /* finish a literal header without incremental indexing with index = 0 */
-static grpc_error* finish_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
-                                          const uint8_t* cur,
-                                          const uint8_t* end) {
+static grpc_error_handle finish_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
+                                                const uint8_t* cur,
+                                                const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_NOTIDX_V();
-  grpc_error* err = on_hdr<false>(
+  grpc_error_handle err = on_hdr<false>(
       p, grpc_mdelem_from_slices(take_string_intern(p, &p->key),
                                  take_string_extern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -919,8 +937,9 @@
 }
 
 /* parse a literal header without incremental indexing; index < 15 */
-static grpc_error* parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_lithdr_notidx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_notidx};
   p->dynamic_table_update_allowed = 0;
@@ -931,9 +950,9 @@
 }
 
 /* parse a literal header without incremental indexing; index >= 15 */
-static grpc_error* parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_notidx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_notidx};
@@ -946,9 +965,9 @@
 }
 
 /* parse a literal header without incremental indexing; index == 0 */
-static grpc_error* parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_notidx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_notidx_v};
@@ -958,12 +977,12 @@
 }
 
 /* finish a literal header that is never indexed */
-static grpc_error* finish_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle finish_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_NVRIDX();
   grpc_mdelem md = get_precomputed_md_for_idx(p);
-  grpc_error* err = on_hdr<false>(
+  grpc_error_handle err = on_hdr<false>(
       p, grpc_mdelem_from_slices(get_indexed_key(md),
                                  take_string_extern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -971,11 +990,11 @@
 }
 
 /* finish a literal header that is never indexed with an extra value */
-static grpc_error* finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
-                                          const uint8_t* cur,
-                                          const uint8_t* end) {
+static grpc_error_handle finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
+                                                const uint8_t* cur,
+                                                const uint8_t* end) {
   GRPC_STATS_INC_HPACK_RECV_LITHDR_NVRIDX_V();
-  grpc_error* err = on_hdr<false>(
+  grpc_error_handle err = on_hdr<false>(
       p, grpc_mdelem_from_slices(take_string_intern(p, &p->key),
                                  take_string_extern(p, &p->value)));
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -983,8 +1002,9 @@
 }
 
 /* parse a literal header that is never indexed; index < 15 */
-static grpc_error* parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_lithdr_nvridx(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_nvridx};
   p->dynamic_table_update_allowed = 0;
@@ -995,9 +1015,9 @@
 }
 
 /* parse a literal header that is never indexed; index >= 15 */
-static grpc_error* parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_string_prefix, parse_value_string_with_indexed_key,
       finish_lithdr_nvridx};
@@ -1010,9 +1030,9 @@
 }
 
 /* parse a literal header that is never indexed; index == 0 */
-static grpc_error* parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
-                                         const uint8_t* cur,
-                                         const uint8_t* end) {
+static grpc_error_handle parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p,
+                                               const uint8_t* cur,
+                                               const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_key_string, parse_string_prefix,
       parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
@@ -1022,20 +1042,22 @@
 }
 
 /* finish parsing a max table size change */
-static grpc_error* finish_max_tbl_size(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle finish_max_tbl_size(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_hpack_parser)) {
     gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
   }
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index);
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
   return parse_begin(p, cur, end);
 }
 
 /* parse a max table size change, max size < 15 */
-static grpc_error* parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
-                                      const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_max_tbl_size(grpc_chttp2_hpack_parser* p,
+                                            const uint8_t* cur,
+                                            const uint8_t* end) {
   if (p->dynamic_table_update_allowed == 0) {
     return parse_error(
         p, cur, end,
@@ -1049,9 +1071,9 @@
 }
 
 /* parse a max table size change, max size >= 15 */
-static grpc_error* parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
-                                        const uint8_t* cur,
-                                        const uint8_t* end) {
+static grpc_error_handle parse_max_tbl_size_x(grpc_chttp2_hpack_parser* p,
+                                              const uint8_t* cur,
+                                              const uint8_t* end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       finish_max_tbl_size};
   if (p->dynamic_table_update_allowed == 0) {
@@ -1069,9 +1091,10 @@
 }
 
 /* a parse error: jam the parse state into parse_error, and return error */
-static grpc_error* parse_error(grpc_chttp2_hpack_parser* p,
-                               const uint8_t* /*cur*/, const uint8_t* /*end*/,
-                               grpc_error* err) {
+static grpc_error_handle parse_error(grpc_chttp2_hpack_parser* p,
+                                     const uint8_t* /*cur*/,
+                                     const uint8_t* /*end*/,
+                                     grpc_error_handle err) {
   GPR_ASSERT(err != GRPC_ERROR_NONE);
   if (p->last_error == GRPC_ERROR_NONE) {
     p->last_error = GRPC_ERROR_REF(err);
@@ -1080,24 +1103,25 @@
   return err;
 }
 
-static grpc_error* still_parse_error(grpc_chttp2_hpack_parser* p,
-                                     const uint8_t* /*cur*/,
-                                     const uint8_t* /*end*/) {
+static grpc_error_handle still_parse_error(grpc_chttp2_hpack_parser* p,
+                                           const uint8_t* /*cur*/,
+                                           const uint8_t* /*end*/) {
   return GRPC_ERROR_REF(p->last_error);
 }
 
-static grpc_error* parse_illegal_op(grpc_chttp2_hpack_parser* p,
-                                    const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_illegal_op(grpc_chttp2_hpack_parser* p,
+                                          const uint8_t* cur,
+                                          const uint8_t* end) {
   GPR_ASSERT(cur != end);
-  grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrCat("Illegal hpack op code ", *cur).c_str());
   return parse_error(p, cur, end, err);
 }
 
 /* parse the 1st byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error* parse_value0(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value0(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_value0;
     return GRPC_ERROR_NONE;
@@ -1114,8 +1138,8 @@
 
 /* parse the 2nd byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error* parse_value1(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value1(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_value1;
     return GRPC_ERROR_NONE;
@@ -1132,8 +1156,8 @@
 
 /* parse the 3rd byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error* parse_value2(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value2(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_value2;
     return GRPC_ERROR_NONE;
@@ -1150,8 +1174,8 @@
 
 /* parse the 4th byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error* parse_value3(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value3(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   if (cur == end) {
     p->state = parse_value3;
     return GRPC_ERROR_NONE;
@@ -1168,8 +1192,8 @@
 
 /* parse the 5th byte of a varint into p->parsing.value
    depending on the byte, we may overflow, and care must be taken */
-static grpc_error* parse_value4(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_value4(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   uint8_t c;
   uint32_t cur_value;
   uint32_t add_value;
@@ -1199,7 +1223,7 @@
   }
 
 error:
-  grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrFormat(
           "integer overflow in hpack integer decoding: have 0x%08x, "
           "got byte 0x%02x on byte 5",
@@ -1211,8 +1235,9 @@
 /* parse any trailing bytes in a varint: it's possible to append an arbitrary
    number of 0x80's and not affect the value - a zero will terminate - and
    anything else will overflow */
-static grpc_error* parse_value5up(grpc_chttp2_hpack_parser* p,
-                                  const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_value5up(grpc_chttp2_hpack_parser* p,
+                                        const uint8_t* cur,
+                                        const uint8_t* end) {
   while (cur != end && *cur == 0x80) {
     ++cur;
   }
@@ -1226,7 +1251,7 @@
     return parse_next(p, cur + 1, end);
   }
 
-  grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrFormat(
           "integer overflow in hpack integer decoding: have 0x%08x, "
           "got byte 0x%02x sometime after byte 5",
@@ -1236,8 +1261,9 @@
 }
 
 /* parse a string prefix */
-static grpc_error* parse_string_prefix(grpc_chttp2_hpack_parser* p,
-                                       const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_string_prefix(grpc_chttp2_hpack_parser* p,
+                                             const uint8_t* cur,
+                                             const uint8_t* end) {
   if (cur == end) {
     p->state = parse_string_prefix;
     return GRPC_ERROR_NONE;
@@ -1269,8 +1295,8 @@
   str->data.copied.length += static_cast<uint32_t>(length);
 }
 
-static grpc_error* append_string(grpc_chttp2_hpack_parser* p,
-                                 const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle append_string(grpc_chttp2_hpack_parser* p,
+                                       const uint8_t* cur, const uint8_t* end) {
   grpc_chttp2_hpack_parser_string* str = p->parsing.str;
   uint32_t bits;
   uint8_t decoded[3];
@@ -1372,8 +1398,8 @@
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here")));
 }
 
-static grpc_error* finish_str(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                              const uint8_t* end) {
+static grpc_error_handle finish_str(grpc_chttp2_hpack_parser* p,
+                                    const uint8_t* cur, const uint8_t* end) {
   uint8_t decoded[2];
   uint32_t bits;
   grpc_chttp2_hpack_parser_string* str = p->parsing.str;
@@ -1391,7 +1417,7 @@
     case B64_BYTE2:
       bits = p->base64_buffer;
       if (bits & 0xffff) {
-        grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrFormat("trailing bits in base64 encoding: 0x%04x",
                             bits & 0xffff)
                 .c_str());
@@ -1403,7 +1429,7 @@
     case B64_BYTE3:
       bits = p->base64_buffer;
       if (bits & 0xff) {
-        grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrFormat("trailing bits in base64 encoding: 0x%02x",
                             bits & 0xff)
                 .c_str());
@@ -1418,13 +1444,14 @@
 }
 
 /* decode a nibble from a huffman encoded stream */
-static grpc_error* huff_nibble(grpc_chttp2_hpack_parser* p, uint8_t nibble) {
+static grpc_error_handle huff_nibble(grpc_chttp2_hpack_parser* p,
+                                     uint8_t nibble) {
   int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble];
   int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
   if (emit != -1) {
     if (emit >= 0 && emit < 256) {
       uint8_t c = static_cast<uint8_t>(emit);
-      grpc_error* err = append_string(p, &c, (&c) + 1);
+      grpc_error_handle err = append_string(p, &c, (&c) + 1);
       if (err != GRPC_ERROR_NONE) return err;
     } else {
       assert(emit == 256);
@@ -1435,10 +1462,11 @@
 }
 
 /* decode full bytes from a huffman encoded stream */
-static grpc_error* add_huff_bytes(grpc_chttp2_hpack_parser* p,
-                                  const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle add_huff_bytes(grpc_chttp2_hpack_parser* p,
+                                        const uint8_t* cur,
+                                        const uint8_t* end) {
   for (; cur != end; ++cur) {
-    grpc_error* err = huff_nibble(p, *cur >> 4);
+    grpc_error_handle err = huff_nibble(p, *cur >> 4);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     err = huff_nibble(p, *cur & 0xf);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -1448,8 +1476,8 @@
 
 /* decode some string bytes based on the current decoding mode
    (huffman or not) */
-static grpc_error* add_str_bytes(grpc_chttp2_hpack_parser* p,
-                                 const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle add_str_bytes(grpc_chttp2_hpack_parser* p,
+                                       const uint8_t* cur, const uint8_t* end) {
   if (p->huff) {
     return add_huff_bytes(p, cur, end);
   } else {
@@ -1458,18 +1486,18 @@
 }
 
 /* parse a string - tries to do large chunks at a time */
-static grpc_error* parse_string(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
-                                const uint8_t* end) {
+static grpc_error_handle parse_string(grpc_chttp2_hpack_parser* p,
+                                      const uint8_t* cur, const uint8_t* end) {
   size_t remaining = p->strlen - p->strgot;
   size_t given = static_cast<size_t>(end - cur);
   if (remaining <= given) {
-    grpc_error* err = add_str_bytes(p, cur, cur + remaining);
+    grpc_error_handle err = add_str_bytes(p, cur, cur + remaining);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     err = finish_str(p, cur + remaining, end);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     return parse_next(p, cur + remaining, end);
   } else {
-    grpc_error* err = add_str_bytes(p, cur, cur + given);
+    grpc_error_handle err = add_str_bytes(p, cur, cur + given);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     GPR_ASSERT(given <= UINT32_MAX - p->strgot);
     p->strgot += static_cast<uint32_t>(given);
@@ -1479,10 +1507,9 @@
 }
 
 /* begin parsing a string - performs setup, calls parse_string */
-static grpc_error* begin_parse_string(grpc_chttp2_hpack_parser* p,
-                                      const uint8_t* cur, const uint8_t* end,
-                                      uint8_t binary,
-                                      grpc_chttp2_hpack_parser_string* str) {
+static grpc_error_handle begin_parse_string(
+    grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end,
+    uint8_t binary, grpc_chttp2_hpack_parser_string* str) {
   if (!p->huff && binary == NOT_BINARY &&
       static_cast<uint32_t>(end - cur) >= p->strlen &&
       p->current_slice_refcount != nullptr) {
@@ -1518,8 +1545,9 @@
 }
 
 /* parse the key string */
-static grpc_error* parse_key_string(grpc_chttp2_hpack_parser* p,
-                                    const uint8_t* cur, const uint8_t* end) {
+static grpc_error_handle parse_key_string(grpc_chttp2_hpack_parser* p,
+                                          const uint8_t* cur,
+                                          const uint8_t* end) {
   return begin_parse_string(p, cur, end, NOT_BINARY, &p->key);
 }
 
@@ -1554,8 +1582,8 @@
    is a binary indexed header during string parsing. We'll need to revisit this
    metadata when we're done parsing, so we cache the metadata for this index
    here using set_precomputed_md_idx(). */
-static grpc_error* is_binary_indexed_header(grpc_chttp2_hpack_parser* p,
-                                            bool* is) {
+static grpc_error_handle is_binary_indexed_header(grpc_chttp2_hpack_parser* p,
+                                                  bool* is) {
   grpc_mdelem elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   if (GPR_UNLIKELY(GRPC_MDISNULL(elem))) {
     return on_invalid_hpack_idx(p);
@@ -1574,29 +1602,30 @@
 }
 
 /* parse the value string */
-static grpc_error* parse_value_string(grpc_chttp2_hpack_parser* p,
-                                      const uint8_t* cur, const uint8_t* end,
-                                      bool is_binary) {
+static grpc_error_handle parse_value_string(grpc_chttp2_hpack_parser* p,
+                                            const uint8_t* cur,
+                                            const uint8_t* end,
+                                            bool is_binary) {
   return begin_parse_string(p, cur, end, is_binary ? BINARY_BEGIN : NOT_BINARY,
                             &p->value);
 }
 
-static grpc_error* parse_value_string_with_indexed_key(
+static grpc_error_handle parse_value_string_with_indexed_key(
     grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end) {
   bool is_binary = false;
-  grpc_error* err = is_binary_indexed_header(p, &is_binary);
+  grpc_error_handle err = is_binary_indexed_header(p, &is_binary);
   if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
   return parse_value_string(p, cur, end, is_binary);
 }
 
-static grpc_error* parse_value_string_with_literal_key(
+static grpc_error_handle parse_value_string_with_literal_key(
     grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end) {
   return parse_value_string(p, cur, end, is_binary_literal_header(p));
 }
 
 /* "Uninitialized" header parser to save us a branch in on_hdr().  */
-static grpc_error* on_header_uninitialized(void* /*user_data*/,
-                                           grpc_mdelem md) {
+static grpc_error_handle on_header_uninitialized(void* /*user_data*/,
+                                                 grpc_mdelem md) {
   GRPC_MDELEM_UNREF(md);
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING("on_header callback not set");
 }
@@ -1645,15 +1674,15 @@
   gpr_free(p->value.data.copied.str);
 }
 
-grpc_error* grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser* p,
-                                           const grpc_slice& slice) {
+grpc_error_handle grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser* p,
+                                                 const grpc_slice& slice) {
 /* max number of bytes to parse at a time... limits call stack depth on
  * compilers without TCO */
 #define MAX_PARSE_LENGTH 1024
   p->current_slice_refcount = slice.refcount;
   const uint8_t* start = GRPC_SLICE_START_PTR(slice);
   const uint8_t* end = GRPC_SLICE_END_PTR(slice);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   while (start != end && error == GRPC_ERROR_NONE) {
     const uint8_t* target = start + GPR_MIN(MAX_PARSE_LENGTH, end - start);
     error = p->state(p, start, target);
@@ -1669,7 +1698,7 @@
     grpc_chttp2_maybe_complete_recv_initial_metadata,
     grpc_chttp2_maybe_complete_recv_trailing_metadata};
 
-static void force_client_rst_stream(void* sp, grpc_error* /*error*/) {
+static void force_client_rst_stream(void* sp, grpc_error_handle /*error*/) {
   grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp);
   grpc_chttp2_transport* t = s->t;
   if (!s->write_closed) {
@@ -1699,18 +1728,18 @@
   }
 }
 
-grpc_error* grpc_chttp2_header_parser_parse(void* hpack_parser,
-                                            grpc_chttp2_transport* t,
-                                            grpc_chttp2_stream* s,
-                                            const grpc_slice& slice,
-                                            int is_last) {
+grpc_error_handle grpc_chttp2_header_parser_parse(void* hpack_parser,
+                                                  grpc_chttp2_transport* t,
+                                                  grpc_chttp2_stream* s,
+                                                  const grpc_slice& slice,
+                                                  int is_last) {
   GPR_TIMER_SCOPE("grpc_chttp2_header_parser_parse", 0);
   grpc_chttp2_hpack_parser* parser =
       static_cast<grpc_chttp2_hpack_parser*>(hpack_parser);
   if (s != nullptr) {
     s->stats.incoming.header_bytes += GRPC_SLICE_LENGTH(slice);
   }
-  grpc_error* error = grpc_chttp2_hpack_parser_parse(parser, slice);
+  grpc_error_handle error = grpc_chttp2_hpack_parser_parse(parser, slice);
   if (error != GRPC_ERROR_NONE) {
     return error;
   }
diff --git a/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.h b/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.h
index 1b859c4..71aa194 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -29,7 +29,7 @@
 
 typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
 
-typedef grpc_error* (*grpc_chttp2_hpack_parser_state)(
+typedef grpc_error_handle (*grpc_chttp2_hpack_parser_state)(
     grpc_chttp2_hpack_parser* p, const uint8_t* beg, const uint8_t* end);
 
 struct grpc_chttp2_hpack_parser_string {
@@ -45,10 +45,10 @@
 };
 struct grpc_chttp2_hpack_parser {
   /* user specified callback for each header output */
-  grpc_error* (*on_header)(void* user_data, grpc_mdelem md);
+  grpc_error_handle (*on_header)(void* user_data, grpc_mdelem md);
   void* on_header_user_data;
 
-  grpc_error* last_error;
+  grpc_error_handle last_error;
 
   /* current parse state - or a function that implements it */
   grpc_chttp2_hpack_parser_state state;
@@ -103,15 +103,15 @@
 
 void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser* p);
 
-grpc_error* grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser* p,
-                                           const grpc_slice& slice);
+grpc_error_handle grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser* p,
+                                                 const grpc_slice& slice);
 
 /* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
    the transport */
-grpc_error* grpc_chttp2_header_parser_parse(void* hpack_parser,
-                                            grpc_chttp2_transport* t,
-                                            grpc_chttp2_stream* s,
-                                            const grpc_slice& slice,
-                                            int is_last);
+grpc_error_handle grpc_chttp2_header_parser_parse(void* hpack_parser,
+                                                  grpc_chttp2_transport* t,
+                                                  grpc_chttp2_stream* s,
+                                                  const grpc_slice& slice,
+                                                  int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H */
diff --git a/grpc/src/core/ext/transport/chttp2/transport/hpack_table.cc b/grpc/src/core/ext/transport/chttp2/transport/hpack_table.cc
index 78ee207..696176b 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/hpack_table.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/hpack_table.cc
@@ -114,8 +114,8 @@
   tbl->max_bytes = max_bytes;
 }
 
-grpc_error* grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl* tbl,
-                                                     uint32_t bytes) {
+grpc_error_handle grpc_chttp2_hptbl_set_current_table_size(
+    grpc_chttp2_hptbl* tbl, uint32_t bytes) {
   if (tbl->current_table_bytes == bytes) {
     return GRPC_ERROR_NONE;
   }
@@ -145,7 +145,8 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl, grpc_mdelem md) {
+grpc_error_handle grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
+                                        grpc_mdelem md) {
   /* determine how many bytes of buffer this entry represents */
   size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(md)) +
                       GRPC_SLICE_LENGTH(GRPC_MDVALUE(md)) +
diff --git a/grpc/src/core/ext/transport/chttp2/transport/hpack_table.h b/grpc/src/core/ext/transport/chttp2/transport/hpack_table.h
index 34c3dce..14a7793 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -89,8 +89,8 @@
 void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl* tbl);
 void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl* tbl,
                                      uint32_t max_bytes);
-grpc_error* grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl* tbl,
-                                                     uint32_t bytes);
+grpc_error_handle grpc_chttp2_hptbl_set_current_table_size(
+    grpc_chttp2_hptbl* tbl, uint32_t bytes);
 
 /* lookup a table entry based on its hpack index */
 grpc_mdelem grpc_chttp2_hptbl_lookup_dynamic_index(const grpc_chttp2_hptbl* tbl,
@@ -117,8 +117,8 @@
   }
 }
 /* add a table entry to the index */
-grpc_error* grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
-                                  grpc_mdelem md) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
+                                        grpc_mdelem md) GRPC_MUST_USE_RESULT;
 
 size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
                                            bool use_true_binary_metadata);
diff --git a/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.cc b/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
index d04630d..361b7b7 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
@@ -27,7 +27,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-grpc_error* grpc_chttp2_incoming_metadata_buffer_add(
+grpc_error_handle grpc_chttp2_incoming_metadata_buffer_add(
     grpc_chttp2_incoming_metadata_buffer* buffer, grpc_mdelem elem) {
   buffer->size += GRPC_MDELEM_LENGTH(elem);
   grpc_linked_mdelem* storage;
@@ -42,7 +42,7 @@
   return grpc_metadata_batch_link_tail(&buffer->batch, storage);
 }
 
-grpc_error* grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+grpc_error_handle grpc_chttp2_incoming_metadata_buffer_replace_or_add(
     grpc_chttp2_incoming_metadata_buffer* buffer, grpc_mdelem elem) {
   for (grpc_linked_mdelem* l = buffer->batch.list.head; l != nullptr;
        l = l->next) {
diff --git a/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.h
index b63caa1..68413b0 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -46,10 +46,10 @@
 void grpc_chttp2_incoming_metadata_buffer_publish(
     grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch);
 
-grpc_error* grpc_chttp2_incoming_metadata_buffer_add(
+grpc_error_handle grpc_chttp2_incoming_metadata_buffer_add(
     grpc_chttp2_incoming_metadata_buffer* buffer,
     grpc_mdelem elem) GRPC_MUST_USE_RESULT;
-grpc_error* grpc_chttp2_incoming_metadata_buffer_replace_or_add(
+grpc_error_handle grpc_chttp2_incoming_metadata_buffer_replace_or_add(
     grpc_chttp2_incoming_metadata_buffer* buffer,
     grpc_mdelem elem) GRPC_MUST_USE_RESULT;
 void grpc_chttp2_incoming_metadata_buffer_set_deadline(
diff --git a/grpc/src/core/ext/transport/chttp2/transport/internal.h b/grpc/src/core/ext/transport/chttp2/transport/internal.h
index 408a425..9c7f5fc 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/internal.h
+++ b/grpc/src/core/ext/transport/chttp2/transport/internal.h
@@ -217,8 +217,8 @@
   void Orphan() override;
 
   bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
-  grpc_error* Pull(grpc_slice* slice) override;
-  void Shutdown(grpc_error* error) override;
+  grpc_error_handle Pull(grpc_slice* slice) override;
+  void Shutdown(grpc_error_handle error) override;
 
   // TODO(roth): When I converted this class to C++, I wanted to make it
   // inherit from RefCounted or InternallyRefCounted instead of continuing
@@ -241,17 +241,17 @@
     }
   }
 
-  void PublishError(grpc_error* error);
+  void PublishError(grpc_error_handle error);
 
-  grpc_error* Push(const grpc_slice& slice, grpc_slice* slice_out);
+  grpc_error_handle Push(const grpc_slice& slice, grpc_slice* slice_out);
 
-  grpc_error* Finished(grpc_error* error, bool reset_on_error);
+  grpc_error_handle Finished(grpc_error_handle error, bool reset_on_error);
 
   uint32_t remaining_bytes() const { return remaining_bytes_; }
 
  private:
-  static void NextLocked(void* arg, grpc_error* error_ignored);
-  static void OrphanLocked(void* arg, grpc_error* error_ignored);
+  static void NextLocked(void* arg, grpc_error_handle error_ignored);
+  static void OrphanLocked(void* arg, grpc_error_handle error_ignored);
 
   void MaybeCreateStreamDecompressionCtx();
 
@@ -301,6 +301,7 @@
   grpc_core::Combiner* combiner;
 
   grpc_closure* notify_on_receive_settings = nullptr;
+  grpc_closure* notify_on_close = nullptr;
 
   /** write execution state of the transport */
   grpc_chttp2_write_state write_state = GRPC_CHTTP2_WRITE_STATE_IDLE;
@@ -308,7 +309,7 @@
   /** is the transport destroying itself? */
   uint8_t destroying = false;
   /** has the upper layer closed the transport? */
-  grpc_error* closed_with_error = GRPC_ERROR_NONE;
+  grpc_error_handle closed_with_error = GRPC_ERROR_NONE;
 
   /** is there a read request to the endpoint outstanding? */
   uint8_t endpoint_reading = 1;
@@ -357,7 +358,7 @@
 
   /** Set to a grpc_error object if a goaway frame is received. By default, set
    * to GRPC_ERROR_NONE */
-  grpc_error* goaway_error = GRPC_ERROR_NONE;
+  grpc_error_handle goaway_error = GRPC_ERROR_NONE;
 
   grpc_chttp2_sent_goaway_state sent_goaway_state = GRPC_CHTTP2_NO_GOAWAY_SEND;
 
@@ -427,9 +428,9 @@
   /* active parser */
   void* parser_data = nullptr;
   grpc_chttp2_stream* incoming_stream = nullptr;
-  grpc_error* (*parser)(void* parser_user_data, grpc_chttp2_transport* t,
-                        grpc_chttp2_stream* s, const grpc_slice& slice,
-                        int is_last);
+  grpc_error_handle (*parser)(void* parser_user_data, grpc_chttp2_transport* t,
+                              grpc_chttp2_stream* s, const grpc_slice& slice,
+                              int is_last);
 
   grpc_chttp2_write_cb* write_cb_pool = nullptr;
 
@@ -442,7 +443,7 @@
 
   /* if non-NULL, close the transport with this error when writes are finished
    */
-  grpc_error* close_transport_on_writes_finished = GRPC_ERROR_NONE;
+  grpc_error_handle close_transport_on_writes_finished = GRPC_ERROR_NONE;
 
   /* a list of closures to run after writes are finished */
   grpc_closure_list run_after_write = GRPC_CLOSURE_LIST_INIT;
@@ -580,9 +581,9 @@
   bool eos_sent = false;
 
   /** the error that resulted in this stream being read-closed */
-  grpc_error* read_closed_error = GRPC_ERROR_NONE;
+  grpc_error_handle read_closed_error = GRPC_ERROR_NONE;
   /** the error that resulted in this stream being write-closed */
-  grpc_error* write_closed_error = GRPC_ERROR_NONE;
+  grpc_error_handle write_closed_error = GRPC_ERROR_NONE;
 
   grpc_published_metadata_method published_metadata[2] = {};
   bool final_metadata_requested = false;
@@ -603,13 +604,14 @@
    * true */
   grpc_slice_buffer unprocessed_incoming_frames_buffer;
   grpc_closure reset_byte_stream;
-  grpc_error* byte_stream_error = GRPC_ERROR_NONE; /* protected by t combiner */
-  bool received_last_frame = false;                /* protected by t combiner */
+  grpc_error_handle byte_stream_error =
+      GRPC_ERROR_NONE;              /* protected by t combiner */
+  bool received_last_frame = false; /* protected by t combiner */
 
   grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
 
   /** saw some stream level error */
-  grpc_error* forced_close_error = GRPC_ERROR_NONE;
+  grpc_error_handle forced_close_error = GRPC_ERROR_NONE;
   /** how many header frames have we received? */
   uint8_t header_frames_received = 0;
   /** parsing state for data frames */
@@ -695,12 +697,12 @@
 };
 grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
     grpc_chttp2_transport* t);
-void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error* error);
+void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error_handle error);
 
 /** Process one slice of incoming data; return 1 if the connection is still
     viable after reading, or 0 if the connection should be torn down */
-grpc_error* grpc_chttp2_perform_read(grpc_chttp2_transport* t,
-                                     const grpc_slice& slice);
+grpc_error_handle grpc_chttp2_perform_read(grpc_chttp2_transport* t,
+                                           const grpc_slice& slice);
 
 bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport* t,
                                           grpc_chttp2_stream* s);
@@ -770,7 +772,8 @@
 void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
                                        grpc_chttp2_stream* s,
                                        grpc_closure** pclosure,
-                                       grpc_error* error, const char* desc);
+                                       grpc_error_handle error,
+                                       const char* desc);
 
 #define GRPC_HEADER_SIZE_IN_BYTES 5
 #define MAX_SIZE_T (~(size_t)0)
@@ -790,10 +793,11 @@
   } while (0)
 
 void grpc_chttp2_fake_status(grpc_chttp2_transport* t,
-                             grpc_chttp2_stream* stream, grpc_error* error);
+                             grpc_chttp2_stream* stream,
+                             grpc_error_handle error);
 void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t,
                                     grpc_chttp2_stream* s, int close_reads,
-                                    int close_writes, grpc_error* error);
+                                    int close_writes, grpc_error_handle error);
 void grpc_chttp2_start_writing(grpc_chttp2_transport* t);
 
 #ifndef NDEBUG
@@ -861,7 +865,7 @@
                                       grpc_chttp2_stream* s);
 
 void grpc_chttp2_cancel_stream(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                               grpc_error* due_to_error);
+                               grpc_error_handle due_to_error);
 
 void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_chttp2_transport* t,
                                                       grpc_chttp2_stream* s);
@@ -871,14 +875,15 @@
                                                        grpc_chttp2_stream* s);
 
 void grpc_chttp2_fail_pending_writes(grpc_chttp2_transport* t,
-                                     grpc_chttp2_stream* s, grpc_error* error);
+                                     grpc_chttp2_stream* s,
+                                     grpc_error_handle error);
 
 /** Set the default keepalive configurations, must only be called at
     initialization */
 void grpc_chttp2_config_default_keepalive_args(grpc_channel_args* args,
                                                bool is_client);
 
-void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error* error);
+void grpc_chttp2_retry_initiate_ping(void* tp, grpc_error_handle error);
 
 void schedule_bdp_ping_locked(grpc_chttp2_transport* t);
 
diff --git a/grpc/src/core/ext/transport/chttp2/transport/parsing.cc b/grpc/src/core/ext/transport/chttp2/transport/parsing.cc
index f4b02bb..68e7c69 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -36,27 +36,29 @@
 #include "src/core/lib/transport/status_conversion.h"
 #include "src/core/lib/transport/timeout_encoding.h"
 
-static grpc_error* init_frame_parser(grpc_chttp2_transport* t);
-static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
-                                            int is_continuation);
-static grpc_error* init_data_frame_parser(grpc_chttp2_transport* t);
-static grpc_error* init_rst_stream_parser(grpc_chttp2_transport* t);
-static grpc_error* init_settings_frame_parser(grpc_chttp2_transport* t);
-static grpc_error* init_window_update_frame_parser(grpc_chttp2_transport* t);
-static grpc_error* init_ping_parser(grpc_chttp2_transport* t);
-static grpc_error* init_goaway_parser(grpc_chttp2_transport* t);
-static grpc_error* init_skip_frame_parser(grpc_chttp2_transport* t,
-                                          int is_header);
+static grpc_error_handle init_frame_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
+                                                  int is_continuation);
+static grpc_error_handle init_data_frame_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_rst_stream_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_window_update_frame_parser(
+    grpc_chttp2_transport* t);
+static grpc_error_handle init_ping_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_goaway_parser(grpc_chttp2_transport* t);
+static grpc_error_handle init_skip_frame_parser(grpc_chttp2_transport* t,
+                                                int is_header);
 
-static grpc_error* parse_frame_slice(grpc_chttp2_transport* t,
-                                     const grpc_slice& slice, int is_last);
+static grpc_error_handle parse_frame_slice(grpc_chttp2_transport* t,
+                                           const grpc_slice& slice,
+                                           int is_last);
 
-grpc_error* grpc_chttp2_perform_read(grpc_chttp2_transport* t,
-                                     const grpc_slice& slice) {
+grpc_error_handle grpc_chttp2_perform_read(grpc_chttp2_transport* t,
+                                           const grpc_slice& slice) {
   const uint8_t* beg = GRPC_SLICE_START_PTR(slice);
   const uint8_t* end = GRPC_SLICE_END_PTR(slice);
   const uint8_t* cur = beg;
-  grpc_error* err;
+  grpc_error_handle err;
 
   if (cur == end) return GRPC_ERROR_NONE;
 
@@ -250,7 +252,7 @@
   GPR_UNREACHABLE_CODE(return nullptr);
 }
 
-static grpc_error* init_frame_parser(grpc_chttp2_transport* t) {
+static grpc_error_handle init_frame_parser(grpc_chttp2_transport* t) {
   if (t->is_first_frame &&
       t->incoming_frame_type != GRPC_CHTTP2_FRAME_SETTINGS) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -303,19 +305,21 @@
   }
 }
 
-static grpc_error* skip_parser(void* /*parser*/, grpc_chttp2_transport* /*t*/,
-                               grpc_chttp2_stream* /*s*/,
-                               const grpc_slice& /*slice*/, int /*is_last*/) {
+static grpc_error_handle skip_parser(void* /*parser*/,
+                                     grpc_chttp2_transport* /*t*/,
+                                     grpc_chttp2_stream* /*s*/,
+                                     const grpc_slice& /*slice*/,
+                                     int /*is_last*/) {
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* skip_header(void* /*tp*/, grpc_mdelem md) {
+static grpc_error_handle skip_header(void* /*tp*/, grpc_mdelem md) {
   GRPC_MDELEM_UNREF(md);
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_skip_frame_parser(grpc_chttp2_transport* t,
-                                          int is_header) {
+static grpc_error_handle init_skip_frame_parser(grpc_chttp2_transport* t,
+                                                int is_header) {
   if (is_header) {
     uint8_t is_eoh = t->expect_continuation_stream_id != 0;
     t->parser = grpc_chttp2_header_parser_parse;
@@ -334,7 +338,7 @@
   init_skip_frame_parser(t, t->parser == grpc_chttp2_header_parser_parse);
 }
 
-static grpc_error* init_data_frame_parser(grpc_chttp2_transport* t) {
+static grpc_error_handle init_data_frame_parser(grpc_chttp2_transport* t) {
   // Update BDP accounting since we have received a data frame.
   grpc_core::BdpEstimator* bdp_est = t->flow_control->bdp_estimator();
   if (bdp_est) {
@@ -347,7 +351,7 @@
   }
   grpc_chttp2_stream* s =
       grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
-  grpc_error* err = GRPC_ERROR_NONE;
+  grpc_error_handle err = GRPC_ERROR_NONE;
   grpc_core::chttp2::FlowControlAction action;
   if (s == nullptr) {
     err = t->flow_control->RecvData(t->incoming_frame_size);
@@ -413,8 +417,8 @@
   gpr_free(value);
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE handle_timeout(grpc_chttp2_stream* s,
-                                                         grpc_mdelem md) {
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
+handle_timeout(grpc_chttp2_stream* s, grpc_mdelem md) {
   grpc_millis* cached_timeout =
       static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
   grpc_millis timeout;
@@ -443,9 +447,11 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE handle_metadata_size_limit_exceeded(
-    grpc_chttp2_transport* t, grpc_chttp2_stream* s, grpc_mdelem md,
-    size_t new_size, size_t metadata_size_limit) {
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
+handle_metadata_size_limit_exceeded(grpc_chttp2_transport* t,
+                                    grpc_chttp2_stream* s, grpc_mdelem md,
+                                    size_t new_size,
+                                    size_t metadata_size_limit) {
   gpr_log(GPR_DEBUG,
           "received initial metadata size exceeds limit (%" PRIuPTR
           " vs. %" PRIuPTR
@@ -463,9 +469,9 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
 handle_metadata_add_failure(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                            grpc_mdelem md, grpc_error* error) {
+                            grpc_mdelem md, grpc_error_handle error) {
   grpc_chttp2_cancel_stream(t, s, error);
   grpc_chttp2_parsing_become_skip_parser(t);
   s->seen_error = true;
@@ -473,7 +479,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* on_initial_header(void* tp, grpc_mdelem md) {
+static grpc_error_handle on_initial_header(void* tp, grpc_mdelem md) {
   GPR_TIMER_SCOPE("on_initial_header", 0);
 
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
@@ -496,7 +502,7 @@
     return handle_metadata_size_limit_exceeded(t, s, md, new_size,
                                                metadata_size_limit);
   } else {
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
     if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
       return handle_metadata_add_failure(t, s, md, error);
@@ -506,7 +512,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* on_trailing_header(void* tp, grpc_mdelem md) {
+static grpc_error_handle on_trailing_header(void* tp, grpc_mdelem md) {
   GPR_TIMER_SCOPE("on_trailing_header", 0);
 
   grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
@@ -545,7 +551,7 @@
     s->seen_error = true;
     GRPC_MDELEM_UNREF(md);
   } else {
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md);
     if (error != GRPC_ERROR_NONE) {
       grpc_chttp2_cancel_stream(t, s, error);
@@ -557,8 +563,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
-                                            int is_continuation) {
+static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
+                                                  int is_continuation) {
   uint8_t is_eoh =
       (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
   grpc_chttp2_stream* s;
@@ -595,7 +601,7 @@
         GRPC_CHTTP2_IF_TRACING(gpr_log(
             GPR_ERROR, "ignoring new grpc_chttp2_stream creation on client"));
       }
-      grpc_error* err = init_skip_frame_parser(t, 1);
+      grpc_error_handle err = init_skip_frame_parser(t, 1);
       if (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_HAS_PRIORITY) {
         grpc_chttp2_hpack_parser_set_has_priority(&t->hpack_parser);
       }
@@ -678,8 +684,9 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_window_update_frame_parser(grpc_chttp2_transport* t) {
-  grpc_error* err = grpc_chttp2_window_update_parser_begin_frame(
+static grpc_error_handle init_window_update_frame_parser(
+    grpc_chttp2_transport* t) {
+  grpc_error_handle err = grpc_chttp2_window_update_parser_begin_frame(
       &t->simple.window_update, t->incoming_frame_size,
       t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
@@ -696,8 +703,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_ping_parser(grpc_chttp2_transport* t) {
-  grpc_error* err = grpc_chttp2_ping_parser_begin_frame(
+static grpc_error_handle init_ping_parser(grpc_chttp2_transport* t) {
+  grpc_error_handle err = grpc_chttp2_ping_parser_begin_frame(
       &t->simple.ping, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
   t->parser = grpc_chttp2_ping_parser_parse;
@@ -705,8 +712,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_rst_stream_parser(grpc_chttp2_transport* t) {
-  grpc_error* err = grpc_chttp2_rst_stream_parser_begin_frame(
+static grpc_error_handle init_rst_stream_parser(grpc_chttp2_transport* t) {
+  grpc_error_handle err = grpc_chttp2_rst_stream_parser_begin_frame(
       &t->simple.rst_stream, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
   grpc_chttp2_stream* s = t->incoming_stream =
@@ -720,8 +727,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_goaway_parser(grpc_chttp2_transport* t) {
-  grpc_error* err = grpc_chttp2_goaway_parser_begin_frame(
+static grpc_error_handle init_goaway_parser(grpc_chttp2_transport* t) {
+  grpc_error_handle err = grpc_chttp2_goaway_parser_begin_frame(
       &t->goaway_parser, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
   t->parser = grpc_chttp2_goaway_parser_parse;
@@ -729,13 +736,13 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* init_settings_frame_parser(grpc_chttp2_transport* t) {
+static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t) {
   if (t->incoming_stream_id != 0) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Settings frame received for grpc_chttp2_stream");
   }
 
-  grpc_error* err = grpc_chttp2_settings_parser_begin_frame(
+  grpc_error_handle err = grpc_chttp2_settings_parser_begin_frame(
       &t->simple.settings, t->incoming_frame_size, t->incoming_frame_flags,
       t->settings[GRPC_PEER_SETTINGS]);
   if (err != GRPC_ERROR_NONE) {
@@ -755,17 +762,17 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* parse_frame_slice(grpc_chttp2_transport* t,
-                                     const grpc_slice& slice, int is_last) {
+static grpc_error_handle parse_frame_slice(grpc_chttp2_transport* t,
+                                           const grpc_slice& slice,
+                                           int is_last) {
   grpc_chttp2_stream* s = t->incoming_stream;
-  grpc_error* err = t->parser(t->parser_data, t, s, slice, is_last);
+  grpc_error_handle err = t->parser(t->parser_data, t, s, slice, is_last);
   intptr_t unused;
   if (GPR_LIKELY(err == GRPC_ERROR_NONE)) {
     return err;
   } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, &unused)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
-      const char* msg = grpc_error_string(err);
-      gpr_log(GPR_ERROR, "%s", msg);
+      gpr_log(GPR_ERROR, "%s", grpc_error_std_string(err).c_str());
     }
     grpc_chttp2_parsing_become_skip_parser(t);
     if (s) {
diff --git a/grpc/src/core/ext/transport/chttp2/transport/writing.cc b/grpc/src/core/ext/transport/chttp2/transport/writing.cc
index 317afcc..e34856c 100644
--- a/grpc/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/grpc/src/core/ext/transport/chttp2/transport/writing.cc
@@ -39,7 +39,7 @@
 }
 
 static void finish_write_cb(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
-                            grpc_chttp2_write_cb* cb, grpc_error* error) {
+                            grpc_chttp2_write_cb* cb, grpc_error_handle error) {
   grpc_chttp2_complete_closure_step(t, s, &cb->closure, error,
                                     "finish_write_cb");
   cb->next = t->write_cb_pool;
@@ -75,6 +75,10 @@
     }
     return;
   }
+  // InvalidateNow to avoid getting stuck re-initializing the ping timer
+  // in a loop while draining the currently-held combiner. Also see
+  // https://github.com/grpc/grpc/issues/26079.
+  grpc_core::ExecCtx::Get()->InvalidateNow();
   grpc_millis now = grpc_core::ExecCtx::Get()->Now();
 
   grpc_millis next_allowed_ping_interval =
@@ -134,7 +138,7 @@
 
 static bool update_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
                         int64_t send_bytes, grpc_chttp2_write_cb** list,
-                        int64_t* ctr, grpc_error* error) {
+                        int64_t* ctr, grpc_error_handle error) {
   bool sched_any = false;
   grpc_chttp2_write_cb* cb = *list;
   *list = nullptr;
@@ -678,7 +682,7 @@
   return ctx.Result();
 }
 
-void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error* error) {
+void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error_handle error) {
   GPR_TIMER_SCOPE("grpc_chttp2_end_write", 0);
   grpc_chttp2_stream* s;
 
diff --git a/grpc/src/core/ext/transport/cronet/BUILD b/grpc/src/core/ext/transport/cronet/BUILD
index 51865d3..9c5848b 100644
--- a/grpc/src/core/ext/transport/cronet/BUILD
+++ b/grpc/src/core/ext/transport/cronet/BUILD
@@ -33,7 +33,7 @@
     name = "grpc_transport_cronet_client_secure",
     srcs = [
         "client/secure/cronet_channel_create.cc",
-        "transport/cronet_api_dummy.cc",
+        "transport/cronet_api_phony.cc",
         "transport/cronet_status.cc",
         "transport/cronet_status.h",
         "transport/cronet_transport.cc",
diff --git a/grpc/src/core/ext/transport/cronet/transport/cronet_api_dummy.cc b/grpc/src/core/ext/transport/cronet/transport/cronet_api_dummy.cc
deleted file mode 100644
index 1a6bded..0000000
--- a/grpc/src/core/ext/transport/cronet/transport/cronet_api_dummy.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/* This file has empty implementation of all the functions exposed by the cronet
-library, so we can build it in all environments */
-
-#include <grpc/support/port_platform.h>
-
-#include <stdbool.h>
-
-#include <grpc/support/log.h>
-
-#include "third_party/objective_c/Cronet/bidirectional_stream_c.h"
-
-#ifdef GRPC_COMPILE_WITH_CRONET
-/* link with the real CRONET library in the build system */
-#else
-/* Dummy implementation of cronet API just to test for build-ability */
-bidirectional_stream* bidirectional_stream_create(
-    stream_engine* engine, void* annotation,
-    bidirectional_stream_callback* callback) {
-  GPR_ASSERT(0);
-  return nullptr;
-}
-
-int bidirectional_stream_destroy(bidirectional_stream* stream) {
-  GPR_ASSERT(0);
-  return 0;
-}
-
-int bidirectional_stream_start(bidirectional_stream* stream, const char* url,
-                               int priority, const char* method,
-                               const bidirectional_stream_header_array* headers,
-                               bool end_of_stream) {
-  GPR_ASSERT(0);
-  return 0;
-}
-
-int bidirectional_stream_read(bidirectional_stream* stream, char* buffer,
-                              int capacity) {
-  GPR_ASSERT(0);
-  return 0;
-}
-
-int bidirectional_stream_write(bidirectional_stream* stream, const char* buffer,
-                               int count, bool end_of_stream) {
-  GPR_ASSERT(0);
-  return 0;
-}
-
-void bidirectional_stream_cancel(bidirectional_stream* stream) {
-  GPR_ASSERT(0);
-}
-
-void bidirectional_stream_disable_auto_flush(bidirectional_stream* stream,
-                                             bool disable_auto_flush) {
-  GPR_ASSERT(0);
-}
-
-void bidirectional_stream_delay_request_headers_until_flush(
-    bidirectional_stream* stream, bool delay_headers_until_flush) {
-  GPR_ASSERT(0);
-}
-
-void bidirectional_stream_flush(bidirectional_stream* stream) { GPR_ASSERT(0); }
-
-#endif /* GRPC_COMPILE_WITH_CRONET */
diff --git a/grpc/src/core/ext/transport/cronet/transport/cronet_api_phony.cc b/grpc/src/core/ext/transport/cronet/transport/cronet_api_phony.cc
new file mode 100644
index 0000000..3063d06
--- /dev/null
+++ b/grpc/src/core/ext/transport/cronet/transport/cronet_api_phony.cc
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* This file has empty implementation of all the functions exposed by the cronet
+library, so we can build it in all environments */
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include <grpc/support/log.h>
+
+#include "third_party/objective_c/Cronet/bidirectional_stream_c.h"
+
+#ifdef GRPC_COMPILE_WITH_CRONET
+/* link with the real CRONET library in the build system */
+#else
+/* Phony implementation of cronet API just to test for build-ability */
+bidirectional_stream* bidirectional_stream_create(
+    stream_engine* /*engine*/, void* /*annotation*/,
+    bidirectional_stream_callback* /*callback*/) {
+  GPR_ASSERT(0);
+  return nullptr;
+}
+
+int bidirectional_stream_destroy(bidirectional_stream* /*stream*/) {
+  GPR_ASSERT(0);
+  return 0;
+}
+
+int bidirectional_stream_start(
+    bidirectional_stream* /*stream*/, const char* /*url*/, int /*priority*/,
+    const char* /*method*/,
+    const bidirectional_stream_header_array* /*headers*/,
+    bool /*end_of_stream*/) {
+  GPR_ASSERT(0);
+  return 0;
+}
+
+int bidirectional_stream_read(bidirectional_stream* /*stream*/,
+                              char* /*buffer*/, int /*capacity*/) {
+  GPR_ASSERT(0);
+  return 0;
+}
+
+int bidirectional_stream_write(bidirectional_stream* /*stream*/,
+                               const char* /*buffer*/, int /*count*/,
+                               bool /*end_of_stream*/) {
+  GPR_ASSERT(0);
+  return 0;
+}
+
+void bidirectional_stream_cancel(bidirectional_stream* /*stream*/) {
+  GPR_ASSERT(0);
+}
+
+void bidirectional_stream_disable_auto_flush(bidirectional_stream* /*stream*/,
+                                             bool /*disable_auto_flush*/) {
+  GPR_ASSERT(0);
+}
+
+void bidirectional_stream_delay_request_headers_until_flush(
+    bidirectional_stream* /*stream*/, bool /*delay_headers_until_flush*/) {
+  GPR_ASSERT(0);
+}
+
+void bidirectional_stream_flush(bidirectional_stream* /*stream*/) {
+  GPR_ASSERT(0);
+}
+
+#endif /* GRPC_COMPILE_WITH_CRONET */
diff --git a/grpc/src/core/ext/transport/cronet/transport/cronet_status.cc b/grpc/src/core/ext/transport/cronet/transport/cronet_status.cc
index f904aee..9c047b3 100644
--- a/grpc/src/core/ext/transport/cronet/transport/cronet_status.cc
+++ b/grpc/src/core/ext/transport/cronet/transport/cronet_status.cc
@@ -491,3 +491,37 @@
   }
   return "UNAVAILABLE.";
 }
+
+grpc_status_code cronet_net_error_to_grpc_error(
+    cronet_net_error_code net_error) {
+  switch (net_error) {
+    case OK:
+      return GRPC_STATUS_OK;
+    case CRONET_NET_ERROR_ABORTED:
+      return GRPC_STATUS_ABORTED;
+    case CRONET_NET_ERROR_ACCESS_DENIED:
+    case CRONET_NET_ERROR_NETWORK_ACCESS_DENIED:
+      return GRPC_STATUS_PERMISSION_DENIED;
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_CERT_NEEDED:
+    case CRONET_NET_ERROR_PROXY_AUTH_UNSUPPORTED:
+    case CRONET_NET_ERROR_BAD_SSL_CLIENT_AUTH_CERT:
+    case CRONET_NET_ERROR_PROXY_AUTH_REQUESTED:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
+    case CRONET_NET_ERROR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT:
+    case CRONET_NET_ERROR_SSL_CLIENT_AUTH_NO_COMMON_ALGORITHMS:
+    case CRONET_NET_ERROR_CERT_AUTHORITY_INVALID:
+    case CRONET_NET_ERROR_UNEXPECTED_PROXY_AUTH:
+    case CRONET_NET_ERROR_MALFORMED_IDENTITY:
+    case CRONET_NET_ERROR_INVALID_AUTH_CREDENTIALS:
+    case CRONET_NET_ERROR_UNSUPPORTED_AUTH_SCHEME:
+    case CRONET_NET_ERROR_MISSING_AUTH_CREDENTIALS:
+      return GRPC_STATUS_UNAUTHENTICATED;
+    default:
+      return GRPC_STATUS_UNAVAILABLE;
+  }
+
+  return GRPC_STATUS_UNAVAILABLE;
+}
diff --git a/grpc/src/core/ext/transport/cronet/transport/cronet_status.h b/grpc/src/core/ext/transport/cronet/transport/cronet_status.h
index d6d1ed8..ee1262a 100644
--- a/grpc/src/core/ext/transport/cronet/transport/cronet_status.h
+++ b/grpc/src/core/ext/transport/cronet/transport/cronet_status.h
@@ -21,6 +21,8 @@
 
 #include <grpc/impl/codegen/port_platform.h>
 
+#include <grpc/status.h>
+
 enum cronet_net_error_code {
   //
   // Ranges:
@@ -1037,5 +1039,7 @@
 };
 
 const char* cronet_net_error_as_string(cronet_net_error_code net_error);
+grpc_status_code cronet_net_error_to_grpc_error(
+    cronet_net_error_code net_error);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CRONET_TRANSPORT_CRONET_STATUS_H */
diff --git a/grpc/src/core/ext/transport/cronet/transport/cronet_transport.cc b/grpc/src/core/ext/transport/cronet/transport/cronet_transport.cc
index b98b6a1..061b2e0 100644
--- a/grpc/src/core/ext/transport/cronet/transport/cronet_transport.cc
+++ b/grpc/src/core/ext/transport/cronet/transport/cronet_transport.cc
@@ -165,7 +165,7 @@
   /* User requested RECV_TRAILING_METADATA */
   bool pending_recv_trailing_metadata = false;
   cronet_net_error_code net_error = OK;
-  grpc_error* cancel_error = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_error = GRPC_ERROR_NONE;
   /* data structure for storing data coming from server */
   struct read_state rs;
   /* data structure for storing data going to the server */
@@ -306,13 +306,13 @@
                             s->state.rs.remaining_bytes);
 }
 
-static grpc_error* make_error_with_desc(int error_code,
-                                        int cronet_internal_error_code,
-                                        const char* desc) {
+static grpc_error_handle make_error_with_desc(int error_code,
+                                              int cronet_internal_error_code,
+                                              const char* desc) {
   std::string error_message =
       absl::StrFormat("Cronet error code:%d, Cronet error detail:%s",
                       cronet_internal_error_code, desc);
-  grpc_error* error =
+  grpc_error_handle error =
       GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_message.c_str());
   error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, error_code);
   return error;
@@ -1200,7 +1200,7 @@
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       oas->state.state_op_done[OP_RECV_MESSAGE] = true;
       result = ACTION_TAKEN_NO_CALLBACK;
-    } else if (stream_state->rs.read_stream_closed == true) {
+    } else if (stream_state->rs.read_stream_closed) {
       /* No more data will be received */
       CRONET_LOG(GPR_DEBUG, "read stream closed");
       grpc_core::ExecCtx::Run(
@@ -1217,7 +1217,7 @@
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       oas->state.state_op_done[OP_RECV_MESSAGE] = true;
       result = ACTION_TAKEN_NO_CALLBACK;
-    } else if (stream_state->rs.length_field_received == false) {
+    } else if (!stream_state->rs.length_field_received) {
       if (stream_state->rs.received_bytes == GRPC_HEADER_SIZE_IN_BYTES &&
           stream_state->rs.remaining_bytes == 0) {
         /* Start a read operation for data */
@@ -1317,13 +1317,15 @@
              op_can_be_run(stream_op, s, &oas->state,
                            OP_RECV_TRAILING_METADATA)) {
     CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_TRAILING_METADATA", oas);
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
       error = GRPC_ERROR_REF(stream_state->cancel_error);
     } else if (stream_state->state_callback_received[OP_FAILED]) {
+      grpc_status_code grpc_error_code =
+          cronet_net_error_to_grpc_error(stream_state->net_error);
       const char* desc = cronet_net_error_as_string(stream_state->net_error);
-      error = make_error_with_desc(GRPC_STATUS_UNAVAILABLE,
-                                   stream_state->net_error, desc);
+      error =
+          make_error_with_desc(grpc_error_code, stream_state->net_error, desc);
     } else if (oas->s->state.rs.trailing_metadata_valid) {
       grpc_chttp2_incoming_metadata_buffer_publish(
           &oas->s->state.rs.trailing_metadata,
@@ -1362,10 +1364,12 @@
       if (stream_op->on_complete) {
         const char* error_message =
             cronet_net_error_as_string(stream_state->net_error);
+        grpc_status_code grpc_error_code =
+            cronet_net_error_to_grpc_error(stream_state->net_error);
         grpc_core::ExecCtx::Run(
             DEBUG_LOCATION, stream_op->on_complete,
-            make_error_with_desc(GRPC_STATUS_UNAVAILABLE,
-                                 stream_state->net_error, error_message));
+            make_error_with_desc(grpc_error_code, stream_state->net_error,
+                                 error_message));
       }
     } else {
       /* All actions in this stream_op are complete. Call the on_complete
@@ -1420,19 +1424,20 @@
 }
 
 static int init_stream(grpc_transport* gt, grpc_stream* gs,
-                       grpc_stream_refcount* refcount, const void* server_data,
-                       grpc_core::Arena* arena) {
+                       grpc_stream_refcount* refcount,
+                       const void* /*server_data*/, grpc_core::Arena* arena) {
   new (gs) stream_obj(gt, gs, refcount, arena);
   return 0;
 }
 
-static void set_pollset_do_nothing(grpc_transport* gt, grpc_stream* gs,
-                                   grpc_pollset* pollset) {}
+static void set_pollset_do_nothing(grpc_transport* /*gt*/, grpc_stream* /*gs*/,
+                                   grpc_pollset* /*pollset*/) {}
 
-static void set_pollset_set_do_nothing(grpc_transport* gt, grpc_stream* gs,
-                                       grpc_pollset_set* pollset_set) {}
+static void set_pollset_set_do_nothing(grpc_transport* /*gt*/,
+                                       grpc_stream* /*gs*/,
+                                       grpc_pollset_set* /*pollset_set*/) {}
 
-static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
+static void perform_stream_op(grpc_transport* /*gt*/, grpc_stream* gs,
                               grpc_transport_stream_op_batch* op) {
   CRONET_LOG(GPR_DEBUG, "perform_stream_op");
   if (op->send_initial_metadata &&
@@ -1466,7 +1471,7 @@
   execute_from_storage(s);
 }
 
-static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
+static void destroy_stream(grpc_transport* /*gt*/, grpc_stream* gs,
                            grpc_closure* then_schedule_closure) {
   stream_obj* s = reinterpret_cast<stream_obj*>(gs);
   s->~stream_obj();
@@ -1474,11 +1479,11 @@
                           GRPC_ERROR_NONE);
 }
 
-static void destroy_transport(grpc_transport* gt) {}
+static void destroy_transport(grpc_transport* /*gt*/) {}
 
-static grpc_endpoint* get_endpoint(grpc_transport* gt) { return nullptr; }
+static grpc_endpoint* get_endpoint(grpc_transport* /*gt*/) { return nullptr; }
 
-static void perform_op(grpc_transport* gt, grpc_transport_op* op) {}
+static void perform_op(grpc_transport* /*gt*/, grpc_transport_op* /*op*/) {}
 
 static const grpc_transport_vtable grpc_cronet_vtable = {
     sizeof(stream_obj),
@@ -1494,7 +1499,7 @@
 
 grpc_transport* grpc_create_cronet_transport(void* engine, const char* target,
                                              const grpc_channel_args* args,
-                                             void* reserved) {
+                                             void* /*reserved*/) {
   grpc_cronet_transport* ct = static_cast<grpc_cronet_transport*>(
       gpr_malloc(sizeof(grpc_cronet_transport)));
   if (!ct) {
diff --git a/grpc/src/core/ext/transport/inproc/inproc_transport.cc b/grpc/src/core/ext/transport/inproc/inproc_transport.cc
index 213c142..0c21db7 100644
--- a/grpc/src/core/ext/transport/inproc/inproc_transport.cc
+++ b/grpc/src/core/ext/transport/inproc/inproc_transport.cc
@@ -50,15 +50,15 @@
 grpc_slice g_fake_auth_value;
 
 struct inproc_stream;
-bool cancel_stream_locked(inproc_stream* s, grpc_error* error);
-void maybe_process_ops_locked(inproc_stream* s, grpc_error* error);
-void op_state_machine_locked(inproc_stream* s, grpc_error* error);
+bool cancel_stream_locked(inproc_stream* s, grpc_error_handle error);
+void maybe_process_ops_locked(inproc_stream* s, grpc_error_handle error);
+void op_state_machine_locked(inproc_stream* s, grpc_error_handle error);
 void log_metadata(const grpc_metadata_batch* md_batch, bool is_client,
                   bool is_initial);
-grpc_error* fill_in_metadata(inproc_stream* s,
-                             const grpc_metadata_batch* metadata,
-                             uint32_t flags, grpc_metadata_batch* out_md,
-                             uint32_t* outflags, bool* markfilled);
+grpc_error_handle fill_in_metadata(inproc_stream* s,
+                                   const grpc_metadata_batch* metadata,
+                                   uint32_t flags, grpc_metadata_batch* out_md,
+                                   uint32_t* outflags, bool* markfilled);
 
 struct shared_mu {
   shared_mu() {
@@ -239,7 +239,7 @@
   grpc_millis write_buffer_deadline = GRPC_MILLIS_INF_FUTURE;
   grpc_metadata_batch write_buffer_trailing_md;
   bool write_buffer_trailing_md_filled = false;
-  grpc_error* write_buffer_cancel_error = GRPC_ERROR_NONE;
+  grpc_error_handle write_buffer_cancel_error = GRPC_ERROR_NONE;
 
   struct inproc_stream* other_side;
   bool other_side_closed = false;               // won't talk anymore
@@ -270,8 +270,8 @@
 
   bool closed = false;
 
-  grpc_error* cancel_self_error = GRPC_ERROR_NONE;
-  grpc_error* cancel_other_error = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_self_error = GRPC_ERROR_NONE;
+  grpc_error_handle cancel_other_error = GRPC_ERROR_NONE;
 
   grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
 
@@ -293,10 +293,10 @@
   }
 }
 
-grpc_error* fill_in_metadata(inproc_stream* s,
-                             const grpc_metadata_batch* metadata,
-                             uint32_t flags, grpc_metadata_batch* out_md,
-                             uint32_t* outflags, bool* markfilled) {
+grpc_error_handle fill_in_metadata(inproc_stream* s,
+                                   const grpc_metadata_batch* metadata,
+                                   uint32_t flags, grpc_metadata_batch* out_md,
+                                   uint32_t* outflags, bool* markfilled) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_inproc_trace)) {
     log_metadata(metadata, s->t->is_client, outflags != nullptr);
   }
@@ -307,7 +307,7 @@
   if (markfilled != nullptr) {
     *markfilled = true;
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   for (grpc_linked_mdelem* elem = metadata->list.head;
        (elem != nullptr) && (error == GRPC_ERROR_NONE); elem = elem->next) {
     grpc_linked_mdelem* nelem =
@@ -374,7 +374,7 @@
 // this stream_op_batch is only one of the pending operations for this
 // stream. This is called when one of the pending operations for the stream
 // is done and about to be NULLed out
-void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error,
+void complete_if_batch_end_locked(inproc_stream* s, grpc_error_handle error,
                                   grpc_transport_stream_op_batch* op,
                                   const char* msg) {
   int is_sm = static_cast<int>(op == s->send_message_op);
@@ -394,14 +394,14 @@
   }
 }
 
-void maybe_process_ops_locked(inproc_stream* s, grpc_error* error) {
+void maybe_process_ops_locked(inproc_stream* s, grpc_error_handle error) {
   if (s && (error != GRPC_ERROR_NONE || s->ops_needed)) {
     s->ops_needed = false;
     op_state_machine_locked(s, error);
   }
 }
 
-void fail_helper_locked(inproc_stream* s, grpc_error* error) {
+void fail_helper_locked(inproc_stream* s, grpc_error_handle error) {
   INPROC_LOG(GPR_INFO, "op_state_machine %p fail_helper", s);
   // If we're failing this side, we need to make sure that
   // we also send or have already sent trailing metadata
@@ -431,7 +431,7 @@
     }
   }
   if (s->recv_initial_md_op) {
-    grpc_error* err;
+    grpc_error_handle err;
     if (!s->t->is_client) {
       // If this is a server, provide initial metadata with a path and authority
       // since it expects that as well as no error yet
@@ -550,7 +550,7 @@
     GPR_ASSERT(
         sender->send_message_op->payload->send_message.send_message->Next(
             SIZE_MAX, &unused));
-    grpc_error* error =
+    grpc_error_handle error =
         sender->send_message_op->payload->send_message.send_message->Pull(
             &message_slice);
     if (error != GRPC_ERROR_NONE) {
@@ -583,13 +583,13 @@
   sender->send_message_op = nullptr;
 }
 
-void op_state_machine_locked(inproc_stream* s, grpc_error* error) {
+void op_state_machine_locked(inproc_stream* s, grpc_error_handle error) {
   // This function gets called when we have contents in the unprocessed reads
   // Get what we want based on our ops wanted
   // Schedule our appropriate closures
   // and then return to ops_needed state if still needed
 
-  grpc_error* new_err = GRPC_ERROR_NONE;
+  grpc_error_handle new_err = GRPC_ERROR_NONE;
 
   bool needs_close = false;
 
@@ -887,9 +887,10 @@
   GRPC_ERROR_UNREF(new_err);
 }
 
-bool cancel_stream_locked(inproc_stream* s, grpc_error* error) {
+bool cancel_stream_locked(inproc_stream* s, grpc_error_handle error) {
   bool ret = false;  // was the cancel accepted
-  INPROC_LOG(GPR_INFO, "cancel_stream %p with %s", s, grpc_error_string(error));
+  INPROC_LOG(GPR_INFO, "cancel_stream %p with %s", s,
+             grpc_error_std_string(error).c_str());
   if (s->cancel_self_error == GRPC_ERROR_NONE) {
     ret = true;
     s->cancel_self_error = GRPC_ERROR_REF(error);
@@ -943,7 +944,7 @@
   return ret;
 }
 
-void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
                        grpc_transport_stream_op_batch* op) {
@@ -962,7 +963,7 @@
                    s->t->is_client, false);
     }
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_closure* on_complete = op->on_complete;
   // TODO(roth): This is a hack needed because we use data inside of the
   // closure itself to do the barrier calculation (i.e., to ensure that
@@ -1293,7 +1294,7 @@
                            client_args);
 
   // TODO(ncteisen): design and support channelz GetSocket for inproc.
-  grpc_error* error = server->core_server->SetupTransport(
+  grpc_error_handle error = server->core_server->SetupTransport(
       server_transport, nullptr, server_args, nullptr);
   grpc_channel* channel = nullptr;
   if (error == GRPC_ERROR_NONE) {
@@ -1303,7 +1304,7 @@
     if (error != GRPC_ERROR_NONE) {
       GPR_ASSERT(!channel);
       gpr_log(GPR_ERROR, "Failed to create client channel: %s",
-              grpc_error_string(error));
+              grpc_error_std_string(error).c_str());
       intptr_t integer;
       grpc_status_code status = GRPC_STATUS_INTERNAL;
       if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &integer)) {
@@ -1318,7 +1319,7 @@
   } else {
     GPR_ASSERT(!channel);
     gpr_log(GPR_ERROR, "Failed to create server channel: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     intptr_t integer;
     grpc_status_code status = GRPC_STATUS_INTERNAL;
     if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &integer)) {
diff --git a/grpc/src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c b/grpc/src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c
new file mode 100644
index 0000000..d230ccb
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c
@@ -0,0 +1,406 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/admin/v3/config_dump.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/admin/v3/config_dump.upb.h"
+#include "envoy/config/bootstrap/v3/bootstrap.upb.h"
+#include "google/protobuf/any.upb.h"
+#include "google/protobuf/timestamp.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_admin_v3_ConfigDump_submsgs[1] = {
+  &google_protobuf_Any_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ConfigDump__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_admin_v3_ConfigDump_msginit = {
+  &envoy_admin_v3_ConfigDump_submsgs[0],
+  &envoy_admin_v3_ConfigDump__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_UpdateFailureState_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_UpdateFailureState__fields[4] = {
+  {1, UPB_SIZE(20, 40), 1, 0, 11, 1},
+  {2, UPB_SIZE(24, 48), 2, 1, 11, 1},
+  {3, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {4, UPB_SIZE(12, 24), 0, 0, 9, 1},
+};
+
+const upb_msglayout envoy_admin_v3_UpdateFailureState_msginit = {
+  &envoy_admin_v3_UpdateFailureState_submsgs[0],
+  &envoy_admin_v3_UpdateFailureState__fields[0],
+  UPB_SIZE(32, 64), 4, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_BootstrapConfigDump_submsgs[2] = {
+  &envoy_config_bootstrap_v3_Bootstrap_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_BootstrapConfigDump__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 2, 1, 11, 1},
+};
+
+const upb_msglayout envoy_admin_v3_BootstrapConfigDump_msginit = {
+  &envoy_admin_v3_BootstrapConfigDump_submsgs[0],
+  &envoy_admin_v3_BootstrapConfigDump__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ListenersConfigDump_submsgs[2] = {
+  &envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit,
+  &envoy_admin_v3_ListenersConfigDump_StaticListener_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ListenersConfigDump__fields[3] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), 0, 1, 11, 3},
+  {3, UPB_SIZE(12, 24), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_admin_v3_ListenersConfigDump_msginit = {
+  &envoy_admin_v3_ListenersConfigDump_submsgs[0],
+  &envoy_admin_v3_ListenersConfigDump__fields[0],
+  UPB_SIZE(16, 32), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ListenersConfigDump_StaticListener_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ListenersConfigDump_StaticListener__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 2, 1, 11, 1},
+};
+
+const upb_msglayout envoy_admin_v3_ListenersConfigDump_StaticListener_msginit = {
+  &envoy_admin_v3_ListenersConfigDump_StaticListener_submsgs[0],
+  &envoy_admin_v3_ListenersConfigDump_StaticListener__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ListenersConfigDump_DynamicListenerState_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ListenersConfigDump_DynamicListenerState__fields[3] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 1, 0, 11, 1},
+  {3, UPB_SIZE(16, 32), 2, 1, 11, 1},
+};
+
+const upb_msglayout envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit = {
+  &envoy_admin_v3_ListenersConfigDump_DynamicListenerState_submsgs[0],
+  &envoy_admin_v3_ListenersConfigDump_DynamicListenerState__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ListenersConfigDump_DynamicListener_submsgs[2] = {
+  &envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit,
+  &envoy_admin_v3_UpdateFailureState_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ListenersConfigDump_DynamicListener__fields[6] = {
+  {1, UPB_SIZE(8, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(16, 24), 1, 0, 11, 1},
+  {3, UPB_SIZE(20, 32), 2, 0, 11, 1},
+  {4, UPB_SIZE(24, 40), 3, 0, 11, 1},
+  {5, UPB_SIZE(28, 48), 4, 1, 11, 1},
+  {6, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit = {
+  &envoy_admin_v3_ListenersConfigDump_DynamicListener_submsgs[0],
+  &envoy_admin_v3_ListenersConfigDump_DynamicListener__fields[0],
+  UPB_SIZE(32, 64), 6, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ClustersConfigDump_submsgs[2] = {
+  &envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit,
+  &envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ClustersConfigDump__fields[4] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), 0, 1, 11, 3},
+  {3, UPB_SIZE(12, 24), 0, 0, 11, 3},
+  {4, UPB_SIZE(16, 32), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_admin_v3_ClustersConfigDump_msginit = {
+  &envoy_admin_v3_ClustersConfigDump_submsgs[0],
+  &envoy_admin_v3_ClustersConfigDump__fields[0],
+  UPB_SIZE(24, 48), 4, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ClustersConfigDump_StaticCluster_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ClustersConfigDump_StaticCluster__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 2, 1, 11, 1},
+};
+
+const upb_msglayout envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit = {
+  &envoy_admin_v3_ClustersConfigDump_StaticCluster_submsgs[0],
+  &envoy_admin_v3_ClustersConfigDump_StaticCluster__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ClustersConfigDump_DynamicCluster_submsgs[3] = {
+  &envoy_admin_v3_UpdateFailureState_msginit,
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ClustersConfigDump_DynamicCluster__fields[5] = {
+  {1, UPB_SIZE(8, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(16, 24), 1, 1, 11, 1},
+  {3, UPB_SIZE(20, 32), 2, 2, 11, 1},
+  {4, UPB_SIZE(24, 40), 3, 0, 11, 1},
+  {5, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit = {
+  &envoy_admin_v3_ClustersConfigDump_DynamicCluster_submsgs[0],
+  &envoy_admin_v3_ClustersConfigDump_DynamicCluster__fields[0],
+  UPB_SIZE(32, 48), 5, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_RoutesConfigDump_submsgs[2] = {
+  &envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit,
+  &envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_RoutesConfigDump__fields[2] = {
+  {2, UPB_SIZE(0, 0), 0, 1, 11, 3},
+  {3, UPB_SIZE(4, 8), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_admin_v3_RoutesConfigDump_msginit = {
+  &envoy_admin_v3_RoutesConfigDump_submsgs[0],
+  &envoy_admin_v3_RoutesConfigDump__fields[0],
+  UPB_SIZE(8, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_RoutesConfigDump_StaticRouteConfig__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 2, 1, 11, 1},
+};
+
+const upb_msglayout envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit = {
+  &envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_submsgs[0],
+  &envoy_admin_v3_RoutesConfigDump_StaticRouteConfig__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_submsgs[3] = {
+  &envoy_admin_v3_UpdateFailureState_msginit,
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig__fields[5] = {
+  {1, UPB_SIZE(8, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(16, 24), 1, 1, 11, 1},
+  {3, UPB_SIZE(20, 32), 2, 2, 11, 1},
+  {4, UPB_SIZE(24, 40), 3, 0, 11, 1},
+  {5, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit = {
+  &envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_submsgs[0],
+  &envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig__fields[0],
+  UPB_SIZE(32, 48), 5, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ScopedRoutesConfigDump_submsgs[2] = {
+  &envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit,
+  &envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ScopedRoutesConfigDump__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 1, 11, 3},
+  {2, UPB_SIZE(4, 8), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_msginit = {
+  &envoy_admin_v3_ScopedRoutesConfigDump_submsgs[0],
+  &envoy_admin_v3_ScopedRoutesConfigDump__fields[0],
+  UPB_SIZE(8, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs__fields[3] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(16, 32), 0, 0, 11, 3},
+  {3, UPB_SIZE(12, 24), 1, 1, 11, 1},
+};
+
+const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit = {
+  &envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_submsgs[0],
+  &envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_submsgs[3] = {
+  &envoy_admin_v3_UpdateFailureState_msginit,
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs__fields[6] = {
+  {1, UPB_SIZE(8, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(16, 24), 0, 0, 9, 1},
+  {3, UPB_SIZE(32, 56), 0, 1, 11, 3},
+  {4, UPB_SIZE(24, 40), 1, 2, 11, 1},
+  {5, UPB_SIZE(28, 48), 2, 0, 11, 1},
+  {6, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit = {
+  &envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_submsgs[0],
+  &envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs__fields[0],
+  UPB_SIZE(40, 64), 6, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_SecretsConfigDump_submsgs[2] = {
+  &envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit,
+  &envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_SecretsConfigDump__fields[3] = {
+  {1, UPB_SIZE(0, 0), 0, 1, 11, 3},
+  {2, UPB_SIZE(4, 8), 0, 0, 11, 3},
+  {3, UPB_SIZE(8, 16), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_admin_v3_SecretsConfigDump_msginit = {
+  &envoy_admin_v3_SecretsConfigDump_submsgs[0],
+  &envoy_admin_v3_SecretsConfigDump__fields[0],
+  UPB_SIZE(16, 24), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_SecretsConfigDump_DynamicSecret_submsgs[3] = {
+  &envoy_admin_v3_UpdateFailureState_msginit,
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_SecretsConfigDump_DynamicSecret__fields[6] = {
+  {1, UPB_SIZE(8, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(16, 24), 0, 0, 9, 1},
+  {3, UPB_SIZE(24, 40), 1, 2, 11, 1},
+  {4, UPB_SIZE(28, 48), 2, 1, 11, 1},
+  {5, UPB_SIZE(32, 56), 3, 0, 11, 1},
+  {6, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit = {
+  &envoy_admin_v3_SecretsConfigDump_DynamicSecret_submsgs[0],
+  &envoy_admin_v3_SecretsConfigDump_DynamicSecret__fields[0],
+  UPB_SIZE(40, 64), 6, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_SecretsConfigDump_StaticSecret_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_SecretsConfigDump_StaticSecret__fields[3] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 1, 1, 11, 1},
+  {3, UPB_SIZE(16, 32), 2, 0, 11, 1},
+};
+
+const upb_msglayout envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit = {
+  &envoy_admin_v3_SecretsConfigDump_StaticSecret_submsgs[0],
+  &envoy_admin_v3_SecretsConfigDump_StaticSecret__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_EndpointsConfigDump_submsgs[2] = {
+  &envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit,
+  &envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_EndpointsConfigDump__fields[2] = {
+  {2, UPB_SIZE(0, 0), 0, 1, 11, 3},
+  {3, UPB_SIZE(4, 8), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_admin_v3_EndpointsConfigDump_msginit = {
+  &envoy_admin_v3_EndpointsConfigDump_submsgs[0],
+  &envoy_admin_v3_EndpointsConfigDump__fields[0],
+  UPB_SIZE(8, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 2, 1, 11, 1},
+};
+
+const upb_msglayout envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit = {
+  &envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_submsgs[0],
+  &envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_submsgs[3] = {
+  &envoy_admin_v3_UpdateFailureState_msginit,
+  &google_protobuf_Any_msginit,
+  &google_protobuf_Timestamp_msginit,
+};
+
+static const upb_msglayout_field envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig__fields[5] = {
+  {1, UPB_SIZE(8, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(16, 24), 1, 1, 11, 1},
+  {3, UPB_SIZE(20, 32), 2, 2, 11, 1},
+  {4, UPB_SIZE(24, 40), 3, 0, 11, 1},
+  {5, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit = {
+  &envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_submsgs[0],
+  &envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig__fields[0],
+  UPB_SIZE(32, 48), 5, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h b/grpc/src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h
new file mode 100644
index 0000000..6f117c6
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h
@@ -0,0 +1,1459 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/admin/v3/config_dump.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_ADMIN_V3_CONFIG_DUMP_PROTO_UPB_H_
+#define ENVOY_ADMIN_V3_CONFIG_DUMP_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_admin_v3_ConfigDump;
+struct envoy_admin_v3_UpdateFailureState;
+struct envoy_admin_v3_BootstrapConfigDump;
+struct envoy_admin_v3_ListenersConfigDump;
+struct envoy_admin_v3_ListenersConfigDump_StaticListener;
+struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState;
+struct envoy_admin_v3_ListenersConfigDump_DynamicListener;
+struct envoy_admin_v3_ClustersConfigDump;
+struct envoy_admin_v3_ClustersConfigDump_StaticCluster;
+struct envoy_admin_v3_ClustersConfigDump_DynamicCluster;
+struct envoy_admin_v3_RoutesConfigDump;
+struct envoy_admin_v3_RoutesConfigDump_StaticRouteConfig;
+struct envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig;
+struct envoy_admin_v3_ScopedRoutesConfigDump;
+struct envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs;
+struct envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs;
+struct envoy_admin_v3_SecretsConfigDump;
+struct envoy_admin_v3_SecretsConfigDump_DynamicSecret;
+struct envoy_admin_v3_SecretsConfigDump_StaticSecret;
+struct envoy_admin_v3_EndpointsConfigDump;
+struct envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig;
+struct envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig;
+typedef struct envoy_admin_v3_ConfigDump envoy_admin_v3_ConfigDump;
+typedef struct envoy_admin_v3_UpdateFailureState envoy_admin_v3_UpdateFailureState;
+typedef struct envoy_admin_v3_BootstrapConfigDump envoy_admin_v3_BootstrapConfigDump;
+typedef struct envoy_admin_v3_ListenersConfigDump envoy_admin_v3_ListenersConfigDump;
+typedef struct envoy_admin_v3_ListenersConfigDump_StaticListener envoy_admin_v3_ListenersConfigDump_StaticListener;
+typedef struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState envoy_admin_v3_ListenersConfigDump_DynamicListenerState;
+typedef struct envoy_admin_v3_ListenersConfigDump_DynamicListener envoy_admin_v3_ListenersConfigDump_DynamicListener;
+typedef struct envoy_admin_v3_ClustersConfigDump envoy_admin_v3_ClustersConfigDump;
+typedef struct envoy_admin_v3_ClustersConfigDump_StaticCluster envoy_admin_v3_ClustersConfigDump_StaticCluster;
+typedef struct envoy_admin_v3_ClustersConfigDump_DynamicCluster envoy_admin_v3_ClustersConfigDump_DynamicCluster;
+typedef struct envoy_admin_v3_RoutesConfigDump envoy_admin_v3_RoutesConfigDump;
+typedef struct envoy_admin_v3_RoutesConfigDump_StaticRouteConfig envoy_admin_v3_RoutesConfigDump_StaticRouteConfig;
+typedef struct envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig;
+typedef struct envoy_admin_v3_ScopedRoutesConfigDump envoy_admin_v3_ScopedRoutesConfigDump;
+typedef struct envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs;
+typedef struct envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs;
+typedef struct envoy_admin_v3_SecretsConfigDump envoy_admin_v3_SecretsConfigDump;
+typedef struct envoy_admin_v3_SecretsConfigDump_DynamicSecret envoy_admin_v3_SecretsConfigDump_DynamicSecret;
+typedef struct envoy_admin_v3_SecretsConfigDump_StaticSecret envoy_admin_v3_SecretsConfigDump_StaticSecret;
+typedef struct envoy_admin_v3_EndpointsConfigDump envoy_admin_v3_EndpointsConfigDump;
+typedef struct envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig;
+typedef struct envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig;
+extern const upb_msglayout envoy_admin_v3_ConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_UpdateFailureState_msginit;
+extern const upb_msglayout envoy_admin_v3_BootstrapConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_StaticListener_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit;
+extern const upb_msglayout envoy_admin_v3_ClustersConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit;
+extern const upb_msglayout envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit;
+extern const upb_msglayout envoy_admin_v3_RoutesConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit;
+extern const upb_msglayout envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit;
+extern const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit;
+extern const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit;
+extern const upb_msglayout envoy_admin_v3_SecretsConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit;
+extern const upb_msglayout envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit;
+extern const upb_msglayout envoy_admin_v3_EndpointsConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit;
+extern const upb_msglayout envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit;
+struct envoy_config_bootstrap_v3_Bootstrap;
+struct google_protobuf_Any;
+struct google_protobuf_Timestamp;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_msginit;
+extern const upb_msglayout google_protobuf_Any_msginit;
+extern const upb_msglayout google_protobuf_Timestamp_msginit;
+
+typedef enum {
+  envoy_admin_v3_UNKNOWN = 0,
+  envoy_admin_v3_REQUESTED = 1,
+  envoy_admin_v3_DOES_NOT_EXIST = 2,
+  envoy_admin_v3_ACKED = 3,
+  envoy_admin_v3_NACKED = 4
+} envoy_admin_v3_ClientResourceStatus;
+
+
+/* envoy.admin.v3.ConfigDump */
+
+UPB_INLINE envoy_admin_v3_ConfigDump *envoy_admin_v3_ConfigDump_new(upb_arena *arena) {
+  return (envoy_admin_v3_ConfigDump *)_upb_msg_new(&envoy_admin_v3_ConfigDump_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ConfigDump *envoy_admin_v3_ConfigDump_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ConfigDump *ret = envoy_admin_v3_ConfigDump_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ConfigDump_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ConfigDump *envoy_admin_v3_ConfigDump_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ConfigDump *ret = envoy_admin_v3_ConfigDump_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ConfigDump_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ConfigDump_serialize(const envoy_admin_v3_ConfigDump *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ConfigDump_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_ConfigDump_has_configs(const envoy_admin_v3_ConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const struct google_protobuf_Any* const* envoy_admin_v3_ConfigDump_configs(const envoy_admin_v3_ConfigDump *msg, size_t *len) { return (const struct google_protobuf_Any* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+
+UPB_INLINE struct google_protobuf_Any** envoy_admin_v3_ConfigDump_mutable_configs(envoy_admin_v3_ConfigDump *msg, size_t *len) {
+  return (struct google_protobuf_Any**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE struct google_protobuf_Any** envoy_admin_v3_ConfigDump_resize_configs(envoy_admin_v3_ConfigDump *msg, size_t len, upb_arena *arena) {
+  return (struct google_protobuf_Any**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_ConfigDump_add_configs(envoy_admin_v3_ConfigDump *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.admin.v3.UpdateFailureState */
+
+UPB_INLINE envoy_admin_v3_UpdateFailureState *envoy_admin_v3_UpdateFailureState_new(upb_arena *arena) {
+  return (envoy_admin_v3_UpdateFailureState *)_upb_msg_new(&envoy_admin_v3_UpdateFailureState_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_UpdateFailureState *envoy_admin_v3_UpdateFailureState_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_UpdateFailureState *ret = envoy_admin_v3_UpdateFailureState_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_UpdateFailureState_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_UpdateFailureState *envoy_admin_v3_UpdateFailureState_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_UpdateFailureState *ret = envoy_admin_v3_UpdateFailureState_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_UpdateFailureState_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_UpdateFailureState_serialize(const envoy_admin_v3_UpdateFailureState *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_UpdateFailureState_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_UpdateFailureState_has_failed_configuration(const envoy_admin_v3_UpdateFailureState *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_UpdateFailureState_failed_configuration(const envoy_admin_v3_UpdateFailureState *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_UpdateFailureState_has_last_update_attempt(const envoy_admin_v3_UpdateFailureState *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_UpdateFailureState_last_update_attempt(const envoy_admin_v3_UpdateFailureState *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), const struct google_protobuf_Timestamp*); }
+UPB_INLINE upb_strview envoy_admin_v3_UpdateFailureState_details(const envoy_admin_v3_UpdateFailureState *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_strview envoy_admin_v3_UpdateFailureState_version_info(const envoy_admin_v3_UpdateFailureState *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+
+UPB_INLINE void envoy_admin_v3_UpdateFailureState_set_failed_configuration(envoy_admin_v3_UpdateFailureState *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_UpdateFailureState_mutable_failed_configuration(envoy_admin_v3_UpdateFailureState *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_UpdateFailureState_failed_configuration(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_UpdateFailureState_set_failed_configuration(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_UpdateFailureState_set_last_update_attempt(envoy_admin_v3_UpdateFailureState *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 48), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_UpdateFailureState_mutable_last_update_attempt(envoy_admin_v3_UpdateFailureState *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_UpdateFailureState_last_update_attempt(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_UpdateFailureState_set_last_update_attempt(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_UpdateFailureState_set_details(envoy_admin_v3_UpdateFailureState *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_UpdateFailureState_set_version_info(envoy_admin_v3_UpdateFailureState *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+
+/* envoy.admin.v3.BootstrapConfigDump */
+
+UPB_INLINE envoy_admin_v3_BootstrapConfigDump *envoy_admin_v3_BootstrapConfigDump_new(upb_arena *arena) {
+  return (envoy_admin_v3_BootstrapConfigDump *)_upb_msg_new(&envoy_admin_v3_BootstrapConfigDump_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_BootstrapConfigDump *envoy_admin_v3_BootstrapConfigDump_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_BootstrapConfigDump *ret = envoy_admin_v3_BootstrapConfigDump_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_BootstrapConfigDump_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_BootstrapConfigDump *envoy_admin_v3_BootstrapConfigDump_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_BootstrapConfigDump *ret = envoy_admin_v3_BootstrapConfigDump_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_BootstrapConfigDump_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_BootstrapConfigDump_serialize(const envoy_admin_v3_BootstrapConfigDump *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_BootstrapConfigDump_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_BootstrapConfigDump_has_bootstrap(const envoy_admin_v3_BootstrapConfigDump *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_bootstrap_v3_Bootstrap* envoy_admin_v3_BootstrapConfigDump_bootstrap(const envoy_admin_v3_BootstrapConfigDump *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_config_bootstrap_v3_Bootstrap*); }
+UPB_INLINE bool envoy_admin_v3_BootstrapConfigDump_has_last_updated(const envoy_admin_v3_BootstrapConfigDump *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_BootstrapConfigDump_last_updated(const envoy_admin_v3_BootstrapConfigDump *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const struct google_protobuf_Timestamp*); }
+
+UPB_INLINE void envoy_admin_v3_BootstrapConfigDump_set_bootstrap(envoy_admin_v3_BootstrapConfigDump *msg, struct envoy_config_bootstrap_v3_Bootstrap* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_config_bootstrap_v3_Bootstrap*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Bootstrap* envoy_admin_v3_BootstrapConfigDump_mutable_bootstrap(envoy_admin_v3_BootstrapConfigDump *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Bootstrap* sub = (struct envoy_config_bootstrap_v3_Bootstrap*)envoy_admin_v3_BootstrapConfigDump_bootstrap(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_Bootstrap*)_upb_msg_new(&envoy_config_bootstrap_v3_Bootstrap_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_BootstrapConfigDump_set_bootstrap(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_BootstrapConfigDump_set_last_updated(envoy_admin_v3_BootstrapConfigDump *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_BootstrapConfigDump_mutable_last_updated(envoy_admin_v3_BootstrapConfigDump *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_BootstrapConfigDump_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_BootstrapConfigDump_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.admin.v3.ListenersConfigDump */
+
+UPB_INLINE envoy_admin_v3_ListenersConfigDump *envoy_admin_v3_ListenersConfigDump_new(upb_arena *arena) {
+  return (envoy_admin_v3_ListenersConfigDump *)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump *envoy_admin_v3_ListenersConfigDump_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ListenersConfigDump *ret = envoy_admin_v3_ListenersConfigDump_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ListenersConfigDump_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump *envoy_admin_v3_ListenersConfigDump_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ListenersConfigDump *ret = envoy_admin_v3_ListenersConfigDump_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ListenersConfigDump_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ListenersConfigDump_serialize(const envoy_admin_v3_ListenersConfigDump *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ListenersConfigDump_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_ListenersConfigDump_version_info(const envoy_admin_v3_ListenersConfigDump *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_has_static_listeners(const envoy_admin_v3_ListenersConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const envoy_admin_v3_ListenersConfigDump_StaticListener* const* envoy_admin_v3_ListenersConfigDump_static_listeners(const envoy_admin_v3_ListenersConfigDump *msg, size_t *len) { return (const envoy_admin_v3_ListenersConfigDump_StaticListener* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_has_dynamic_listeners(const envoy_admin_v3_ListenersConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); }
+UPB_INLINE const envoy_admin_v3_ListenersConfigDump_DynamicListener* const* envoy_admin_v3_ListenersConfigDump_dynamic_listeners(const envoy_admin_v3_ListenersConfigDump *msg, size_t *len) { return (const envoy_admin_v3_ListenersConfigDump_DynamicListener* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); }
+
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_set_version_info(envoy_admin_v3_ListenersConfigDump *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_StaticListener** envoy_admin_v3_ListenersConfigDump_mutable_static_listeners(envoy_admin_v3_ListenersConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_ListenersConfigDump_StaticListener**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_StaticListener** envoy_admin_v3_ListenersConfigDump_resize_static_listeners(envoy_admin_v3_ListenersConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_ListenersConfigDump_StaticListener**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_ListenersConfigDump_StaticListener* envoy_admin_v3_ListenersConfigDump_add_static_listeners(envoy_admin_v3_ListenersConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ListenersConfigDump_StaticListener* sub = (struct envoy_admin_v3_ListenersConfigDump_StaticListener*)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_StaticListener_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_DynamicListener** envoy_admin_v3_ListenersConfigDump_mutable_dynamic_listeners(envoy_admin_v3_ListenersConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_ListenersConfigDump_DynamicListener**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len);
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_DynamicListener** envoy_admin_v3_ListenersConfigDump_resize_dynamic_listeners(envoy_admin_v3_ListenersConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_ListenersConfigDump_DynamicListener**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_ListenersConfigDump_DynamicListener* envoy_admin_v3_ListenersConfigDump_add_dynamic_listeners(envoy_admin_v3_ListenersConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ListenersConfigDump_DynamicListener* sub = (struct envoy_admin_v3_ListenersConfigDump_DynamicListener*)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.admin.v3.ListenersConfigDump.StaticListener */
+
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_StaticListener *envoy_admin_v3_ListenersConfigDump_StaticListener_new(upb_arena *arena) {
+  return (envoy_admin_v3_ListenersConfigDump_StaticListener *)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_StaticListener_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_StaticListener *envoy_admin_v3_ListenersConfigDump_StaticListener_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ListenersConfigDump_StaticListener *ret = envoy_admin_v3_ListenersConfigDump_StaticListener_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ListenersConfigDump_StaticListener_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_StaticListener *envoy_admin_v3_ListenersConfigDump_StaticListener_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ListenersConfigDump_StaticListener *ret = envoy_admin_v3_ListenersConfigDump_StaticListener_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ListenersConfigDump_StaticListener_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ListenersConfigDump_StaticListener_serialize(const envoy_admin_v3_ListenersConfigDump_StaticListener *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ListenersConfigDump_StaticListener_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_StaticListener_has_listener(const envoy_admin_v3_ListenersConfigDump_StaticListener *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_ListenersConfigDump_StaticListener_listener(const envoy_admin_v3_ListenersConfigDump_StaticListener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_StaticListener_has_last_updated(const envoy_admin_v3_ListenersConfigDump_StaticListener *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_ListenersConfigDump_StaticListener_last_updated(const envoy_admin_v3_ListenersConfigDump_StaticListener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const struct google_protobuf_Timestamp*); }
+
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_StaticListener_set_listener(envoy_admin_v3_ListenersConfigDump_StaticListener *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_ListenersConfigDump_StaticListener_mutable_listener(envoy_admin_v3_ListenersConfigDump_StaticListener *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_ListenersConfigDump_StaticListener_listener(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ListenersConfigDump_StaticListener_set_listener(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_StaticListener_set_last_updated(envoy_admin_v3_ListenersConfigDump_StaticListener *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_ListenersConfigDump_StaticListener_mutable_last_updated(envoy_admin_v3_ListenersConfigDump_StaticListener *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_ListenersConfigDump_StaticListener_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ListenersConfigDump_StaticListener_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.admin.v3.ListenersConfigDump.DynamicListenerState */
+
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_DynamicListenerState *envoy_admin_v3_ListenersConfigDump_DynamicListenerState_new(upb_arena *arena) {
+  return (envoy_admin_v3_ListenersConfigDump_DynamicListenerState *)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_DynamicListenerState *envoy_admin_v3_ListenersConfigDump_DynamicListenerState_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ListenersConfigDump_DynamicListenerState *ret = envoy_admin_v3_ListenersConfigDump_DynamicListenerState_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_DynamicListenerState *envoy_admin_v3_ListenersConfigDump_DynamicListenerState_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ListenersConfigDump_DynamicListenerState *ret = envoy_admin_v3_ListenersConfigDump_DynamicListenerState_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ListenersConfigDump_DynamicListenerState_serialize(const envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_ListenersConfigDump_DynamicListenerState_version_info(const envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_DynamicListenerState_has_listener(const envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_ListenersConfigDump_DynamicListenerState_listener(const envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_DynamicListenerState_has_last_updated(const envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_ListenersConfigDump_DynamicListenerState_last_updated(const envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct google_protobuf_Timestamp*); }
+
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListenerState_set_version_info(envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListenerState_set_listener(envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_ListenersConfigDump_DynamicListenerState_mutable_listener(envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_ListenersConfigDump_DynamicListenerState_listener(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ListenersConfigDump_DynamicListenerState_set_listener(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListenerState_set_last_updated(envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_ListenersConfigDump_DynamicListenerState_mutable_last_updated(envoy_admin_v3_ListenersConfigDump_DynamicListenerState *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_ListenersConfigDump_DynamicListenerState_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ListenersConfigDump_DynamicListenerState_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.admin.v3.ListenersConfigDump.DynamicListener */
+
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_DynamicListener *envoy_admin_v3_ListenersConfigDump_DynamicListener_new(upb_arena *arena) {
+  return (envoy_admin_v3_ListenersConfigDump_DynamicListener *)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_DynamicListener *envoy_admin_v3_ListenersConfigDump_DynamicListener_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ListenersConfigDump_DynamicListener *ret = envoy_admin_v3_ListenersConfigDump_DynamicListener_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ListenersConfigDump_DynamicListener *envoy_admin_v3_ListenersConfigDump_DynamicListener_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ListenersConfigDump_DynamicListener *ret = envoy_admin_v3_ListenersConfigDump_DynamicListener_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ListenersConfigDump_DynamicListener_serialize(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_ListenersConfigDump_DynamicListener_name(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_DynamicListener_has_active_state(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const envoy_admin_v3_ListenersConfigDump_DynamicListenerState* envoy_admin_v3_ListenersConfigDump_DynamicListener_active_state(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const envoy_admin_v3_ListenersConfigDump_DynamicListenerState*); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_DynamicListener_has_warming_state(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const envoy_admin_v3_ListenersConfigDump_DynamicListenerState* envoy_admin_v3_ListenersConfigDump_DynamicListener_warming_state(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 32), const envoy_admin_v3_ListenersConfigDump_DynamicListenerState*); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_DynamicListener_has_draining_state(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const envoy_admin_v3_ListenersConfigDump_DynamicListenerState* envoy_admin_v3_ListenersConfigDump_DynamicListener_draining_state(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 40), const envoy_admin_v3_ListenersConfigDump_DynamicListenerState*); }
+UPB_INLINE bool envoy_admin_v3_ListenersConfigDump_DynamicListener_has_error_state(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE const envoy_admin_v3_UpdateFailureState* envoy_admin_v3_ListenersConfigDump_DynamicListener_error_state(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 48), const envoy_admin_v3_UpdateFailureState*); }
+UPB_INLINE int32_t envoy_admin_v3_ListenersConfigDump_DynamicListener_client_status(const envoy_admin_v3_ListenersConfigDump_DynamicListener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListener_set_name(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListener_set_active_state(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, envoy_admin_v3_ListenersConfigDump_DynamicListenerState* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 24), envoy_admin_v3_ListenersConfigDump_DynamicListenerState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState* envoy_admin_v3_ListenersConfigDump_DynamicListener_mutable_active_state(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState* sub = (struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState*)envoy_admin_v3_ListenersConfigDump_DynamicListener_active_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState*)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ListenersConfigDump_DynamicListener_set_active_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListener_set_warming_state(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, envoy_admin_v3_ListenersConfigDump_DynamicListenerState* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 32), envoy_admin_v3_ListenersConfigDump_DynamicListenerState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState* envoy_admin_v3_ListenersConfigDump_DynamicListener_mutable_warming_state(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState* sub = (struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState*)envoy_admin_v3_ListenersConfigDump_DynamicListener_warming_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState*)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ListenersConfigDump_DynamicListener_set_warming_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListener_set_draining_state(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, envoy_admin_v3_ListenersConfigDump_DynamicListenerState* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 40), envoy_admin_v3_ListenersConfigDump_DynamicListenerState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState* envoy_admin_v3_ListenersConfigDump_DynamicListener_mutable_draining_state(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState* sub = (struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState*)envoy_admin_v3_ListenersConfigDump_DynamicListener_draining_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_ListenersConfigDump_DynamicListenerState*)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ListenersConfigDump_DynamicListener_set_draining_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListener_set_error_state(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, envoy_admin_v3_UpdateFailureState* value) {
+  _upb_sethas(msg, 4);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 48), envoy_admin_v3_UpdateFailureState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_UpdateFailureState* envoy_admin_v3_ListenersConfigDump_DynamicListener_mutable_error_state(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, upb_arena *arena) {
+  struct envoy_admin_v3_UpdateFailureState* sub = (struct envoy_admin_v3_UpdateFailureState*)envoy_admin_v3_ListenersConfigDump_DynamicListener_error_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_UpdateFailureState*)_upb_msg_new(&envoy_admin_v3_UpdateFailureState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ListenersConfigDump_DynamicListener_set_error_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ListenersConfigDump_DynamicListener_set_client_status(envoy_admin_v3_ListenersConfigDump_DynamicListener *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
+/* envoy.admin.v3.ClustersConfigDump */
+
+UPB_INLINE envoy_admin_v3_ClustersConfigDump *envoy_admin_v3_ClustersConfigDump_new(upb_arena *arena) {
+  return (envoy_admin_v3_ClustersConfigDump *)_upb_msg_new(&envoy_admin_v3_ClustersConfigDump_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump *envoy_admin_v3_ClustersConfigDump_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ClustersConfigDump *ret = envoy_admin_v3_ClustersConfigDump_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ClustersConfigDump_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump *envoy_admin_v3_ClustersConfigDump_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ClustersConfigDump *ret = envoy_admin_v3_ClustersConfigDump_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ClustersConfigDump_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ClustersConfigDump_serialize(const envoy_admin_v3_ClustersConfigDump *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ClustersConfigDump_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_ClustersConfigDump_version_info(const envoy_admin_v3_ClustersConfigDump *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_ClustersConfigDump_has_static_clusters(const envoy_admin_v3_ClustersConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const envoy_admin_v3_ClustersConfigDump_StaticCluster* const* envoy_admin_v3_ClustersConfigDump_static_clusters(const envoy_admin_v3_ClustersConfigDump *msg, size_t *len) { return (const envoy_admin_v3_ClustersConfigDump_StaticCluster* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+UPB_INLINE bool envoy_admin_v3_ClustersConfigDump_has_dynamic_active_clusters(const envoy_admin_v3_ClustersConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); }
+UPB_INLINE const envoy_admin_v3_ClustersConfigDump_DynamicCluster* const* envoy_admin_v3_ClustersConfigDump_dynamic_active_clusters(const envoy_admin_v3_ClustersConfigDump *msg, size_t *len) { return (const envoy_admin_v3_ClustersConfigDump_DynamicCluster* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); }
+UPB_INLINE bool envoy_admin_v3_ClustersConfigDump_has_dynamic_warming_clusters(const envoy_admin_v3_ClustersConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
+UPB_INLINE const envoy_admin_v3_ClustersConfigDump_DynamicCluster* const* envoy_admin_v3_ClustersConfigDump_dynamic_warming_clusters(const envoy_admin_v3_ClustersConfigDump *msg, size_t *len) { return (const envoy_admin_v3_ClustersConfigDump_DynamicCluster* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
+
+UPB_INLINE void envoy_admin_v3_ClustersConfigDump_set_version_info(envoy_admin_v3_ClustersConfigDump *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_StaticCluster** envoy_admin_v3_ClustersConfigDump_mutable_static_clusters(envoy_admin_v3_ClustersConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_ClustersConfigDump_StaticCluster**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_StaticCluster** envoy_admin_v3_ClustersConfigDump_resize_static_clusters(envoy_admin_v3_ClustersConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_ClustersConfigDump_StaticCluster**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_ClustersConfigDump_StaticCluster* envoy_admin_v3_ClustersConfigDump_add_static_clusters(envoy_admin_v3_ClustersConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ClustersConfigDump_StaticCluster* sub = (struct envoy_admin_v3_ClustersConfigDump_StaticCluster*)_upb_msg_new(&envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_DynamicCluster** envoy_admin_v3_ClustersConfigDump_mutable_dynamic_active_clusters(envoy_admin_v3_ClustersConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_ClustersConfigDump_DynamicCluster**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len);
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_DynamicCluster** envoy_admin_v3_ClustersConfigDump_resize_dynamic_active_clusters(envoy_admin_v3_ClustersConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_ClustersConfigDump_DynamicCluster**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_ClustersConfigDump_DynamicCluster* envoy_admin_v3_ClustersConfigDump_add_dynamic_active_clusters(envoy_admin_v3_ClustersConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ClustersConfigDump_DynamicCluster* sub = (struct envoy_admin_v3_ClustersConfigDump_DynamicCluster*)_upb_msg_new(&envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_DynamicCluster** envoy_admin_v3_ClustersConfigDump_mutable_dynamic_warming_clusters(envoy_admin_v3_ClustersConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_ClustersConfigDump_DynamicCluster**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_DynamicCluster** envoy_admin_v3_ClustersConfigDump_resize_dynamic_warming_clusters(envoy_admin_v3_ClustersConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_ClustersConfigDump_DynamicCluster**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_ClustersConfigDump_DynamicCluster* envoy_admin_v3_ClustersConfigDump_add_dynamic_warming_clusters(envoy_admin_v3_ClustersConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ClustersConfigDump_DynamicCluster* sub = (struct envoy_admin_v3_ClustersConfigDump_DynamicCluster*)_upb_msg_new(&envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.admin.v3.ClustersConfigDump.StaticCluster */
+
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_StaticCluster *envoy_admin_v3_ClustersConfigDump_StaticCluster_new(upb_arena *arena) {
+  return (envoy_admin_v3_ClustersConfigDump_StaticCluster *)_upb_msg_new(&envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_StaticCluster *envoy_admin_v3_ClustersConfigDump_StaticCluster_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ClustersConfigDump_StaticCluster *ret = envoy_admin_v3_ClustersConfigDump_StaticCluster_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_StaticCluster *envoy_admin_v3_ClustersConfigDump_StaticCluster_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ClustersConfigDump_StaticCluster *ret = envoy_admin_v3_ClustersConfigDump_StaticCluster_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ClustersConfigDump_StaticCluster_serialize(const envoy_admin_v3_ClustersConfigDump_StaticCluster *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_ClustersConfigDump_StaticCluster_has_cluster(const envoy_admin_v3_ClustersConfigDump_StaticCluster *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_ClustersConfigDump_StaticCluster_cluster(const envoy_admin_v3_ClustersConfigDump_StaticCluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_ClustersConfigDump_StaticCluster_has_last_updated(const envoy_admin_v3_ClustersConfigDump_StaticCluster *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_ClustersConfigDump_StaticCluster_last_updated(const envoy_admin_v3_ClustersConfigDump_StaticCluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const struct google_protobuf_Timestamp*); }
+
+UPB_INLINE void envoy_admin_v3_ClustersConfigDump_StaticCluster_set_cluster(envoy_admin_v3_ClustersConfigDump_StaticCluster *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_ClustersConfigDump_StaticCluster_mutable_cluster(envoy_admin_v3_ClustersConfigDump_StaticCluster *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_ClustersConfigDump_StaticCluster_cluster(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ClustersConfigDump_StaticCluster_set_cluster(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ClustersConfigDump_StaticCluster_set_last_updated(envoy_admin_v3_ClustersConfigDump_StaticCluster *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_ClustersConfigDump_StaticCluster_mutable_last_updated(envoy_admin_v3_ClustersConfigDump_StaticCluster *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_ClustersConfigDump_StaticCluster_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ClustersConfigDump_StaticCluster_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.admin.v3.ClustersConfigDump.DynamicCluster */
+
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_DynamicCluster *envoy_admin_v3_ClustersConfigDump_DynamicCluster_new(upb_arena *arena) {
+  return (envoy_admin_v3_ClustersConfigDump_DynamicCluster *)_upb_msg_new(&envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_DynamicCluster *envoy_admin_v3_ClustersConfigDump_DynamicCluster_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ClustersConfigDump_DynamicCluster *ret = envoy_admin_v3_ClustersConfigDump_DynamicCluster_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ClustersConfigDump_DynamicCluster *envoy_admin_v3_ClustersConfigDump_DynamicCluster_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ClustersConfigDump_DynamicCluster *ret = envoy_admin_v3_ClustersConfigDump_DynamicCluster_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ClustersConfigDump_DynamicCluster_serialize(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_ClustersConfigDump_DynamicCluster_version_info(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_ClustersConfigDump_DynamicCluster_has_cluster(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_ClustersConfigDump_DynamicCluster_cluster(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_ClustersConfigDump_DynamicCluster_has_last_updated(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_ClustersConfigDump_DynamicCluster_last_updated(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 32), const struct google_protobuf_Timestamp*); }
+UPB_INLINE bool envoy_admin_v3_ClustersConfigDump_DynamicCluster_has_error_state(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const envoy_admin_v3_UpdateFailureState* envoy_admin_v3_ClustersConfigDump_DynamicCluster_error_state(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 40), const envoy_admin_v3_UpdateFailureState*); }
+UPB_INLINE int32_t envoy_admin_v3_ClustersConfigDump_DynamicCluster_client_status(const envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_version_info(envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_cluster(envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 24), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_ClustersConfigDump_DynamicCluster_mutable_cluster(envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_ClustersConfigDump_DynamicCluster_cluster(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_cluster(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_last_updated(envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 32), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_ClustersConfigDump_DynamicCluster_mutable_last_updated(envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_ClustersConfigDump_DynamicCluster_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_error_state(envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, envoy_admin_v3_UpdateFailureState* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 40), envoy_admin_v3_UpdateFailureState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_UpdateFailureState* envoy_admin_v3_ClustersConfigDump_DynamicCluster_mutable_error_state(envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, upb_arena *arena) {
+  struct envoy_admin_v3_UpdateFailureState* sub = (struct envoy_admin_v3_UpdateFailureState*)envoy_admin_v3_ClustersConfigDump_DynamicCluster_error_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_UpdateFailureState*)_upb_msg_new(&envoy_admin_v3_UpdateFailureState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_error_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_client_status(envoy_admin_v3_ClustersConfigDump_DynamicCluster *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
+/* envoy.admin.v3.RoutesConfigDump */
+
+UPB_INLINE envoy_admin_v3_RoutesConfigDump *envoy_admin_v3_RoutesConfigDump_new(upb_arena *arena) {
+  return (envoy_admin_v3_RoutesConfigDump *)_upb_msg_new(&envoy_admin_v3_RoutesConfigDump_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump *envoy_admin_v3_RoutesConfigDump_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_RoutesConfigDump *ret = envoy_admin_v3_RoutesConfigDump_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_RoutesConfigDump_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump *envoy_admin_v3_RoutesConfigDump_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_RoutesConfigDump *ret = envoy_admin_v3_RoutesConfigDump_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_RoutesConfigDump_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_RoutesConfigDump_serialize(const envoy_admin_v3_RoutesConfigDump *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_RoutesConfigDump_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_RoutesConfigDump_has_static_route_configs(const envoy_admin_v3_RoutesConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const envoy_admin_v3_RoutesConfigDump_StaticRouteConfig* const* envoy_admin_v3_RoutesConfigDump_static_route_configs(const envoy_admin_v3_RoutesConfigDump *msg, size_t *len) { return (const envoy_admin_v3_RoutesConfigDump_StaticRouteConfig* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+UPB_INLINE bool envoy_admin_v3_RoutesConfigDump_has_dynamic_route_configs(const envoy_admin_v3_RoutesConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
+UPB_INLINE const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig* const* envoy_admin_v3_RoutesConfigDump_dynamic_route_configs(const envoy_admin_v3_RoutesConfigDump *msg, size_t *len) { return (const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
+
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_StaticRouteConfig** envoy_admin_v3_RoutesConfigDump_mutable_static_route_configs(envoy_admin_v3_RoutesConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_RoutesConfigDump_StaticRouteConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_StaticRouteConfig** envoy_admin_v3_RoutesConfigDump_resize_static_route_configs(envoy_admin_v3_RoutesConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_RoutesConfigDump_StaticRouteConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_RoutesConfigDump_StaticRouteConfig* envoy_admin_v3_RoutesConfigDump_add_static_route_configs(envoy_admin_v3_RoutesConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_RoutesConfigDump_StaticRouteConfig* sub = (struct envoy_admin_v3_RoutesConfigDump_StaticRouteConfig*)_upb_msg_new(&envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig** envoy_admin_v3_RoutesConfigDump_mutable_dynamic_route_configs(envoy_admin_v3_RoutesConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig** envoy_admin_v3_RoutesConfigDump_resize_dynamic_route_configs(envoy_admin_v3_RoutesConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig* envoy_admin_v3_RoutesConfigDump_add_dynamic_route_configs(envoy_admin_v3_RoutesConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig* sub = (struct envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig*)_upb_msg_new(&envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.admin.v3.RoutesConfigDump.StaticRouteConfig */
+
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_new(upb_arena *arena) {
+  return (envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *)_upb_msg_new(&envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *ret = envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *ret = envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_serialize(const envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_has_route_config(const envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_route_config(const envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_has_last_updated(const envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_last_updated(const envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const struct google_protobuf_Timestamp*); }
+
+UPB_INLINE void envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_set_route_config(envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_mutable_route_config(envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_route_config(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_set_route_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_set_last_updated(envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_mutable_last_updated(envoy_admin_v3_RoutesConfigDump_StaticRouteConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.admin.v3.RoutesConfigDump.DynamicRouteConfig */
+
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_new(upb_arena *arena) {
+  return (envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *)_upb_msg_new(&envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *ret = envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *ret = envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_serialize(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_version_info(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_has_route_config(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_route_config(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_has_last_updated(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_last_updated(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 32), const struct google_protobuf_Timestamp*); }
+UPB_INLINE bool envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_has_error_state(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const envoy_admin_v3_UpdateFailureState* envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_error_state(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 40), const envoy_admin_v3_UpdateFailureState*); }
+UPB_INLINE int32_t envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_client_status(const envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_version_info(envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_route_config(envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 24), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_mutable_route_config(envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_route_config(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_route_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_last_updated(envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 32), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_mutable_last_updated(envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_error_state(envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, envoy_admin_v3_UpdateFailureState* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 40), envoy_admin_v3_UpdateFailureState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_UpdateFailureState* envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_mutable_error_state(envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, upb_arena *arena) {
+  struct envoy_admin_v3_UpdateFailureState* sub = (struct envoy_admin_v3_UpdateFailureState*)envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_error_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_UpdateFailureState*)_upb_msg_new(&envoy_admin_v3_UpdateFailureState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_error_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_client_status(envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
+/* envoy.admin.v3.ScopedRoutesConfigDump */
+
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump *envoy_admin_v3_ScopedRoutesConfigDump_new(upb_arena *arena) {
+  return (envoy_admin_v3_ScopedRoutesConfigDump *)_upb_msg_new(&envoy_admin_v3_ScopedRoutesConfigDump_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump *envoy_admin_v3_ScopedRoutesConfigDump_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ScopedRoutesConfigDump *ret = envoy_admin_v3_ScopedRoutesConfigDump_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ScopedRoutesConfigDump_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump *envoy_admin_v3_ScopedRoutesConfigDump_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ScopedRoutesConfigDump *ret = envoy_admin_v3_ScopedRoutesConfigDump_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ScopedRoutesConfigDump_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ScopedRoutesConfigDump_serialize(const envoy_admin_v3_ScopedRoutesConfigDump *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ScopedRoutesConfigDump_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_ScopedRoutesConfigDump_has_inline_scoped_route_configs(const envoy_admin_v3_ScopedRoutesConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs* const* envoy_admin_v3_ScopedRoutesConfigDump_inline_scoped_route_configs(const envoy_admin_v3_ScopedRoutesConfigDump *msg, size_t *len) { return (const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+UPB_INLINE bool envoy_admin_v3_ScopedRoutesConfigDump_has_dynamic_scoped_route_configs(const envoy_admin_v3_ScopedRoutesConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
+UPB_INLINE const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs* const* envoy_admin_v3_ScopedRoutesConfigDump_dynamic_scoped_route_configs(const envoy_admin_v3_ScopedRoutesConfigDump *msg, size_t *len) { return (const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
+
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs** envoy_admin_v3_ScopedRoutesConfigDump_mutable_inline_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs** envoy_admin_v3_ScopedRoutesConfigDump_resize_inline_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs* envoy_admin_v3_ScopedRoutesConfigDump_add_inline_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs* sub = (struct envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs*)_upb_msg_new(&envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs** envoy_admin_v3_ScopedRoutesConfigDump_mutable_dynamic_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs** envoy_admin_v3_ScopedRoutesConfigDump_resize_dynamic_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs* envoy_admin_v3_ScopedRoutesConfigDump_add_dynamic_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs* sub = (struct envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs*)_upb_msg_new(&envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.admin.v3.ScopedRoutesConfigDump.InlineScopedRouteConfigs */
+
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_new(upb_arena *arena) {
+  return (envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *)_upb_msg_new(&envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *ret = envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *ret = envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_serialize(const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_name(const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_has_scoped_route_configs(const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
+UPB_INLINE const struct google_protobuf_Any* const* envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_scoped_route_configs(const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg, size_t *len) { return (const struct google_protobuf_Any* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
+UPB_INLINE bool envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_has_last_updated(const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_last_updated(const envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct google_protobuf_Timestamp*); }
+
+UPB_INLINE void envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_set_name(envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE struct google_protobuf_Any** envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_mutable_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg, size_t *len) {
+  return (struct google_protobuf_Any**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
+}
+UPB_INLINE struct google_protobuf_Any** envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_resize_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg, size_t len, upb_arena *arena) {
+  return (struct google_protobuf_Any**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_add_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_set_last_updated(envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_mutable_last_updated(envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.admin.v3.ScopedRoutesConfigDump.DynamicScopedRouteConfigs */
+
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_new(upb_arena *arena) {
+  return (envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *)_upb_msg_new(&envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *ret = envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *ret = envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_serialize(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_name(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
+UPB_INLINE upb_strview envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_version_info(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_has_scoped_route_configs(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 56)); }
+UPB_INLINE const struct google_protobuf_Any* const* envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_scoped_route_configs(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, size_t *len) { return (const struct google_protobuf_Any* const*)_upb_array_accessor(msg, UPB_SIZE(32, 56), len); }
+UPB_INLINE bool envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_has_last_updated(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_last_updated(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 40), const struct google_protobuf_Timestamp*); }
+UPB_INLINE bool envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_has_error_state(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const envoy_admin_v3_UpdateFailureState* envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_error_state(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 48), const envoy_admin_v3_UpdateFailureState*); }
+UPB_INLINE int32_t envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_client_status(const envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_set_name(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_set_version_info(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_strview) = value;
+}
+UPB_INLINE struct google_protobuf_Any** envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_mutable_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, size_t *len) {
+  return (struct google_protobuf_Any**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 56), len);
+}
+UPB_INLINE struct google_protobuf_Any** envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_resize_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, size_t len, upb_arena *arena) {
+  return (struct google_protobuf_Any**)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 56), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_add_scoped_route_configs(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(32, 56), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_set_last_updated(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 40), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_mutable_last_updated(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_set_error_state(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, envoy_admin_v3_UpdateFailureState* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 48), envoy_admin_v3_UpdateFailureState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_UpdateFailureState* envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_mutable_error_state(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, upb_arena *arena) {
+  struct envoy_admin_v3_UpdateFailureState* sub = (struct envoy_admin_v3_UpdateFailureState*)envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_error_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_UpdateFailureState*)_upb_msg_new(&envoy_admin_v3_UpdateFailureState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_set_error_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_set_client_status(envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
+/* envoy.admin.v3.SecretsConfigDump */
+
+UPB_INLINE envoy_admin_v3_SecretsConfigDump *envoy_admin_v3_SecretsConfigDump_new(upb_arena *arena) {
+  return (envoy_admin_v3_SecretsConfigDump *)_upb_msg_new(&envoy_admin_v3_SecretsConfigDump_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump *envoy_admin_v3_SecretsConfigDump_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_SecretsConfigDump *ret = envoy_admin_v3_SecretsConfigDump_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_SecretsConfigDump_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump *envoy_admin_v3_SecretsConfigDump_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_SecretsConfigDump *ret = envoy_admin_v3_SecretsConfigDump_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_SecretsConfigDump_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_SecretsConfigDump_serialize(const envoy_admin_v3_SecretsConfigDump *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_SecretsConfigDump_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_SecretsConfigDump_has_static_secrets(const envoy_admin_v3_SecretsConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const envoy_admin_v3_SecretsConfigDump_StaticSecret* const* envoy_admin_v3_SecretsConfigDump_static_secrets(const envoy_admin_v3_SecretsConfigDump *msg, size_t *len) { return (const envoy_admin_v3_SecretsConfigDump_StaticSecret* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+UPB_INLINE bool envoy_admin_v3_SecretsConfigDump_has_dynamic_active_secrets(const envoy_admin_v3_SecretsConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
+UPB_INLINE const envoy_admin_v3_SecretsConfigDump_DynamicSecret* const* envoy_admin_v3_SecretsConfigDump_dynamic_active_secrets(const envoy_admin_v3_SecretsConfigDump *msg, size_t *len) { return (const envoy_admin_v3_SecretsConfigDump_DynamicSecret* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
+UPB_INLINE bool envoy_admin_v3_SecretsConfigDump_has_dynamic_warming_secrets(const envoy_admin_v3_SecretsConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const envoy_admin_v3_SecretsConfigDump_DynamicSecret* const* envoy_admin_v3_SecretsConfigDump_dynamic_warming_secrets(const envoy_admin_v3_SecretsConfigDump *msg, size_t *len) { return (const envoy_admin_v3_SecretsConfigDump_DynamicSecret* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_StaticSecret** envoy_admin_v3_SecretsConfigDump_mutable_static_secrets(envoy_admin_v3_SecretsConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_SecretsConfigDump_StaticSecret**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_StaticSecret** envoy_admin_v3_SecretsConfigDump_resize_static_secrets(envoy_admin_v3_SecretsConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_SecretsConfigDump_StaticSecret**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_SecretsConfigDump_StaticSecret* envoy_admin_v3_SecretsConfigDump_add_static_secrets(envoy_admin_v3_SecretsConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_SecretsConfigDump_StaticSecret* sub = (struct envoy_admin_v3_SecretsConfigDump_StaticSecret*)_upb_msg_new(&envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_DynamicSecret** envoy_admin_v3_SecretsConfigDump_mutable_dynamic_active_secrets(envoy_admin_v3_SecretsConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_SecretsConfigDump_DynamicSecret**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_DynamicSecret** envoy_admin_v3_SecretsConfigDump_resize_dynamic_active_secrets(envoy_admin_v3_SecretsConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_SecretsConfigDump_DynamicSecret**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_SecretsConfigDump_DynamicSecret* envoy_admin_v3_SecretsConfigDump_add_dynamic_active_secrets(envoy_admin_v3_SecretsConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_SecretsConfigDump_DynamicSecret* sub = (struct envoy_admin_v3_SecretsConfigDump_DynamicSecret*)_upb_msg_new(&envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_DynamicSecret** envoy_admin_v3_SecretsConfigDump_mutable_dynamic_warming_secrets(envoy_admin_v3_SecretsConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_SecretsConfigDump_DynamicSecret**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_DynamicSecret** envoy_admin_v3_SecretsConfigDump_resize_dynamic_warming_secrets(envoy_admin_v3_SecretsConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_SecretsConfigDump_DynamicSecret**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_SecretsConfigDump_DynamicSecret* envoy_admin_v3_SecretsConfigDump_add_dynamic_warming_secrets(envoy_admin_v3_SecretsConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_SecretsConfigDump_DynamicSecret* sub = (struct envoy_admin_v3_SecretsConfigDump_DynamicSecret*)_upb_msg_new(&envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.admin.v3.SecretsConfigDump.DynamicSecret */
+
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_DynamicSecret *envoy_admin_v3_SecretsConfigDump_DynamicSecret_new(upb_arena *arena) {
+  return (envoy_admin_v3_SecretsConfigDump_DynamicSecret *)_upb_msg_new(&envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_DynamicSecret *envoy_admin_v3_SecretsConfigDump_DynamicSecret_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_SecretsConfigDump_DynamicSecret *ret = envoy_admin_v3_SecretsConfigDump_DynamicSecret_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_DynamicSecret *envoy_admin_v3_SecretsConfigDump_DynamicSecret_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_SecretsConfigDump_DynamicSecret *ret = envoy_admin_v3_SecretsConfigDump_DynamicSecret_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_SecretsConfigDump_DynamicSecret_serialize(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_SecretsConfigDump_DynamicSecret_name(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
+UPB_INLINE upb_strview envoy_admin_v3_SecretsConfigDump_DynamicSecret_version_info(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_SecretsConfigDump_DynamicSecret_has_last_updated(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_SecretsConfigDump_DynamicSecret_last_updated(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 40), const struct google_protobuf_Timestamp*); }
+UPB_INLINE bool envoy_admin_v3_SecretsConfigDump_DynamicSecret_has_secret(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_SecretsConfigDump_DynamicSecret_secret(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 48), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_SecretsConfigDump_DynamicSecret_has_error_state(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const envoy_admin_v3_UpdateFailureState* envoy_admin_v3_SecretsConfigDump_DynamicSecret_error_state(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 56), const envoy_admin_v3_UpdateFailureState*); }
+UPB_INLINE int32_t envoy_admin_v3_SecretsConfigDump_DynamicSecret_client_status(const envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_name(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_version_info(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_last_updated(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 40), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_SecretsConfigDump_DynamicSecret_mutable_last_updated(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_SecretsConfigDump_DynamicSecret_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_secret(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 48), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_SecretsConfigDump_DynamicSecret_mutable_secret(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_SecretsConfigDump_DynamicSecret_secret(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_secret(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_error_state(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, envoy_admin_v3_UpdateFailureState* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(32, 56), envoy_admin_v3_UpdateFailureState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_UpdateFailureState* envoy_admin_v3_SecretsConfigDump_DynamicSecret_mutable_error_state(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, upb_arena *arena) {
+  struct envoy_admin_v3_UpdateFailureState* sub = (struct envoy_admin_v3_UpdateFailureState*)envoy_admin_v3_SecretsConfigDump_DynamicSecret_error_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_UpdateFailureState*)_upb_msg_new(&envoy_admin_v3_UpdateFailureState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_error_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_DynamicSecret_set_client_status(envoy_admin_v3_SecretsConfigDump_DynamicSecret *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
+/* envoy.admin.v3.SecretsConfigDump.StaticSecret */
+
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_StaticSecret *envoy_admin_v3_SecretsConfigDump_StaticSecret_new(upb_arena *arena) {
+  return (envoy_admin_v3_SecretsConfigDump_StaticSecret *)_upb_msg_new(&envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_StaticSecret *envoy_admin_v3_SecretsConfigDump_StaticSecret_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_SecretsConfigDump_StaticSecret *ret = envoy_admin_v3_SecretsConfigDump_StaticSecret_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_SecretsConfigDump_StaticSecret *envoy_admin_v3_SecretsConfigDump_StaticSecret_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_SecretsConfigDump_StaticSecret *ret = envoy_admin_v3_SecretsConfigDump_StaticSecret_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_SecretsConfigDump_StaticSecret_serialize(const envoy_admin_v3_SecretsConfigDump_StaticSecret *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_SecretsConfigDump_StaticSecret_name(const envoy_admin_v3_SecretsConfigDump_StaticSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_SecretsConfigDump_StaticSecret_has_last_updated(const envoy_admin_v3_SecretsConfigDump_StaticSecret *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_SecretsConfigDump_StaticSecret_last_updated(const envoy_admin_v3_SecretsConfigDump_StaticSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct google_protobuf_Timestamp*); }
+UPB_INLINE bool envoy_admin_v3_SecretsConfigDump_StaticSecret_has_secret(const envoy_admin_v3_SecretsConfigDump_StaticSecret *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_SecretsConfigDump_StaticSecret_secret(const envoy_admin_v3_SecretsConfigDump_StaticSecret *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct google_protobuf_Any*); }
+
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_StaticSecret_set_name(envoy_admin_v3_SecretsConfigDump_StaticSecret *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_StaticSecret_set_last_updated(envoy_admin_v3_SecretsConfigDump_StaticSecret *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_SecretsConfigDump_StaticSecret_mutable_last_updated(envoy_admin_v3_SecretsConfigDump_StaticSecret *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_SecretsConfigDump_StaticSecret_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_SecretsConfigDump_StaticSecret_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_SecretsConfigDump_StaticSecret_set_secret(envoy_admin_v3_SecretsConfigDump_StaticSecret *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_SecretsConfigDump_StaticSecret_mutable_secret(envoy_admin_v3_SecretsConfigDump_StaticSecret *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_SecretsConfigDump_StaticSecret_secret(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_SecretsConfigDump_StaticSecret_set_secret(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.admin.v3.EndpointsConfigDump */
+
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump *envoy_admin_v3_EndpointsConfigDump_new(upb_arena *arena) {
+  return (envoy_admin_v3_EndpointsConfigDump *)_upb_msg_new(&envoy_admin_v3_EndpointsConfigDump_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump *envoy_admin_v3_EndpointsConfigDump_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_EndpointsConfigDump *ret = envoy_admin_v3_EndpointsConfigDump_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_EndpointsConfigDump_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump *envoy_admin_v3_EndpointsConfigDump_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_EndpointsConfigDump *ret = envoy_admin_v3_EndpointsConfigDump_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_EndpointsConfigDump_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_EndpointsConfigDump_serialize(const envoy_admin_v3_EndpointsConfigDump *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_EndpointsConfigDump_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_EndpointsConfigDump_has_static_endpoint_configs(const envoy_admin_v3_EndpointsConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig* const* envoy_admin_v3_EndpointsConfigDump_static_endpoint_configs(const envoy_admin_v3_EndpointsConfigDump *msg, size_t *len) { return (const envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+UPB_INLINE bool envoy_admin_v3_EndpointsConfigDump_has_dynamic_endpoint_configs(const envoy_admin_v3_EndpointsConfigDump *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
+UPB_INLINE const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig* const* envoy_admin_v3_EndpointsConfigDump_dynamic_endpoint_configs(const envoy_admin_v3_EndpointsConfigDump *msg, size_t *len) { return (const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
+
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig** envoy_admin_v3_EndpointsConfigDump_mutable_static_endpoint_configs(envoy_admin_v3_EndpointsConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig** envoy_admin_v3_EndpointsConfigDump_resize_static_endpoint_configs(envoy_admin_v3_EndpointsConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig* envoy_admin_v3_EndpointsConfigDump_add_static_endpoint_configs(envoy_admin_v3_EndpointsConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig* sub = (struct envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig*)_upb_msg_new(&envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig** envoy_admin_v3_EndpointsConfigDump_mutable_dynamic_endpoint_configs(envoy_admin_v3_EndpointsConfigDump *msg, size_t *len) {
+  return (envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig** envoy_admin_v3_EndpointsConfigDump_resize_dynamic_endpoint_configs(envoy_admin_v3_EndpointsConfigDump *msg, size_t len, upb_arena *arena) {
+  return (envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig* envoy_admin_v3_EndpointsConfigDump_add_dynamic_endpoint_configs(envoy_admin_v3_EndpointsConfigDump *msg, upb_arena *arena) {
+  struct envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig* sub = (struct envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig*)_upb_msg_new(&envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.admin.v3.EndpointsConfigDump.StaticEndpointConfig */
+
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_new(upb_arena *arena) {
+  return (envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *)_upb_msg_new(&envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *ret = envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *ret = envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_serialize(const envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_has_endpoint_config(const envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_endpoint_config(const envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_has_last_updated(const envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_last_updated(const envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const struct google_protobuf_Timestamp*); }
+
+UPB_INLINE void envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_set_endpoint_config(envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_mutable_endpoint_config(envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_endpoint_config(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_set_endpoint_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_set_last_updated(envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_mutable_last_updated(envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.admin.v3.EndpointsConfigDump.DynamicEndpointConfig */
+
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_new(upb_arena *arena) {
+  return (envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *)_upb_msg_new(&envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit, arena);
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *ret = envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *ret = envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_serialize(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_version_info(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
+UPB_INLINE bool envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_has_endpoint_config(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_endpoint_config(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_has_last_updated(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Timestamp* envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_last_updated(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 32), const struct google_protobuf_Timestamp*); }
+UPB_INLINE bool envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_has_error_state(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const envoy_admin_v3_UpdateFailureState* envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_error_state(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 40), const envoy_admin_v3_UpdateFailureState*); }
+UPB_INLINE int32_t envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_client_status(const envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_version_info(envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_endpoint_config(envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 24), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_mutable_endpoint_config(envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_endpoint_config(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_endpoint_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_last_updated(envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, struct google_protobuf_Timestamp* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 32), struct google_protobuf_Timestamp*) = value;
+}
+UPB_INLINE struct google_protobuf_Timestamp* envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_mutable_last_updated(envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Timestamp* sub = (struct google_protobuf_Timestamp*)envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_last_updated(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Timestamp*)_upb_msg_new(&google_protobuf_Timestamp_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_last_updated(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_error_state(envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, envoy_admin_v3_UpdateFailureState* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 40), envoy_admin_v3_UpdateFailureState*) = value;
+}
+UPB_INLINE struct envoy_admin_v3_UpdateFailureState* envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_mutable_error_state(envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, upb_arena *arena) {
+  struct envoy_admin_v3_UpdateFailureState* sub = (struct envoy_admin_v3_UpdateFailureState*)envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_error_state(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_UpdateFailureState*)_upb_msg_new(&envoy_admin_v3_UpdateFailureState_msginit, arena);
+    if (!sub) return NULL;
+    envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_error_state(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_client_status(envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_ADMIN_V3_CONFIG_DUMP_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c
index 5de540f..fa6dcbc 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c
@@ -14,7 +14,6 @@
 #include "envoy/type/matcher/v3/metadata.upb.h"
 #include "envoy/type/v3/percent.upb.h"
 #include "google/protobuf/any.upb.h"
-#include "google/protobuf/struct.upb.h"
 #include "google/protobuf/wrappers.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c
new file mode 100644
index 0000000..b7f9387
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c
@@ -0,0 +1,350 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/bootstrap/v3/bootstrap.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/config/bootstrap/v3/bootstrap.upb.h"
+#include "envoy/config/cluster/v3/cluster.upb.h"
+#include "envoy/config/core/v3/address.upb.h"
+#include "envoy/config/core/v3/base.upb.h"
+#include "envoy/config/core/v3/config_source.upb.h"
+#include "envoy/config/core/v3/event_service_config.upb.h"
+#include "envoy/config/core/v3/extension.upb.h"
+#include "envoy/config/core/v3/socket_option.upb.h"
+#include "envoy/config/listener/v3/listener.upb.h"
+#include "envoy/config/metrics/v3/stats.upb.h"
+#include "envoy/config/overload/v3/overload.upb.h"
+#include "envoy/config/trace/v3/http_tracer.upb.h"
+#include "envoy/extensions/transport_sockets/tls/v3/secret.upb.h"
+#include "envoy/type/v3/percent.upb.h"
+#include "google/protobuf/duration.upb.h"
+#include "google/protobuf/struct.upb.h"
+#include "google/protobuf/wrappers.upb.h"
+#include "udpa/annotations/migrate.upb.h"
+#include "udpa/annotations/security.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Bootstrap_submsgs[19] = {
+  &envoy_config_bootstrap_v3_Admin_msginit,
+  &envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_msginit,
+  &envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit,
+  &envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit,
+  &envoy_config_bootstrap_v3_ClusterManager_msginit,
+  &envoy_config_bootstrap_v3_FatalAction_msginit,
+  &envoy_config_bootstrap_v3_LayeredRuntime_msginit,
+  &envoy_config_bootstrap_v3_Watchdog_msginit,
+  &envoy_config_bootstrap_v3_Watchdogs_msginit,
+  &envoy_config_core_v3_ApiConfigSource_msginit,
+  &envoy_config_core_v3_ConfigSource_msginit,
+  &envoy_config_core_v3_Node_msginit,
+  &envoy_config_core_v3_TypedExtensionConfig_msginit,
+  &envoy_config_metrics_v3_StatsConfig_msginit,
+  &envoy_config_metrics_v3_StatsSink_msginit,
+  &envoy_config_overload_v3_OverloadManager_msginit,
+  &envoy_config_trace_v3_Tracing_msginit,
+  &google_protobuf_Duration_msginit,
+  &google_protobuf_UInt64Value_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Bootstrap__fields[27] = {
+  {1, UPB_SIZE(28, 56), 1, 11, 11, 1},
+  {2, UPB_SIZE(32, 64), 2, 3, 11, 1},
+  {3, UPB_SIZE(36, 72), 3, 2, 11, 1},
+  {4, UPB_SIZE(40, 80), 4, 4, 11, 1},
+  {5, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {6, UPB_SIZE(88, 176), 0, 14, 11, 3},
+  {7, UPB_SIZE(44, 88), 5, 17, 11, 1},
+  {8, UPB_SIZE(48, 96), 6, 7, 11, 1},
+  {9, UPB_SIZE(52, 104), 7, 16, 11, 1},
+  {12, UPB_SIZE(56, 112), 8, 0, 11, 1},
+  {13, UPB_SIZE(60, 120), 9, 13, 11, 1},
+  {14, UPB_SIZE(64, 128), 10, 9, 11, 1},
+  {15, UPB_SIZE(68, 136), 11, 15, 11, 1},
+  {16, UPB_SIZE(2, 2), 0, 0, 8, 1},
+  {17, UPB_SIZE(72, 144), 12, 6, 11, 1},
+  {18, UPB_SIZE(12, 24), 0, 0, 9, 1},
+  {19, UPB_SIZE(76, 152), 13, 18, 11, 1},
+  {20, UPB_SIZE(3, 3), 0, 0, 8, 1},
+  {21, UPB_SIZE(92, 184), 0, 12, 11, 3},
+  {22, UPB_SIZE(96, 192), 0, 10, 11, 3},
+  {23, UPB_SIZE(80, 160), 14, 10, 11, 1},
+  {24, UPB_SIZE(20, 40), 0, 0, 9, 1},
+  {25, UPB_SIZE(100, 200), 0, 1, 11, _UPB_LABEL_MAP},
+  {26, UPB_SIZE(104, 208), 0, 0, 9, 3},
+  {27, UPB_SIZE(84, 168), 15, 8, 11, 1},
+  {28, UPB_SIZE(108, 216), 0, 5, 11, 3},
+  {29, UPB_SIZE(112, 224), UPB_SIZE(-117, -229), 0, 8, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_msginit = {
+  &envoy_config_bootstrap_v3_Bootstrap_submsgs[0],
+  &envoy_config_bootstrap_v3_Bootstrap__fields[0],
+  UPB_SIZE(120, 240), 27, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Bootstrap_StaticResources_submsgs[3] = {
+  &envoy_config_cluster_v3_Cluster_msginit,
+  &envoy_config_listener_v3_Listener_msginit,
+  &envoy_extensions_transport_sockets_tls_v3_Secret_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Bootstrap_StaticResources__fields[3] = {
+  {1, UPB_SIZE(0, 0), 0, 1, 11, 3},
+  {2, UPB_SIZE(4, 8), 0, 0, 11, 3},
+  {3, UPB_SIZE(8, 16), 0, 2, 11, 3},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit = {
+  &envoy_config_bootstrap_v3_Bootstrap_StaticResources_submsgs[0],
+  &envoy_config_bootstrap_v3_Bootstrap_StaticResources__fields[0],
+  UPB_SIZE(16, 24), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Bootstrap_DynamicResources_submsgs[2] = {
+  &envoy_config_core_v3_ApiConfigSource_msginit,
+  &envoy_config_core_v3_ConfigSource_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Bootstrap_DynamicResources__fields[5] = {
+  {1, UPB_SIZE(20, 40), 1, 1, 11, 1},
+  {2, UPB_SIZE(24, 48), 2, 1, 11, 1},
+  {3, UPB_SIZE(28, 56), 3, 0, 11, 1},
+  {5, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {6, UPB_SIZE(12, 24), 0, 0, 9, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit = {
+  &envoy_config_bootstrap_v3_Bootstrap_DynamicResources_submsgs[0],
+  &envoy_config_bootstrap_v3_Bootstrap_DynamicResources__fields[0],
+  UPB_SIZE(32, 64), 5, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_submsgs[1] = {
+  &envoy_config_core_v3_TypedExtensionConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), 0, 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_msginit = {
+  &envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_submsgs[0],
+  &envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Admin_submsgs[2] = {
+  &envoy_config_core_v3_Address_msginit,
+  &envoy_config_core_v3_SocketOption_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Admin__fields[4] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 0, 0, 9, 1},
+  {3, UPB_SIZE(20, 40), 1, 0, 11, 1},
+  {4, UPB_SIZE(24, 48), 0, 1, 11, 3},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Admin_msginit = {
+  &envoy_config_bootstrap_v3_Admin_submsgs[0],
+  &envoy_config_bootstrap_v3_Admin__fields[0],
+  UPB_SIZE(32, 64), 4, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_ClusterManager_submsgs[3] = {
+  &envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit,
+  &envoy_config_core_v3_ApiConfigSource_msginit,
+  &envoy_config_core_v3_BindConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_ClusterManager__fields[4] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 1, 0, 11, 1},
+  {3, UPB_SIZE(16, 32), 2, 2, 11, 1},
+  {4, UPB_SIZE(20, 40), 3, 1, 11, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_ClusterManager_msginit = {
+  &envoy_config_bootstrap_v3_ClusterManager_submsgs[0],
+  &envoy_config_bootstrap_v3_ClusterManager__fields[0],
+  UPB_SIZE(24, 48), 4, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_submsgs[1] = {
+  &envoy_config_core_v3_EventServiceConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_ClusterManager_OutlierDetection__fields[2] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 1, 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit = {
+  &envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_submsgs[0],
+  &envoy_config_bootstrap_v3_ClusterManager_OutlierDetection__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Watchdogs_submsgs[1] = {
+  &envoy_config_bootstrap_v3_Watchdog_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Watchdogs__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 2, 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Watchdogs_msginit = {
+  &envoy_config_bootstrap_v3_Watchdogs_submsgs[0],
+  &envoy_config_bootstrap_v3_Watchdogs__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Watchdog_submsgs[3] = {
+  &envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit,
+  &envoy_type_v3_Percent_msginit,
+  &google_protobuf_Duration_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Watchdog__fields[7] = {
+  {1, UPB_SIZE(4, 8), 1, 2, 11, 1},
+  {2, UPB_SIZE(8, 16), 2, 2, 11, 1},
+  {3, UPB_SIZE(12, 24), 3, 2, 11, 1},
+  {4, UPB_SIZE(16, 32), 4, 2, 11, 1},
+  {5, UPB_SIZE(20, 40), 5, 1, 11, 1},
+  {6, UPB_SIZE(24, 48), 6, 2, 11, 1},
+  {7, UPB_SIZE(28, 56), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Watchdog_msginit = {
+  &envoy_config_bootstrap_v3_Watchdog_submsgs[0],
+  &envoy_config_bootstrap_v3_Watchdog__fields[0],
+  UPB_SIZE(32, 64), 7, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Watchdog_WatchdogAction_submsgs[1] = {
+  &envoy_config_core_v3_TypedExtensionConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Watchdog_WatchdogAction__fields[2] = {
+  {1, UPB_SIZE(8, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit = {
+  &envoy_config_bootstrap_v3_Watchdog_WatchdogAction_submsgs[0],
+  &envoy_config_bootstrap_v3_Watchdog_WatchdogAction__fields[0],
+  UPB_SIZE(16, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_FatalAction_submsgs[1] = {
+  &envoy_config_core_v3_TypedExtensionConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_FatalAction__fields[1] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_FatalAction_msginit = {
+  &envoy_config_bootstrap_v3_FatalAction_submsgs[0],
+  &envoy_config_bootstrap_v3_FatalAction__fields[0],
+  UPB_SIZE(8, 16), 1, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_Runtime_submsgs[1] = {
+  &google_protobuf_Struct_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_Runtime__fields[4] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 0, 0, 9, 1},
+  {3, UPB_SIZE(20, 40), 0, 0, 9, 1},
+  {4, UPB_SIZE(28, 56), 1, 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_Runtime_msginit = {
+  &envoy_config_bootstrap_v3_Runtime_submsgs[0],
+  &envoy_config_bootstrap_v3_Runtime__fields[0],
+  UPB_SIZE(32, 64), 4, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_RuntimeLayer_submsgs[4] = {
+  &envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit,
+  &envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit,
+  &envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit,
+  &google_protobuf_Struct_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_RuntimeLayer__fields[5] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 3, 11, 1},
+  {3, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 1, 11, 1},
+  {4, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+  {5, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 2, 11, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_msginit = {
+  &envoy_config_bootstrap_v3_RuntimeLayer_submsgs[0],
+  &envoy_config_bootstrap_v3_RuntimeLayer__fields[0],
+  UPB_SIZE(16, 32), 5, false, 255,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer__fields[3] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(0, 0), 0, 0, 8, 1},
+  {3, UPB_SIZE(12, 24), 0, 0, 9, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit = {
+  NULL,
+  &envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit = {
+  NULL,
+  NULL,
+  UPB_SIZE(0, 0), 0, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_submsgs[1] = {
+  &envoy_config_core_v3_ConfigSource_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer__fields[2] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 1, 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit = {
+  &envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_submsgs[0],
+  &envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_bootstrap_v3_LayeredRuntime_submsgs[1] = {
+  &envoy_config_bootstrap_v3_RuntimeLayer_msginit,
+};
+
+static const upb_msglayout_field envoy_config_bootstrap_v3_LayeredRuntime__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_config_bootstrap_v3_LayeredRuntime_msginit = {
+  &envoy_config_bootstrap_v3_LayeredRuntime_submsgs[0],
+  &envoy_config_bootstrap_v3_LayeredRuntime__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h
new file mode 100644
index 0000000..42e4c85
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h
@@ -0,0 +1,1348 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/bootstrap/v3/bootstrap.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_CONFIG_BOOTSTRAP_V3_BOOTSTRAP_PROTO_UPB_H_
+#define ENVOY_CONFIG_BOOTSTRAP_V3_BOOTSTRAP_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_config_bootstrap_v3_Bootstrap;
+struct envoy_config_bootstrap_v3_Bootstrap_StaticResources;
+struct envoy_config_bootstrap_v3_Bootstrap_DynamicResources;
+struct envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry;
+struct envoy_config_bootstrap_v3_Admin;
+struct envoy_config_bootstrap_v3_ClusterManager;
+struct envoy_config_bootstrap_v3_ClusterManager_OutlierDetection;
+struct envoy_config_bootstrap_v3_Watchdogs;
+struct envoy_config_bootstrap_v3_Watchdog;
+struct envoy_config_bootstrap_v3_Watchdog_WatchdogAction;
+struct envoy_config_bootstrap_v3_FatalAction;
+struct envoy_config_bootstrap_v3_Runtime;
+struct envoy_config_bootstrap_v3_RuntimeLayer;
+struct envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer;
+struct envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer;
+struct envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer;
+struct envoy_config_bootstrap_v3_LayeredRuntime;
+typedef struct envoy_config_bootstrap_v3_Bootstrap envoy_config_bootstrap_v3_Bootstrap;
+typedef struct envoy_config_bootstrap_v3_Bootstrap_StaticResources envoy_config_bootstrap_v3_Bootstrap_StaticResources;
+typedef struct envoy_config_bootstrap_v3_Bootstrap_DynamicResources envoy_config_bootstrap_v3_Bootstrap_DynamicResources;
+typedef struct envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry;
+typedef struct envoy_config_bootstrap_v3_Admin envoy_config_bootstrap_v3_Admin;
+typedef struct envoy_config_bootstrap_v3_ClusterManager envoy_config_bootstrap_v3_ClusterManager;
+typedef struct envoy_config_bootstrap_v3_ClusterManager_OutlierDetection envoy_config_bootstrap_v3_ClusterManager_OutlierDetection;
+typedef struct envoy_config_bootstrap_v3_Watchdogs envoy_config_bootstrap_v3_Watchdogs;
+typedef struct envoy_config_bootstrap_v3_Watchdog envoy_config_bootstrap_v3_Watchdog;
+typedef struct envoy_config_bootstrap_v3_Watchdog_WatchdogAction envoy_config_bootstrap_v3_Watchdog_WatchdogAction;
+typedef struct envoy_config_bootstrap_v3_FatalAction envoy_config_bootstrap_v3_FatalAction;
+typedef struct envoy_config_bootstrap_v3_Runtime envoy_config_bootstrap_v3_Runtime;
+typedef struct envoy_config_bootstrap_v3_RuntimeLayer envoy_config_bootstrap_v3_RuntimeLayer;
+typedef struct envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer;
+typedef struct envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer;
+typedef struct envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer;
+typedef struct envoy_config_bootstrap_v3_LayeredRuntime envoy_config_bootstrap_v3_LayeredRuntime;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Admin_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_ClusterManager_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Watchdogs_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Watchdog_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_FatalAction_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Runtime_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_LayeredRuntime_msginit;
+struct envoy_config_cluster_v3_Cluster;
+struct envoy_config_core_v3_Address;
+struct envoy_config_core_v3_ApiConfigSource;
+struct envoy_config_core_v3_BindConfig;
+struct envoy_config_core_v3_ConfigSource;
+struct envoy_config_core_v3_EventServiceConfig;
+struct envoy_config_core_v3_Node;
+struct envoy_config_core_v3_SocketOption;
+struct envoy_config_core_v3_TypedExtensionConfig;
+struct envoy_config_listener_v3_Listener;
+struct envoy_config_metrics_v3_StatsConfig;
+struct envoy_config_metrics_v3_StatsSink;
+struct envoy_config_overload_v3_OverloadManager;
+struct envoy_config_trace_v3_Tracing;
+struct envoy_extensions_transport_sockets_tls_v3_Secret;
+struct envoy_type_v3_Percent;
+struct google_protobuf_Duration;
+struct google_protobuf_Struct;
+struct google_protobuf_UInt64Value;
+extern const upb_msglayout envoy_config_cluster_v3_Cluster_msginit;
+extern const upb_msglayout envoy_config_core_v3_Address_msginit;
+extern const upb_msglayout envoy_config_core_v3_ApiConfigSource_msginit;
+extern const upb_msglayout envoy_config_core_v3_BindConfig_msginit;
+extern const upb_msglayout envoy_config_core_v3_ConfigSource_msginit;
+extern const upb_msglayout envoy_config_core_v3_EventServiceConfig_msginit;
+extern const upb_msglayout envoy_config_core_v3_Node_msginit;
+extern const upb_msglayout envoy_config_core_v3_SocketOption_msginit;
+extern const upb_msglayout envoy_config_core_v3_TypedExtensionConfig_msginit;
+extern const upb_msglayout envoy_config_listener_v3_Listener_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsConfig_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsSink_msginit;
+extern const upb_msglayout envoy_config_overload_v3_OverloadManager_msginit;
+extern const upb_msglayout envoy_config_trace_v3_Tracing_msginit;
+extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_Secret_msginit;
+extern const upb_msglayout envoy_type_v3_Percent_msginit;
+extern const upb_msglayout google_protobuf_Duration_msginit;
+extern const upb_msglayout google_protobuf_Struct_msginit;
+extern const upb_msglayout google_protobuf_UInt64Value_msginit;
+
+typedef enum {
+  envoy_config_bootstrap_v3_Watchdog_WatchdogAction_UNKNOWN = 0,
+  envoy_config_bootstrap_v3_Watchdog_WatchdogAction_KILL = 1,
+  envoy_config_bootstrap_v3_Watchdog_WatchdogAction_MULTIKILL = 2,
+  envoy_config_bootstrap_v3_Watchdog_WatchdogAction_MEGAMISS = 3,
+  envoy_config_bootstrap_v3_Watchdog_WatchdogAction_MISS = 4
+} envoy_config_bootstrap_v3_Watchdog_WatchdogAction_WatchdogEvent;
+
+
+/* envoy.config.bootstrap.v3.Bootstrap */
+
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap *envoy_config_bootstrap_v3_Bootstrap_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Bootstrap *)_upb_msg_new(&envoy_config_bootstrap_v3_Bootstrap_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap *envoy_config_bootstrap_v3_Bootstrap_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_Bootstrap *ret = envoy_config_bootstrap_v3_Bootstrap_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Bootstrap_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap *envoy_config_bootstrap_v3_Bootstrap_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_Bootstrap *ret = envoy_config_bootstrap_v3_Bootstrap_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Bootstrap_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_Bootstrap_serialize(const envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_Bootstrap_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_bootstrap_v3_Bootstrap_stats_flush_stats_flush_on_admin = 29,
+  envoy_config_bootstrap_v3_Bootstrap_stats_flush_NOT_SET = 0
+} envoy_config_bootstrap_v3_Bootstrap_stats_flush_oneofcases;
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap_stats_flush_oneofcases envoy_config_bootstrap_v3_Bootstrap_stats_flush_case(const envoy_config_bootstrap_v3_Bootstrap* msg) { return (envoy_config_bootstrap_v3_Bootstrap_stats_flush_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(116, 228), int32_t); }
+
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_node(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_Node* envoy_config_bootstrap_v3_Bootstrap_node(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const struct envoy_config_core_v3_Node*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_static_resources(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const envoy_config_bootstrap_v3_Bootstrap_StaticResources* envoy_config_bootstrap_v3_Bootstrap_static_resources(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const envoy_config_bootstrap_v3_Bootstrap_StaticResources*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_dynamic_resources(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const envoy_config_bootstrap_v3_Bootstrap_DynamicResources* envoy_config_bootstrap_v3_Bootstrap_dynamic_resources(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 72), const envoy_config_bootstrap_v3_Bootstrap_DynamicResources*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_cluster_manager(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE const envoy_config_bootstrap_v3_ClusterManager* envoy_config_bootstrap_v3_Bootstrap_cluster_manager(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const envoy_config_bootstrap_v3_ClusterManager*); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Bootstrap_flags_path(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_stats_sinks(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(88, 176)); }
+UPB_INLINE const struct envoy_config_metrics_v3_StatsSink* const* envoy_config_bootstrap_v3_Bootstrap_stats_sinks(const envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) { return (const struct envoy_config_metrics_v3_StatsSink* const*)_upb_array_accessor(msg, UPB_SIZE(88, 176), len); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_stats_flush_interval(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 5); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_bootstrap_v3_Bootstrap_stats_flush_interval(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_watchdog(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE const envoy_config_bootstrap_v3_Watchdog* envoy_config_bootstrap_v3_Bootstrap_watchdog(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 96), const envoy_config_bootstrap_v3_Watchdog*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_tracing(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 7); }
+UPB_INLINE const struct envoy_config_trace_v3_Tracing* envoy_config_bootstrap_v3_Bootstrap_tracing(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 104), const struct envoy_config_trace_v3_Tracing*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_admin(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 8); }
+UPB_INLINE const envoy_config_bootstrap_v3_Admin* envoy_config_bootstrap_v3_Bootstrap_admin(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(56, 112), const envoy_config_bootstrap_v3_Admin*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_stats_config(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 9); }
+UPB_INLINE const struct envoy_config_metrics_v3_StatsConfig* envoy_config_bootstrap_v3_Bootstrap_stats_config(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 120), const struct envoy_config_metrics_v3_StatsConfig*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_hds_config(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 10); }
+UPB_INLINE const struct envoy_config_core_v3_ApiConfigSource* envoy_config_bootstrap_v3_Bootstrap_hds_config(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(64, 128), const struct envoy_config_core_v3_ApiConfigSource*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_overload_manager(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 11); }
+UPB_INLINE const struct envoy_config_overload_v3_OverloadManager* envoy_config_bootstrap_v3_Bootstrap_overload_manager(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 136), const struct envoy_config_overload_v3_OverloadManager*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_enable_dispatcher_stats(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_layered_runtime(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 12); }
+UPB_INLINE const envoy_config_bootstrap_v3_LayeredRuntime* envoy_config_bootstrap_v3_Bootstrap_layered_runtime(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(72, 144), const envoy_config_bootstrap_v3_LayeredRuntime*); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Bootstrap_header_prefix(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_stats_server_version_override(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 13); }
+UPB_INLINE const struct google_protobuf_UInt64Value* envoy_config_bootstrap_v3_Bootstrap_stats_server_version_override(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 152), const struct google_protobuf_UInt64Value*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_use_tcp_for_dns_lookups(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_bootstrap_extensions(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(92, 184)); }
+UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* const* envoy_config_bootstrap_v3_Bootstrap_bootstrap_extensions(const envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) { return (const struct envoy_config_core_v3_TypedExtensionConfig* const*)_upb_array_accessor(msg, UPB_SIZE(92, 184), len); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_config_sources(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(96, 192)); }
+UPB_INLINE const struct envoy_config_core_v3_ConfigSource* const* envoy_config_bootstrap_v3_Bootstrap_config_sources(const envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) { return (const struct envoy_config_core_v3_ConfigSource* const*)_upb_array_accessor(msg, UPB_SIZE(96, 192), len); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_default_config_source(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 14); }
+UPB_INLINE const struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_Bootstrap_default_config_source(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(80, 160), const struct envoy_config_core_v3_ConfigSource*); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Bootstrap_default_socket_interface(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_certificate_provider_instances(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 200)); }
+UPB_INLINE size_t envoy_config_bootstrap_v3_Bootstrap_certificate_provider_instances_size(const envoy_config_bootstrap_v3_Bootstrap *msg) {return _upb_msg_map_size(msg, UPB_SIZE(100, 200)); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_certificate_provider_instances_get(const envoy_config_bootstrap_v3_Bootstrap *msg, upb_strview key, struct envoy_config_core_v3_TypedExtensionConfig* *val) { return _upb_msg_map_get(msg, UPB_SIZE(100, 200), &key, 0, val, sizeof(*val)); }
+UPB_INLINE const envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry* envoy_config_bootstrap_v3_Bootstrap_certificate_provider_instances_next(const envoy_config_bootstrap_v3_Bootstrap *msg, size_t* iter) { return (const envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry*)_upb_msg_map_next(msg, UPB_SIZE(100, 200), iter); }
+UPB_INLINE upb_strview const* envoy_config_bootstrap_v3_Bootstrap_node_context_params(const envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(104, 208), len); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_watchdogs(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_hasbit(msg, 15); }
+UPB_INLINE const envoy_config_bootstrap_v3_Watchdogs* envoy_config_bootstrap_v3_Bootstrap_watchdogs(const envoy_config_bootstrap_v3_Bootstrap *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 168), const envoy_config_bootstrap_v3_Watchdogs*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_fatal_actions(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(108, 216)); }
+UPB_INLINE const envoy_config_bootstrap_v3_FatalAction* const* envoy_config_bootstrap_v3_Bootstrap_fatal_actions(const envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) { return (const envoy_config_bootstrap_v3_FatalAction* const*)_upb_array_accessor(msg, UPB_SIZE(108, 216), len); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_has_stats_flush_on_admin(const envoy_config_bootstrap_v3_Bootstrap *msg) { return _upb_getoneofcase(msg, UPB_SIZE(116, 228)) == 29; }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_stats_flush_on_admin(const envoy_config_bootstrap_v3_Bootstrap *msg) { return UPB_READ_ONEOF(msg, bool, UPB_SIZE(112, 224), UPB_SIZE(116, 228), 29, false); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_node(envoy_config_bootstrap_v3_Bootstrap *msg, struct envoy_config_core_v3_Node* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 56), struct envoy_config_core_v3_Node*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_Node* envoy_config_bootstrap_v3_Bootstrap_mutable_node(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_Node* sub = (struct envoy_config_core_v3_Node*)envoy_config_bootstrap_v3_Bootstrap_node(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_Node*)_upb_msg_new(&envoy_config_core_v3_Node_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_node(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_static_resources(envoy_config_bootstrap_v3_Bootstrap *msg, envoy_config_bootstrap_v3_Bootstrap_StaticResources* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(32, 64), envoy_config_bootstrap_v3_Bootstrap_StaticResources*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Bootstrap_StaticResources* envoy_config_bootstrap_v3_Bootstrap_mutable_static_resources(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Bootstrap_StaticResources* sub = (struct envoy_config_bootstrap_v3_Bootstrap_StaticResources*)envoy_config_bootstrap_v3_Bootstrap_static_resources(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_Bootstrap_StaticResources*)_upb_msg_new(&envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_static_resources(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_dynamic_resources(envoy_config_bootstrap_v3_Bootstrap *msg, envoy_config_bootstrap_v3_Bootstrap_DynamicResources* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(36, 72), envoy_config_bootstrap_v3_Bootstrap_DynamicResources*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Bootstrap_DynamicResources* envoy_config_bootstrap_v3_Bootstrap_mutable_dynamic_resources(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Bootstrap_DynamicResources* sub = (struct envoy_config_bootstrap_v3_Bootstrap_DynamicResources*)envoy_config_bootstrap_v3_Bootstrap_dynamic_resources(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_Bootstrap_DynamicResources*)_upb_msg_new(&envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_dynamic_resources(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_cluster_manager(envoy_config_bootstrap_v3_Bootstrap *msg, envoy_config_bootstrap_v3_ClusterManager* value) {
+  _upb_sethas(msg, 4);
+  *UPB_PTR_AT(msg, UPB_SIZE(40, 80), envoy_config_bootstrap_v3_ClusterManager*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_ClusterManager* envoy_config_bootstrap_v3_Bootstrap_mutable_cluster_manager(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_ClusterManager* sub = (struct envoy_config_bootstrap_v3_ClusterManager*)envoy_config_bootstrap_v3_Bootstrap_cluster_manager(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_ClusterManager*)_upb_msg_new(&envoy_config_bootstrap_v3_ClusterManager_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_cluster_manager(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_flags_path(envoy_config_bootstrap_v3_Bootstrap *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE struct envoy_config_metrics_v3_StatsSink** envoy_config_bootstrap_v3_Bootstrap_mutable_stats_sinks(envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) {
+  return (struct envoy_config_metrics_v3_StatsSink**)_upb_array_mutable_accessor(msg, UPB_SIZE(88, 176), len);
+}
+UPB_INLINE struct envoy_config_metrics_v3_StatsSink** envoy_config_bootstrap_v3_Bootstrap_resize_stats_sinks(envoy_config_bootstrap_v3_Bootstrap *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_metrics_v3_StatsSink**)_upb_array_resize_accessor2(msg, UPB_SIZE(88, 176), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_metrics_v3_StatsSink* envoy_config_bootstrap_v3_Bootstrap_add_stats_sinks(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_metrics_v3_StatsSink* sub = (struct envoy_config_metrics_v3_StatsSink*)_upb_msg_new(&envoy_config_metrics_v3_StatsSink_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(88, 176), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_stats_flush_interval(envoy_config_bootstrap_v3_Bootstrap *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 5);
+  *UPB_PTR_AT(msg, UPB_SIZE(44, 88), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_bootstrap_v3_Bootstrap_mutable_stats_flush_interval(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_bootstrap_v3_Bootstrap_stats_flush_interval(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_stats_flush_interval(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_watchdog(envoy_config_bootstrap_v3_Bootstrap *msg, envoy_config_bootstrap_v3_Watchdog* value) {
+  _upb_sethas(msg, 6);
+  *UPB_PTR_AT(msg, UPB_SIZE(48, 96), envoy_config_bootstrap_v3_Watchdog*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Watchdog* envoy_config_bootstrap_v3_Bootstrap_mutable_watchdog(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Watchdog* sub = (struct envoy_config_bootstrap_v3_Watchdog*)envoy_config_bootstrap_v3_Bootstrap_watchdog(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_Watchdog*)_upb_msg_new(&envoy_config_bootstrap_v3_Watchdog_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_watchdog(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_tracing(envoy_config_bootstrap_v3_Bootstrap *msg, struct envoy_config_trace_v3_Tracing* value) {
+  _upb_sethas(msg, 7);
+  *UPB_PTR_AT(msg, UPB_SIZE(52, 104), struct envoy_config_trace_v3_Tracing*) = value;
+}
+UPB_INLINE struct envoy_config_trace_v3_Tracing* envoy_config_bootstrap_v3_Bootstrap_mutable_tracing(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_trace_v3_Tracing* sub = (struct envoy_config_trace_v3_Tracing*)envoy_config_bootstrap_v3_Bootstrap_tracing(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_trace_v3_Tracing*)_upb_msg_new(&envoy_config_trace_v3_Tracing_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_tracing(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_admin(envoy_config_bootstrap_v3_Bootstrap *msg, envoy_config_bootstrap_v3_Admin* value) {
+  _upb_sethas(msg, 8);
+  *UPB_PTR_AT(msg, UPB_SIZE(56, 112), envoy_config_bootstrap_v3_Admin*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Admin* envoy_config_bootstrap_v3_Bootstrap_mutable_admin(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Admin* sub = (struct envoy_config_bootstrap_v3_Admin*)envoy_config_bootstrap_v3_Bootstrap_admin(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_Admin*)_upb_msg_new(&envoy_config_bootstrap_v3_Admin_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_admin(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_stats_config(envoy_config_bootstrap_v3_Bootstrap *msg, struct envoy_config_metrics_v3_StatsConfig* value) {
+  _upb_sethas(msg, 9);
+  *UPB_PTR_AT(msg, UPB_SIZE(60, 120), struct envoy_config_metrics_v3_StatsConfig*) = value;
+}
+UPB_INLINE struct envoy_config_metrics_v3_StatsConfig* envoy_config_bootstrap_v3_Bootstrap_mutable_stats_config(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_metrics_v3_StatsConfig* sub = (struct envoy_config_metrics_v3_StatsConfig*)envoy_config_bootstrap_v3_Bootstrap_stats_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_metrics_v3_StatsConfig*)_upb_msg_new(&envoy_config_metrics_v3_StatsConfig_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_stats_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_hds_config(envoy_config_bootstrap_v3_Bootstrap *msg, struct envoy_config_core_v3_ApiConfigSource* value) {
+  _upb_sethas(msg, 10);
+  *UPB_PTR_AT(msg, UPB_SIZE(64, 128), struct envoy_config_core_v3_ApiConfigSource*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_ApiConfigSource* envoy_config_bootstrap_v3_Bootstrap_mutable_hds_config(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ApiConfigSource* sub = (struct envoy_config_core_v3_ApiConfigSource*)envoy_config_bootstrap_v3_Bootstrap_hds_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ApiConfigSource*)_upb_msg_new(&envoy_config_core_v3_ApiConfigSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_hds_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_overload_manager(envoy_config_bootstrap_v3_Bootstrap *msg, struct envoy_config_overload_v3_OverloadManager* value) {
+  _upb_sethas(msg, 11);
+  *UPB_PTR_AT(msg, UPB_SIZE(68, 136), struct envoy_config_overload_v3_OverloadManager*) = value;
+}
+UPB_INLINE struct envoy_config_overload_v3_OverloadManager* envoy_config_bootstrap_v3_Bootstrap_mutable_overload_manager(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_overload_v3_OverloadManager* sub = (struct envoy_config_overload_v3_OverloadManager*)envoy_config_bootstrap_v3_Bootstrap_overload_manager(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_overload_v3_OverloadManager*)_upb_msg_new(&envoy_config_overload_v3_OverloadManager_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_overload_manager(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_enable_dispatcher_stats(envoy_config_bootstrap_v3_Bootstrap *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_layered_runtime(envoy_config_bootstrap_v3_Bootstrap *msg, envoy_config_bootstrap_v3_LayeredRuntime* value) {
+  _upb_sethas(msg, 12);
+  *UPB_PTR_AT(msg, UPB_SIZE(72, 144), envoy_config_bootstrap_v3_LayeredRuntime*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_LayeredRuntime* envoy_config_bootstrap_v3_Bootstrap_mutable_layered_runtime(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_LayeredRuntime* sub = (struct envoy_config_bootstrap_v3_LayeredRuntime*)envoy_config_bootstrap_v3_Bootstrap_layered_runtime(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_LayeredRuntime*)_upb_msg_new(&envoy_config_bootstrap_v3_LayeredRuntime_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_layered_runtime(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_header_prefix(envoy_config_bootstrap_v3_Bootstrap *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_stats_server_version_override(envoy_config_bootstrap_v3_Bootstrap *msg, struct google_protobuf_UInt64Value* value) {
+  _upb_sethas(msg, 13);
+  *UPB_PTR_AT(msg, UPB_SIZE(76, 152), struct google_protobuf_UInt64Value*) = value;
+}
+UPB_INLINE struct google_protobuf_UInt64Value* envoy_config_bootstrap_v3_Bootstrap_mutable_stats_server_version_override(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct google_protobuf_UInt64Value* sub = (struct google_protobuf_UInt64Value*)envoy_config_bootstrap_v3_Bootstrap_stats_server_version_override(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_UInt64Value*)_upb_msg_new(&google_protobuf_UInt64Value_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_stats_server_version_override(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_use_tcp_for_dns_lookups(envoy_config_bootstrap_v3_Bootstrap *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig** envoy_config_bootstrap_v3_Bootstrap_mutable_bootstrap_extensions(envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) {
+  return (struct envoy_config_core_v3_TypedExtensionConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(92, 184), len);
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig** envoy_config_bootstrap_v3_Bootstrap_resize_bootstrap_extensions(envoy_config_bootstrap_v3_Bootstrap *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_core_v3_TypedExtensionConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(92, 184), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_bootstrap_v3_Bootstrap_add_bootstrap_extensions(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_TypedExtensionConfig* sub = (struct envoy_config_core_v3_TypedExtensionConfig*)_upb_msg_new(&envoy_config_core_v3_TypedExtensionConfig_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(92, 184), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE struct envoy_config_core_v3_ConfigSource** envoy_config_bootstrap_v3_Bootstrap_mutable_config_sources(envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) {
+  return (struct envoy_config_core_v3_ConfigSource**)_upb_array_mutable_accessor(msg, UPB_SIZE(96, 192), len);
+}
+UPB_INLINE struct envoy_config_core_v3_ConfigSource** envoy_config_bootstrap_v3_Bootstrap_resize_config_sources(envoy_config_bootstrap_v3_Bootstrap *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_core_v3_ConfigSource**)_upb_array_resize_accessor2(msg, UPB_SIZE(96, 192), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_Bootstrap_add_config_sources(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ConfigSource* sub = (struct envoy_config_core_v3_ConfigSource*)_upb_msg_new(&envoy_config_core_v3_ConfigSource_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(96, 192), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_default_config_source(envoy_config_bootstrap_v3_Bootstrap *msg, struct envoy_config_core_v3_ConfigSource* value) {
+  _upb_sethas(msg, 14);
+  *UPB_PTR_AT(msg, UPB_SIZE(80, 160), struct envoy_config_core_v3_ConfigSource*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_Bootstrap_mutable_default_config_source(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ConfigSource* sub = (struct envoy_config_core_v3_ConfigSource*)envoy_config_bootstrap_v3_Bootstrap_default_config_source(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ConfigSource*)_upb_msg_new(&envoy_config_core_v3_ConfigSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_default_config_source(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_default_socket_interface(envoy_config_bootstrap_v3_Bootstrap *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_certificate_provider_instances_clear(envoy_config_bootstrap_v3_Bootstrap *msg) { _upb_msg_map_clear(msg, UPB_SIZE(100, 200)); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_certificate_provider_instances_set(envoy_config_bootstrap_v3_Bootstrap *msg, upb_strview key, struct envoy_config_core_v3_TypedExtensionConfig* val, upb_arena *a) { return _upb_msg_map_set(msg, UPB_SIZE(100, 200), &key, 0, &val, sizeof(val), a); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_certificate_provider_instances_delete(envoy_config_bootstrap_v3_Bootstrap *msg, upb_strview key) { return _upb_msg_map_delete(msg, UPB_SIZE(100, 200), &key, 0); }
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry* envoy_config_bootstrap_v3_Bootstrap_certificate_provider_instances_nextmutable(envoy_config_bootstrap_v3_Bootstrap *msg, size_t* iter) { return (envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry*)_upb_msg_map_next(msg, UPB_SIZE(100, 200), iter); }
+UPB_INLINE upb_strview* envoy_config_bootstrap_v3_Bootstrap_mutable_node_context_params(envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) {
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(104, 208), len);
+}
+UPB_INLINE upb_strview* envoy_config_bootstrap_v3_Bootstrap_resize_node_context_params(envoy_config_bootstrap_v3_Bootstrap *msg, size_t len, upb_arena *arena) {
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(104, 208), len, UPB_SIZE(3, 4), arena);
+}
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_add_node_context_params(envoy_config_bootstrap_v3_Bootstrap *msg, upb_strview val, upb_arena *arena) {
+  return _upb_array_append_accessor2(msg, UPB_SIZE(104, 208), UPB_SIZE(3, 4), &val,
+      arena);
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_watchdogs(envoy_config_bootstrap_v3_Bootstrap *msg, envoy_config_bootstrap_v3_Watchdogs* value) {
+  _upb_sethas(msg, 15);
+  *UPB_PTR_AT(msg, UPB_SIZE(84, 168), envoy_config_bootstrap_v3_Watchdogs*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Watchdogs* envoy_config_bootstrap_v3_Bootstrap_mutable_watchdogs(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Watchdogs* sub = (struct envoy_config_bootstrap_v3_Watchdogs*)envoy_config_bootstrap_v3_Bootstrap_watchdogs(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_Watchdogs*)_upb_msg_new(&envoy_config_bootstrap_v3_Watchdogs_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_set_watchdogs(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE envoy_config_bootstrap_v3_FatalAction** envoy_config_bootstrap_v3_Bootstrap_mutable_fatal_actions(envoy_config_bootstrap_v3_Bootstrap *msg, size_t *len) {
+  return (envoy_config_bootstrap_v3_FatalAction**)_upb_array_mutable_accessor(msg, UPB_SIZE(108, 216), len);
+}
+UPB_INLINE envoy_config_bootstrap_v3_FatalAction** envoy_config_bootstrap_v3_Bootstrap_resize_fatal_actions(envoy_config_bootstrap_v3_Bootstrap *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_FatalAction**)_upb_array_resize_accessor2(msg, UPB_SIZE(108, 216), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_FatalAction* envoy_config_bootstrap_v3_Bootstrap_add_fatal_actions(envoy_config_bootstrap_v3_Bootstrap *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_FatalAction* sub = (struct envoy_config_bootstrap_v3_FatalAction*)_upb_msg_new(&envoy_config_bootstrap_v3_FatalAction_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(108, 216), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_set_stats_flush_on_admin(envoy_config_bootstrap_v3_Bootstrap *msg, bool value) {
+  UPB_WRITE_ONEOF(msg, bool, UPB_SIZE(112, 224), value, UPB_SIZE(116, 228), 29);
+}
+
+/* envoy.config.bootstrap.v3.Bootstrap.StaticResources */
+
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap_StaticResources *envoy_config_bootstrap_v3_Bootstrap_StaticResources_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Bootstrap_StaticResources *)_upb_msg_new(&envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap_StaticResources *envoy_config_bootstrap_v3_Bootstrap_StaticResources_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_Bootstrap_StaticResources *ret = envoy_config_bootstrap_v3_Bootstrap_StaticResources_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap_StaticResources *envoy_config_bootstrap_v3_Bootstrap_StaticResources_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_Bootstrap_StaticResources *ret = envoy_config_bootstrap_v3_Bootstrap_StaticResources_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_Bootstrap_StaticResources_serialize(const envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_StaticResources_has_listeners(const envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const struct envoy_config_listener_v3_Listener* const* envoy_config_bootstrap_v3_Bootstrap_StaticResources_listeners(const envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t *len) { return (const struct envoy_config_listener_v3_Listener* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_StaticResources_has_clusters(const envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
+UPB_INLINE const struct envoy_config_cluster_v3_Cluster* const* envoy_config_bootstrap_v3_Bootstrap_StaticResources_clusters(const envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t *len) { return (const struct envoy_config_cluster_v3_Cluster* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_StaticResources_has_secrets(const envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const struct envoy_extensions_transport_sockets_tls_v3_Secret* const* envoy_config_bootstrap_v3_Bootstrap_StaticResources_secrets(const envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t *len) { return (const struct envoy_extensions_transport_sockets_tls_v3_Secret* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+
+UPB_INLINE struct envoy_config_listener_v3_Listener** envoy_config_bootstrap_v3_Bootstrap_StaticResources_mutable_listeners(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t *len) {
+  return (struct envoy_config_listener_v3_Listener**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE struct envoy_config_listener_v3_Listener** envoy_config_bootstrap_v3_Bootstrap_StaticResources_resize_listeners(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_listener_v3_Listener**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_listener_v3_Listener* envoy_config_bootstrap_v3_Bootstrap_StaticResources_add_listeners(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, upb_arena *arena) {
+  struct envoy_config_listener_v3_Listener* sub = (struct envoy_config_listener_v3_Listener*)_upb_msg_new(&envoy_config_listener_v3_Listener_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE struct envoy_config_cluster_v3_Cluster** envoy_config_bootstrap_v3_Bootstrap_StaticResources_mutable_clusters(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t *len) {
+  return (struct envoy_config_cluster_v3_Cluster**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
+}
+UPB_INLINE struct envoy_config_cluster_v3_Cluster** envoy_config_bootstrap_v3_Bootstrap_StaticResources_resize_clusters(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_cluster_v3_Cluster**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_cluster_v3_Cluster* envoy_config_bootstrap_v3_Bootstrap_StaticResources_add_clusters(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, upb_arena *arena) {
+  struct envoy_config_cluster_v3_Cluster* sub = (struct envoy_config_cluster_v3_Cluster*)_upb_msg_new(&envoy_config_cluster_v3_Cluster_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE struct envoy_extensions_transport_sockets_tls_v3_Secret** envoy_config_bootstrap_v3_Bootstrap_StaticResources_mutable_secrets(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t *len) {
+  return (struct envoy_extensions_transport_sockets_tls_v3_Secret**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE struct envoy_extensions_transport_sockets_tls_v3_Secret** envoy_config_bootstrap_v3_Bootstrap_StaticResources_resize_secrets(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_extensions_transport_sockets_tls_v3_Secret**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_extensions_transport_sockets_tls_v3_Secret* envoy_config_bootstrap_v3_Bootstrap_StaticResources_add_secrets(envoy_config_bootstrap_v3_Bootstrap_StaticResources *msg, upb_arena *arena) {
+  struct envoy_extensions_transport_sockets_tls_v3_Secret* sub = (struct envoy_extensions_transport_sockets_tls_v3_Secret*)_upb_msg_new(&envoy_extensions_transport_sockets_tls_v3_Secret_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.Bootstrap.DynamicResources */
+
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap_DynamicResources *envoy_config_bootstrap_v3_Bootstrap_DynamicResources_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Bootstrap_DynamicResources *)_upb_msg_new(&envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap_DynamicResources *envoy_config_bootstrap_v3_Bootstrap_DynamicResources_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_Bootstrap_DynamicResources *ret = envoy_config_bootstrap_v3_Bootstrap_DynamicResources_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Bootstrap_DynamicResources *envoy_config_bootstrap_v3_Bootstrap_DynamicResources_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_Bootstrap_DynamicResources *ret = envoy_config_bootstrap_v3_Bootstrap_DynamicResources_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_Bootstrap_DynamicResources_serialize(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_DynamicResources_has_lds_config(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_Bootstrap_DynamicResources_lds_config(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct envoy_config_core_v3_ConfigSource*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_DynamicResources_has_cds_config(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_Bootstrap_DynamicResources_cds_config(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), const struct envoy_config_core_v3_ConfigSource*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_DynamicResources_has_ads_config(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const struct envoy_config_core_v3_ApiConfigSource* envoy_config_bootstrap_v3_Bootstrap_DynamicResources_ads_config(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const struct envoy_config_core_v3_ApiConfigSource*); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Bootstrap_DynamicResources_lds_resources_locator(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Bootstrap_DynamicResources_cds_resources_locator(const envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_DynamicResources_set_lds_config(envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, struct envoy_config_core_v3_ConfigSource* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct envoy_config_core_v3_ConfigSource*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_Bootstrap_DynamicResources_mutable_lds_config(envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ConfigSource* sub = (struct envoy_config_core_v3_ConfigSource*)envoy_config_bootstrap_v3_Bootstrap_DynamicResources_lds_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ConfigSource*)_upb_msg_new(&envoy_config_core_v3_ConfigSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_DynamicResources_set_lds_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_DynamicResources_set_cds_config(envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, struct envoy_config_core_v3_ConfigSource* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 48), struct envoy_config_core_v3_ConfigSource*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_Bootstrap_DynamicResources_mutable_cds_config(envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ConfigSource* sub = (struct envoy_config_core_v3_ConfigSource*)envoy_config_bootstrap_v3_Bootstrap_DynamicResources_cds_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ConfigSource*)_upb_msg_new(&envoy_config_core_v3_ConfigSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_DynamicResources_set_cds_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_DynamicResources_set_ads_config(envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, struct envoy_config_core_v3_ApiConfigSource* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 56), struct envoy_config_core_v3_ApiConfigSource*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_ApiConfigSource* envoy_config_bootstrap_v3_Bootstrap_DynamicResources_mutable_ads_config(envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ApiConfigSource* sub = (struct envoy_config_core_v3_ApiConfigSource*)envoy_config_bootstrap_v3_Bootstrap_DynamicResources_ads_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ApiConfigSource*)_upb_msg_new(&envoy_config_core_v3_ApiConfigSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Bootstrap_DynamicResources_set_ads_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_DynamicResources_set_lds_resources_locator(envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_DynamicResources_set_cds_resources_locator(envoy_config_bootstrap_v3_Bootstrap_DynamicResources *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+
+/* envoy.config.bootstrap.v3.Bootstrap.CertificateProviderInstancesEntry */
+
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_key(const envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry *msg) {
+  upb_strview ret;
+  _upb_msg_map_key(msg, &ret, 0);
+  return ret;
+}
+UPB_INLINE bool envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_has_value(const envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_value(const envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry *msg) {
+  struct envoy_config_core_v3_TypedExtensionConfig* ret;
+  _upb_msg_map_value(msg, &ret, sizeof(ret));
+  return ret;
+}
+
+UPB_INLINE void envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_set_value(envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry *msg, struct envoy_config_core_v3_TypedExtensionConfig* value) {
+  _upb_msg_map_set_value(msg, &value, sizeof(struct envoy_config_core_v3_TypedExtensionConfig*));
+}
+
+/* envoy.config.bootstrap.v3.Admin */
+
+UPB_INLINE envoy_config_bootstrap_v3_Admin *envoy_config_bootstrap_v3_Admin_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Admin *)_upb_msg_new(&envoy_config_bootstrap_v3_Admin_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Admin *envoy_config_bootstrap_v3_Admin_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_Admin *ret = envoy_config_bootstrap_v3_Admin_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Admin_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Admin *envoy_config_bootstrap_v3_Admin_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_Admin *ret = envoy_config_bootstrap_v3_Admin_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Admin_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_Admin_serialize(const envoy_config_bootstrap_v3_Admin *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_Admin_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Admin_access_log_path(const envoy_config_bootstrap_v3_Admin *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Admin_profile_path(const envoy_config_bootstrap_v3_Admin *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Admin_has_address(const envoy_config_bootstrap_v3_Admin *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_Address* envoy_config_bootstrap_v3_Admin_address(const envoy_config_bootstrap_v3_Admin *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct envoy_config_core_v3_Address*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Admin_has_socket_options(const envoy_config_bootstrap_v3_Admin *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); }
+UPB_INLINE const struct envoy_config_core_v3_SocketOption* const* envoy_config_bootstrap_v3_Admin_socket_options(const envoy_config_bootstrap_v3_Admin *msg, size_t *len) { return (const struct envoy_config_core_v3_SocketOption* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_Admin_set_access_log_path(envoy_config_bootstrap_v3_Admin *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Admin_set_profile_path(envoy_config_bootstrap_v3_Admin *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Admin_set_address(envoy_config_bootstrap_v3_Admin *msg, struct envoy_config_core_v3_Address* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct envoy_config_core_v3_Address*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_Address* envoy_config_bootstrap_v3_Admin_mutable_address(envoy_config_bootstrap_v3_Admin *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_Address* sub = (struct envoy_config_core_v3_Address*)envoy_config_bootstrap_v3_Admin_address(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_Address*)_upb_msg_new(&envoy_config_core_v3_Address_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Admin_set_address(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE struct envoy_config_core_v3_SocketOption** envoy_config_bootstrap_v3_Admin_mutable_socket_options(envoy_config_bootstrap_v3_Admin *msg, size_t *len) {
+  return (struct envoy_config_core_v3_SocketOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
+}
+UPB_INLINE struct envoy_config_core_v3_SocketOption** envoy_config_bootstrap_v3_Admin_resize_socket_options(envoy_config_bootstrap_v3_Admin *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_core_v3_SocketOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_core_v3_SocketOption* envoy_config_bootstrap_v3_Admin_add_socket_options(envoy_config_bootstrap_v3_Admin *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_SocketOption* sub = (struct envoy_config_core_v3_SocketOption*)_upb_msg_new(&envoy_config_core_v3_SocketOption_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.ClusterManager */
+
+UPB_INLINE envoy_config_bootstrap_v3_ClusterManager *envoy_config_bootstrap_v3_ClusterManager_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_ClusterManager *)_upb_msg_new(&envoy_config_bootstrap_v3_ClusterManager_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_ClusterManager *envoy_config_bootstrap_v3_ClusterManager_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_ClusterManager *ret = envoy_config_bootstrap_v3_ClusterManager_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_ClusterManager_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_ClusterManager *envoy_config_bootstrap_v3_ClusterManager_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_ClusterManager *ret = envoy_config_bootstrap_v3_ClusterManager_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_ClusterManager_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_ClusterManager_serialize(const envoy_config_bootstrap_v3_ClusterManager *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_ClusterManager_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_ClusterManager_local_cluster_name(const envoy_config_bootstrap_v3_ClusterManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_ClusterManager_has_outlier_detection(const envoy_config_bootstrap_v3_ClusterManager *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const envoy_config_bootstrap_v3_ClusterManager_OutlierDetection* envoy_config_bootstrap_v3_ClusterManager_outlier_detection(const envoy_config_bootstrap_v3_ClusterManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const envoy_config_bootstrap_v3_ClusterManager_OutlierDetection*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_ClusterManager_has_upstream_bind_config(const envoy_config_bootstrap_v3_ClusterManager *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct envoy_config_core_v3_BindConfig* envoy_config_bootstrap_v3_ClusterManager_upstream_bind_config(const envoy_config_bootstrap_v3_ClusterManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct envoy_config_core_v3_BindConfig*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_ClusterManager_has_load_stats_config(const envoy_config_bootstrap_v3_ClusterManager *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const struct envoy_config_core_v3_ApiConfigSource* envoy_config_bootstrap_v3_ClusterManager_load_stats_config(const envoy_config_bootstrap_v3_ClusterManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct envoy_config_core_v3_ApiConfigSource*); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_ClusterManager_set_local_cluster_name(envoy_config_bootstrap_v3_ClusterManager *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_ClusterManager_set_outlier_detection(envoy_config_bootstrap_v3_ClusterManager *msg, envoy_config_bootstrap_v3_ClusterManager_OutlierDetection* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), envoy_config_bootstrap_v3_ClusterManager_OutlierDetection*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_ClusterManager_OutlierDetection* envoy_config_bootstrap_v3_ClusterManager_mutable_outlier_detection(envoy_config_bootstrap_v3_ClusterManager *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_ClusterManager_OutlierDetection* sub = (struct envoy_config_bootstrap_v3_ClusterManager_OutlierDetection*)envoy_config_bootstrap_v3_ClusterManager_outlier_detection(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_ClusterManager_OutlierDetection*)_upb_msg_new(&envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_ClusterManager_set_outlier_detection(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_ClusterManager_set_upstream_bind_config(envoy_config_bootstrap_v3_ClusterManager *msg, struct envoy_config_core_v3_BindConfig* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct envoy_config_core_v3_BindConfig*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_BindConfig* envoy_config_bootstrap_v3_ClusterManager_mutable_upstream_bind_config(envoy_config_bootstrap_v3_ClusterManager *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_BindConfig* sub = (struct envoy_config_core_v3_BindConfig*)envoy_config_bootstrap_v3_ClusterManager_upstream_bind_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_BindConfig*)_upb_msg_new(&envoy_config_core_v3_BindConfig_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_ClusterManager_set_upstream_bind_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_ClusterManager_set_load_stats_config(envoy_config_bootstrap_v3_ClusterManager *msg, struct envoy_config_core_v3_ApiConfigSource* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct envoy_config_core_v3_ApiConfigSource*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_ApiConfigSource* envoy_config_bootstrap_v3_ClusterManager_mutable_load_stats_config(envoy_config_bootstrap_v3_ClusterManager *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ApiConfigSource* sub = (struct envoy_config_core_v3_ApiConfigSource*)envoy_config_bootstrap_v3_ClusterManager_load_stats_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ApiConfigSource*)_upb_msg_new(&envoy_config_core_v3_ApiConfigSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_ClusterManager_set_load_stats_config(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.ClusterManager.OutlierDetection */
+
+UPB_INLINE envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *)_upb_msg_new(&envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *ret = envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *ret = envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_serialize(const envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_event_log_path(const envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_has_event_service(const envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_EventServiceConfig* envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_event_service(const envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct envoy_config_core_v3_EventServiceConfig*); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_set_event_log_path(envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_set_event_service(envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *msg, struct envoy_config_core_v3_EventServiceConfig* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct envoy_config_core_v3_EventServiceConfig*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_EventServiceConfig* envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_mutable_event_service(envoy_config_bootstrap_v3_ClusterManager_OutlierDetection *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_EventServiceConfig* sub = (struct envoy_config_core_v3_EventServiceConfig*)envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_event_service(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_EventServiceConfig*)_upb_msg_new(&envoy_config_core_v3_EventServiceConfig_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_set_event_service(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.Watchdogs */
+
+UPB_INLINE envoy_config_bootstrap_v3_Watchdogs *envoy_config_bootstrap_v3_Watchdogs_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Watchdogs *)_upb_msg_new(&envoy_config_bootstrap_v3_Watchdogs_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Watchdogs *envoy_config_bootstrap_v3_Watchdogs_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_Watchdogs *ret = envoy_config_bootstrap_v3_Watchdogs_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Watchdogs_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Watchdogs *envoy_config_bootstrap_v3_Watchdogs_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_Watchdogs *ret = envoy_config_bootstrap_v3_Watchdogs_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Watchdogs_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_Watchdogs_serialize(const envoy_config_bootstrap_v3_Watchdogs *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_Watchdogs_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdogs_has_main_thread_watchdog(const envoy_config_bootstrap_v3_Watchdogs *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const envoy_config_bootstrap_v3_Watchdog* envoy_config_bootstrap_v3_Watchdogs_main_thread_watchdog(const envoy_config_bootstrap_v3_Watchdogs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const envoy_config_bootstrap_v3_Watchdog*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdogs_has_worker_watchdog(const envoy_config_bootstrap_v3_Watchdogs *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const envoy_config_bootstrap_v3_Watchdog* envoy_config_bootstrap_v3_Watchdogs_worker_watchdog(const envoy_config_bootstrap_v3_Watchdogs *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const envoy_config_bootstrap_v3_Watchdog*); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdogs_set_main_thread_watchdog(envoy_config_bootstrap_v3_Watchdogs *msg, envoy_config_bootstrap_v3_Watchdog* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), envoy_config_bootstrap_v3_Watchdog*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Watchdog* envoy_config_bootstrap_v3_Watchdogs_mutable_main_thread_watchdog(envoy_config_bootstrap_v3_Watchdogs *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Watchdog* sub = (struct envoy_config_bootstrap_v3_Watchdog*)envoy_config_bootstrap_v3_Watchdogs_main_thread_watchdog(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_Watchdog*)_upb_msg_new(&envoy_config_bootstrap_v3_Watchdog_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdogs_set_main_thread_watchdog(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdogs_set_worker_watchdog(envoy_config_bootstrap_v3_Watchdogs *msg, envoy_config_bootstrap_v3_Watchdog* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), envoy_config_bootstrap_v3_Watchdog*) = value;
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Watchdog* envoy_config_bootstrap_v3_Watchdogs_mutable_worker_watchdog(envoy_config_bootstrap_v3_Watchdogs *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Watchdog* sub = (struct envoy_config_bootstrap_v3_Watchdog*)envoy_config_bootstrap_v3_Watchdogs_worker_watchdog(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_Watchdog*)_upb_msg_new(&envoy_config_bootstrap_v3_Watchdog_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdogs_set_worker_watchdog(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.Watchdog */
+
+UPB_INLINE envoy_config_bootstrap_v3_Watchdog *envoy_config_bootstrap_v3_Watchdog_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Watchdog *)_upb_msg_new(&envoy_config_bootstrap_v3_Watchdog_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Watchdog *envoy_config_bootstrap_v3_Watchdog_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_Watchdog *ret = envoy_config_bootstrap_v3_Watchdog_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Watchdog_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Watchdog *envoy_config_bootstrap_v3_Watchdog_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_Watchdog *ret = envoy_config_bootstrap_v3_Watchdog_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Watchdog_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_Watchdog_serialize(const envoy_config_bootstrap_v3_Watchdog *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_Watchdog_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdog_has_miss_timeout(const envoy_config_bootstrap_v3_Watchdog *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_miss_timeout(const envoy_config_bootstrap_v3_Watchdog *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdog_has_megamiss_timeout(const envoy_config_bootstrap_v3_Watchdog *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_megamiss_timeout(const envoy_config_bootstrap_v3_Watchdog *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdog_has_kill_timeout(const envoy_config_bootstrap_v3_Watchdog *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_kill_timeout(const envoy_config_bootstrap_v3_Watchdog *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdog_has_multikill_timeout(const envoy_config_bootstrap_v3_Watchdog *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_multikill_timeout(const envoy_config_bootstrap_v3_Watchdog *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdog_has_multikill_threshold(const envoy_config_bootstrap_v3_Watchdog *msg) { return _upb_hasbit(msg, 5); }
+UPB_INLINE const struct envoy_type_v3_Percent* envoy_config_bootstrap_v3_Watchdog_multikill_threshold(const envoy_config_bootstrap_v3_Watchdog *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct envoy_type_v3_Percent*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdog_has_max_kill_timeout_jitter(const envoy_config_bootstrap_v3_Watchdog *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_max_kill_timeout_jitter(const envoy_config_bootstrap_v3_Watchdog *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdog_has_actions(const envoy_config_bootstrap_v3_Watchdog *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); }
+UPB_INLINE const envoy_config_bootstrap_v3_Watchdog_WatchdogAction* const* envoy_config_bootstrap_v3_Watchdog_actions(const envoy_config_bootstrap_v3_Watchdog *msg, size_t *len) { return (const envoy_config_bootstrap_v3_Watchdog_WatchdogAction* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdog_set_miss_timeout(envoy_config_bootstrap_v3_Watchdog *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_mutable_miss_timeout(envoy_config_bootstrap_v3_Watchdog *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_bootstrap_v3_Watchdog_miss_timeout(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdog_set_miss_timeout(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdog_set_megamiss_timeout(envoy_config_bootstrap_v3_Watchdog *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_mutable_megamiss_timeout(envoy_config_bootstrap_v3_Watchdog *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_bootstrap_v3_Watchdog_megamiss_timeout(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdog_set_megamiss_timeout(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdog_set_kill_timeout(envoy_config_bootstrap_v3_Watchdog *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_mutable_kill_timeout(envoy_config_bootstrap_v3_Watchdog *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_bootstrap_v3_Watchdog_kill_timeout(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdog_set_kill_timeout(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdog_set_multikill_timeout(envoy_config_bootstrap_v3_Watchdog *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 4);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_mutable_multikill_timeout(envoy_config_bootstrap_v3_Watchdog *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_bootstrap_v3_Watchdog_multikill_timeout(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdog_set_multikill_timeout(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdog_set_multikill_threshold(envoy_config_bootstrap_v3_Watchdog *msg, struct envoy_type_v3_Percent* value) {
+  _upb_sethas(msg, 5);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct envoy_type_v3_Percent*) = value;
+}
+UPB_INLINE struct envoy_type_v3_Percent* envoy_config_bootstrap_v3_Watchdog_mutable_multikill_threshold(envoy_config_bootstrap_v3_Watchdog *msg, upb_arena *arena) {
+  struct envoy_type_v3_Percent* sub = (struct envoy_type_v3_Percent*)envoy_config_bootstrap_v3_Watchdog_multikill_threshold(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_v3_Percent*)_upb_msg_new(&envoy_type_v3_Percent_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdog_set_multikill_threshold(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdog_set_max_kill_timeout_jitter(envoy_config_bootstrap_v3_Watchdog *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 6);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 48), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_bootstrap_v3_Watchdog_mutable_max_kill_timeout_jitter(envoy_config_bootstrap_v3_Watchdog *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_bootstrap_v3_Watchdog_max_kill_timeout_jitter(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdog_set_max_kill_timeout_jitter(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Watchdog_WatchdogAction** envoy_config_bootstrap_v3_Watchdog_mutable_actions(envoy_config_bootstrap_v3_Watchdog *msg, size_t *len) {
+  return (envoy_config_bootstrap_v3_Watchdog_WatchdogAction**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Watchdog_WatchdogAction** envoy_config_bootstrap_v3_Watchdog_resize_actions(envoy_config_bootstrap_v3_Watchdog *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Watchdog_WatchdogAction**)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_Watchdog_WatchdogAction* envoy_config_bootstrap_v3_Watchdog_add_actions(envoy_config_bootstrap_v3_Watchdog *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_Watchdog_WatchdogAction* sub = (struct envoy_config_bootstrap_v3_Watchdog_WatchdogAction*)_upb_msg_new(&envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.Watchdog.WatchdogAction */
+
+UPB_INLINE envoy_config_bootstrap_v3_Watchdog_WatchdogAction *envoy_config_bootstrap_v3_Watchdog_WatchdogAction_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Watchdog_WatchdogAction *)_upb_msg_new(&envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Watchdog_WatchdogAction *envoy_config_bootstrap_v3_Watchdog_WatchdogAction_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_Watchdog_WatchdogAction *ret = envoy_config_bootstrap_v3_Watchdog_WatchdogAction_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Watchdog_WatchdogAction *envoy_config_bootstrap_v3_Watchdog_WatchdogAction_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_Watchdog_WatchdogAction *ret = envoy_config_bootstrap_v3_Watchdog_WatchdogAction_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_Watchdog_WatchdogAction_serialize(const envoy_config_bootstrap_v3_Watchdog_WatchdogAction *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_bootstrap_v3_Watchdog_WatchdogAction_has_config(const envoy_config_bootstrap_v3_Watchdog_WatchdogAction *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_bootstrap_v3_Watchdog_WatchdogAction_config(const envoy_config_bootstrap_v3_Watchdog_WatchdogAction *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), const struct envoy_config_core_v3_TypedExtensionConfig*); }
+UPB_INLINE int32_t envoy_config_bootstrap_v3_Watchdog_WatchdogAction_event(const envoy_config_bootstrap_v3_Watchdog_WatchdogAction *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdog_WatchdogAction_set_config(envoy_config_bootstrap_v3_Watchdog_WatchdogAction *msg, struct envoy_config_core_v3_TypedExtensionConfig* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), struct envoy_config_core_v3_TypedExtensionConfig*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_bootstrap_v3_Watchdog_WatchdogAction_mutable_config(envoy_config_bootstrap_v3_Watchdog_WatchdogAction *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_TypedExtensionConfig* sub = (struct envoy_config_core_v3_TypedExtensionConfig*)envoy_config_bootstrap_v3_Watchdog_WatchdogAction_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_TypedExtensionConfig*)_upb_msg_new(&envoy_config_core_v3_TypedExtensionConfig_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Watchdog_WatchdogAction_set_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Watchdog_WatchdogAction_set_event(envoy_config_bootstrap_v3_Watchdog_WatchdogAction *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
+/* envoy.config.bootstrap.v3.FatalAction */
+
+UPB_INLINE envoy_config_bootstrap_v3_FatalAction *envoy_config_bootstrap_v3_FatalAction_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_FatalAction *)_upb_msg_new(&envoy_config_bootstrap_v3_FatalAction_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_FatalAction *envoy_config_bootstrap_v3_FatalAction_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_FatalAction *ret = envoy_config_bootstrap_v3_FatalAction_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_FatalAction_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_FatalAction *envoy_config_bootstrap_v3_FatalAction_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_FatalAction *ret = envoy_config_bootstrap_v3_FatalAction_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_FatalAction_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_FatalAction_serialize(const envoy_config_bootstrap_v3_FatalAction *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_FatalAction_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_bootstrap_v3_FatalAction_has_config(const envoy_config_bootstrap_v3_FatalAction *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_bootstrap_v3_FatalAction_config(const envoy_config_bootstrap_v3_FatalAction *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_config_core_v3_TypedExtensionConfig*); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_FatalAction_set_config(envoy_config_bootstrap_v3_FatalAction *msg, struct envoy_config_core_v3_TypedExtensionConfig* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_config_core_v3_TypedExtensionConfig*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_bootstrap_v3_FatalAction_mutable_config(envoy_config_bootstrap_v3_FatalAction *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_TypedExtensionConfig* sub = (struct envoy_config_core_v3_TypedExtensionConfig*)envoy_config_bootstrap_v3_FatalAction_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_TypedExtensionConfig*)_upb_msg_new(&envoy_config_core_v3_TypedExtensionConfig_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_FatalAction_set_config(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.Runtime */
+
+UPB_INLINE envoy_config_bootstrap_v3_Runtime *envoy_config_bootstrap_v3_Runtime_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_Runtime *)_upb_msg_new(&envoy_config_bootstrap_v3_Runtime_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_Runtime *envoy_config_bootstrap_v3_Runtime_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_Runtime *ret = envoy_config_bootstrap_v3_Runtime_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Runtime_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_Runtime *envoy_config_bootstrap_v3_Runtime_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_Runtime *ret = envoy_config_bootstrap_v3_Runtime_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_Runtime_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_Runtime_serialize(const envoy_config_bootstrap_v3_Runtime *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_Runtime_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Runtime_symlink_root(const envoy_config_bootstrap_v3_Runtime *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Runtime_subdirectory(const envoy_config_bootstrap_v3_Runtime *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_Runtime_override_subdirectory(const envoy_config_bootstrap_v3_Runtime *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_Runtime_has_base(const envoy_config_bootstrap_v3_Runtime *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Struct* envoy_config_bootstrap_v3_Runtime_base(const envoy_config_bootstrap_v3_Runtime *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const struct google_protobuf_Struct*); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_Runtime_set_symlink_root(envoy_config_bootstrap_v3_Runtime *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Runtime_set_subdirectory(envoy_config_bootstrap_v3_Runtime *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Runtime_set_override_subdirectory(envoy_config_bootstrap_v3_Runtime *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_Runtime_set_base(envoy_config_bootstrap_v3_Runtime *msg, struct google_protobuf_Struct* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 56), struct google_protobuf_Struct*) = value;
+}
+UPB_INLINE struct google_protobuf_Struct* envoy_config_bootstrap_v3_Runtime_mutable_base(envoy_config_bootstrap_v3_Runtime *msg, upb_arena *arena) {
+  struct google_protobuf_Struct* sub = (struct google_protobuf_Struct*)envoy_config_bootstrap_v3_Runtime_base(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Struct*)_upb_msg_new(&google_protobuf_Struct_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_Runtime_set_base(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.RuntimeLayer */
+
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer *envoy_config_bootstrap_v3_RuntimeLayer_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_RuntimeLayer *)_upb_msg_new(&envoy_config_bootstrap_v3_RuntimeLayer_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer *envoy_config_bootstrap_v3_RuntimeLayer_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_RuntimeLayer *ret = envoy_config_bootstrap_v3_RuntimeLayer_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_RuntimeLayer_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer *envoy_config_bootstrap_v3_RuntimeLayer_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_RuntimeLayer *ret = envoy_config_bootstrap_v3_RuntimeLayer_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_RuntimeLayer_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_RuntimeLayer_serialize(const envoy_config_bootstrap_v3_RuntimeLayer *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_RuntimeLayer_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_static_layer = 2,
+  envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_disk_layer = 3,
+  envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_admin_layer = 4,
+  envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_rtds_layer = 5,
+  envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_NOT_SET = 0
+} envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_oneofcases;
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_oneofcases envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_case(const envoy_config_bootstrap_v3_RuntimeLayer* msg) { return (envoy_config_bootstrap_v3_RuntimeLayer_layer_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
+
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_RuntimeLayer_name(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_RuntimeLayer_has_static_layer(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 2; }
+UPB_INLINE const struct google_protobuf_Struct* envoy_config_bootstrap_v3_RuntimeLayer_static_layer(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Struct*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 2, NULL); }
+UPB_INLINE bool envoy_config_bootstrap_v3_RuntimeLayer_has_disk_layer(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 3; }
+UPB_INLINE const envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer* envoy_config_bootstrap_v3_RuntimeLayer_disk_layer(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return UPB_READ_ONEOF(msg, const envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 3, NULL); }
+UPB_INLINE bool envoy_config_bootstrap_v3_RuntimeLayer_has_admin_layer(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 4; }
+UPB_INLINE const envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer* envoy_config_bootstrap_v3_RuntimeLayer_admin_layer(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return UPB_READ_ONEOF(msg, const envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 4, NULL); }
+UPB_INLINE bool envoy_config_bootstrap_v3_RuntimeLayer_has_rtds_layer(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 5; }
+UPB_INLINE const envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer* envoy_config_bootstrap_v3_RuntimeLayer_rtds_layer(const envoy_config_bootstrap_v3_RuntimeLayer *msg) { return UPB_READ_ONEOF(msg, const envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 5, NULL); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_set_name(envoy_config_bootstrap_v3_RuntimeLayer *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_set_static_layer(envoy_config_bootstrap_v3_RuntimeLayer *msg, struct google_protobuf_Struct* value) {
+  UPB_WRITE_ONEOF(msg, struct google_protobuf_Struct*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 2);
+}
+UPB_INLINE struct google_protobuf_Struct* envoy_config_bootstrap_v3_RuntimeLayer_mutable_static_layer(envoy_config_bootstrap_v3_RuntimeLayer *msg, upb_arena *arena) {
+  struct google_protobuf_Struct* sub = (struct google_protobuf_Struct*)envoy_config_bootstrap_v3_RuntimeLayer_static_layer(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Struct*)_upb_msg_new(&google_protobuf_Struct_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_RuntimeLayer_set_static_layer(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_set_disk_layer(envoy_config_bootstrap_v3_RuntimeLayer *msg, envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer* value) {
+  UPB_WRITE_ONEOF(msg, envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 3);
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer* envoy_config_bootstrap_v3_RuntimeLayer_mutable_disk_layer(envoy_config_bootstrap_v3_RuntimeLayer *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer* sub = (struct envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer*)envoy_config_bootstrap_v3_RuntimeLayer_disk_layer(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer*)_upb_msg_new(&envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_RuntimeLayer_set_disk_layer(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_set_admin_layer(envoy_config_bootstrap_v3_RuntimeLayer *msg, envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer* value) {
+  UPB_WRITE_ONEOF(msg, envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 4);
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer* envoy_config_bootstrap_v3_RuntimeLayer_mutable_admin_layer(envoy_config_bootstrap_v3_RuntimeLayer *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer* sub = (struct envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer*)envoy_config_bootstrap_v3_RuntimeLayer_admin_layer(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer*)_upb_msg_new(&envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_RuntimeLayer_set_admin_layer(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_set_rtds_layer(envoy_config_bootstrap_v3_RuntimeLayer *msg, envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer* value) {
+  UPB_WRITE_ONEOF(msg, envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 5);
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer* envoy_config_bootstrap_v3_RuntimeLayer_mutable_rtds_layer(envoy_config_bootstrap_v3_RuntimeLayer *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer* sub = (struct envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer*)envoy_config_bootstrap_v3_RuntimeLayer_rtds_layer(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer*)_upb_msg_new(&envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_RuntimeLayer_set_rtds_layer(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.RuntimeLayer.DiskLayer */
+
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *)_upb_msg_new(&envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *ret = envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *ret = envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_serialize(const envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_symlink_root(const envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_append_service_cluster(const envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), bool); }
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_subdirectory(const envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_set_symlink_root(envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_set_append_service_cluster(envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), bool) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_set_subdirectory(envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+
+/* envoy.config.bootstrap.v3.RuntimeLayer.AdminLayer */
+
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer *envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer *)_upb_msg_new(&envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer *envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer *ret = envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer *envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer *ret = envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_serialize(const envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit, arena, len);
+}
+
+
+
+/* envoy.config.bootstrap.v3.RuntimeLayer.RtdsLayer */
+
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *)_upb_msg_new(&envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *ret = envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *ret = envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_serialize(const envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_name(const envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_has_rtds_config(const envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_rtds_config(const envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct envoy_config_core_v3_ConfigSource*); }
+
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_set_name(envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_set_rtds_config(envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *msg, struct envoy_config_core_v3_ConfigSource* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct envoy_config_core_v3_ConfigSource*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_ConfigSource* envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_mutable_rtds_config(envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ConfigSource* sub = (struct envoy_config_core_v3_ConfigSource*)envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_rtds_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ConfigSource*)_upb_msg_new(&envoy_config_core_v3_ConfigSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_set_rtds_config(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.bootstrap.v3.LayeredRuntime */
+
+UPB_INLINE envoy_config_bootstrap_v3_LayeredRuntime *envoy_config_bootstrap_v3_LayeredRuntime_new(upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_LayeredRuntime *)_upb_msg_new(&envoy_config_bootstrap_v3_LayeredRuntime_msginit, arena);
+}
+UPB_INLINE envoy_config_bootstrap_v3_LayeredRuntime *envoy_config_bootstrap_v3_LayeredRuntime_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_bootstrap_v3_LayeredRuntime *ret = envoy_config_bootstrap_v3_LayeredRuntime_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_LayeredRuntime_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_bootstrap_v3_LayeredRuntime *envoy_config_bootstrap_v3_LayeredRuntime_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_bootstrap_v3_LayeredRuntime *ret = envoy_config_bootstrap_v3_LayeredRuntime_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_bootstrap_v3_LayeredRuntime_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_bootstrap_v3_LayeredRuntime_serialize(const envoy_config_bootstrap_v3_LayeredRuntime *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_bootstrap_v3_LayeredRuntime_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_bootstrap_v3_LayeredRuntime_has_layers(const envoy_config_bootstrap_v3_LayeredRuntime *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const envoy_config_bootstrap_v3_RuntimeLayer* const* envoy_config_bootstrap_v3_LayeredRuntime_layers(const envoy_config_bootstrap_v3_LayeredRuntime *msg, size_t *len) { return (const envoy_config_bootstrap_v3_RuntimeLayer* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer** envoy_config_bootstrap_v3_LayeredRuntime_mutable_layers(envoy_config_bootstrap_v3_LayeredRuntime *msg, size_t *len) {
+  return (envoy_config_bootstrap_v3_RuntimeLayer**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE envoy_config_bootstrap_v3_RuntimeLayer** envoy_config_bootstrap_v3_LayeredRuntime_resize_layers(envoy_config_bootstrap_v3_LayeredRuntime *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_bootstrap_v3_RuntimeLayer**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_bootstrap_v3_RuntimeLayer* envoy_config_bootstrap_v3_LayeredRuntime_add_layers(envoy_config_bootstrap_v3_LayeredRuntime *msg, upb_arena *arena) {
+  struct envoy_config_bootstrap_v3_RuntimeLayer* sub = (struct envoy_config_bootstrap_v3_RuntimeLayer*)_upb_msg_new(&envoy_config_bootstrap_v3_RuntimeLayer_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_CONFIG_BOOTSTRAP_V3_BOOTSTRAP_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c
index 10bdb30..8854ed0 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c
@@ -24,10 +24,7 @@
 #include "google/protobuf/duration.upb.h"
 #include "google/protobuf/struct.upb.h"
 #include "google/protobuf/wrappers.upb.h"
-#include "udpa/core/v1/collection_entry.upb.h"
-#include "udpa/core/v1/resource_locator.upb.h"
-#include "envoy/annotations/deprecation.upb.h"
-#include "udpa/annotations/migrate.upb.h"
+#include "xds/core/v3/collection_entry.upb.h"
 #include "udpa/annotations/security.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
@@ -36,7 +33,7 @@
 #include "upb/port_def.inc"
 
 static const upb_msglayout *const envoy_config_cluster_v3_ClusterCollection_submsgs[1] = {
-  &udpa_core_v1_CollectionEntry_msginit,
+  &xds_core_v3_CollectionEntry_msginit,
 };
 
 static const upb_msglayout_field envoy_config_cluster_v3_ClusterCollection__fields[1] = {
@@ -58,7 +55,7 @@
   &envoy_config_cluster_v3_Cluster_LeastRequestLbConfig_msginit,
   &envoy_config_cluster_v3_Cluster_MaglevLbConfig_msginit,
   &envoy_config_cluster_v3_Cluster_OriginalDstLbConfig_msginit,
-  &envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit,
+  &envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit,
   &envoy_config_cluster_v3_Cluster_RefreshRate_msginit,
   &envoy_config_cluster_v3_Cluster_RingHashLbConfig_msginit,
   &envoy_config_cluster_v3_Cluster_TransportSocketMatch_msginit,
@@ -172,21 +169,19 @@
   UPB_SIZE(16, 32), 2, false, 255,
 };
 
-static const upb_msglayout *const envoy_config_cluster_v3_Cluster_EdsClusterConfig_submsgs[2] = {
+static const upb_msglayout *const envoy_config_cluster_v3_Cluster_EdsClusterConfig_submsgs[1] = {
   &envoy_config_core_v3_ConfigSource_msginit,
-  &udpa_core_v1_ResourceLocator_msginit,
 };
 
-static const upb_msglayout_field envoy_config_cluster_v3_Cluster_EdsClusterConfig__fields[3] = {
+static const upb_msglayout_field envoy_config_cluster_v3_Cluster_EdsClusterConfig__fields[2] = {
   {1, UPB_SIZE(12, 24), 1, 0, 11, 1},
   {2, UPB_SIZE(4, 8), 0, 0, 9, 1},
-  {3, UPB_SIZE(16, 32), 2, 1, 11, 1},
 };
 
 const upb_msglayout envoy_config_cluster_v3_Cluster_EdsClusterConfig_msginit = {
   &envoy_config_cluster_v3_Cluster_EdsClusterConfig_submsgs[0],
   &envoy_config_cluster_v3_Cluster_EdsClusterConfig__fields[0],
-  UPB_SIZE(24, 48), 3, false, 255,
+  UPB_SIZE(16, 32), 2, false, 255,
 };
 
 static const upb_msglayout *const envoy_config_cluster_v3_Cluster_LbSubsetConfig_submsgs[2] = {
@@ -356,18 +351,18 @@
   UPB_SIZE(16, 24), 2, false, 255,
 };
 
-static const upb_msglayout *const envoy_config_cluster_v3_Cluster_PrefetchPolicy_submsgs[1] = {
+static const upb_msglayout *const envoy_config_cluster_v3_Cluster_PreconnectPolicy_submsgs[1] = {
   &google_protobuf_DoubleValue_msginit,
 };
 
-static const upb_msglayout_field envoy_config_cluster_v3_Cluster_PrefetchPolicy__fields[2] = {
+static const upb_msglayout_field envoy_config_cluster_v3_Cluster_PreconnectPolicy__fields[2] = {
   {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
   {2, UPB_SIZE(8, 16), 2, 0, 11, 1},
 };
 
-const upb_msglayout envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit = {
-  &envoy_config_cluster_v3_Cluster_PrefetchPolicy_submsgs[0],
-  &envoy_config_cluster_v3_Cluster_PrefetchPolicy__fields[0],
+const upb_msglayout envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit = {
+  &envoy_config_cluster_v3_Cluster_PreconnectPolicy_submsgs[0],
+  &envoy_config_cluster_v3_Cluster_PreconnectPolicy__fields[0],
   UPB_SIZE(16, 24), 2, false, 255,
 };
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h
index 6f27dc7..da4d620 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.h
@@ -36,7 +36,7 @@
 struct envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig;
 struct envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig;
 struct envoy_config_cluster_v3_Cluster_RefreshRate;
-struct envoy_config_cluster_v3_Cluster_PrefetchPolicy;
+struct envoy_config_cluster_v3_Cluster_PreconnectPolicy;
 struct envoy_config_cluster_v3_Cluster_TypedExtensionProtocolOptionsEntry;
 struct envoy_config_cluster_v3_LoadBalancingPolicy;
 struct envoy_config_cluster_v3_LoadBalancingPolicy_Policy;
@@ -59,7 +59,7 @@
 typedef struct envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig;
 typedef struct envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig;
 typedef struct envoy_config_cluster_v3_Cluster_RefreshRate envoy_config_cluster_v3_Cluster_RefreshRate;
-typedef struct envoy_config_cluster_v3_Cluster_PrefetchPolicy envoy_config_cluster_v3_Cluster_PrefetchPolicy;
+typedef struct envoy_config_cluster_v3_Cluster_PreconnectPolicy envoy_config_cluster_v3_Cluster_PreconnectPolicy;
 typedef struct envoy_config_cluster_v3_Cluster_TypedExtensionProtocolOptionsEntry envoy_config_cluster_v3_Cluster_TypedExtensionProtocolOptionsEntry;
 typedef struct envoy_config_cluster_v3_LoadBalancingPolicy envoy_config_cluster_v3_LoadBalancingPolicy;
 typedef struct envoy_config_cluster_v3_LoadBalancingPolicy_Policy envoy_config_cluster_v3_LoadBalancingPolicy_Policy;
@@ -82,7 +82,7 @@
 extern const upb_msglayout envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_Cluster_RefreshRate_msginit;
-extern const upb_msglayout envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit;
+extern const upb_msglayout envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_Cluster_TypedExtensionProtocolOptionsEntry_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_LoadBalancingPolicy_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_LoadBalancingPolicy_Policy_msginit;
@@ -113,8 +113,7 @@
 struct google_protobuf_Struct;
 struct google_protobuf_UInt32Value;
 struct google_protobuf_UInt64Value;
-struct udpa_core_v1_CollectionEntry;
-struct udpa_core_v1_ResourceLocator;
+struct xds_core_v3_CollectionEntry;
 extern const upb_msglayout envoy_config_cluster_v3_CircuitBreakers_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_Filter_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_OutlierDetection_msginit;
@@ -139,8 +138,7 @@
 extern const upb_msglayout google_protobuf_Struct_msginit;
 extern const upb_msglayout google_protobuf_UInt32Value_msginit;
 extern const upb_msglayout google_protobuf_UInt64Value_msginit;
-extern const upb_msglayout udpa_core_v1_CollectionEntry_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_msginit;
+extern const upb_msglayout xds_core_v3_CollectionEntry_msginit;
 
 typedef enum {
   envoy_config_cluster_v3_Cluster_USE_CONFIGURED_PROTOCOL = 0,
@@ -212,16 +210,16 @@
 }
 
 UPB_INLINE bool envoy_config_cluster_v3_ClusterCollection_has_entries(const envoy_config_cluster_v3_ClusterCollection *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE const struct udpa_core_v1_CollectionEntry* envoy_config_cluster_v3_ClusterCollection_entries(const envoy_config_cluster_v3_ClusterCollection *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct udpa_core_v1_CollectionEntry*); }
+UPB_INLINE const struct xds_core_v3_CollectionEntry* envoy_config_cluster_v3_ClusterCollection_entries(const envoy_config_cluster_v3_ClusterCollection *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct xds_core_v3_CollectionEntry*); }
 
-UPB_INLINE void envoy_config_cluster_v3_ClusterCollection_set_entries(envoy_config_cluster_v3_ClusterCollection *msg, struct udpa_core_v1_CollectionEntry* value) {
+UPB_INLINE void envoy_config_cluster_v3_ClusterCollection_set_entries(envoy_config_cluster_v3_ClusterCollection *msg, struct xds_core_v3_CollectionEntry* value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct udpa_core_v1_CollectionEntry*) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct xds_core_v3_CollectionEntry*) = value;
 }
-UPB_INLINE struct udpa_core_v1_CollectionEntry* envoy_config_cluster_v3_ClusterCollection_mutable_entries(envoy_config_cluster_v3_ClusterCollection *msg, upb_arena *arena) {
-  struct udpa_core_v1_CollectionEntry* sub = (struct udpa_core_v1_CollectionEntry*)envoy_config_cluster_v3_ClusterCollection_entries(msg);
+UPB_INLINE struct xds_core_v3_CollectionEntry* envoy_config_cluster_v3_ClusterCollection_mutable_entries(envoy_config_cluster_v3_ClusterCollection *msg, upb_arena *arena) {
+  struct xds_core_v3_CollectionEntry* sub = (struct xds_core_v3_CollectionEntry*)envoy_config_cluster_v3_ClusterCollection_entries(msg);
   if (sub == NULL) {
-    sub = (struct udpa_core_v1_CollectionEntry*)_upb_msg_new(&udpa_core_v1_CollectionEntry_msginit, arena);
+    sub = (struct xds_core_v3_CollectionEntry*)_upb_msg_new(&xds_core_v3_CollectionEntry_msginit, arena);
     if (!sub) return NULL;
     envoy_config_cluster_v3_ClusterCollection_set_entries(msg, sub);
   }
@@ -344,8 +342,8 @@
 UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_cluster_v3_Cluster_upstream_config(const envoy_config_cluster_v3_Cluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(128, 232), const struct envoy_config_core_v3_TypedExtensionConfig*); }
 UPB_INLINE bool envoy_config_cluster_v3_Cluster_has_track_cluster_stats(const envoy_config_cluster_v3_Cluster *msg) { return _upb_hasbit(msg, 24); }
 UPB_INLINE const envoy_config_cluster_v3_TrackClusterStats* envoy_config_cluster_v3_Cluster_track_cluster_stats(const envoy_config_cluster_v3_Cluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(132, 240), const envoy_config_cluster_v3_TrackClusterStats*); }
-UPB_INLINE bool envoy_config_cluster_v3_Cluster_has_prefetch_policy(const envoy_config_cluster_v3_Cluster *msg) { return _upb_hasbit(msg, 25); }
-UPB_INLINE const envoy_config_cluster_v3_Cluster_PrefetchPolicy* envoy_config_cluster_v3_Cluster_prefetch_policy(const envoy_config_cluster_v3_Cluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(136, 248), const envoy_config_cluster_v3_Cluster_PrefetchPolicy*); }
+UPB_INLINE bool envoy_config_cluster_v3_Cluster_has_preconnect_policy(const envoy_config_cluster_v3_Cluster *msg) { return _upb_hasbit(msg, 25); }
+UPB_INLINE const envoy_config_cluster_v3_Cluster_PreconnectPolicy* envoy_config_cluster_v3_Cluster_preconnect_policy(const envoy_config_cluster_v3_Cluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(136, 248), const envoy_config_cluster_v3_Cluster_PreconnectPolicy*); }
 UPB_INLINE bool envoy_config_cluster_v3_Cluster_connection_pool_per_downstream_connection(const envoy_config_cluster_v3_Cluster *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(21, 21), bool); }
 UPB_INLINE bool envoy_config_cluster_v3_Cluster_has_maglev_lb_config(const envoy_config_cluster_v3_Cluster *msg) { return _upb_getoneofcase(msg, UPB_SIZE(172, 320)) == 52; }
 UPB_INLINE const envoy_config_cluster_v3_Cluster_MaglevLbConfig* envoy_config_cluster_v3_Cluster_maglev_lb_config(const envoy_config_cluster_v3_Cluster *msg) { return UPB_READ_ONEOF(msg, const envoy_config_cluster_v3_Cluster_MaglevLbConfig*, UPB_SIZE(168, 312), UPB_SIZE(172, 320), 52, NULL); }
@@ -799,16 +797,16 @@
   }
   return sub;
 }
-UPB_INLINE void envoy_config_cluster_v3_Cluster_set_prefetch_policy(envoy_config_cluster_v3_Cluster *msg, envoy_config_cluster_v3_Cluster_PrefetchPolicy* value) {
+UPB_INLINE void envoy_config_cluster_v3_Cluster_set_preconnect_policy(envoy_config_cluster_v3_Cluster *msg, envoy_config_cluster_v3_Cluster_PreconnectPolicy* value) {
   _upb_sethas(msg, 25);
-  *UPB_PTR_AT(msg, UPB_SIZE(136, 248), envoy_config_cluster_v3_Cluster_PrefetchPolicy*) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(136, 248), envoy_config_cluster_v3_Cluster_PreconnectPolicy*) = value;
 }
-UPB_INLINE struct envoy_config_cluster_v3_Cluster_PrefetchPolicy* envoy_config_cluster_v3_Cluster_mutable_prefetch_policy(envoy_config_cluster_v3_Cluster *msg, upb_arena *arena) {
-  struct envoy_config_cluster_v3_Cluster_PrefetchPolicy* sub = (struct envoy_config_cluster_v3_Cluster_PrefetchPolicy*)envoy_config_cluster_v3_Cluster_prefetch_policy(msg);
+UPB_INLINE struct envoy_config_cluster_v3_Cluster_PreconnectPolicy* envoy_config_cluster_v3_Cluster_mutable_preconnect_policy(envoy_config_cluster_v3_Cluster *msg, upb_arena *arena) {
+  struct envoy_config_cluster_v3_Cluster_PreconnectPolicy* sub = (struct envoy_config_cluster_v3_Cluster_PreconnectPolicy*)envoy_config_cluster_v3_Cluster_preconnect_policy(msg);
   if (sub == NULL) {
-    sub = (struct envoy_config_cluster_v3_Cluster_PrefetchPolicy*)_upb_msg_new(&envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit, arena);
+    sub = (struct envoy_config_cluster_v3_Cluster_PreconnectPolicy*)_upb_msg_new(&envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit, arena);
     if (!sub) return NULL;
-    envoy_config_cluster_v3_Cluster_set_prefetch_policy(msg, sub);
+    envoy_config_cluster_v3_Cluster_set_preconnect_policy(msg, sub);
   }
   return sub;
 }
@@ -948,8 +946,6 @@
 UPB_INLINE bool envoy_config_cluster_v3_Cluster_EdsClusterConfig_has_eds_config(const envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct envoy_config_core_v3_ConfigSource* envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_config(const envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct envoy_config_core_v3_ConfigSource*); }
 UPB_INLINE upb_strview envoy_config_cluster_v3_Cluster_EdsClusterConfig_service_name(const envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool envoy_config_cluster_v3_Cluster_EdsClusterConfig_has_eds_resource_locator(const envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const struct udpa_core_v1_ResourceLocator* envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_resource_locator(const envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct udpa_core_v1_ResourceLocator*); }
 
 UPB_INLINE void envoy_config_cluster_v3_Cluster_EdsClusterConfig_set_eds_config(envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg, struct envoy_config_core_v3_ConfigSource* value) {
   _upb_sethas(msg, 1);
@@ -967,19 +963,6 @@
 UPB_INLINE void envoy_config_cluster_v3_Cluster_EdsClusterConfig_set_service_name(envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
 }
-UPB_INLINE void envoy_config_cluster_v3_Cluster_EdsClusterConfig_set_eds_resource_locator(envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg, struct udpa_core_v1_ResourceLocator* value) {
-  _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct udpa_core_v1_ResourceLocator*) = value;
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator* envoy_config_cluster_v3_Cluster_EdsClusterConfig_mutable_eds_resource_locator(envoy_config_cluster_v3_Cluster_EdsClusterConfig *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceLocator* sub = (struct udpa_core_v1_ResourceLocator*)envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_resource_locator(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_ResourceLocator*)_upb_msg_new(&udpa_core_v1_ResourceLocator_msginit, arena);
-    if (!sub) return NULL;
-    envoy_config_cluster_v3_Cluster_EdsClusterConfig_set_eds_resource_locator(msg, sub);
-  }
-  return sub;
-}
 
 /* envoy.config.cluster.v3.Cluster.LbSubsetConfig */
 
@@ -1557,54 +1540,54 @@
   return sub;
 }
 
-/* envoy.config.cluster.v3.Cluster.PrefetchPolicy */
+/* envoy.config.cluster.v3.Cluster.PreconnectPolicy */
 
-UPB_INLINE envoy_config_cluster_v3_Cluster_PrefetchPolicy *envoy_config_cluster_v3_Cluster_PrefetchPolicy_new(upb_arena *arena) {
-  return (envoy_config_cluster_v3_Cluster_PrefetchPolicy *)_upb_msg_new(&envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit, arena);
+UPB_INLINE envoy_config_cluster_v3_Cluster_PreconnectPolicy *envoy_config_cluster_v3_Cluster_PreconnectPolicy_new(upb_arena *arena) {
+  return (envoy_config_cluster_v3_Cluster_PreconnectPolicy *)_upb_msg_new(&envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit, arena);
 }
-UPB_INLINE envoy_config_cluster_v3_Cluster_PrefetchPolicy *envoy_config_cluster_v3_Cluster_PrefetchPolicy_parse(const char *buf, size_t size,
+UPB_INLINE envoy_config_cluster_v3_Cluster_PreconnectPolicy *envoy_config_cluster_v3_Cluster_PreconnectPolicy_parse(const char *buf, size_t size,
                         upb_arena *arena) {
-  envoy_config_cluster_v3_Cluster_PrefetchPolicy *ret = envoy_config_cluster_v3_Cluster_PrefetchPolicy_new(arena);
-  return (ret && upb_decode(buf, size, ret, &envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit, arena)) ? ret : NULL;
+  envoy_config_cluster_v3_Cluster_PreconnectPolicy *ret = envoy_config_cluster_v3_Cluster_PreconnectPolicy_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit, arena)) ? ret : NULL;
 }
-UPB_INLINE envoy_config_cluster_v3_Cluster_PrefetchPolicy *envoy_config_cluster_v3_Cluster_PrefetchPolicy_parse_ex(const char *buf, size_t size,
+UPB_INLINE envoy_config_cluster_v3_Cluster_PreconnectPolicy *envoy_config_cluster_v3_Cluster_PreconnectPolicy_parse_ex(const char *buf, size_t size,
                            upb_arena *arena, int options) {
-  envoy_config_cluster_v3_Cluster_PrefetchPolicy *ret = envoy_config_cluster_v3_Cluster_PrefetchPolicy_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit, arena, options))
+  envoy_config_cluster_v3_Cluster_PreconnectPolicy *ret = envoy_config_cluster_v3_Cluster_PreconnectPolicy_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit, arena, options))
       ? ret : NULL;
 }
-UPB_INLINE char *envoy_config_cluster_v3_Cluster_PrefetchPolicy_serialize(const envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit, arena, len);
+UPB_INLINE char *envoy_config_cluster_v3_Cluster_PreconnectPolicy_serialize(const envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit, arena, len);
 }
 
-UPB_INLINE bool envoy_config_cluster_v3_Cluster_PrefetchPolicy_has_per_upstream_prefetch_ratio(const envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE const struct google_protobuf_DoubleValue* envoy_config_cluster_v3_Cluster_PrefetchPolicy_per_upstream_prefetch_ratio(const envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_DoubleValue*); }
-UPB_INLINE bool envoy_config_cluster_v3_Cluster_PrefetchPolicy_has_predictive_prefetch_ratio(const envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const struct google_protobuf_DoubleValue* envoy_config_cluster_v3_Cluster_PrefetchPolicy_predictive_prefetch_ratio(const envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const struct google_protobuf_DoubleValue*); }
+UPB_INLINE bool envoy_config_cluster_v3_Cluster_PreconnectPolicy_has_per_upstream_preconnect_ratio(const envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_DoubleValue* envoy_config_cluster_v3_Cluster_PreconnectPolicy_per_upstream_preconnect_ratio(const envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_DoubleValue*); }
+UPB_INLINE bool envoy_config_cluster_v3_Cluster_PreconnectPolicy_has_predictive_preconnect_ratio(const envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_DoubleValue* envoy_config_cluster_v3_Cluster_PreconnectPolicy_predictive_preconnect_ratio(const envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const struct google_protobuf_DoubleValue*); }
 
-UPB_INLINE void envoy_config_cluster_v3_Cluster_PrefetchPolicy_set_per_upstream_prefetch_ratio(envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg, struct google_protobuf_DoubleValue* value) {
+UPB_INLINE void envoy_config_cluster_v3_Cluster_PreconnectPolicy_set_per_upstream_preconnect_ratio(envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg, struct google_protobuf_DoubleValue* value) {
   _upb_sethas(msg, 1);
   *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_DoubleValue*) = value;
 }
-UPB_INLINE struct google_protobuf_DoubleValue* envoy_config_cluster_v3_Cluster_PrefetchPolicy_mutable_per_upstream_prefetch_ratio(envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg, upb_arena *arena) {
-  struct google_protobuf_DoubleValue* sub = (struct google_protobuf_DoubleValue*)envoy_config_cluster_v3_Cluster_PrefetchPolicy_per_upstream_prefetch_ratio(msg);
+UPB_INLINE struct google_protobuf_DoubleValue* envoy_config_cluster_v3_Cluster_PreconnectPolicy_mutable_per_upstream_preconnect_ratio(envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg, upb_arena *arena) {
+  struct google_protobuf_DoubleValue* sub = (struct google_protobuf_DoubleValue*)envoy_config_cluster_v3_Cluster_PreconnectPolicy_per_upstream_preconnect_ratio(msg);
   if (sub == NULL) {
     sub = (struct google_protobuf_DoubleValue*)_upb_msg_new(&google_protobuf_DoubleValue_msginit, arena);
     if (!sub) return NULL;
-    envoy_config_cluster_v3_Cluster_PrefetchPolicy_set_per_upstream_prefetch_ratio(msg, sub);
+    envoy_config_cluster_v3_Cluster_PreconnectPolicy_set_per_upstream_preconnect_ratio(msg, sub);
   }
   return sub;
 }
-UPB_INLINE void envoy_config_cluster_v3_Cluster_PrefetchPolicy_set_predictive_prefetch_ratio(envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg, struct google_protobuf_DoubleValue* value) {
+UPB_INLINE void envoy_config_cluster_v3_Cluster_PreconnectPolicy_set_predictive_preconnect_ratio(envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg, struct google_protobuf_DoubleValue* value) {
   _upb_sethas(msg, 2);
   *UPB_PTR_AT(msg, UPB_SIZE(8, 16), struct google_protobuf_DoubleValue*) = value;
 }
-UPB_INLINE struct google_protobuf_DoubleValue* envoy_config_cluster_v3_Cluster_PrefetchPolicy_mutable_predictive_prefetch_ratio(envoy_config_cluster_v3_Cluster_PrefetchPolicy *msg, upb_arena *arena) {
-  struct google_protobuf_DoubleValue* sub = (struct google_protobuf_DoubleValue*)envoy_config_cluster_v3_Cluster_PrefetchPolicy_predictive_prefetch_ratio(msg);
+UPB_INLINE struct google_protobuf_DoubleValue* envoy_config_cluster_v3_Cluster_PreconnectPolicy_mutable_predictive_preconnect_ratio(envoy_config_cluster_v3_Cluster_PreconnectPolicy *msg, upb_arena *arena) {
+  struct google_protobuf_DoubleValue* sub = (struct google_protobuf_DoubleValue*)envoy_config_cluster_v3_Cluster_PreconnectPolicy_predictive_preconnect_ratio(msg);
   if (sub == NULL) {
     sub = (struct google_protobuf_DoubleValue*)_upb_msg_new(&google_protobuf_DoubleValue_msginit, arena);
     if (!sub) return NULL;
-    envoy_config_cluster_v3_Cluster_PrefetchPolicy_set_predictive_prefetch_ratio(msg, sub);
+    envoy_config_cluster_v3_Cluster_PreconnectPolicy_set_predictive_preconnect_ratio(msg, sub);
   }
   return sub;
 }
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/outlier_detection.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/outlier_detection.upb.c
index 9e32e67..f90563f 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/outlier_detection.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/outlier_detection.upb.c
@@ -22,7 +22,7 @@
   &google_protobuf_UInt32Value_msginit,
 };
 
-static const upb_msglayout_field envoy_config_cluster_v3_OutlierDetection__fields[20] = {
+static const upb_msglayout_field envoy_config_cluster_v3_OutlierDetection__fields[21] = {
   {1, UPB_SIZE(4, 8), 1, 1, 11, 1},
   {2, UPB_SIZE(8, 16), 2, 0, 11, 1},
   {3, UPB_SIZE(12, 24), 3, 0, 11, 1},
@@ -43,12 +43,13 @@
   {18, UPB_SIZE(68, 136), 17, 1, 11, 1},
   {19, UPB_SIZE(72, 144), 18, 1, 11, 1},
   {20, UPB_SIZE(76, 152), 19, 1, 11, 1},
+  {21, UPB_SIZE(80, 160), 20, 0, 11, 1},
 };
 
 const upb_msglayout envoy_config_cluster_v3_OutlierDetection_msginit = {
   &envoy_config_cluster_v3_OutlierDetection_submsgs[0],
   &envoy_config_cluster_v3_OutlierDetection__fields[0],
-  UPB_SIZE(80, 160), 20, false, 255,
+  UPB_SIZE(88, 168), 21, false, 255,
 };
 
 #include "upb/port_undef.inc"
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/outlier_detection.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/outlier_detection.upb.h
index 8d43fa9..70b7623 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/outlier_detection.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/cluster/v3/outlier_detection.upb.h
@@ -88,6 +88,8 @@
 UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_cluster_v3_OutlierDetection_failure_percentage_minimum_hosts(const envoy_config_cluster_v3_OutlierDetection *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(72, 144), const struct google_protobuf_UInt32Value*); }
 UPB_INLINE bool envoy_config_cluster_v3_OutlierDetection_has_failure_percentage_request_volume(const envoy_config_cluster_v3_OutlierDetection *msg) { return _upb_hasbit(msg, 19); }
 UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_cluster_v3_OutlierDetection_failure_percentage_request_volume(const envoy_config_cluster_v3_OutlierDetection *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 152), const struct google_protobuf_UInt32Value*); }
+UPB_INLINE bool envoy_config_cluster_v3_OutlierDetection_has_max_ejection_time(const envoy_config_cluster_v3_OutlierDetection *msg) { return _upb_hasbit(msg, 20); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_cluster_v3_OutlierDetection_max_ejection_time(const envoy_config_cluster_v3_OutlierDetection *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(80, 160), const struct google_protobuf_Duration*); }
 
 UPB_INLINE void envoy_config_cluster_v3_OutlierDetection_set_consecutive_5xx(envoy_config_cluster_v3_OutlierDetection *msg, struct google_protobuf_UInt32Value* value) {
   _upb_sethas(msg, 1);
@@ -339,6 +341,19 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_config_cluster_v3_OutlierDetection_set_max_ejection_time(envoy_config_cluster_v3_OutlierDetection *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 20);
+  *UPB_PTR_AT(msg, UPB_SIZE(80, 160), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_cluster_v3_OutlierDetection_mutable_max_ejection_time(envoy_config_cluster_v3_OutlierDetection *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_cluster_v3_OutlierDetection_max_ejection_time(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_cluster_v3_OutlierDetection_set_max_ejection_time(msg, sub);
+  }
+  return sub;
+}
 
 #ifdef __cplusplus
 }  /* extern "C" */
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/base.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/base.upb.c
index 355bbdc..0baf9e9 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/base.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/base.upb.c
@@ -15,7 +15,6 @@
 #include "envoy/type/v3/percent.upb.h"
 #include "envoy/type/v3/semantic_version.upb.h"
 #include "google/protobuf/any.upb.h"
-#include "google/protobuf/duration.upb.h"
 #include "google/protobuf/struct.upb.h"
 #include "google/protobuf/wrappers.upb.h"
 #include "udpa/annotations/migrate.upb.h"
@@ -138,6 +137,21 @@
   UPB_SIZE(16, 32), 2, false, 255,
 };
 
+static const upb_msglayout *const envoy_config_core_v3_RuntimePercent_submsgs[1] = {
+  &envoy_type_v3_Percent_msginit,
+};
+
+static const upb_msglayout_field envoy_config_core_v3_RuntimePercent__fields[2] = {
+  {1, UPB_SIZE(12, 24), 1, 0, 11, 1},
+  {2, UPB_SIZE(4, 8), 0, 0, 9, 1},
+};
+
+const upb_msglayout envoy_config_core_v3_RuntimePercent_msginit = {
+  &envoy_config_core_v3_RuntimePercent_submsgs[0],
+  &envoy_config_core_v3_RuntimePercent__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
 static const upb_msglayout_field envoy_config_core_v3_RuntimeDouble__fields[2] = {
   {1, UPB_SIZE(0, 0), 0, 0, 1, 1},
   {2, UPB_SIZE(8, 8), 0, 0, 9, 1},
@@ -205,6 +219,16 @@
   UPB_SIZE(8, 8), 1, false, 255,
 };
 
+static const upb_msglayout_field envoy_config_core_v3_WatchedDirectory__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+};
+
+const upb_msglayout envoy_config_core_v3_WatchedDirectory_msginit = {
+  NULL,
+  &envoy_config_core_v3_WatchedDirectory__fields[0],
+  UPB_SIZE(8, 16), 1, false, 255,
+};
+
 static const upb_msglayout_field envoy_config_core_v3_DataSource__fields[3] = {
   {1, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 9, 1},
   {2, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 12, 1},
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/base.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/base.upb.h
index 07cbaf4..bfb4fd4 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/base.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/base.upb.h
@@ -27,11 +27,13 @@
 struct envoy_config_core_v3_Metadata;
 struct envoy_config_core_v3_Metadata_FilterMetadataEntry;
 struct envoy_config_core_v3_RuntimeUInt32;
+struct envoy_config_core_v3_RuntimePercent;
 struct envoy_config_core_v3_RuntimeDouble;
 struct envoy_config_core_v3_RuntimeFeatureFlag;
 struct envoy_config_core_v3_HeaderValue;
 struct envoy_config_core_v3_HeaderValueOption;
 struct envoy_config_core_v3_HeaderMap;
+struct envoy_config_core_v3_WatchedDirectory;
 struct envoy_config_core_v3_DataSource;
 struct envoy_config_core_v3_RetryPolicy;
 struct envoy_config_core_v3_RemoteDataSource;
@@ -46,11 +48,13 @@
 typedef struct envoy_config_core_v3_Metadata envoy_config_core_v3_Metadata;
 typedef struct envoy_config_core_v3_Metadata_FilterMetadataEntry envoy_config_core_v3_Metadata_FilterMetadataEntry;
 typedef struct envoy_config_core_v3_RuntimeUInt32 envoy_config_core_v3_RuntimeUInt32;
+typedef struct envoy_config_core_v3_RuntimePercent envoy_config_core_v3_RuntimePercent;
 typedef struct envoy_config_core_v3_RuntimeDouble envoy_config_core_v3_RuntimeDouble;
 typedef struct envoy_config_core_v3_RuntimeFeatureFlag envoy_config_core_v3_RuntimeFeatureFlag;
 typedef struct envoy_config_core_v3_HeaderValue envoy_config_core_v3_HeaderValue;
 typedef struct envoy_config_core_v3_HeaderValueOption envoy_config_core_v3_HeaderValueOption;
 typedef struct envoy_config_core_v3_HeaderMap envoy_config_core_v3_HeaderMap;
+typedef struct envoy_config_core_v3_WatchedDirectory envoy_config_core_v3_WatchedDirectory;
 typedef struct envoy_config_core_v3_DataSource envoy_config_core_v3_DataSource;
 typedef struct envoy_config_core_v3_RetryPolicy envoy_config_core_v3_RetryPolicy;
 typedef struct envoy_config_core_v3_RemoteDataSource envoy_config_core_v3_RemoteDataSource;
@@ -65,11 +69,13 @@
 extern const upb_msglayout envoy_config_core_v3_Metadata_msginit;
 extern const upb_msglayout envoy_config_core_v3_Metadata_FilterMetadataEntry_msginit;
 extern const upb_msglayout envoy_config_core_v3_RuntimeUInt32_msginit;
+extern const upb_msglayout envoy_config_core_v3_RuntimePercent_msginit;
 extern const upb_msglayout envoy_config_core_v3_RuntimeDouble_msginit;
 extern const upb_msglayout envoy_config_core_v3_RuntimeFeatureFlag_msginit;
 extern const upb_msglayout envoy_config_core_v3_HeaderValue_msginit;
 extern const upb_msglayout envoy_config_core_v3_HeaderValueOption_msginit;
 extern const upb_msglayout envoy_config_core_v3_HeaderMap_msginit;
+extern const upb_msglayout envoy_config_core_v3_WatchedDirectory_msginit;
 extern const upb_msglayout envoy_config_core_v3_DataSource_msginit;
 extern const upb_msglayout envoy_config_core_v3_RetryPolicy_msginit;
 extern const upb_msglayout envoy_config_core_v3_RemoteDataSource_msginit;
@@ -81,6 +87,7 @@
 struct envoy_config_core_v3_BackoffStrategy;
 struct envoy_config_core_v3_HttpUri;
 struct envoy_type_v3_FractionalPercent;
+struct envoy_type_v3_Percent;
 struct envoy_type_v3_SemanticVersion;
 struct google_protobuf_Any;
 struct google_protobuf_BoolValue;
@@ -90,6 +97,7 @@
 extern const upb_msglayout envoy_config_core_v3_BackoffStrategy_msginit;
 extern const upb_msglayout envoy_config_core_v3_HttpUri_msginit;
 extern const upb_msglayout envoy_type_v3_FractionalPercent_msginit;
+extern const upb_msglayout envoy_type_v3_Percent_msginit;
 extern const upb_msglayout envoy_type_v3_SemanticVersion_msginit;
 extern const upb_msglayout google_protobuf_Any_msginit;
 extern const upb_msglayout google_protobuf_BoolValue_msginit;
@@ -469,6 +477,47 @@
   *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
 }
 
+/* envoy.config.core.v3.RuntimePercent */
+
+UPB_INLINE envoy_config_core_v3_RuntimePercent *envoy_config_core_v3_RuntimePercent_new(upb_arena *arena) {
+  return (envoy_config_core_v3_RuntimePercent *)_upb_msg_new(&envoy_config_core_v3_RuntimePercent_msginit, arena);
+}
+UPB_INLINE envoy_config_core_v3_RuntimePercent *envoy_config_core_v3_RuntimePercent_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_core_v3_RuntimePercent *ret = envoy_config_core_v3_RuntimePercent_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_core_v3_RuntimePercent_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_core_v3_RuntimePercent *envoy_config_core_v3_RuntimePercent_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_core_v3_RuntimePercent *ret = envoy_config_core_v3_RuntimePercent_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_core_v3_RuntimePercent_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_core_v3_RuntimePercent_serialize(const envoy_config_core_v3_RuntimePercent *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_core_v3_RuntimePercent_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_core_v3_RuntimePercent_has_default_value(const envoy_config_core_v3_RuntimePercent *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_type_v3_Percent* envoy_config_core_v3_RuntimePercent_default_value(const envoy_config_core_v3_RuntimePercent *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct envoy_type_v3_Percent*); }
+UPB_INLINE upb_strview envoy_config_core_v3_RuntimePercent_runtime_key(const envoy_config_core_v3_RuntimePercent *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+
+UPB_INLINE void envoy_config_core_v3_RuntimePercent_set_default_value(envoy_config_core_v3_RuntimePercent *msg, struct envoy_type_v3_Percent* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct envoy_type_v3_Percent*) = value;
+}
+UPB_INLINE struct envoy_type_v3_Percent* envoy_config_core_v3_RuntimePercent_mutable_default_value(envoy_config_core_v3_RuntimePercent *msg, upb_arena *arena) {
+  struct envoy_type_v3_Percent* sub = (struct envoy_type_v3_Percent*)envoy_config_core_v3_RuntimePercent_default_value(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_v3_Percent*)_upb_msg_new(&envoy_type_v3_Percent_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_core_v3_RuntimePercent_set_default_value(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_core_v3_RuntimePercent_set_runtime_key(envoy_config_core_v3_RuntimePercent *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+
 /* envoy.config.core.v3.RuntimeDouble */
 
 UPB_INLINE envoy_config_core_v3_RuntimeDouble *envoy_config_core_v3_RuntimeDouble_new(upb_arena *arena) {
@@ -659,6 +708,32 @@
   return sub;
 }
 
+/* envoy.config.core.v3.WatchedDirectory */
+
+UPB_INLINE envoy_config_core_v3_WatchedDirectory *envoy_config_core_v3_WatchedDirectory_new(upb_arena *arena) {
+  return (envoy_config_core_v3_WatchedDirectory *)_upb_msg_new(&envoy_config_core_v3_WatchedDirectory_msginit, arena);
+}
+UPB_INLINE envoy_config_core_v3_WatchedDirectory *envoy_config_core_v3_WatchedDirectory_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_core_v3_WatchedDirectory *ret = envoy_config_core_v3_WatchedDirectory_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_core_v3_WatchedDirectory_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_core_v3_WatchedDirectory *envoy_config_core_v3_WatchedDirectory_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_core_v3_WatchedDirectory *ret = envoy_config_core_v3_WatchedDirectory_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_core_v3_WatchedDirectory_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_core_v3_WatchedDirectory_serialize(const envoy_config_core_v3_WatchedDirectory *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_core_v3_WatchedDirectory_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_core_v3_WatchedDirectory_path(const envoy_config_core_v3_WatchedDirectory *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+
+UPB_INLINE void envoy_config_core_v3_WatchedDirectory_set_path(envoy_config_core_v3_WatchedDirectory *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+
 /* envoy.config.core.v3.DataSource */
 
 UPB_INLINE envoy_config_core_v3_DataSource *envoy_config_core_v3_DataSource_new(upb_arena *arena) {
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/config_source.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/config_source.upb.c
index 60be5fb..30a2e75 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/config_source.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/config_source.upb.c
@@ -12,7 +12,7 @@
 #include "envoy/config/core/v3/grpc_service.upb.h"
 #include "google/protobuf/duration.upb.h"
 #include "google/protobuf/wrappers.upb.h"
-#include "udpa/core/v1/authority.upb.h"
+#include "xds/core/v3/authority.upb.h"
 #include "envoy/annotations/deprecation.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
@@ -80,7 +80,7 @@
   &envoy_config_core_v3_ApiConfigSource_msginit,
   &envoy_config_core_v3_SelfConfigSource_msginit,
   &google_protobuf_Duration_msginit,
-  &udpa_core_v1_Authority_msginit,
+  &xds_core_v3_Authority_msginit,
 };
 
 static const upb_msglayout_field envoy_config_core_v3_ConfigSource__fields[7] = {
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/config_source.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/config_source.upb.h
index bbc165f..1fc8534 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/config_source.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/config_source.upb.h
@@ -39,12 +39,12 @@
 struct google_protobuf_DoubleValue;
 struct google_protobuf_Duration;
 struct google_protobuf_UInt32Value;
-struct udpa_core_v1_Authority;
+struct xds_core_v3_Authority;
 extern const upb_msglayout envoy_config_core_v3_GrpcService_msginit;
 extern const upb_msglayout google_protobuf_DoubleValue_msginit;
 extern const upb_msglayout google_protobuf_Duration_msginit;
 extern const upb_msglayout google_protobuf_UInt32Value_msginit;
-extern const upb_msglayout udpa_core_v1_Authority_msginit;
+extern const upb_msglayout xds_core_v3_Authority_msginit;
 
 typedef enum {
   envoy_config_core_v3_ApiConfigSource_DEPRECATED_AND_UNAVAILABLE_DO_NOT_USE = 0,
@@ -308,7 +308,7 @@
 UPB_INLINE const envoy_config_core_v3_SelfConfigSource* envoy_config_core_v3_ConfigSource_self(const envoy_config_core_v3_ConfigSource *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_SelfConfigSource*, UPB_SIZE(16, 24), UPB_SIZE(24, 40), 5, NULL); }
 UPB_INLINE int32_t envoy_config_core_v3_ConfigSource_resource_api_version(const envoy_config_core_v3_ConfigSource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
 UPB_INLINE bool envoy_config_core_v3_ConfigSource_has_authorities(const envoy_config_core_v3_ConfigSource *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); }
-UPB_INLINE const struct udpa_core_v1_Authority* const* envoy_config_core_v3_ConfigSource_authorities(const envoy_config_core_v3_ConfigSource *msg, size_t *len) { return (const struct udpa_core_v1_Authority* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); }
+UPB_INLINE const struct xds_core_v3_Authority* const* envoy_config_core_v3_ConfigSource_authorities(const envoy_config_core_v3_ConfigSource *msg, size_t *len) { return (const struct xds_core_v3_Authority* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); }
 
 UPB_INLINE void envoy_config_core_v3_ConfigSource_set_path(envoy_config_core_v3_ConfigSource *msg, upb_strview value) {
   UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(16, 24), value, UPB_SIZE(24, 40), 1);
@@ -365,14 +365,14 @@
 UPB_INLINE void envoy_config_core_v3_ConfigSource_set_resource_api_version(envoy_config_core_v3_ConfigSource *msg, int32_t value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
 }
-UPB_INLINE struct udpa_core_v1_Authority** envoy_config_core_v3_ConfigSource_mutable_authorities(envoy_config_core_v3_ConfigSource *msg, size_t *len) {
-  return (struct udpa_core_v1_Authority**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len);
+UPB_INLINE struct xds_core_v3_Authority** envoy_config_core_v3_ConfigSource_mutable_authorities(envoy_config_core_v3_ConfigSource *msg, size_t *len) {
+  return (struct xds_core_v3_Authority**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len);
 }
-UPB_INLINE struct udpa_core_v1_Authority** envoy_config_core_v3_ConfigSource_resize_authorities(envoy_config_core_v3_ConfigSource *msg, size_t len, upb_arena *arena) {
-  return (struct udpa_core_v1_Authority**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE struct xds_core_v3_Authority** envoy_config_core_v3_ConfigSource_resize_authorities(envoy_config_core_v3_ConfigSource *msg, size_t len, upb_arena *arena) {
+  return (struct xds_core_v3_Authority**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct udpa_core_v1_Authority* envoy_config_core_v3_ConfigSource_add_authorities(envoy_config_core_v3_ConfigSource *msg, upb_arena *arena) {
-  struct udpa_core_v1_Authority* sub = (struct udpa_core_v1_Authority*)_upb_msg_new(&udpa_core_v1_Authority_msginit, arena);
+UPB_INLINE struct xds_core_v3_Authority* envoy_config_core_v3_ConfigSource_add_authorities(envoy_config_core_v3_ConfigSource *msg, upb_arena *arena) {
+  struct xds_core_v3_Authority* sub = (struct xds_core_v3_Authority*)_upb_msg_new(&xds_core_v3_Authority_msginit, arena);
   bool ok = _upb_array_append_accessor2(
       msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/health_check.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/health_check.upb.c
index c3f4339..b0a5a64 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/health_check.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/health_check.upb.c
@@ -18,7 +18,6 @@
 #include "google/protobuf/duration.upb.h"
 #include "google/protobuf/struct.upb.h"
 #include "google/protobuf/wrappers.upb.h"
-#include "envoy/annotations/deprecation.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
 #include "validate/validate.upb.h"
@@ -38,7 +37,7 @@
   &google_protobuf_UInt32Value_msginit,
 };
 
-static const upb_msglayout_field envoy_config_core_v3_HealthCheck__fields[22] = {
+static const upb_msglayout_field envoy_config_core_v3_HealthCheck__fields[23] = {
   {1, UPB_SIZE(20, 32), 1, 7, 11, 1},
   {2, UPB_SIZE(24, 40), 2, 7, 11, 1},
   {3, UPB_SIZE(28, 48), 3, 7, 11, 1},
@@ -46,11 +45,11 @@
   {5, UPB_SIZE(36, 64), 5, 9, 11, 1},
   {6, UPB_SIZE(40, 72), 6, 9, 11, 1},
   {7, UPB_SIZE(44, 80), 7, 6, 11, 1},
-  {8, UPB_SIZE(80, 152), UPB_SIZE(-85, -161), 3, 11, 1},
-  {9, UPB_SIZE(80, 152), UPB_SIZE(-85, -161), 4, 11, 1},
-  {11, UPB_SIZE(80, 152), UPB_SIZE(-85, -161), 2, 11, 1},
+  {8, UPB_SIZE(84, 160), UPB_SIZE(-89, -169), 3, 11, 1},
+  {9, UPB_SIZE(84, 160), UPB_SIZE(-89, -169), 4, 11, 1},
+  {11, UPB_SIZE(84, 160), UPB_SIZE(-89, -169), 2, 11, 1},
   {12, UPB_SIZE(48, 88), 8, 7, 11, 1},
-  {13, UPB_SIZE(80, 152), UPB_SIZE(-85, -161), 1, 11, 1},
+  {13, UPB_SIZE(84, 160), UPB_SIZE(-89, -169), 1, 11, 1},
   {14, UPB_SIZE(52, 96), 9, 7, 11, 1},
   {15, UPB_SIZE(56, 104), 10, 7, 11, 1},
   {16, UPB_SIZE(60, 112), 11, 7, 11, 1},
@@ -61,12 +60,13 @@
   {21, UPB_SIZE(68, 128), 13, 5, 11, 1},
   {22, UPB_SIZE(72, 136), 14, 0, 11, 1},
   {23, UPB_SIZE(76, 144), 15, 8, 11, 1},
+  {24, UPB_SIZE(80, 152), 16, 7, 11, 1},
 };
 
 const upb_msglayout envoy_config_core_v3_HealthCheck_msginit = {
   &envoy_config_core_v3_HealthCheck_submsgs[0],
   &envoy_config_core_v3_HealthCheck__fields[0],
-  UPB_SIZE(88, 176), 22, false, 255,
+  UPB_SIZE(96, 176), 23, false, 255,
 };
 
 static const upb_msglayout_field envoy_config_core_v3_HealthCheck_Payload__fields[2] = {
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/health_check.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/health_check.upb.h
index 711bbfc..e4a803a 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/health_check.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/health_check.upb.h
@@ -100,7 +100,7 @@
   envoy_config_core_v3_HealthCheck_health_checker_custom_health_check = 13,
   envoy_config_core_v3_HealthCheck_health_checker_NOT_SET = 0
 } envoy_config_core_v3_HealthCheck_health_checker_oneofcases;
-UPB_INLINE envoy_config_core_v3_HealthCheck_health_checker_oneofcases envoy_config_core_v3_HealthCheck_health_checker_case(const envoy_config_core_v3_HealthCheck* msg) { return (envoy_config_core_v3_HealthCheck_health_checker_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(84, 160), int32_t); }
+UPB_INLINE envoy_config_core_v3_HealthCheck_health_checker_oneofcases envoy_config_core_v3_HealthCheck_health_checker_case(const envoy_config_core_v3_HealthCheck* msg) { return (envoy_config_core_v3_HealthCheck_health_checker_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(88, 168), int32_t); }
 
 UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_timeout(const envoy_config_core_v3_HealthCheck *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct google_protobuf_Duration* envoy_config_core_v3_HealthCheck_timeout(const envoy_config_core_v3_HealthCheck *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 32), const struct google_protobuf_Duration*); }
@@ -116,16 +116,16 @@
 UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_core_v3_HealthCheck_alt_port(const envoy_config_core_v3_HealthCheck *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 72), const struct google_protobuf_UInt32Value*); }
 UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_reuse_connection(const envoy_config_core_v3_HealthCheck *msg) { return _upb_hasbit(msg, 7); }
 UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_core_v3_HealthCheck_reuse_connection(const envoy_config_core_v3_HealthCheck *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 80), const struct google_protobuf_BoolValue*); }
-UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_http_health_check(const envoy_config_core_v3_HealthCheck *msg) { return _upb_getoneofcase(msg, UPB_SIZE(84, 160)) == 8; }
-UPB_INLINE const envoy_config_core_v3_HealthCheck_HttpHealthCheck* envoy_config_core_v3_HealthCheck_http_health_check(const envoy_config_core_v3_HealthCheck *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_HealthCheck_HttpHealthCheck*, UPB_SIZE(80, 152), UPB_SIZE(84, 160), 8, NULL); }
-UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_tcp_health_check(const envoy_config_core_v3_HealthCheck *msg) { return _upb_getoneofcase(msg, UPB_SIZE(84, 160)) == 9; }
-UPB_INLINE const envoy_config_core_v3_HealthCheck_TcpHealthCheck* envoy_config_core_v3_HealthCheck_tcp_health_check(const envoy_config_core_v3_HealthCheck *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_HealthCheck_TcpHealthCheck*, UPB_SIZE(80, 152), UPB_SIZE(84, 160), 9, NULL); }
-UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_grpc_health_check(const envoy_config_core_v3_HealthCheck *msg) { return _upb_getoneofcase(msg, UPB_SIZE(84, 160)) == 11; }
-UPB_INLINE const envoy_config_core_v3_HealthCheck_GrpcHealthCheck* envoy_config_core_v3_HealthCheck_grpc_health_check(const envoy_config_core_v3_HealthCheck *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_HealthCheck_GrpcHealthCheck*, UPB_SIZE(80, 152), UPB_SIZE(84, 160), 11, NULL); }
+UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_http_health_check(const envoy_config_core_v3_HealthCheck *msg) { return _upb_getoneofcase(msg, UPB_SIZE(88, 168)) == 8; }
+UPB_INLINE const envoy_config_core_v3_HealthCheck_HttpHealthCheck* envoy_config_core_v3_HealthCheck_http_health_check(const envoy_config_core_v3_HealthCheck *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_HealthCheck_HttpHealthCheck*, UPB_SIZE(84, 160), UPB_SIZE(88, 168), 8, NULL); }
+UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_tcp_health_check(const envoy_config_core_v3_HealthCheck *msg) { return _upb_getoneofcase(msg, UPB_SIZE(88, 168)) == 9; }
+UPB_INLINE const envoy_config_core_v3_HealthCheck_TcpHealthCheck* envoy_config_core_v3_HealthCheck_tcp_health_check(const envoy_config_core_v3_HealthCheck *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_HealthCheck_TcpHealthCheck*, UPB_SIZE(84, 160), UPB_SIZE(88, 168), 9, NULL); }
+UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_grpc_health_check(const envoy_config_core_v3_HealthCheck *msg) { return _upb_getoneofcase(msg, UPB_SIZE(88, 168)) == 11; }
+UPB_INLINE const envoy_config_core_v3_HealthCheck_GrpcHealthCheck* envoy_config_core_v3_HealthCheck_grpc_health_check(const envoy_config_core_v3_HealthCheck *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_HealthCheck_GrpcHealthCheck*, UPB_SIZE(84, 160), UPB_SIZE(88, 168), 11, NULL); }
 UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_no_traffic_interval(const envoy_config_core_v3_HealthCheck *msg) { return _upb_hasbit(msg, 8); }
 UPB_INLINE const struct google_protobuf_Duration* envoy_config_core_v3_HealthCheck_no_traffic_interval(const envoy_config_core_v3_HealthCheck *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 88), const struct google_protobuf_Duration*); }
-UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_custom_health_check(const envoy_config_core_v3_HealthCheck *msg) { return _upb_getoneofcase(msg, UPB_SIZE(84, 160)) == 13; }
-UPB_INLINE const envoy_config_core_v3_HealthCheck_CustomHealthCheck* envoy_config_core_v3_HealthCheck_custom_health_check(const envoy_config_core_v3_HealthCheck *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_HealthCheck_CustomHealthCheck*, UPB_SIZE(80, 152), UPB_SIZE(84, 160), 13, NULL); }
+UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_custom_health_check(const envoy_config_core_v3_HealthCheck *msg) { return _upb_getoneofcase(msg, UPB_SIZE(88, 168)) == 13; }
+UPB_INLINE const envoy_config_core_v3_HealthCheck_CustomHealthCheck* envoy_config_core_v3_HealthCheck_custom_health_check(const envoy_config_core_v3_HealthCheck *msg) { return UPB_READ_ONEOF(msg, const envoy_config_core_v3_HealthCheck_CustomHealthCheck*, UPB_SIZE(84, 160), UPB_SIZE(88, 168), 13, NULL); }
 UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_unhealthy_interval(const envoy_config_core_v3_HealthCheck *msg) { return _upb_hasbit(msg, 9); }
 UPB_INLINE const struct google_protobuf_Duration* envoy_config_core_v3_HealthCheck_unhealthy_interval(const envoy_config_core_v3_HealthCheck *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 96), const struct google_protobuf_Duration*); }
 UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_unhealthy_edge_interval(const envoy_config_core_v3_HealthCheck *msg) { return _upb_hasbit(msg, 10); }
@@ -143,6 +143,8 @@
 UPB_INLINE const struct envoy_config_core_v3_EventServiceConfig* envoy_config_core_v3_HealthCheck_event_service(const envoy_config_core_v3_HealthCheck *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(72, 136), const struct envoy_config_core_v3_EventServiceConfig*); }
 UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_transport_socket_match_criteria(const envoy_config_core_v3_HealthCheck *msg) { return _upb_hasbit(msg, 15); }
 UPB_INLINE const struct google_protobuf_Struct* envoy_config_core_v3_HealthCheck_transport_socket_match_criteria(const envoy_config_core_v3_HealthCheck *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 144), const struct google_protobuf_Struct*); }
+UPB_INLINE bool envoy_config_core_v3_HealthCheck_has_no_traffic_healthy_interval(const envoy_config_core_v3_HealthCheck *msg) { return _upb_hasbit(msg, 16); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_core_v3_HealthCheck_no_traffic_healthy_interval(const envoy_config_core_v3_HealthCheck *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(80, 152), const struct google_protobuf_Duration*); }
 
 UPB_INLINE void envoy_config_core_v3_HealthCheck_set_timeout(envoy_config_core_v3_HealthCheck *msg, struct google_protobuf_Duration* value) {
   _upb_sethas(msg, 1);
@@ -236,7 +238,7 @@
   return sub;
 }
 UPB_INLINE void envoy_config_core_v3_HealthCheck_set_http_health_check(envoy_config_core_v3_HealthCheck *msg, envoy_config_core_v3_HealthCheck_HttpHealthCheck* value) {
-  UPB_WRITE_ONEOF(msg, envoy_config_core_v3_HealthCheck_HttpHealthCheck*, UPB_SIZE(80, 152), value, UPB_SIZE(84, 160), 8);
+  UPB_WRITE_ONEOF(msg, envoy_config_core_v3_HealthCheck_HttpHealthCheck*, UPB_SIZE(84, 160), value, UPB_SIZE(88, 168), 8);
 }
 UPB_INLINE struct envoy_config_core_v3_HealthCheck_HttpHealthCheck* envoy_config_core_v3_HealthCheck_mutable_http_health_check(envoy_config_core_v3_HealthCheck *msg, upb_arena *arena) {
   struct envoy_config_core_v3_HealthCheck_HttpHealthCheck* sub = (struct envoy_config_core_v3_HealthCheck_HttpHealthCheck*)envoy_config_core_v3_HealthCheck_http_health_check(msg);
@@ -248,7 +250,7 @@
   return sub;
 }
 UPB_INLINE void envoy_config_core_v3_HealthCheck_set_tcp_health_check(envoy_config_core_v3_HealthCheck *msg, envoy_config_core_v3_HealthCheck_TcpHealthCheck* value) {
-  UPB_WRITE_ONEOF(msg, envoy_config_core_v3_HealthCheck_TcpHealthCheck*, UPB_SIZE(80, 152), value, UPB_SIZE(84, 160), 9);
+  UPB_WRITE_ONEOF(msg, envoy_config_core_v3_HealthCheck_TcpHealthCheck*, UPB_SIZE(84, 160), value, UPB_SIZE(88, 168), 9);
 }
 UPB_INLINE struct envoy_config_core_v3_HealthCheck_TcpHealthCheck* envoy_config_core_v3_HealthCheck_mutable_tcp_health_check(envoy_config_core_v3_HealthCheck *msg, upb_arena *arena) {
   struct envoy_config_core_v3_HealthCheck_TcpHealthCheck* sub = (struct envoy_config_core_v3_HealthCheck_TcpHealthCheck*)envoy_config_core_v3_HealthCheck_tcp_health_check(msg);
@@ -260,7 +262,7 @@
   return sub;
 }
 UPB_INLINE void envoy_config_core_v3_HealthCheck_set_grpc_health_check(envoy_config_core_v3_HealthCheck *msg, envoy_config_core_v3_HealthCheck_GrpcHealthCheck* value) {
-  UPB_WRITE_ONEOF(msg, envoy_config_core_v3_HealthCheck_GrpcHealthCheck*, UPB_SIZE(80, 152), value, UPB_SIZE(84, 160), 11);
+  UPB_WRITE_ONEOF(msg, envoy_config_core_v3_HealthCheck_GrpcHealthCheck*, UPB_SIZE(84, 160), value, UPB_SIZE(88, 168), 11);
 }
 UPB_INLINE struct envoy_config_core_v3_HealthCheck_GrpcHealthCheck* envoy_config_core_v3_HealthCheck_mutable_grpc_health_check(envoy_config_core_v3_HealthCheck *msg, upb_arena *arena) {
   struct envoy_config_core_v3_HealthCheck_GrpcHealthCheck* sub = (struct envoy_config_core_v3_HealthCheck_GrpcHealthCheck*)envoy_config_core_v3_HealthCheck_grpc_health_check(msg);
@@ -285,7 +287,7 @@
   return sub;
 }
 UPB_INLINE void envoy_config_core_v3_HealthCheck_set_custom_health_check(envoy_config_core_v3_HealthCheck *msg, envoy_config_core_v3_HealthCheck_CustomHealthCheck* value) {
-  UPB_WRITE_ONEOF(msg, envoy_config_core_v3_HealthCheck_CustomHealthCheck*, UPB_SIZE(80, 152), value, UPB_SIZE(84, 160), 13);
+  UPB_WRITE_ONEOF(msg, envoy_config_core_v3_HealthCheck_CustomHealthCheck*, UPB_SIZE(84, 160), value, UPB_SIZE(88, 168), 13);
 }
 UPB_INLINE struct envoy_config_core_v3_HealthCheck_CustomHealthCheck* envoy_config_core_v3_HealthCheck_mutable_custom_health_check(envoy_config_core_v3_HealthCheck *msg, upb_arena *arena) {
   struct envoy_config_core_v3_HealthCheck_CustomHealthCheck* sub = (struct envoy_config_core_v3_HealthCheck_CustomHealthCheck*)envoy_config_core_v3_HealthCheck_custom_health_check(msg);
@@ -396,6 +398,19 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_config_core_v3_HealthCheck_set_no_traffic_healthy_interval(envoy_config_core_v3_HealthCheck *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 16);
+  *UPB_PTR_AT(msg, UPB_SIZE(80, 152), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_core_v3_HealthCheck_mutable_no_traffic_healthy_interval(envoy_config_core_v3_HealthCheck *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_core_v3_HealthCheck_no_traffic_healthy_interval(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_core_v3_HealthCheck_set_no_traffic_healthy_interval(msg, sub);
+  }
+  return sub;
+}
 
 /* envoy.config.core.v3.HealthCheck.Payload */
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/protocol.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/protocol.upb.c
index 2825011..67c9b10 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/protocol.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/protocol.upb.c
@@ -172,5 +172,11 @@
   UPB_SIZE(8, 16), 1, false, 255,
 };
 
+const upb_msglayout envoy_config_core_v3_Http3ProtocolOptions_msginit = {
+  NULL,
+  NULL,
+  UPB_SIZE(0, 0), 0, false, 255,
+};
+
 #include "upb/port_undef.inc"
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/protocol.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/protocol.upb.h
index c690693..8bfcae6 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/protocol.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/protocol.upb.h
@@ -30,6 +30,7 @@
 struct envoy_config_core_v3_Http2ProtocolOptions;
 struct envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter;
 struct envoy_config_core_v3_GrpcProtocolOptions;
+struct envoy_config_core_v3_Http3ProtocolOptions;
 typedef struct envoy_config_core_v3_TcpProtocolOptions envoy_config_core_v3_TcpProtocolOptions;
 typedef struct envoy_config_core_v3_UpstreamHttpProtocolOptions envoy_config_core_v3_UpstreamHttpProtocolOptions;
 typedef struct envoy_config_core_v3_HttpProtocolOptions envoy_config_core_v3_HttpProtocolOptions;
@@ -40,6 +41,7 @@
 typedef struct envoy_config_core_v3_Http2ProtocolOptions envoy_config_core_v3_Http2ProtocolOptions;
 typedef struct envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter;
 typedef struct envoy_config_core_v3_GrpcProtocolOptions envoy_config_core_v3_GrpcProtocolOptions;
+typedef struct envoy_config_core_v3_Http3ProtocolOptions envoy_config_core_v3_Http3ProtocolOptions;
 extern const upb_msglayout envoy_config_core_v3_TcpProtocolOptions_msginit;
 extern const upb_msglayout envoy_config_core_v3_UpstreamHttpProtocolOptions_msginit;
 extern const upb_msglayout envoy_config_core_v3_HttpProtocolOptions_msginit;
@@ -50,6 +52,7 @@
 extern const upb_msglayout envoy_config_core_v3_Http2ProtocolOptions_msginit;
 extern const upb_msglayout envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter_msginit;
 extern const upb_msglayout envoy_config_core_v3_GrpcProtocolOptions_msginit;
+extern const upb_msglayout envoy_config_core_v3_Http3ProtocolOptions_msginit;
 struct envoy_type_v3_Percent;
 struct google_protobuf_BoolValue;
 struct google_protobuf_Duration;
@@ -721,6 +724,28 @@
   return sub;
 }
 
+/* envoy.config.core.v3.Http3ProtocolOptions */
+
+UPB_INLINE envoy_config_core_v3_Http3ProtocolOptions *envoy_config_core_v3_Http3ProtocolOptions_new(upb_arena *arena) {
+  return (envoy_config_core_v3_Http3ProtocolOptions *)_upb_msg_new(&envoy_config_core_v3_Http3ProtocolOptions_msginit, arena);
+}
+UPB_INLINE envoy_config_core_v3_Http3ProtocolOptions *envoy_config_core_v3_Http3ProtocolOptions_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_core_v3_Http3ProtocolOptions *ret = envoy_config_core_v3_Http3ProtocolOptions_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_core_v3_Http3ProtocolOptions_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_core_v3_Http3ProtocolOptions *envoy_config_core_v3_Http3ProtocolOptions_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_core_v3_Http3ProtocolOptions *ret = envoy_config_core_v3_Http3ProtocolOptions_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_core_v3_Http3ProtocolOptions_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_core_v3_Http3ProtocolOptions_serialize(const envoy_config_core_v3_Http3ProtocolOptions *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_core_v3_Http3ProtocolOptions_msginit, arena, len);
+}
+
+
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/proxy_protocol.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/proxy_protocol.upb.c
index 3434439..4c56e07 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/proxy_protocol.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/proxy_protocol.upb.c
@@ -10,7 +10,6 @@
 #include "upb/msg.h"
 #include "envoy/config/core/v3/proxy_protocol.upb.h"
 #include "udpa/annotations/status.upb.h"
-#include "validate/validate.upb.h"
 
 #include "upb/port_def.inc"
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/substitution_format_string.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/substitution_format_string.upb.c
index cf56861..7178164 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/substitution_format_string.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/substitution_format_string.upb.c
@@ -9,27 +9,33 @@
 #include <stddef.h>
 #include "upb/msg.h"
 #include "envoy/config/core/v3/substitution_format_string.upb.h"
+#include "envoy/config/core/v3/base.upb.h"
+#include "envoy/config/core/v3/extension.upb.h"
 #include "google/protobuf/struct.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "validate/validate.upb.h"
 
 #include "upb/port_def.inc"
 
-static const upb_msglayout *const envoy_config_core_v3_SubstitutionFormatString_submsgs[1] = {
+static const upb_msglayout *const envoy_config_core_v3_SubstitutionFormatString_submsgs[3] = {
+  &envoy_config_core_v3_DataSource_msginit,
+  &envoy_config_core_v3_TypedExtensionConfig_msginit,
   &google_protobuf_Struct_msginit,
 };
 
-static const upb_msglayout_field envoy_config_core_v3_SubstitutionFormatString__fields[4] = {
-  {1, UPB_SIZE(12, 24), UPB_SIZE(-21, -41), 0, 9, 1},
-  {2, UPB_SIZE(12, 24), UPB_SIZE(-21, -41), 0, 11, 1},
+static const upb_msglayout_field envoy_config_core_v3_SubstitutionFormatString__fields[6] = {
+  {1, UPB_SIZE(16, 32), UPB_SIZE(-25, -49), 0, 9, 1},
+  {2, UPB_SIZE(16, 32), UPB_SIZE(-25, -49), 2, 11, 1},
   {3, UPB_SIZE(0, 0), 0, 0, 8, 1},
   {4, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {5, UPB_SIZE(16, 32), UPB_SIZE(-25, -49), 0, 11, 1},
+  {6, UPB_SIZE(12, 24), 0, 1, 11, 3},
 };
 
 const upb_msglayout envoy_config_core_v3_SubstitutionFormatString_msginit = {
   &envoy_config_core_v3_SubstitutionFormatString_submsgs[0],
   &envoy_config_core_v3_SubstitutionFormatString__fields[0],
-  UPB_SIZE(24, 48), 4, false, 255,
+  UPB_SIZE(32, 64), 6, false, 255,
 };
 
 #include "upb/port_undef.inc"
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/substitution_format_string.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/substitution_format_string.upb.h
index 439b19f..3f450e9 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/core/v3/substitution_format_string.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/core/v3/substitution_format_string.upb.h
@@ -23,7 +23,11 @@
 struct envoy_config_core_v3_SubstitutionFormatString;
 typedef struct envoy_config_core_v3_SubstitutionFormatString envoy_config_core_v3_SubstitutionFormatString;
 extern const upb_msglayout envoy_config_core_v3_SubstitutionFormatString_msginit;
+struct envoy_config_core_v3_DataSource;
+struct envoy_config_core_v3_TypedExtensionConfig;
 struct google_protobuf_Struct;
+extern const upb_msglayout envoy_config_core_v3_DataSource_msginit;
+extern const upb_msglayout envoy_config_core_v3_TypedExtensionConfig_msginit;
 extern const upb_msglayout google_protobuf_Struct_msginit;
 
 
@@ -50,22 +54,27 @@
 typedef enum {
   envoy_config_core_v3_SubstitutionFormatString_format_text_format = 1,
   envoy_config_core_v3_SubstitutionFormatString_format_json_format = 2,
+  envoy_config_core_v3_SubstitutionFormatString_format_text_format_source = 5,
   envoy_config_core_v3_SubstitutionFormatString_format_NOT_SET = 0
 } envoy_config_core_v3_SubstitutionFormatString_format_oneofcases;
-UPB_INLINE envoy_config_core_v3_SubstitutionFormatString_format_oneofcases envoy_config_core_v3_SubstitutionFormatString_format_case(const envoy_config_core_v3_SubstitutionFormatString* msg) { return (envoy_config_core_v3_SubstitutionFormatString_format_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(20, 40), int32_t); }
+UPB_INLINE envoy_config_core_v3_SubstitutionFormatString_format_oneofcases envoy_config_core_v3_SubstitutionFormatString_format_case(const envoy_config_core_v3_SubstitutionFormatString* msg) { return (envoy_config_core_v3_SubstitutionFormatString_format_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(24, 48), int32_t); }
 
-UPB_INLINE bool envoy_config_core_v3_SubstitutionFormatString_has_text_format(const envoy_config_core_v3_SubstitutionFormatString *msg) { return _upb_getoneofcase(msg, UPB_SIZE(20, 40)) == 1; }
-UPB_INLINE upb_strview envoy_config_core_v3_SubstitutionFormatString_text_format(const envoy_config_core_v3_SubstitutionFormatString *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(12, 24), UPB_SIZE(20, 40), 1, upb_strview_make("", strlen(""))); }
-UPB_INLINE bool envoy_config_core_v3_SubstitutionFormatString_has_json_format(const envoy_config_core_v3_SubstitutionFormatString *msg) { return _upb_getoneofcase(msg, UPB_SIZE(20, 40)) == 2; }
-UPB_INLINE const struct google_protobuf_Struct* envoy_config_core_v3_SubstitutionFormatString_json_format(const envoy_config_core_v3_SubstitutionFormatString *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Struct*, UPB_SIZE(12, 24), UPB_SIZE(20, 40), 2, NULL); }
+UPB_INLINE bool envoy_config_core_v3_SubstitutionFormatString_has_text_format(const envoy_config_core_v3_SubstitutionFormatString *msg) { return _upb_getoneofcase(msg, UPB_SIZE(24, 48)) == 1; }
+UPB_INLINE upb_strview envoy_config_core_v3_SubstitutionFormatString_text_format(const envoy_config_core_v3_SubstitutionFormatString *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(16, 32), UPB_SIZE(24, 48), 1, upb_strview_make("", strlen(""))); }
+UPB_INLINE bool envoy_config_core_v3_SubstitutionFormatString_has_json_format(const envoy_config_core_v3_SubstitutionFormatString *msg) { return _upb_getoneofcase(msg, UPB_SIZE(24, 48)) == 2; }
+UPB_INLINE const struct google_protobuf_Struct* envoy_config_core_v3_SubstitutionFormatString_json_format(const envoy_config_core_v3_SubstitutionFormatString *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Struct*, UPB_SIZE(16, 32), UPB_SIZE(24, 48), 2, NULL); }
 UPB_INLINE bool envoy_config_core_v3_SubstitutionFormatString_omit_empty_values(const envoy_config_core_v3_SubstitutionFormatString *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), bool); }
 UPB_INLINE upb_strview envoy_config_core_v3_SubstitutionFormatString_content_type(const envoy_config_core_v3_SubstitutionFormatString *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_config_core_v3_SubstitutionFormatString_has_text_format_source(const envoy_config_core_v3_SubstitutionFormatString *msg) { return _upb_getoneofcase(msg, UPB_SIZE(24, 48)) == 5; }
+UPB_INLINE const struct envoy_config_core_v3_DataSource* envoy_config_core_v3_SubstitutionFormatString_text_format_source(const envoy_config_core_v3_SubstitutionFormatString *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_core_v3_DataSource*, UPB_SIZE(16, 32), UPB_SIZE(24, 48), 5, NULL); }
+UPB_INLINE bool envoy_config_core_v3_SubstitutionFormatString_has_formatters(const envoy_config_core_v3_SubstitutionFormatString *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); }
+UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* const* envoy_config_core_v3_SubstitutionFormatString_formatters(const envoy_config_core_v3_SubstitutionFormatString *msg, size_t *len) { return (const struct envoy_config_core_v3_TypedExtensionConfig* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); }
 
 UPB_INLINE void envoy_config_core_v3_SubstitutionFormatString_set_text_format(envoy_config_core_v3_SubstitutionFormatString *msg, upb_strview value) {
-  UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(12, 24), value, UPB_SIZE(20, 40), 1);
+  UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(16, 32), value, UPB_SIZE(24, 48), 1);
 }
 UPB_INLINE void envoy_config_core_v3_SubstitutionFormatString_set_json_format(envoy_config_core_v3_SubstitutionFormatString *msg, struct google_protobuf_Struct* value) {
-  UPB_WRITE_ONEOF(msg, struct google_protobuf_Struct*, UPB_SIZE(12, 24), value, UPB_SIZE(20, 40), 2);
+  UPB_WRITE_ONEOF(msg, struct google_protobuf_Struct*, UPB_SIZE(16, 32), value, UPB_SIZE(24, 48), 2);
 }
 UPB_INLINE struct google_protobuf_Struct* envoy_config_core_v3_SubstitutionFormatString_mutable_json_format(envoy_config_core_v3_SubstitutionFormatString *msg, upb_arena *arena) {
   struct google_protobuf_Struct* sub = (struct google_protobuf_Struct*)envoy_config_core_v3_SubstitutionFormatString_json_format(msg);
@@ -82,6 +91,31 @@
 UPB_INLINE void envoy_config_core_v3_SubstitutionFormatString_set_content_type(envoy_config_core_v3_SubstitutionFormatString *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
 }
+UPB_INLINE void envoy_config_core_v3_SubstitutionFormatString_set_text_format_source(envoy_config_core_v3_SubstitutionFormatString *msg, struct envoy_config_core_v3_DataSource* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_config_core_v3_DataSource*, UPB_SIZE(16, 32), value, UPB_SIZE(24, 48), 5);
+}
+UPB_INLINE struct envoy_config_core_v3_DataSource* envoy_config_core_v3_SubstitutionFormatString_mutable_text_format_source(envoy_config_core_v3_SubstitutionFormatString *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_DataSource* sub = (struct envoy_config_core_v3_DataSource*)envoy_config_core_v3_SubstitutionFormatString_text_format_source(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_DataSource*)_upb_msg_new(&envoy_config_core_v3_DataSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_core_v3_SubstitutionFormatString_set_text_format_source(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig** envoy_config_core_v3_SubstitutionFormatString_mutable_formatters(envoy_config_core_v3_SubstitutionFormatString *msg, size_t *len) {
+  return (struct envoy_config_core_v3_TypedExtensionConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len);
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig** envoy_config_core_v3_SubstitutionFormatString_resize_formatters(envoy_config_core_v3_SubstitutionFormatString *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_core_v3_TypedExtensionConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_core_v3_SubstitutionFormatString_add_formatters(envoy_config_core_v3_SubstitutionFormatString *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_TypedExtensionConfig* sub = (struct envoy_config_core_v3_TypedExtensionConfig*)_upb_msg_new(&envoy_config_core_v3_TypedExtensionConfig_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
 
 #ifdef __cplusplus
 }  /* extern "C" */
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/endpoint/v3/endpoint.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/endpoint/v3/endpoint.upb.c
index b53f726..3f9c789 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/endpoint/v3/endpoint.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/endpoint/v3/endpoint.upb.c
@@ -11,7 +11,6 @@
 #include "envoy/config/endpoint/v3/endpoint.upb.h"
 #include "envoy/config/endpoint/v3/endpoint_components.upb.h"
 #include "envoy/type/v3/percent.upb.h"
-#include "google/api/annotations.upb.h"
 #include "google/protobuf/duration.upb.h"
 #include "google/protobuf/wrappers.upb.h"
 #include "udpa/annotations/status.upb.h"
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c
index 6a8a837..e7e0cad 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.c
@@ -17,10 +17,9 @@
 #include "envoy/config/listener/v3/api_listener.upb.h"
 #include "envoy/config/listener/v3/listener_components.upb.h"
 #include "envoy/config/listener/v3/udp_listener_config.upb.h"
-#include "google/api/annotations.upb.h"
 #include "google/protobuf/duration.upb.h"
 #include "google/protobuf/wrappers.upb.h"
-#include "udpa/core/v1/collection_entry.upb.h"
+#include "xds/core/v3/collection_entry.upb.h"
 #include "udpa/annotations/security.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
@@ -29,7 +28,7 @@
 #include "upb/port_def.inc"
 
 static const upb_msglayout *const envoy_config_listener_v3_ListenerCollection_submsgs[1] = {
-  &udpa_core_v1_CollectionEntry_msginit,
+  &xds_core_v3_CollectionEntry_msginit,
 };
 
 static const upb_msglayout_field envoy_config_listener_v3_ListenerCollection__fields[1] = {
@@ -59,35 +58,38 @@
   &google_protobuf_UInt32Value_msginit,
 };
 
-static const upb_msglayout_field envoy_config_listener_v3_Listener__fields[22] = {
+static const upb_msglayout_field envoy_config_listener_v3_Listener__fields[25] = {
   {1, UPB_SIZE(16, 16), 0, 0, 9, 1},
   {2, UPB_SIZE(24, 32), 1, 1, 11, 1},
-  {3, UPB_SIZE(76, 136), 0, 6, 11, 3},
-  {5, UPB_SIZE(28, 40), 2, 13, 11, 1},
-  {6, UPB_SIZE(32, 48), 3, 2, 11, 1},
-  {7, UPB_SIZE(36, 56), 4, 8, 11, 1},
+  {3, UPB_SIZE(88, 160), 0, 6, 11, 3},
+  {4, UPB_SIZE(28, 40), 2, 11, 11, 1},
+  {5, UPB_SIZE(32, 48), 3, 13, 11, 1},
+  {6, UPB_SIZE(36, 56), 4, 2, 11, 1},
+  {7, UPB_SIZE(40, 64), 5, 8, 11, 1},
   {8, UPB_SIZE(4, 4), 0, 0, 14, 1},
-  {9, UPB_SIZE(80, 144), 0, 9, 11, 3},
-  {10, UPB_SIZE(40, 64), 5, 11, 11, 1},
-  {11, UPB_SIZE(44, 72), 6, 11, 11, 1},
-  {12, UPB_SIZE(48, 80), 7, 13, 11, 1},
-  {13, UPB_SIZE(84, 152), 0, 3, 11, 3},
-  {15, UPB_SIZE(52, 88), 8, 12, 11, 1},
+  {9, UPB_SIZE(92, 168), 0, 9, 11, 3},
+  {10, UPB_SIZE(44, 72), 6, 11, 11, 1},
+  {11, UPB_SIZE(48, 80), 7, 11, 11, 1},
+  {12, UPB_SIZE(52, 88), 8, 13, 11, 1},
+  {13, UPB_SIZE(96, 176), 0, 3, 11, 3},
+  {15, UPB_SIZE(56, 96), 9, 12, 11, 1},
   {16, UPB_SIZE(8, 8), 0, 0, 14, 1},
   {17, UPB_SIZE(12, 12), 0, 0, 8, 1},
-  {18, UPB_SIZE(56, 96), 9, 10, 11, 1},
-  {19, UPB_SIZE(60, 104), 10, 5, 11, 1},
-  {20, UPB_SIZE(64, 112), 11, 7, 11, 1},
+  {18, UPB_SIZE(60, 104), 10, 10, 11, 1},
+  {19, UPB_SIZE(64, 112), 11, 5, 11, 1},
+  {20, UPB_SIZE(68, 120), 12, 7, 11, 1},
   {21, UPB_SIZE(13, 13), 0, 0, 8, 1},
-  {22, UPB_SIZE(88, 160), 0, 0, 11, 3},
-  {23, UPB_SIZE(68, 120), 12, 4, 11, 1},
-  {24, UPB_SIZE(72, 128), 13, 13, 11, 1},
+  {22, UPB_SIZE(100, 184), 0, 0, 11, 3},
+  {23, UPB_SIZE(72, 128), 13, 4, 11, 1},
+  {24, UPB_SIZE(76, 136), 14, 13, 11, 1},
+  {25, UPB_SIZE(80, 144), 15, 6, 11, 1},
+  {26, UPB_SIZE(84, 152), 16, 11, 11, 1},
 };
 
 const upb_msglayout envoy_config_listener_v3_Listener_msginit = {
   &envoy_config_listener_v3_Listener_submsgs[0],
   &envoy_config_listener_v3_Listener__fields[0],
-  UPB_SIZE(96, 176), 22, false, 255,
+  UPB_SIZE(104, 192), 25, false, 255,
 };
 
 static const upb_msglayout *const envoy_config_listener_v3_Listener_DeprecatedV1_submsgs[1] = {
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h
index 7f97584..1d13373 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener.upb.h
@@ -47,7 +47,7 @@
 struct google_protobuf_BoolValue;
 struct google_protobuf_Duration;
 struct google_protobuf_UInt32Value;
-struct udpa_core_v1_CollectionEntry;
+struct xds_core_v3_CollectionEntry;
 extern const upb_msglayout envoy_config_accesslog_v3_AccessLog_msginit;
 extern const upb_msglayout envoy_config_core_v3_Address_msginit;
 extern const upb_msglayout envoy_config_core_v3_Metadata_msginit;
@@ -60,7 +60,7 @@
 extern const upb_msglayout google_protobuf_BoolValue_msginit;
 extern const upb_msglayout google_protobuf_Duration_msginit;
 extern const upb_msglayout google_protobuf_UInt32Value_msginit;
-extern const upb_msglayout udpa_core_v1_CollectionEntry_msginit;
+extern const upb_msglayout xds_core_v3_CollectionEntry_msginit;
 
 typedef enum {
   envoy_config_listener_v3_Listener_DEFAULT = 0,
@@ -89,16 +89,16 @@
 }
 
 UPB_INLINE bool envoy_config_listener_v3_ListenerCollection_has_entries(const envoy_config_listener_v3_ListenerCollection *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
-UPB_INLINE const struct udpa_core_v1_CollectionEntry* const* envoy_config_listener_v3_ListenerCollection_entries(const envoy_config_listener_v3_ListenerCollection *msg, size_t *len) { return (const struct udpa_core_v1_CollectionEntry* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+UPB_INLINE const struct xds_core_v3_CollectionEntry* const* envoy_config_listener_v3_ListenerCollection_entries(const envoy_config_listener_v3_ListenerCollection *msg, size_t *len) { return (const struct xds_core_v3_CollectionEntry* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
 
-UPB_INLINE struct udpa_core_v1_CollectionEntry** envoy_config_listener_v3_ListenerCollection_mutable_entries(envoy_config_listener_v3_ListenerCollection *msg, size_t *len) {
-  return (struct udpa_core_v1_CollectionEntry**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+UPB_INLINE struct xds_core_v3_CollectionEntry** envoy_config_listener_v3_ListenerCollection_mutable_entries(envoy_config_listener_v3_ListenerCollection *msg, size_t *len) {
+  return (struct xds_core_v3_CollectionEntry**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
 }
-UPB_INLINE struct udpa_core_v1_CollectionEntry** envoy_config_listener_v3_ListenerCollection_resize_entries(envoy_config_listener_v3_ListenerCollection *msg, size_t len, upb_arena *arena) {
-  return (struct udpa_core_v1_CollectionEntry**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE struct xds_core_v3_CollectionEntry** envoy_config_listener_v3_ListenerCollection_resize_entries(envoy_config_listener_v3_ListenerCollection *msg, size_t len, upb_arena *arena) {
+  return (struct xds_core_v3_CollectionEntry**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct udpa_core_v1_CollectionEntry* envoy_config_listener_v3_ListenerCollection_add_entries(envoy_config_listener_v3_ListenerCollection *msg, upb_arena *arena) {
-  struct udpa_core_v1_CollectionEntry* sub = (struct udpa_core_v1_CollectionEntry*)_upb_msg_new(&udpa_core_v1_CollectionEntry_msginit, arena);
+UPB_INLINE struct xds_core_v3_CollectionEntry* envoy_config_listener_v3_ListenerCollection_add_entries(envoy_config_listener_v3_ListenerCollection *msg, upb_arena *arena) {
+  struct xds_core_v3_CollectionEntry* sub = (struct xds_core_v3_CollectionEntry*)_upb_msg_new(&xds_core_v3_CollectionEntry_msginit, arena);
   bool ok = _upb_array_append_accessor2(
       msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
@@ -128,42 +128,48 @@
 UPB_INLINE upb_strview envoy_config_listener_v3_Listener_name(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), upb_strview); }
 UPB_INLINE bool envoy_config_listener_v3_Listener_has_address(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct envoy_config_core_v3_Address* envoy_config_listener_v3_Listener_address(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 32), const struct envoy_config_core_v3_Address*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_filter_chains(const envoy_config_listener_v3_Listener *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(76, 136)); }
-UPB_INLINE const struct envoy_config_listener_v3_FilterChain* const* envoy_config_listener_v3_Listener_filter_chains(const envoy_config_listener_v3_Listener *msg, size_t *len) { return (const struct envoy_config_listener_v3_FilterChain* const*)_upb_array_accessor(msg, UPB_SIZE(76, 136), len); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_per_connection_buffer_limit_bytes(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_per_connection_buffer_limit_bytes(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), const struct google_protobuf_UInt32Value*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_metadata(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE const struct envoy_config_core_v3_Metadata* envoy_config_listener_v3_Listener_metadata(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 48), const struct envoy_config_core_v3_Metadata*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_deprecated_v1(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 4); }
-UPB_INLINE const envoy_config_listener_v3_Listener_DeprecatedV1* envoy_config_listener_v3_Listener_deprecated_v1(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), const envoy_config_listener_v3_Listener_DeprecatedV1*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_filter_chains(const envoy_config_listener_v3_Listener *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(88, 160)); }
+UPB_INLINE const struct envoy_config_listener_v3_FilterChain* const* envoy_config_listener_v3_Listener_filter_chains(const envoy_config_listener_v3_Listener *msg, size_t *len) { return (const struct envoy_config_listener_v3_FilterChain* const*)_upb_array_accessor(msg, UPB_SIZE(88, 160), len); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_use_original_dst(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_use_original_dst(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), const struct google_protobuf_BoolValue*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_per_connection_buffer_limit_bytes(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_per_connection_buffer_limit_bytes(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 48), const struct google_protobuf_UInt32Value*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_metadata(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE const struct envoy_config_core_v3_Metadata* envoy_config_listener_v3_Listener_metadata(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), const struct envoy_config_core_v3_Metadata*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_deprecated_v1(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 5); }
+UPB_INLINE const envoy_config_listener_v3_Listener_DeprecatedV1* envoy_config_listener_v3_Listener_deprecated_v1(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 64), const envoy_config_listener_v3_Listener_DeprecatedV1*); }
 UPB_INLINE int32_t envoy_config_listener_v3_Listener_drain_type(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_listener_filters(const envoy_config_listener_v3_Listener *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(80, 144)); }
-UPB_INLINE const struct envoy_config_listener_v3_ListenerFilter* const* envoy_config_listener_v3_Listener_listener_filters(const envoy_config_listener_v3_Listener *msg, size_t *len) { return (const struct envoy_config_listener_v3_ListenerFilter* const*)_upb_array_accessor(msg, UPB_SIZE(80, 144), len); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_transparent(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 5); }
-UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_transparent(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 64), const struct google_protobuf_BoolValue*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_freebind(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 6); }
-UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_freebind(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), const struct google_protobuf_BoolValue*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_tcp_fast_open_queue_length(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 7); }
-UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_tcp_fast_open_queue_length(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 80), const struct google_protobuf_UInt32Value*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_socket_options(const envoy_config_listener_v3_Listener *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(84, 152)); }
-UPB_INLINE const struct envoy_config_core_v3_SocketOption* const* envoy_config_listener_v3_Listener_socket_options(const envoy_config_listener_v3_Listener *msg, size_t *len) { return (const struct envoy_config_core_v3_SocketOption* const*)_upb_array_accessor(msg, UPB_SIZE(84, 152), len); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_listener_filters_timeout(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 8); }
-UPB_INLINE const struct google_protobuf_Duration* envoy_config_listener_v3_Listener_listener_filters_timeout(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_listener_filters(const envoy_config_listener_v3_Listener *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(92, 168)); }
+UPB_INLINE const struct envoy_config_listener_v3_ListenerFilter* const* envoy_config_listener_v3_Listener_listener_filters(const envoy_config_listener_v3_Listener *msg, size_t *len) { return (const struct envoy_config_listener_v3_ListenerFilter* const*)_upb_array_accessor(msg, UPB_SIZE(92, 168), len); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_transparent(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_transparent(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), const struct google_protobuf_BoolValue*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_freebind(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 7); }
+UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_freebind(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 80), const struct google_protobuf_BoolValue*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_tcp_fast_open_queue_length(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 8); }
+UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_tcp_fast_open_queue_length(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), const struct google_protobuf_UInt32Value*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_socket_options(const envoy_config_listener_v3_Listener *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(96, 176)); }
+UPB_INLINE const struct envoy_config_core_v3_SocketOption* const* envoy_config_listener_v3_Listener_socket_options(const envoy_config_listener_v3_Listener *msg, size_t *len) { return (const struct envoy_config_core_v3_SocketOption* const*)_upb_array_accessor(msg, UPB_SIZE(96, 176), len); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_listener_filters_timeout(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 9); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_listener_v3_Listener_listener_filters_timeout(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(56, 96), const struct google_protobuf_Duration*); }
 UPB_INLINE int32_t envoy_config_listener_v3_Listener_traffic_direction(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
 UPB_INLINE bool envoy_config_listener_v3_Listener_continue_on_listener_filters_timeout(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_udp_listener_config(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 9); }
-UPB_INLINE const struct envoy_config_listener_v3_UdpListenerConfig* envoy_config_listener_v3_Listener_udp_listener_config(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(56, 96), const struct envoy_config_listener_v3_UdpListenerConfig*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_api_listener(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 10); }
-UPB_INLINE const struct envoy_config_listener_v3_ApiListener* envoy_config_listener_v3_Listener_api_listener(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), const struct envoy_config_listener_v3_ApiListener*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_connection_balance_config(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 11); }
-UPB_INLINE const envoy_config_listener_v3_Listener_ConnectionBalanceConfig* envoy_config_listener_v3_Listener_connection_balance_config(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(64, 112), const envoy_config_listener_v3_Listener_ConnectionBalanceConfig*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_udp_listener_config(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 10); }
+UPB_INLINE const struct envoy_config_listener_v3_UdpListenerConfig* envoy_config_listener_v3_Listener_udp_listener_config(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), const struct envoy_config_listener_v3_UdpListenerConfig*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_api_listener(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 11); }
+UPB_INLINE const struct envoy_config_listener_v3_ApiListener* envoy_config_listener_v3_Listener_api_listener(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(64, 112), const struct envoy_config_listener_v3_ApiListener*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_connection_balance_config(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 12); }
+UPB_INLINE const envoy_config_listener_v3_Listener_ConnectionBalanceConfig* envoy_config_listener_v3_Listener_connection_balance_config(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), const envoy_config_listener_v3_Listener_ConnectionBalanceConfig*); }
 UPB_INLINE bool envoy_config_listener_v3_Listener_reuse_port(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_access_log(const envoy_config_listener_v3_Listener *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(88, 160)); }
-UPB_INLINE const struct envoy_config_accesslog_v3_AccessLog* const* envoy_config_listener_v3_Listener_access_log(const envoy_config_listener_v3_Listener *msg, size_t *len) { return (const struct envoy_config_accesslog_v3_AccessLog* const*)_upb_array_accessor(msg, UPB_SIZE(88, 160), len); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_udp_writer_config(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 12); }
-UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_listener_v3_Listener_udp_writer_config(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), const struct envoy_config_core_v3_TypedExtensionConfig*); }
-UPB_INLINE bool envoy_config_listener_v3_Listener_has_tcp_backlog_size(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 13); }
-UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_tcp_backlog_size(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(72, 128), const struct google_protobuf_UInt32Value*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_access_log(const envoy_config_listener_v3_Listener *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); }
+UPB_INLINE const struct envoy_config_accesslog_v3_AccessLog* const* envoy_config_listener_v3_Listener_access_log(const envoy_config_listener_v3_Listener *msg, size_t *len) { return (const struct envoy_config_accesslog_v3_AccessLog* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_udp_writer_config(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 13); }
+UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_listener_v3_Listener_udp_writer_config(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(72, 128), const struct envoy_config_core_v3_TypedExtensionConfig*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_tcp_backlog_size(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 14); }
+UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_tcp_backlog_size(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), const struct google_protobuf_UInt32Value*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_default_filter_chain(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 15); }
+UPB_INLINE const struct envoy_config_listener_v3_FilterChain* envoy_config_listener_v3_Listener_default_filter_chain(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(80, 144), const struct envoy_config_listener_v3_FilterChain*); }
+UPB_INLINE bool envoy_config_listener_v3_Listener_has_bind_to_port(const envoy_config_listener_v3_Listener *msg) { return _upb_hasbit(msg, 16); }
+UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_bind_to_port(const envoy_config_listener_v3_Listener *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), const struct google_protobuf_BoolValue*); }
 
 UPB_INLINE void envoy_config_listener_v3_Listener_set_name(envoy_config_listener_v3_Listener *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(16, 16), upb_strview) = value;
@@ -182,21 +188,34 @@
   return sub;
 }
 UPB_INLINE struct envoy_config_listener_v3_FilterChain** envoy_config_listener_v3_Listener_mutable_filter_chains(envoy_config_listener_v3_Listener *msg, size_t *len) {
-  return (struct envoy_config_listener_v3_FilterChain**)_upb_array_mutable_accessor(msg, UPB_SIZE(76, 136), len);
+  return (struct envoy_config_listener_v3_FilterChain**)_upb_array_mutable_accessor(msg, UPB_SIZE(88, 160), len);
 }
 UPB_INLINE struct envoy_config_listener_v3_FilterChain** envoy_config_listener_v3_Listener_resize_filter_chains(envoy_config_listener_v3_Listener *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_listener_v3_FilterChain**)_upb_array_resize_accessor2(msg, UPB_SIZE(76, 136), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_listener_v3_FilterChain**)_upb_array_resize_accessor2(msg, UPB_SIZE(88, 160), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_listener_v3_FilterChain* envoy_config_listener_v3_Listener_add_filter_chains(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_listener_v3_FilterChain* sub = (struct envoy_config_listener_v3_FilterChain*)_upb_msg_new(&envoy_config_listener_v3_FilterChain_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(76, 136), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(88, 160), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
-UPB_INLINE void envoy_config_listener_v3_Listener_set_per_connection_buffer_limit_bytes(envoy_config_listener_v3_Listener *msg, struct google_protobuf_UInt32Value* value) {
+UPB_INLINE void envoy_config_listener_v3_Listener_set_use_original_dst(envoy_config_listener_v3_Listener *msg, struct google_protobuf_BoolValue* value) {
   _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(28, 40), struct google_protobuf_UInt32Value*) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 40), struct google_protobuf_BoolValue*) = value;
+}
+UPB_INLINE struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_mutable_use_original_dst(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
+  struct google_protobuf_BoolValue* sub = (struct google_protobuf_BoolValue*)envoy_config_listener_v3_Listener_use_original_dst(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_BoolValue*)_upb_msg_new(&google_protobuf_BoolValue_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_listener_v3_Listener_set_use_original_dst(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_listener_v3_Listener_set_per_connection_buffer_limit_bytes(envoy_config_listener_v3_Listener *msg, struct google_protobuf_UInt32Value* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(32, 48), struct google_protobuf_UInt32Value*) = value;
 }
 UPB_INLINE struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_mutable_per_connection_buffer_limit_bytes(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct google_protobuf_UInt32Value* sub = (struct google_protobuf_UInt32Value*)envoy_config_listener_v3_Listener_per_connection_buffer_limit_bytes(msg);
@@ -208,8 +227,8 @@
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_metadata(envoy_config_listener_v3_Listener *msg, struct envoy_config_core_v3_Metadata* value) {
-  _upb_sethas(msg, 3);
-  *UPB_PTR_AT(msg, UPB_SIZE(32, 48), struct envoy_config_core_v3_Metadata*) = value;
+  _upb_sethas(msg, 4);
+  *UPB_PTR_AT(msg, UPB_SIZE(36, 56), struct envoy_config_core_v3_Metadata*) = value;
 }
 UPB_INLINE struct envoy_config_core_v3_Metadata* envoy_config_listener_v3_Listener_mutable_metadata(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_core_v3_Metadata* sub = (struct envoy_config_core_v3_Metadata*)envoy_config_listener_v3_Listener_metadata(msg);
@@ -221,8 +240,8 @@
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_deprecated_v1(envoy_config_listener_v3_Listener *msg, envoy_config_listener_v3_Listener_DeprecatedV1* value) {
-  _upb_sethas(msg, 4);
-  *UPB_PTR_AT(msg, UPB_SIZE(36, 56), envoy_config_listener_v3_Listener_DeprecatedV1*) = value;
+  _upb_sethas(msg, 5);
+  *UPB_PTR_AT(msg, UPB_SIZE(40, 64), envoy_config_listener_v3_Listener_DeprecatedV1*) = value;
 }
 UPB_INLINE struct envoy_config_listener_v3_Listener_DeprecatedV1* envoy_config_listener_v3_Listener_mutable_deprecated_v1(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_listener_v3_Listener_DeprecatedV1* sub = (struct envoy_config_listener_v3_Listener_DeprecatedV1*)envoy_config_listener_v3_Listener_deprecated_v1(msg);
@@ -237,21 +256,21 @@
   *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
 }
 UPB_INLINE struct envoy_config_listener_v3_ListenerFilter** envoy_config_listener_v3_Listener_mutable_listener_filters(envoy_config_listener_v3_Listener *msg, size_t *len) {
-  return (struct envoy_config_listener_v3_ListenerFilter**)_upb_array_mutable_accessor(msg, UPB_SIZE(80, 144), len);
+  return (struct envoy_config_listener_v3_ListenerFilter**)_upb_array_mutable_accessor(msg, UPB_SIZE(92, 168), len);
 }
 UPB_INLINE struct envoy_config_listener_v3_ListenerFilter** envoy_config_listener_v3_Listener_resize_listener_filters(envoy_config_listener_v3_Listener *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_listener_v3_ListenerFilter**)_upb_array_resize_accessor2(msg, UPB_SIZE(80, 144), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_listener_v3_ListenerFilter**)_upb_array_resize_accessor2(msg, UPB_SIZE(92, 168), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_listener_v3_ListenerFilter* envoy_config_listener_v3_Listener_add_listener_filters(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_listener_v3_ListenerFilter* sub = (struct envoy_config_listener_v3_ListenerFilter*)_upb_msg_new(&envoy_config_listener_v3_ListenerFilter_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(80, 144), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(92, 168), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_transparent(envoy_config_listener_v3_Listener *msg, struct google_protobuf_BoolValue* value) {
-  _upb_sethas(msg, 5);
-  *UPB_PTR_AT(msg, UPB_SIZE(40, 64), struct google_protobuf_BoolValue*) = value;
+  _upb_sethas(msg, 6);
+  *UPB_PTR_AT(msg, UPB_SIZE(44, 72), struct google_protobuf_BoolValue*) = value;
 }
 UPB_INLINE struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_mutable_transparent(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct google_protobuf_BoolValue* sub = (struct google_protobuf_BoolValue*)envoy_config_listener_v3_Listener_transparent(msg);
@@ -263,8 +282,8 @@
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_freebind(envoy_config_listener_v3_Listener *msg, struct google_protobuf_BoolValue* value) {
-  _upb_sethas(msg, 6);
-  *UPB_PTR_AT(msg, UPB_SIZE(44, 72), struct google_protobuf_BoolValue*) = value;
+  _upb_sethas(msg, 7);
+  *UPB_PTR_AT(msg, UPB_SIZE(48, 80), struct google_protobuf_BoolValue*) = value;
 }
 UPB_INLINE struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_mutable_freebind(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct google_protobuf_BoolValue* sub = (struct google_protobuf_BoolValue*)envoy_config_listener_v3_Listener_freebind(msg);
@@ -276,8 +295,8 @@
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_tcp_fast_open_queue_length(envoy_config_listener_v3_Listener *msg, struct google_protobuf_UInt32Value* value) {
-  _upb_sethas(msg, 7);
-  *UPB_PTR_AT(msg, UPB_SIZE(48, 80), struct google_protobuf_UInt32Value*) = value;
+  _upb_sethas(msg, 8);
+  *UPB_PTR_AT(msg, UPB_SIZE(52, 88), struct google_protobuf_UInt32Value*) = value;
 }
 UPB_INLINE struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_mutable_tcp_fast_open_queue_length(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct google_protobuf_UInt32Value* sub = (struct google_protobuf_UInt32Value*)envoy_config_listener_v3_Listener_tcp_fast_open_queue_length(msg);
@@ -289,21 +308,21 @@
   return sub;
 }
 UPB_INLINE struct envoy_config_core_v3_SocketOption** envoy_config_listener_v3_Listener_mutable_socket_options(envoy_config_listener_v3_Listener *msg, size_t *len) {
-  return (struct envoy_config_core_v3_SocketOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(84, 152), len);
+  return (struct envoy_config_core_v3_SocketOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(96, 176), len);
 }
 UPB_INLINE struct envoy_config_core_v3_SocketOption** envoy_config_listener_v3_Listener_resize_socket_options(envoy_config_listener_v3_Listener *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_core_v3_SocketOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(84, 152), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_core_v3_SocketOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(96, 176), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_core_v3_SocketOption* envoy_config_listener_v3_Listener_add_socket_options(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_core_v3_SocketOption* sub = (struct envoy_config_core_v3_SocketOption*)_upb_msg_new(&envoy_config_core_v3_SocketOption_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(84, 152), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(96, 176), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_listener_filters_timeout(envoy_config_listener_v3_Listener *msg, struct google_protobuf_Duration* value) {
-  _upb_sethas(msg, 8);
-  *UPB_PTR_AT(msg, UPB_SIZE(52, 88), struct google_protobuf_Duration*) = value;
+  _upb_sethas(msg, 9);
+  *UPB_PTR_AT(msg, UPB_SIZE(56, 96), struct google_protobuf_Duration*) = value;
 }
 UPB_INLINE struct google_protobuf_Duration* envoy_config_listener_v3_Listener_mutable_listener_filters_timeout(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_listener_v3_Listener_listener_filters_timeout(msg);
@@ -321,8 +340,8 @@
   *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_udp_listener_config(envoy_config_listener_v3_Listener *msg, struct envoy_config_listener_v3_UdpListenerConfig* value) {
-  _upb_sethas(msg, 9);
-  *UPB_PTR_AT(msg, UPB_SIZE(56, 96), struct envoy_config_listener_v3_UdpListenerConfig*) = value;
+  _upb_sethas(msg, 10);
+  *UPB_PTR_AT(msg, UPB_SIZE(60, 104), struct envoy_config_listener_v3_UdpListenerConfig*) = value;
 }
 UPB_INLINE struct envoy_config_listener_v3_UdpListenerConfig* envoy_config_listener_v3_Listener_mutable_udp_listener_config(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_listener_v3_UdpListenerConfig* sub = (struct envoy_config_listener_v3_UdpListenerConfig*)envoy_config_listener_v3_Listener_udp_listener_config(msg);
@@ -334,8 +353,8 @@
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_api_listener(envoy_config_listener_v3_Listener *msg, struct envoy_config_listener_v3_ApiListener* value) {
-  _upb_sethas(msg, 10);
-  *UPB_PTR_AT(msg, UPB_SIZE(60, 104), struct envoy_config_listener_v3_ApiListener*) = value;
+  _upb_sethas(msg, 11);
+  *UPB_PTR_AT(msg, UPB_SIZE(64, 112), struct envoy_config_listener_v3_ApiListener*) = value;
 }
 UPB_INLINE struct envoy_config_listener_v3_ApiListener* envoy_config_listener_v3_Listener_mutable_api_listener(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_listener_v3_ApiListener* sub = (struct envoy_config_listener_v3_ApiListener*)envoy_config_listener_v3_Listener_api_listener(msg);
@@ -347,8 +366,8 @@
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_connection_balance_config(envoy_config_listener_v3_Listener *msg, envoy_config_listener_v3_Listener_ConnectionBalanceConfig* value) {
-  _upb_sethas(msg, 11);
-  *UPB_PTR_AT(msg, UPB_SIZE(64, 112), envoy_config_listener_v3_Listener_ConnectionBalanceConfig*) = value;
+  _upb_sethas(msg, 12);
+  *UPB_PTR_AT(msg, UPB_SIZE(68, 120), envoy_config_listener_v3_Listener_ConnectionBalanceConfig*) = value;
 }
 UPB_INLINE struct envoy_config_listener_v3_Listener_ConnectionBalanceConfig* envoy_config_listener_v3_Listener_mutable_connection_balance_config(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_listener_v3_Listener_ConnectionBalanceConfig* sub = (struct envoy_config_listener_v3_Listener_ConnectionBalanceConfig*)envoy_config_listener_v3_Listener_connection_balance_config(msg);
@@ -363,21 +382,21 @@
   *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value;
 }
 UPB_INLINE struct envoy_config_accesslog_v3_AccessLog** envoy_config_listener_v3_Listener_mutable_access_log(envoy_config_listener_v3_Listener *msg, size_t *len) {
-  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_mutable_accessor(msg, UPB_SIZE(88, 160), len);
+  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_mutable_accessor(msg, UPB_SIZE(100, 184), len);
 }
 UPB_INLINE struct envoy_config_accesslog_v3_AccessLog** envoy_config_listener_v3_Listener_resize_access_log(envoy_config_listener_v3_Listener *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_resize_accessor2(msg, UPB_SIZE(88, 160), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_resize_accessor2(msg, UPB_SIZE(100, 184), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_accesslog_v3_AccessLog* envoy_config_listener_v3_Listener_add_access_log(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_accesslog_v3_AccessLog* sub = (struct envoy_config_accesslog_v3_AccessLog*)_upb_msg_new(&envoy_config_accesslog_v3_AccessLog_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(88, 160), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_udp_writer_config(envoy_config_listener_v3_Listener *msg, struct envoy_config_core_v3_TypedExtensionConfig* value) {
-  _upb_sethas(msg, 12);
-  *UPB_PTR_AT(msg, UPB_SIZE(68, 120), struct envoy_config_core_v3_TypedExtensionConfig*) = value;
+  _upb_sethas(msg, 13);
+  *UPB_PTR_AT(msg, UPB_SIZE(72, 128), struct envoy_config_core_v3_TypedExtensionConfig*) = value;
 }
 UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_listener_v3_Listener_mutable_udp_writer_config(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct envoy_config_core_v3_TypedExtensionConfig* sub = (struct envoy_config_core_v3_TypedExtensionConfig*)envoy_config_listener_v3_Listener_udp_writer_config(msg);
@@ -389,8 +408,8 @@
   return sub;
 }
 UPB_INLINE void envoy_config_listener_v3_Listener_set_tcp_backlog_size(envoy_config_listener_v3_Listener *msg, struct google_protobuf_UInt32Value* value) {
-  _upb_sethas(msg, 13);
-  *UPB_PTR_AT(msg, UPB_SIZE(72, 128), struct google_protobuf_UInt32Value*) = value;
+  _upb_sethas(msg, 14);
+  *UPB_PTR_AT(msg, UPB_SIZE(76, 136), struct google_protobuf_UInt32Value*) = value;
 }
 UPB_INLINE struct google_protobuf_UInt32Value* envoy_config_listener_v3_Listener_mutable_tcp_backlog_size(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
   struct google_protobuf_UInt32Value* sub = (struct google_protobuf_UInt32Value*)envoy_config_listener_v3_Listener_tcp_backlog_size(msg);
@@ -401,6 +420,32 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_config_listener_v3_Listener_set_default_filter_chain(envoy_config_listener_v3_Listener *msg, struct envoy_config_listener_v3_FilterChain* value) {
+  _upb_sethas(msg, 15);
+  *UPB_PTR_AT(msg, UPB_SIZE(80, 144), struct envoy_config_listener_v3_FilterChain*) = value;
+}
+UPB_INLINE struct envoy_config_listener_v3_FilterChain* envoy_config_listener_v3_Listener_mutable_default_filter_chain(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
+  struct envoy_config_listener_v3_FilterChain* sub = (struct envoy_config_listener_v3_FilterChain*)envoy_config_listener_v3_Listener_default_filter_chain(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_listener_v3_FilterChain*)_upb_msg_new(&envoy_config_listener_v3_FilterChain_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_listener_v3_Listener_set_default_filter_chain(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_listener_v3_Listener_set_bind_to_port(envoy_config_listener_v3_Listener *msg, struct google_protobuf_BoolValue* value) {
+  _upb_sethas(msg, 16);
+  *UPB_PTR_AT(msg, UPB_SIZE(84, 152), struct google_protobuf_BoolValue*) = value;
+}
+UPB_INLINE struct google_protobuf_BoolValue* envoy_config_listener_v3_Listener_mutable_bind_to_port(envoy_config_listener_v3_Listener *msg, upb_arena *arena) {
+  struct google_protobuf_BoolValue* sub = (struct google_protobuf_BoolValue*)envoy_config_listener_v3_Listener_bind_to_port(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_BoolValue*)_upb_msg_new(&google_protobuf_BoolValue_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_listener_v3_Listener_set_bind_to_port(msg, sub);
+  }
+  return sub;
+}
 
 /* envoy.config.listener.v3.Listener.DeprecatedV1 */
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c
index a3cc15e..303b6ab 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.c
@@ -11,10 +11,10 @@
 #include "envoy/config/listener/v3/listener_components.upb.h"
 #include "envoy/config/core/v3/address.upb.h"
 #include "envoy/config/core/v3/base.upb.h"
+#include "envoy/config/core/v3/extension.upb.h"
 #include "envoy/type/v3/range.upb.h"
 #include "google/protobuf/any.upb.h"
 #include "google/protobuf/duration.upb.h"
-#include "google/protobuf/struct.upb.h"
 #include "google/protobuf/wrappers.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
@@ -22,19 +22,21 @@
 
 #include "upb/port_def.inc"
 
-static const upb_msglayout *const envoy_config_listener_v3_Filter_submsgs[1] = {
+static const upb_msglayout *const envoy_config_listener_v3_Filter_submsgs[2] = {
+  &envoy_config_core_v3_ExtensionConfigSource_msginit,
   &google_protobuf_Any_msginit,
 };
 
-static const upb_msglayout_field envoy_config_listener_v3_Filter__fields[2] = {
+static const upb_msglayout_field envoy_config_listener_v3_Filter__fields[3] = {
   {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
-  {4, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+  {4, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 1, 11, 1},
+  {5, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
 };
 
 const upb_msglayout envoy_config_listener_v3_Filter_msginit = {
   &envoy_config_listener_v3_Filter_submsgs[0],
   &envoy_config_listener_v3_Filter__fields[0],
-  UPB_SIZE(16, 32), 2, false, 255,
+  UPB_SIZE(16, 32), 3, false, 255,
 };
 
 static const upb_msglayout *const envoy_config_listener_v3_FilterChainMatch_submsgs[2] = {
@@ -61,29 +63,31 @@
   UPB_SIZE(56, 96), 10, false, 255,
 };
 
-static const upb_msglayout *const envoy_config_listener_v3_FilterChain_submsgs[6] = {
+static const upb_msglayout *const envoy_config_listener_v3_FilterChain_submsgs[7] = {
   &envoy_config_core_v3_Metadata_msginit,
   &envoy_config_core_v3_TransportSocket_msginit,
   &envoy_config_listener_v3_Filter_msginit,
   &envoy_config_listener_v3_FilterChain_OnDemandConfiguration_msginit,
   &envoy_config_listener_v3_FilterChainMatch_msginit,
   &google_protobuf_BoolValue_msginit,
+  &google_protobuf_Duration_msginit,
 };
 
-static const upb_msglayout_field envoy_config_listener_v3_FilterChain__fields[7] = {
+static const upb_msglayout_field envoy_config_listener_v3_FilterChain__fields[8] = {
   {1, UPB_SIZE(12, 24), 1, 4, 11, 1},
-  {3, UPB_SIZE(32, 64), 0, 2, 11, 3},
+  {3, UPB_SIZE(36, 72), 0, 2, 11, 3},
   {4, UPB_SIZE(16, 32), 2, 5, 11, 1},
   {5, UPB_SIZE(20, 40), 3, 0, 11, 1},
   {6, UPB_SIZE(24, 48), 4, 1, 11, 1},
   {7, UPB_SIZE(4, 8), 0, 0, 9, 1},
   {8, UPB_SIZE(28, 56), 5, 3, 11, 1},
+  {9, UPB_SIZE(32, 64), 6, 6, 11, 1},
 };
 
 const upb_msglayout envoy_config_listener_v3_FilterChain_msginit = {
   &envoy_config_listener_v3_FilterChain_submsgs[0],
   &envoy_config_listener_v3_FilterChain__fields[0],
-  UPB_SIZE(40, 80), 7, false, 255,
+  UPB_SIZE(40, 80), 8, false, 255,
 };
 
 static const upb_msglayout *const envoy_config_listener_v3_FilterChain_OnDemandConfiguration_submsgs[1] = {
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h
index 6c2a503..b8ef382 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h
@@ -42,6 +42,7 @@
 extern const upb_msglayout envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet_msginit;
 extern const upb_msglayout envoy_config_listener_v3_ListenerFilter_msginit;
 struct envoy_config_core_v3_CidrRange;
+struct envoy_config_core_v3_ExtensionConfigSource;
 struct envoy_config_core_v3_Metadata;
 struct envoy_config_core_v3_TransportSocket;
 struct envoy_type_v3_Int32Range;
@@ -50,6 +51,7 @@
 struct google_protobuf_Duration;
 struct google_protobuf_UInt32Value;
 extern const upb_msglayout envoy_config_core_v3_CidrRange_msginit;
+extern const upb_msglayout envoy_config_core_v3_ExtensionConfigSource_msginit;
 extern const upb_msglayout envoy_config_core_v3_Metadata_msginit;
 extern const upb_msglayout envoy_config_core_v3_TransportSocket_msginit;
 extern const upb_msglayout envoy_type_v3_Int32Range_msginit;
@@ -87,6 +89,7 @@
 
 typedef enum {
   envoy_config_listener_v3_Filter_config_type_typed_config = 4,
+  envoy_config_listener_v3_Filter_config_type_config_discovery = 5,
   envoy_config_listener_v3_Filter_config_type_NOT_SET = 0
 } envoy_config_listener_v3_Filter_config_type_oneofcases;
 UPB_INLINE envoy_config_listener_v3_Filter_config_type_oneofcases envoy_config_listener_v3_Filter_config_type_case(const envoy_config_listener_v3_Filter* msg) { return (envoy_config_listener_v3_Filter_config_type_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
@@ -94,6 +97,8 @@
 UPB_INLINE upb_strview envoy_config_listener_v3_Filter_name(const envoy_config_listener_v3_Filter *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
 UPB_INLINE bool envoy_config_listener_v3_Filter_has_typed_config(const envoy_config_listener_v3_Filter *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 4; }
 UPB_INLINE const struct google_protobuf_Any* envoy_config_listener_v3_Filter_typed_config(const envoy_config_listener_v3_Filter *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Any*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 4, NULL); }
+UPB_INLINE bool envoy_config_listener_v3_Filter_has_config_discovery(const envoy_config_listener_v3_Filter *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 5; }
+UPB_INLINE const struct envoy_config_core_v3_ExtensionConfigSource* envoy_config_listener_v3_Filter_config_discovery(const envoy_config_listener_v3_Filter *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_core_v3_ExtensionConfigSource*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 5, NULL); }
 
 UPB_INLINE void envoy_config_listener_v3_Filter_set_name(envoy_config_listener_v3_Filter *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
@@ -110,6 +115,18 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_config_listener_v3_Filter_set_config_discovery(envoy_config_listener_v3_Filter *msg, struct envoy_config_core_v3_ExtensionConfigSource* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_config_core_v3_ExtensionConfigSource*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 5);
+}
+UPB_INLINE struct envoy_config_core_v3_ExtensionConfigSource* envoy_config_listener_v3_Filter_mutable_config_discovery(envoy_config_listener_v3_Filter *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ExtensionConfigSource* sub = (struct envoy_config_core_v3_ExtensionConfigSource*)envoy_config_listener_v3_Filter_config_discovery(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ExtensionConfigSource*)_upb_msg_new(&envoy_config_core_v3_ExtensionConfigSource_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_listener_v3_Filter_set_config_discovery(msg, sub);
+  }
+  return sub;
+}
 
 /* envoy.config.listener.v3.FilterChainMatch */
 
@@ -260,8 +277,8 @@
 
 UPB_INLINE bool envoy_config_listener_v3_FilterChain_has_filter_chain_match(const envoy_config_listener_v3_FilterChain *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const envoy_config_listener_v3_FilterChainMatch* envoy_config_listener_v3_FilterChain_filter_chain_match(const envoy_config_listener_v3_FilterChain *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const envoy_config_listener_v3_FilterChainMatch*); }
-UPB_INLINE bool envoy_config_listener_v3_FilterChain_has_filters(const envoy_config_listener_v3_FilterChain *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); }
-UPB_INLINE const envoy_config_listener_v3_Filter* const* envoy_config_listener_v3_FilterChain_filters(const envoy_config_listener_v3_FilterChain *msg, size_t *len) { return (const envoy_config_listener_v3_Filter* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); }
+UPB_INLINE bool envoy_config_listener_v3_FilterChain_has_filters(const envoy_config_listener_v3_FilterChain *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); }
+UPB_INLINE const envoy_config_listener_v3_Filter* const* envoy_config_listener_v3_FilterChain_filters(const envoy_config_listener_v3_FilterChain *msg, size_t *len) { return (const envoy_config_listener_v3_Filter* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
 UPB_INLINE bool envoy_config_listener_v3_FilterChain_has_use_proxy_proto(const envoy_config_listener_v3_FilterChain *msg) { return _upb_hasbit(msg, 2); }
 UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_listener_v3_FilterChain_use_proxy_proto(const envoy_config_listener_v3_FilterChain *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct google_protobuf_BoolValue*); }
 UPB_INLINE bool envoy_config_listener_v3_FilterChain_has_metadata(const envoy_config_listener_v3_FilterChain *msg) { return _upb_hasbit(msg, 3); }
@@ -271,6 +288,8 @@
 UPB_INLINE upb_strview envoy_config_listener_v3_FilterChain_name(const envoy_config_listener_v3_FilterChain *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
 UPB_INLINE bool envoy_config_listener_v3_FilterChain_has_on_demand_configuration(const envoy_config_listener_v3_FilterChain *msg) { return _upb_hasbit(msg, 5); }
 UPB_INLINE const envoy_config_listener_v3_FilterChain_OnDemandConfiguration* envoy_config_listener_v3_FilterChain_on_demand_configuration(const envoy_config_listener_v3_FilterChain *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const envoy_config_listener_v3_FilterChain_OnDemandConfiguration*); }
+UPB_INLINE bool envoy_config_listener_v3_FilterChain_has_transport_socket_connect_timeout(const envoy_config_listener_v3_FilterChain *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_listener_v3_FilterChain_transport_socket_connect_timeout(const envoy_config_listener_v3_FilterChain *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const struct google_protobuf_Duration*); }
 
 UPB_INLINE void envoy_config_listener_v3_FilterChain_set_filter_chain_match(envoy_config_listener_v3_FilterChain *msg, envoy_config_listener_v3_FilterChainMatch* value) {
   _upb_sethas(msg, 1);
@@ -286,15 +305,15 @@
   return sub;
 }
 UPB_INLINE envoy_config_listener_v3_Filter** envoy_config_listener_v3_FilterChain_mutable_filters(envoy_config_listener_v3_FilterChain *msg, size_t *len) {
-  return (envoy_config_listener_v3_Filter**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len);
+  return (envoy_config_listener_v3_Filter**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
 }
 UPB_INLINE envoy_config_listener_v3_Filter** envoy_config_listener_v3_FilterChain_resize_filters(envoy_config_listener_v3_FilterChain *msg, size_t len, upb_arena *arena) {
-  return (envoy_config_listener_v3_Filter**)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena);
+  return (envoy_config_listener_v3_Filter**)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_listener_v3_Filter* envoy_config_listener_v3_FilterChain_add_filters(envoy_config_listener_v3_FilterChain *msg, upb_arena *arena) {
   struct envoy_config_listener_v3_Filter* sub = (struct envoy_config_listener_v3_Filter*)_upb_msg_new(&envoy_config_listener_v3_Filter_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
@@ -353,6 +372,19 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_config_listener_v3_FilterChain_set_transport_socket_connect_timeout(envoy_config_listener_v3_FilterChain *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 6);
+  *UPB_PTR_AT(msg, UPB_SIZE(32, 64), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_listener_v3_FilterChain_mutable_transport_socket_connect_timeout(envoy_config_listener_v3_FilterChain *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_listener_v3_FilterChain_transport_socket_connect_timeout(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_listener_v3_FilterChain_set_transport_socket_connect_timeout(msg, sub);
+  }
+  return sub;
+}
 
 /* envoy.config.listener.v3.FilterChain.OnDemandConfiguration */
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c
index e13d3e4..34696f6 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c
@@ -10,7 +10,6 @@
 #include "upb/msg.h"
 #include "envoy/config/listener/v3/udp_listener_config.upb.h"
 #include "google/protobuf/any.upb.h"
-#include "google/protobuf/struct.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c
new file mode 100644
index 0000000..26d00f1
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c
@@ -0,0 +1,144 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/metrics/v3/stats.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/config/metrics/v3/stats.upb.h"
+#include "envoy/config/core/v3/address.upb.h"
+#include "envoy/type/matcher/v3/string.upb.h"
+#include "google/protobuf/any.upb.h"
+#include "google/protobuf/wrappers.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_config_metrics_v3_StatsSink_submsgs[1] = {
+  &google_protobuf_Any_msginit,
+};
+
+static const upb_msglayout_field envoy_config_metrics_v3_StatsSink__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {3, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_metrics_v3_StatsSink_msginit = {
+  &envoy_config_metrics_v3_StatsSink_submsgs[0],
+  &envoy_config_metrics_v3_StatsSink__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_metrics_v3_StatsConfig_submsgs[4] = {
+  &envoy_config_metrics_v3_HistogramBucketSettings_msginit,
+  &envoy_config_metrics_v3_StatsMatcher_msginit,
+  &envoy_config_metrics_v3_TagSpecifier_msginit,
+  &google_protobuf_BoolValue_msginit,
+};
+
+static const upb_msglayout_field envoy_config_metrics_v3_StatsConfig__fields[4] = {
+  {1, UPB_SIZE(12, 24), 0, 2, 11, 3},
+  {2, UPB_SIZE(4, 8), 1, 3, 11, 1},
+  {3, UPB_SIZE(8, 16), 2, 1, 11, 1},
+  {4, UPB_SIZE(16, 32), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_config_metrics_v3_StatsConfig_msginit = {
+  &envoy_config_metrics_v3_StatsConfig_submsgs[0],
+  &envoy_config_metrics_v3_StatsConfig__fields[0],
+  UPB_SIZE(24, 40), 4, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_metrics_v3_StatsMatcher_submsgs[1] = {
+  &envoy_type_matcher_v3_ListStringMatcher_msginit,
+};
+
+static const upb_msglayout_field envoy_config_metrics_v3_StatsMatcher__fields[3] = {
+  {1, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 0, 8, 1},
+  {2, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 0, 11, 1},
+  {3, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_metrics_v3_StatsMatcher_msginit = {
+  &envoy_config_metrics_v3_StatsMatcher_submsgs[0],
+  &envoy_config_metrics_v3_StatsMatcher__fields[0],
+  UPB_SIZE(8, 16), 3, false, 255,
+};
+
+static const upb_msglayout_field envoy_config_metrics_v3_TagSpecifier__fields[3] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), UPB_SIZE(-17, -33), 0, 9, 1},
+  {3, UPB_SIZE(8, 16), UPB_SIZE(-17, -33), 0, 9, 1},
+};
+
+const upb_msglayout envoy_config_metrics_v3_TagSpecifier_msginit = {
+  NULL,
+  &envoy_config_metrics_v3_TagSpecifier__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_metrics_v3_HistogramBucketSettings_submsgs[1] = {
+  &envoy_type_matcher_v3_StringMatcher_msginit,
+};
+
+static const upb_msglayout_field envoy_config_metrics_v3_HistogramBucketSettings__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 0, 0, 1, _UPB_LABEL_PACKED},
+};
+
+const upb_msglayout envoy_config_metrics_v3_HistogramBucketSettings_msginit = {
+  &envoy_config_metrics_v3_HistogramBucketSettings_submsgs[0],
+  &envoy_config_metrics_v3_HistogramBucketSettings__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_metrics_v3_StatsdSink_submsgs[1] = {
+  &envoy_config_core_v3_Address_msginit,
+};
+
+static const upb_msglayout_field envoy_config_metrics_v3_StatsdSink__fields[3] = {
+  {1, UPB_SIZE(8, 16), UPB_SIZE(-17, -33), 0, 11, 1},
+  {2, UPB_SIZE(8, 16), UPB_SIZE(-17, -33), 0, 9, 1},
+  {3, UPB_SIZE(0, 0), 0, 0, 9, 1},
+};
+
+const upb_msglayout envoy_config_metrics_v3_StatsdSink_msginit = {
+  &envoy_config_metrics_v3_StatsdSink_submsgs[0],
+  &envoy_config_metrics_v3_StatsdSink__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_metrics_v3_DogStatsdSink_submsgs[2] = {
+  &envoy_config_core_v3_Address_msginit,
+  &google_protobuf_UInt64Value_msginit,
+};
+
+static const upb_msglayout_field envoy_config_metrics_v3_DogStatsdSink__fields[3] = {
+  {1, UPB_SIZE(16, 32), UPB_SIZE(-21, -41), 0, 11, 1},
+  {3, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {4, UPB_SIZE(12, 24), 1, 1, 11, 1},
+};
+
+const upb_msglayout envoy_config_metrics_v3_DogStatsdSink_msginit = {
+  &envoy_config_metrics_v3_DogStatsdSink_submsgs[0],
+  &envoy_config_metrics_v3_DogStatsdSink__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout_field envoy_config_metrics_v3_HystrixSink__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 3, 1},
+};
+
+const upb_msglayout envoy_config_metrics_v3_HystrixSink_msginit = {
+  NULL,
+  &envoy_config_metrics_v3_HystrixSink__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h
new file mode 100644
index 0000000..dab0415
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h
@@ -0,0 +1,488 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/metrics/v3/stats.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_CONFIG_METRICS_V3_STATS_PROTO_UPB_H_
+#define ENVOY_CONFIG_METRICS_V3_STATS_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_config_metrics_v3_StatsSink;
+struct envoy_config_metrics_v3_StatsConfig;
+struct envoy_config_metrics_v3_StatsMatcher;
+struct envoy_config_metrics_v3_TagSpecifier;
+struct envoy_config_metrics_v3_HistogramBucketSettings;
+struct envoy_config_metrics_v3_StatsdSink;
+struct envoy_config_metrics_v3_DogStatsdSink;
+struct envoy_config_metrics_v3_HystrixSink;
+typedef struct envoy_config_metrics_v3_StatsSink envoy_config_metrics_v3_StatsSink;
+typedef struct envoy_config_metrics_v3_StatsConfig envoy_config_metrics_v3_StatsConfig;
+typedef struct envoy_config_metrics_v3_StatsMatcher envoy_config_metrics_v3_StatsMatcher;
+typedef struct envoy_config_metrics_v3_TagSpecifier envoy_config_metrics_v3_TagSpecifier;
+typedef struct envoy_config_metrics_v3_HistogramBucketSettings envoy_config_metrics_v3_HistogramBucketSettings;
+typedef struct envoy_config_metrics_v3_StatsdSink envoy_config_metrics_v3_StatsdSink;
+typedef struct envoy_config_metrics_v3_DogStatsdSink envoy_config_metrics_v3_DogStatsdSink;
+typedef struct envoy_config_metrics_v3_HystrixSink envoy_config_metrics_v3_HystrixSink;
+extern const upb_msglayout envoy_config_metrics_v3_StatsSink_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsConfig_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsMatcher_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_TagSpecifier_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_HistogramBucketSettings_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsdSink_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_DogStatsdSink_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_HystrixSink_msginit;
+struct envoy_config_core_v3_Address;
+struct envoy_type_matcher_v3_ListStringMatcher;
+struct envoy_type_matcher_v3_StringMatcher;
+struct google_protobuf_Any;
+struct google_protobuf_BoolValue;
+struct google_protobuf_UInt64Value;
+extern const upb_msglayout envoy_config_core_v3_Address_msginit;
+extern const upb_msglayout envoy_type_matcher_v3_ListStringMatcher_msginit;
+extern const upb_msglayout envoy_type_matcher_v3_StringMatcher_msginit;
+extern const upb_msglayout google_protobuf_Any_msginit;
+extern const upb_msglayout google_protobuf_BoolValue_msginit;
+extern const upb_msglayout google_protobuf_UInt64Value_msginit;
+
+
+/* envoy.config.metrics.v3.StatsSink */
+
+UPB_INLINE envoy_config_metrics_v3_StatsSink *envoy_config_metrics_v3_StatsSink_new(upb_arena *arena) {
+  return (envoy_config_metrics_v3_StatsSink *)_upb_msg_new(&envoy_config_metrics_v3_StatsSink_msginit, arena);
+}
+UPB_INLINE envoy_config_metrics_v3_StatsSink *envoy_config_metrics_v3_StatsSink_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_metrics_v3_StatsSink *ret = envoy_config_metrics_v3_StatsSink_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_metrics_v3_StatsSink_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_metrics_v3_StatsSink *envoy_config_metrics_v3_StatsSink_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_metrics_v3_StatsSink *ret = envoy_config_metrics_v3_StatsSink_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_metrics_v3_StatsSink_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_metrics_v3_StatsSink_serialize(const envoy_config_metrics_v3_StatsSink *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_metrics_v3_StatsSink_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_metrics_v3_StatsSink_config_type_typed_config = 3,
+  envoy_config_metrics_v3_StatsSink_config_type_NOT_SET = 0
+} envoy_config_metrics_v3_StatsSink_config_type_oneofcases;
+UPB_INLINE envoy_config_metrics_v3_StatsSink_config_type_oneofcases envoy_config_metrics_v3_StatsSink_config_type_case(const envoy_config_metrics_v3_StatsSink* msg) { return (envoy_config_metrics_v3_StatsSink_config_type_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
+
+UPB_INLINE upb_strview envoy_config_metrics_v3_StatsSink_name(const envoy_config_metrics_v3_StatsSink *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE bool envoy_config_metrics_v3_StatsSink_has_typed_config(const envoy_config_metrics_v3_StatsSink *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 3; }
+UPB_INLINE const struct google_protobuf_Any* envoy_config_metrics_v3_StatsSink_typed_config(const envoy_config_metrics_v3_StatsSink *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Any*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 3, NULL); }
+
+UPB_INLINE void envoy_config_metrics_v3_StatsSink_set_name(envoy_config_metrics_v3_StatsSink *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_metrics_v3_StatsSink_set_typed_config(envoy_config_metrics_v3_StatsSink *msg, struct google_protobuf_Any* value) {
+  UPB_WRITE_ONEOF(msg, struct google_protobuf_Any*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 3);
+}
+UPB_INLINE struct google_protobuf_Any* envoy_config_metrics_v3_StatsSink_mutable_typed_config(envoy_config_metrics_v3_StatsSink *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_config_metrics_v3_StatsSink_typed_config(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_StatsSink_set_typed_config(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.metrics.v3.StatsConfig */
+
+UPB_INLINE envoy_config_metrics_v3_StatsConfig *envoy_config_metrics_v3_StatsConfig_new(upb_arena *arena) {
+  return (envoy_config_metrics_v3_StatsConfig *)_upb_msg_new(&envoy_config_metrics_v3_StatsConfig_msginit, arena);
+}
+UPB_INLINE envoy_config_metrics_v3_StatsConfig *envoy_config_metrics_v3_StatsConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_metrics_v3_StatsConfig *ret = envoy_config_metrics_v3_StatsConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_metrics_v3_StatsConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_metrics_v3_StatsConfig *envoy_config_metrics_v3_StatsConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_metrics_v3_StatsConfig *ret = envoy_config_metrics_v3_StatsConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_metrics_v3_StatsConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_metrics_v3_StatsConfig_serialize(const envoy_config_metrics_v3_StatsConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_metrics_v3_StatsConfig_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_metrics_v3_StatsConfig_has_stats_tags(const envoy_config_metrics_v3_StatsConfig *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); }
+UPB_INLINE const envoy_config_metrics_v3_TagSpecifier* const* envoy_config_metrics_v3_StatsConfig_stats_tags(const envoy_config_metrics_v3_StatsConfig *msg, size_t *len) { return (const envoy_config_metrics_v3_TagSpecifier* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); }
+UPB_INLINE bool envoy_config_metrics_v3_StatsConfig_has_use_all_default_tags(const envoy_config_metrics_v3_StatsConfig *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_metrics_v3_StatsConfig_use_all_default_tags(const envoy_config_metrics_v3_StatsConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_BoolValue*); }
+UPB_INLINE bool envoy_config_metrics_v3_StatsConfig_has_stats_matcher(const envoy_config_metrics_v3_StatsConfig *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const envoy_config_metrics_v3_StatsMatcher* envoy_config_metrics_v3_StatsConfig_stats_matcher(const envoy_config_metrics_v3_StatsConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), const envoy_config_metrics_v3_StatsMatcher*); }
+UPB_INLINE bool envoy_config_metrics_v3_StatsConfig_has_histogram_bucket_settings(const envoy_config_metrics_v3_StatsConfig *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
+UPB_INLINE const envoy_config_metrics_v3_HistogramBucketSettings* const* envoy_config_metrics_v3_StatsConfig_histogram_bucket_settings(const envoy_config_metrics_v3_StatsConfig *msg, size_t *len) { return (const envoy_config_metrics_v3_HistogramBucketSettings* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
+
+UPB_INLINE envoy_config_metrics_v3_TagSpecifier** envoy_config_metrics_v3_StatsConfig_mutable_stats_tags(envoy_config_metrics_v3_StatsConfig *msg, size_t *len) {
+  return (envoy_config_metrics_v3_TagSpecifier**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len);
+}
+UPB_INLINE envoy_config_metrics_v3_TagSpecifier** envoy_config_metrics_v3_StatsConfig_resize_stats_tags(envoy_config_metrics_v3_StatsConfig *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_metrics_v3_TagSpecifier**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_metrics_v3_TagSpecifier* envoy_config_metrics_v3_StatsConfig_add_stats_tags(envoy_config_metrics_v3_StatsConfig *msg, upb_arena *arena) {
+  struct envoy_config_metrics_v3_TagSpecifier* sub = (struct envoy_config_metrics_v3_TagSpecifier*)_upb_msg_new(&envoy_config_metrics_v3_TagSpecifier_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_config_metrics_v3_StatsConfig_set_use_all_default_tags(envoy_config_metrics_v3_StatsConfig *msg, struct google_protobuf_BoolValue* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_BoolValue*) = value;
+}
+UPB_INLINE struct google_protobuf_BoolValue* envoy_config_metrics_v3_StatsConfig_mutable_use_all_default_tags(envoy_config_metrics_v3_StatsConfig *msg, upb_arena *arena) {
+  struct google_protobuf_BoolValue* sub = (struct google_protobuf_BoolValue*)envoy_config_metrics_v3_StatsConfig_use_all_default_tags(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_BoolValue*)_upb_msg_new(&google_protobuf_BoolValue_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_StatsConfig_set_use_all_default_tags(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_metrics_v3_StatsConfig_set_stats_matcher(envoy_config_metrics_v3_StatsConfig *msg, envoy_config_metrics_v3_StatsMatcher* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), envoy_config_metrics_v3_StatsMatcher*) = value;
+}
+UPB_INLINE struct envoy_config_metrics_v3_StatsMatcher* envoy_config_metrics_v3_StatsConfig_mutable_stats_matcher(envoy_config_metrics_v3_StatsConfig *msg, upb_arena *arena) {
+  struct envoy_config_metrics_v3_StatsMatcher* sub = (struct envoy_config_metrics_v3_StatsMatcher*)envoy_config_metrics_v3_StatsConfig_stats_matcher(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_metrics_v3_StatsMatcher*)_upb_msg_new(&envoy_config_metrics_v3_StatsMatcher_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_StatsConfig_set_stats_matcher(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE envoy_config_metrics_v3_HistogramBucketSettings** envoy_config_metrics_v3_StatsConfig_mutable_histogram_bucket_settings(envoy_config_metrics_v3_StatsConfig *msg, size_t *len) {
+  return (envoy_config_metrics_v3_HistogramBucketSettings**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
+}
+UPB_INLINE envoy_config_metrics_v3_HistogramBucketSettings** envoy_config_metrics_v3_StatsConfig_resize_histogram_bucket_settings(envoy_config_metrics_v3_StatsConfig *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_metrics_v3_HistogramBucketSettings**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_metrics_v3_HistogramBucketSettings* envoy_config_metrics_v3_StatsConfig_add_histogram_bucket_settings(envoy_config_metrics_v3_StatsConfig *msg, upb_arena *arena) {
+  struct envoy_config_metrics_v3_HistogramBucketSettings* sub = (struct envoy_config_metrics_v3_HistogramBucketSettings*)_upb_msg_new(&envoy_config_metrics_v3_HistogramBucketSettings_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.config.metrics.v3.StatsMatcher */
+
+UPB_INLINE envoy_config_metrics_v3_StatsMatcher *envoy_config_metrics_v3_StatsMatcher_new(upb_arena *arena) {
+  return (envoy_config_metrics_v3_StatsMatcher *)_upb_msg_new(&envoy_config_metrics_v3_StatsMatcher_msginit, arena);
+}
+UPB_INLINE envoy_config_metrics_v3_StatsMatcher *envoy_config_metrics_v3_StatsMatcher_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_metrics_v3_StatsMatcher *ret = envoy_config_metrics_v3_StatsMatcher_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_metrics_v3_StatsMatcher_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_metrics_v3_StatsMatcher *envoy_config_metrics_v3_StatsMatcher_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_metrics_v3_StatsMatcher *ret = envoy_config_metrics_v3_StatsMatcher_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_metrics_v3_StatsMatcher_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_metrics_v3_StatsMatcher_serialize(const envoy_config_metrics_v3_StatsMatcher *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_metrics_v3_StatsMatcher_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_metrics_v3_StatsMatcher_stats_matcher_reject_all = 1,
+  envoy_config_metrics_v3_StatsMatcher_stats_matcher_exclusion_list = 2,
+  envoy_config_metrics_v3_StatsMatcher_stats_matcher_inclusion_list = 3,
+  envoy_config_metrics_v3_StatsMatcher_stats_matcher_NOT_SET = 0
+} envoy_config_metrics_v3_StatsMatcher_stats_matcher_oneofcases;
+UPB_INLINE envoy_config_metrics_v3_StatsMatcher_stats_matcher_oneofcases envoy_config_metrics_v3_StatsMatcher_stats_matcher_case(const envoy_config_metrics_v3_StatsMatcher* msg) { return (envoy_config_metrics_v3_StatsMatcher_stats_matcher_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(4, 8), int32_t); }
+
+UPB_INLINE bool envoy_config_metrics_v3_StatsMatcher_has_reject_all(const envoy_config_metrics_v3_StatsMatcher *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 1; }
+UPB_INLINE bool envoy_config_metrics_v3_StatsMatcher_reject_all(const envoy_config_metrics_v3_StatsMatcher *msg) { return UPB_READ_ONEOF(msg, bool, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 1, false); }
+UPB_INLINE bool envoy_config_metrics_v3_StatsMatcher_has_exclusion_list(const envoy_config_metrics_v3_StatsMatcher *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 2; }
+UPB_INLINE const struct envoy_type_matcher_v3_ListStringMatcher* envoy_config_metrics_v3_StatsMatcher_exclusion_list(const envoy_config_metrics_v3_StatsMatcher *msg) { return UPB_READ_ONEOF(msg, const struct envoy_type_matcher_v3_ListStringMatcher*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 2, NULL); }
+UPB_INLINE bool envoy_config_metrics_v3_StatsMatcher_has_inclusion_list(const envoy_config_metrics_v3_StatsMatcher *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 3; }
+UPB_INLINE const struct envoy_type_matcher_v3_ListStringMatcher* envoy_config_metrics_v3_StatsMatcher_inclusion_list(const envoy_config_metrics_v3_StatsMatcher *msg) { return UPB_READ_ONEOF(msg, const struct envoy_type_matcher_v3_ListStringMatcher*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 3, NULL); }
+
+UPB_INLINE void envoy_config_metrics_v3_StatsMatcher_set_reject_all(envoy_config_metrics_v3_StatsMatcher *msg, bool value) {
+  UPB_WRITE_ONEOF(msg, bool, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 1);
+}
+UPB_INLINE void envoy_config_metrics_v3_StatsMatcher_set_exclusion_list(envoy_config_metrics_v3_StatsMatcher *msg, struct envoy_type_matcher_v3_ListStringMatcher* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_type_matcher_v3_ListStringMatcher*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 2);
+}
+UPB_INLINE struct envoy_type_matcher_v3_ListStringMatcher* envoy_config_metrics_v3_StatsMatcher_mutable_exclusion_list(envoy_config_metrics_v3_StatsMatcher *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_ListStringMatcher* sub = (struct envoy_type_matcher_v3_ListStringMatcher*)envoy_config_metrics_v3_StatsMatcher_exclusion_list(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_matcher_v3_ListStringMatcher*)_upb_msg_new(&envoy_type_matcher_v3_ListStringMatcher_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_StatsMatcher_set_exclusion_list(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_metrics_v3_StatsMatcher_set_inclusion_list(envoy_config_metrics_v3_StatsMatcher *msg, struct envoy_type_matcher_v3_ListStringMatcher* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_type_matcher_v3_ListStringMatcher*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 3);
+}
+UPB_INLINE struct envoy_type_matcher_v3_ListStringMatcher* envoy_config_metrics_v3_StatsMatcher_mutable_inclusion_list(envoy_config_metrics_v3_StatsMatcher *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_ListStringMatcher* sub = (struct envoy_type_matcher_v3_ListStringMatcher*)envoy_config_metrics_v3_StatsMatcher_inclusion_list(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_matcher_v3_ListStringMatcher*)_upb_msg_new(&envoy_type_matcher_v3_ListStringMatcher_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_StatsMatcher_set_inclusion_list(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.metrics.v3.TagSpecifier */
+
+UPB_INLINE envoy_config_metrics_v3_TagSpecifier *envoy_config_metrics_v3_TagSpecifier_new(upb_arena *arena) {
+  return (envoy_config_metrics_v3_TagSpecifier *)_upb_msg_new(&envoy_config_metrics_v3_TagSpecifier_msginit, arena);
+}
+UPB_INLINE envoy_config_metrics_v3_TagSpecifier *envoy_config_metrics_v3_TagSpecifier_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_metrics_v3_TagSpecifier *ret = envoy_config_metrics_v3_TagSpecifier_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_metrics_v3_TagSpecifier_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_metrics_v3_TagSpecifier *envoy_config_metrics_v3_TagSpecifier_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_metrics_v3_TagSpecifier *ret = envoy_config_metrics_v3_TagSpecifier_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_metrics_v3_TagSpecifier_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_metrics_v3_TagSpecifier_serialize(const envoy_config_metrics_v3_TagSpecifier *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_metrics_v3_TagSpecifier_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_metrics_v3_TagSpecifier_tag_value_regex = 2,
+  envoy_config_metrics_v3_TagSpecifier_tag_value_fixed_value = 3,
+  envoy_config_metrics_v3_TagSpecifier_tag_value_NOT_SET = 0
+} envoy_config_metrics_v3_TagSpecifier_tag_value_oneofcases;
+UPB_INLINE envoy_config_metrics_v3_TagSpecifier_tag_value_oneofcases envoy_config_metrics_v3_TagSpecifier_tag_value_case(const envoy_config_metrics_v3_TagSpecifier* msg) { return (envoy_config_metrics_v3_TagSpecifier_tag_value_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(16, 32), int32_t); }
+
+UPB_INLINE upb_strview envoy_config_metrics_v3_TagSpecifier_tag_name(const envoy_config_metrics_v3_TagSpecifier *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE bool envoy_config_metrics_v3_TagSpecifier_has_regex(const envoy_config_metrics_v3_TagSpecifier *msg) { return _upb_getoneofcase(msg, UPB_SIZE(16, 32)) == 2; }
+UPB_INLINE upb_strview envoy_config_metrics_v3_TagSpecifier_regex(const envoy_config_metrics_v3_TagSpecifier *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(8, 16), UPB_SIZE(16, 32), 2, upb_strview_make("", strlen(""))); }
+UPB_INLINE bool envoy_config_metrics_v3_TagSpecifier_has_fixed_value(const envoy_config_metrics_v3_TagSpecifier *msg) { return _upb_getoneofcase(msg, UPB_SIZE(16, 32)) == 3; }
+UPB_INLINE upb_strview envoy_config_metrics_v3_TagSpecifier_fixed_value(const envoy_config_metrics_v3_TagSpecifier *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(8, 16), UPB_SIZE(16, 32), 3, upb_strview_make("", strlen(""))); }
+
+UPB_INLINE void envoy_config_metrics_v3_TagSpecifier_set_tag_name(envoy_config_metrics_v3_TagSpecifier *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_metrics_v3_TagSpecifier_set_regex(envoy_config_metrics_v3_TagSpecifier *msg, upb_strview value) {
+  UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(8, 16), value, UPB_SIZE(16, 32), 2);
+}
+UPB_INLINE void envoy_config_metrics_v3_TagSpecifier_set_fixed_value(envoy_config_metrics_v3_TagSpecifier *msg, upb_strview value) {
+  UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(8, 16), value, UPB_SIZE(16, 32), 3);
+}
+
+/* envoy.config.metrics.v3.HistogramBucketSettings */
+
+UPB_INLINE envoy_config_metrics_v3_HistogramBucketSettings *envoy_config_metrics_v3_HistogramBucketSettings_new(upb_arena *arena) {
+  return (envoy_config_metrics_v3_HistogramBucketSettings *)_upb_msg_new(&envoy_config_metrics_v3_HistogramBucketSettings_msginit, arena);
+}
+UPB_INLINE envoy_config_metrics_v3_HistogramBucketSettings *envoy_config_metrics_v3_HistogramBucketSettings_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_metrics_v3_HistogramBucketSettings *ret = envoy_config_metrics_v3_HistogramBucketSettings_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_metrics_v3_HistogramBucketSettings_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_metrics_v3_HistogramBucketSettings *envoy_config_metrics_v3_HistogramBucketSettings_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_metrics_v3_HistogramBucketSettings *ret = envoy_config_metrics_v3_HistogramBucketSettings_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_metrics_v3_HistogramBucketSettings_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_metrics_v3_HistogramBucketSettings_serialize(const envoy_config_metrics_v3_HistogramBucketSettings *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_metrics_v3_HistogramBucketSettings_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_metrics_v3_HistogramBucketSettings_has_match(const envoy_config_metrics_v3_HistogramBucketSettings *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_type_matcher_v3_StringMatcher* envoy_config_metrics_v3_HistogramBucketSettings_match(const envoy_config_metrics_v3_HistogramBucketSettings *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_type_matcher_v3_StringMatcher*); }
+UPB_INLINE double const* envoy_config_metrics_v3_HistogramBucketSettings_buckets(const envoy_config_metrics_v3_HistogramBucketSettings *msg, size_t *len) { return (double const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+
+UPB_INLINE void envoy_config_metrics_v3_HistogramBucketSettings_set_match(envoy_config_metrics_v3_HistogramBucketSettings *msg, struct envoy_type_matcher_v3_StringMatcher* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_type_matcher_v3_StringMatcher*) = value;
+}
+UPB_INLINE struct envoy_type_matcher_v3_StringMatcher* envoy_config_metrics_v3_HistogramBucketSettings_mutable_match(envoy_config_metrics_v3_HistogramBucketSettings *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_StringMatcher* sub = (struct envoy_type_matcher_v3_StringMatcher*)envoy_config_metrics_v3_HistogramBucketSettings_match(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_matcher_v3_StringMatcher*)_upb_msg_new(&envoy_type_matcher_v3_StringMatcher_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_HistogramBucketSettings_set_match(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE double* envoy_config_metrics_v3_HistogramBucketSettings_mutable_buckets(envoy_config_metrics_v3_HistogramBucketSettings *msg, size_t *len) {
+  return (double*)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE double* envoy_config_metrics_v3_HistogramBucketSettings_resize_buckets(envoy_config_metrics_v3_HistogramBucketSettings *msg, size_t len, upb_arena *arena) {
+  return (double*)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, 3, arena);
+}
+UPB_INLINE bool envoy_config_metrics_v3_HistogramBucketSettings_add_buckets(envoy_config_metrics_v3_HistogramBucketSettings *msg, double val, upb_arena *arena) {
+  return _upb_array_append_accessor2(msg, UPB_SIZE(8, 16), 3, &val,
+      arena);
+}
+
+/* envoy.config.metrics.v3.StatsdSink */
+
+UPB_INLINE envoy_config_metrics_v3_StatsdSink *envoy_config_metrics_v3_StatsdSink_new(upb_arena *arena) {
+  return (envoy_config_metrics_v3_StatsdSink *)_upb_msg_new(&envoy_config_metrics_v3_StatsdSink_msginit, arena);
+}
+UPB_INLINE envoy_config_metrics_v3_StatsdSink *envoy_config_metrics_v3_StatsdSink_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_metrics_v3_StatsdSink *ret = envoy_config_metrics_v3_StatsdSink_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_metrics_v3_StatsdSink_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_metrics_v3_StatsdSink *envoy_config_metrics_v3_StatsdSink_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_metrics_v3_StatsdSink *ret = envoy_config_metrics_v3_StatsdSink_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_metrics_v3_StatsdSink_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_metrics_v3_StatsdSink_serialize(const envoy_config_metrics_v3_StatsdSink *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_metrics_v3_StatsdSink_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_metrics_v3_StatsdSink_statsd_specifier_address = 1,
+  envoy_config_metrics_v3_StatsdSink_statsd_specifier_tcp_cluster_name = 2,
+  envoy_config_metrics_v3_StatsdSink_statsd_specifier_NOT_SET = 0
+} envoy_config_metrics_v3_StatsdSink_statsd_specifier_oneofcases;
+UPB_INLINE envoy_config_metrics_v3_StatsdSink_statsd_specifier_oneofcases envoy_config_metrics_v3_StatsdSink_statsd_specifier_case(const envoy_config_metrics_v3_StatsdSink* msg) { return (envoy_config_metrics_v3_StatsdSink_statsd_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(16, 32), int32_t); }
+
+UPB_INLINE bool envoy_config_metrics_v3_StatsdSink_has_address(const envoy_config_metrics_v3_StatsdSink *msg) { return _upb_getoneofcase(msg, UPB_SIZE(16, 32)) == 1; }
+UPB_INLINE const struct envoy_config_core_v3_Address* envoy_config_metrics_v3_StatsdSink_address(const envoy_config_metrics_v3_StatsdSink *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_core_v3_Address*, UPB_SIZE(8, 16), UPB_SIZE(16, 32), 1, NULL); }
+UPB_INLINE bool envoy_config_metrics_v3_StatsdSink_has_tcp_cluster_name(const envoy_config_metrics_v3_StatsdSink *msg) { return _upb_getoneofcase(msg, UPB_SIZE(16, 32)) == 2; }
+UPB_INLINE upb_strview envoy_config_metrics_v3_StatsdSink_tcp_cluster_name(const envoy_config_metrics_v3_StatsdSink *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(8, 16), UPB_SIZE(16, 32), 2, upb_strview_make("", strlen(""))); }
+UPB_INLINE upb_strview envoy_config_metrics_v3_StatsdSink_prefix(const envoy_config_metrics_v3_StatsdSink *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+
+UPB_INLINE void envoy_config_metrics_v3_StatsdSink_set_address(envoy_config_metrics_v3_StatsdSink *msg, struct envoy_config_core_v3_Address* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_config_core_v3_Address*, UPB_SIZE(8, 16), value, UPB_SIZE(16, 32), 1);
+}
+UPB_INLINE struct envoy_config_core_v3_Address* envoy_config_metrics_v3_StatsdSink_mutable_address(envoy_config_metrics_v3_StatsdSink *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_Address* sub = (struct envoy_config_core_v3_Address*)envoy_config_metrics_v3_StatsdSink_address(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_Address*)_upb_msg_new(&envoy_config_core_v3_Address_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_StatsdSink_set_address(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_metrics_v3_StatsdSink_set_tcp_cluster_name(envoy_config_metrics_v3_StatsdSink *msg, upb_strview value) {
+  UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(8, 16), value, UPB_SIZE(16, 32), 2);
+}
+UPB_INLINE void envoy_config_metrics_v3_StatsdSink_set_prefix(envoy_config_metrics_v3_StatsdSink *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+
+/* envoy.config.metrics.v3.DogStatsdSink */
+
+UPB_INLINE envoy_config_metrics_v3_DogStatsdSink *envoy_config_metrics_v3_DogStatsdSink_new(upb_arena *arena) {
+  return (envoy_config_metrics_v3_DogStatsdSink *)_upb_msg_new(&envoy_config_metrics_v3_DogStatsdSink_msginit, arena);
+}
+UPB_INLINE envoy_config_metrics_v3_DogStatsdSink *envoy_config_metrics_v3_DogStatsdSink_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_metrics_v3_DogStatsdSink *ret = envoy_config_metrics_v3_DogStatsdSink_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_metrics_v3_DogStatsdSink_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_metrics_v3_DogStatsdSink *envoy_config_metrics_v3_DogStatsdSink_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_metrics_v3_DogStatsdSink *ret = envoy_config_metrics_v3_DogStatsdSink_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_metrics_v3_DogStatsdSink_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_metrics_v3_DogStatsdSink_serialize(const envoy_config_metrics_v3_DogStatsdSink *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_metrics_v3_DogStatsdSink_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_metrics_v3_DogStatsdSink_dog_statsd_specifier_address = 1,
+  envoy_config_metrics_v3_DogStatsdSink_dog_statsd_specifier_NOT_SET = 0
+} envoy_config_metrics_v3_DogStatsdSink_dog_statsd_specifier_oneofcases;
+UPB_INLINE envoy_config_metrics_v3_DogStatsdSink_dog_statsd_specifier_oneofcases envoy_config_metrics_v3_DogStatsdSink_dog_statsd_specifier_case(const envoy_config_metrics_v3_DogStatsdSink* msg) { return (envoy_config_metrics_v3_DogStatsdSink_dog_statsd_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(20, 40), int32_t); }
+
+UPB_INLINE bool envoy_config_metrics_v3_DogStatsdSink_has_address(const envoy_config_metrics_v3_DogStatsdSink *msg) { return _upb_getoneofcase(msg, UPB_SIZE(20, 40)) == 1; }
+UPB_INLINE const struct envoy_config_core_v3_Address* envoy_config_metrics_v3_DogStatsdSink_address(const envoy_config_metrics_v3_DogStatsdSink *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_core_v3_Address*, UPB_SIZE(16, 32), UPB_SIZE(20, 40), 1, NULL); }
+UPB_INLINE upb_strview envoy_config_metrics_v3_DogStatsdSink_prefix(const envoy_config_metrics_v3_DogStatsdSink *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_config_metrics_v3_DogStatsdSink_has_max_bytes_per_datagram(const envoy_config_metrics_v3_DogStatsdSink *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_UInt64Value* envoy_config_metrics_v3_DogStatsdSink_max_bytes_per_datagram(const envoy_config_metrics_v3_DogStatsdSink *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct google_protobuf_UInt64Value*); }
+
+UPB_INLINE void envoy_config_metrics_v3_DogStatsdSink_set_address(envoy_config_metrics_v3_DogStatsdSink *msg, struct envoy_config_core_v3_Address* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_config_core_v3_Address*, UPB_SIZE(16, 32), value, UPB_SIZE(20, 40), 1);
+}
+UPB_INLINE struct envoy_config_core_v3_Address* envoy_config_metrics_v3_DogStatsdSink_mutable_address(envoy_config_metrics_v3_DogStatsdSink *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_Address* sub = (struct envoy_config_core_v3_Address*)envoy_config_metrics_v3_DogStatsdSink_address(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_Address*)_upb_msg_new(&envoy_config_core_v3_Address_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_DogStatsdSink_set_address(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_metrics_v3_DogStatsdSink_set_prefix(envoy_config_metrics_v3_DogStatsdSink *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_metrics_v3_DogStatsdSink_set_max_bytes_per_datagram(envoy_config_metrics_v3_DogStatsdSink *msg, struct google_protobuf_UInt64Value* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct google_protobuf_UInt64Value*) = value;
+}
+UPB_INLINE struct google_protobuf_UInt64Value* envoy_config_metrics_v3_DogStatsdSink_mutable_max_bytes_per_datagram(envoy_config_metrics_v3_DogStatsdSink *msg, upb_arena *arena) {
+  struct google_protobuf_UInt64Value* sub = (struct google_protobuf_UInt64Value*)envoy_config_metrics_v3_DogStatsdSink_max_bytes_per_datagram(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_UInt64Value*)_upb_msg_new(&google_protobuf_UInt64Value_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_metrics_v3_DogStatsdSink_set_max_bytes_per_datagram(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.metrics.v3.HystrixSink */
+
+UPB_INLINE envoy_config_metrics_v3_HystrixSink *envoy_config_metrics_v3_HystrixSink_new(upb_arena *arena) {
+  return (envoy_config_metrics_v3_HystrixSink *)_upb_msg_new(&envoy_config_metrics_v3_HystrixSink_msginit, arena);
+}
+UPB_INLINE envoy_config_metrics_v3_HystrixSink *envoy_config_metrics_v3_HystrixSink_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_metrics_v3_HystrixSink *ret = envoy_config_metrics_v3_HystrixSink_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_metrics_v3_HystrixSink_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_metrics_v3_HystrixSink *envoy_config_metrics_v3_HystrixSink_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_metrics_v3_HystrixSink *ret = envoy_config_metrics_v3_HystrixSink_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_metrics_v3_HystrixSink_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_metrics_v3_HystrixSink_serialize(const envoy_config_metrics_v3_HystrixSink *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_metrics_v3_HystrixSink_msginit, arena, len);
+}
+
+UPB_INLINE int64_t envoy_config_metrics_v3_HystrixSink_num_buckets(const envoy_config_metrics_v3_HystrixSink *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int64_t); }
+
+UPB_INLINE void envoy_config_metrics_v3_HystrixSink_set_num_buckets(envoy_config_metrics_v3_HystrixSink *msg, int64_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int64_t) = value;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_CONFIG_METRICS_V3_STATS_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c
new file mode 100644
index 0000000..a306e71
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c
@@ -0,0 +1,141 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/overload/v3/overload.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/config/overload/v3/overload.upb.h"
+#include "envoy/type/v3/percent.upb.h"
+#include "google/protobuf/any.upb.h"
+#include "google/protobuf/duration.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_config_overload_v3_ResourceMonitor_submsgs[1] = {
+  &google_protobuf_Any_msginit,
+};
+
+static const upb_msglayout_field envoy_config_overload_v3_ResourceMonitor__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {3, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_overload_v3_ResourceMonitor_msginit = {
+  &envoy_config_overload_v3_ResourceMonitor_submsgs[0],
+  &envoy_config_overload_v3_ResourceMonitor__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+static const upb_msglayout_field envoy_config_overload_v3_ThresholdTrigger__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 1, 1},
+};
+
+const upb_msglayout envoy_config_overload_v3_ThresholdTrigger_msginit = {
+  NULL,
+  &envoy_config_overload_v3_ThresholdTrigger__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout_field envoy_config_overload_v3_ScaledTrigger__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 1, 1},
+  {2, UPB_SIZE(8, 8), 0, 0, 1, 1},
+};
+
+const upb_msglayout envoy_config_overload_v3_ScaledTrigger_msginit = {
+  NULL,
+  &envoy_config_overload_v3_ScaledTrigger__fields[0],
+  UPB_SIZE(16, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_overload_v3_Trigger_submsgs[2] = {
+  &envoy_config_overload_v3_ScaledTrigger_msginit,
+  &envoy_config_overload_v3_ThresholdTrigger_msginit,
+};
+
+static const upb_msglayout_field envoy_config_overload_v3_Trigger__fields[3] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 1, 11, 1},
+  {3, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_overload_v3_Trigger_msginit = {
+  &envoy_config_overload_v3_Trigger_submsgs[0],
+  &envoy_config_overload_v3_Trigger__fields[0],
+  UPB_SIZE(16, 32), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_submsgs[1] = {
+  &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit,
+};
+
+static const upb_msglayout_field envoy_config_overload_v3_ScaleTimersOverloadActionConfig__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_config_overload_v3_ScaleTimersOverloadActionConfig_msginit = {
+  &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_submsgs[0],
+  &envoy_config_overload_v3_ScaleTimersOverloadActionConfig__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_submsgs[2] = {
+  &envoy_type_v3_Percent_msginit,
+  &google_protobuf_Duration_msginit,
+};
+
+static const upb_msglayout_field envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer__fields[3] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 14, 1},
+  {2, UPB_SIZE(4, 8), UPB_SIZE(-9, -17), 1, 11, 1},
+  {3, UPB_SIZE(4, 8), UPB_SIZE(-9, -17), 0, 11, 1},
+};
+
+const upb_msglayout envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit = {
+  &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_submsgs[0],
+  &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer__fields[0],
+  UPB_SIZE(16, 24), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_overload_v3_OverloadAction_submsgs[2] = {
+  &envoy_config_overload_v3_Trigger_msginit,
+  &google_protobuf_Any_msginit,
+};
+
+static const upb_msglayout_field envoy_config_overload_v3_OverloadAction__fields[3] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(16, 32), 0, 0, 11, 3},
+  {3, UPB_SIZE(12, 24), 1, 1, 11, 1},
+};
+
+const upb_msglayout envoy_config_overload_v3_OverloadAction_msginit = {
+  &envoy_config_overload_v3_OverloadAction_submsgs[0],
+  &envoy_config_overload_v3_OverloadAction__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout *const envoy_config_overload_v3_OverloadManager_submsgs[3] = {
+  &envoy_config_overload_v3_OverloadAction_msginit,
+  &envoy_config_overload_v3_ResourceMonitor_msginit,
+  &google_protobuf_Duration_msginit,
+};
+
+static const upb_msglayout_field envoy_config_overload_v3_OverloadManager__fields[3] = {
+  {1, UPB_SIZE(4, 8), 1, 2, 11, 1},
+  {2, UPB_SIZE(8, 16), 0, 1, 11, 3},
+  {3, UPB_SIZE(12, 24), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_config_overload_v3_OverloadManager_msginit = {
+  &envoy_config_overload_v3_OverloadManager_submsgs[0],
+  &envoy_config_overload_v3_OverloadManager__fields[0],
+  UPB_SIZE(16, 32), 3, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h
new file mode 100644
index 0000000..d800aa9
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h
@@ -0,0 +1,452 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/overload/v3/overload.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_CONFIG_OVERLOAD_V3_OVERLOAD_PROTO_UPB_H_
+#define ENVOY_CONFIG_OVERLOAD_V3_OVERLOAD_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_config_overload_v3_ResourceMonitor;
+struct envoy_config_overload_v3_ThresholdTrigger;
+struct envoy_config_overload_v3_ScaledTrigger;
+struct envoy_config_overload_v3_Trigger;
+struct envoy_config_overload_v3_ScaleTimersOverloadActionConfig;
+struct envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer;
+struct envoy_config_overload_v3_OverloadAction;
+struct envoy_config_overload_v3_OverloadManager;
+typedef struct envoy_config_overload_v3_ResourceMonitor envoy_config_overload_v3_ResourceMonitor;
+typedef struct envoy_config_overload_v3_ThresholdTrigger envoy_config_overload_v3_ThresholdTrigger;
+typedef struct envoy_config_overload_v3_ScaledTrigger envoy_config_overload_v3_ScaledTrigger;
+typedef struct envoy_config_overload_v3_Trigger envoy_config_overload_v3_Trigger;
+typedef struct envoy_config_overload_v3_ScaleTimersOverloadActionConfig envoy_config_overload_v3_ScaleTimersOverloadActionConfig;
+typedef struct envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer;
+typedef struct envoy_config_overload_v3_OverloadAction envoy_config_overload_v3_OverloadAction;
+typedef struct envoy_config_overload_v3_OverloadManager envoy_config_overload_v3_OverloadManager;
+extern const upb_msglayout envoy_config_overload_v3_ResourceMonitor_msginit;
+extern const upb_msglayout envoy_config_overload_v3_ThresholdTrigger_msginit;
+extern const upb_msglayout envoy_config_overload_v3_ScaledTrigger_msginit;
+extern const upb_msglayout envoy_config_overload_v3_Trigger_msginit;
+extern const upb_msglayout envoy_config_overload_v3_ScaleTimersOverloadActionConfig_msginit;
+extern const upb_msglayout envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit;
+extern const upb_msglayout envoy_config_overload_v3_OverloadAction_msginit;
+extern const upb_msglayout envoy_config_overload_v3_OverloadManager_msginit;
+struct envoy_type_v3_Percent;
+struct google_protobuf_Any;
+struct google_protobuf_Duration;
+extern const upb_msglayout envoy_type_v3_Percent_msginit;
+extern const upb_msglayout google_protobuf_Any_msginit;
+extern const upb_msglayout google_protobuf_Duration_msginit;
+
+typedef enum {
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_UNSPECIFIED = 0,
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_HTTP_DOWNSTREAM_CONNECTION_IDLE = 1,
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_HTTP_DOWNSTREAM_STREAM_IDLE = 2,
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_TRANSPORT_SOCKET_CONNECT = 3
+} envoy_config_overload_v3_ScaleTimersOverloadActionConfig_TimerType;
+
+
+/* envoy.config.overload.v3.ResourceMonitor */
+
+UPB_INLINE envoy_config_overload_v3_ResourceMonitor *envoy_config_overload_v3_ResourceMonitor_new(upb_arena *arena) {
+  return (envoy_config_overload_v3_ResourceMonitor *)_upb_msg_new(&envoy_config_overload_v3_ResourceMonitor_msginit, arena);
+}
+UPB_INLINE envoy_config_overload_v3_ResourceMonitor *envoy_config_overload_v3_ResourceMonitor_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_overload_v3_ResourceMonitor *ret = envoy_config_overload_v3_ResourceMonitor_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_overload_v3_ResourceMonitor_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_overload_v3_ResourceMonitor *envoy_config_overload_v3_ResourceMonitor_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_overload_v3_ResourceMonitor *ret = envoy_config_overload_v3_ResourceMonitor_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_overload_v3_ResourceMonitor_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_overload_v3_ResourceMonitor_serialize(const envoy_config_overload_v3_ResourceMonitor *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_overload_v3_ResourceMonitor_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_overload_v3_ResourceMonitor_config_type_typed_config = 3,
+  envoy_config_overload_v3_ResourceMonitor_config_type_NOT_SET = 0
+} envoy_config_overload_v3_ResourceMonitor_config_type_oneofcases;
+UPB_INLINE envoy_config_overload_v3_ResourceMonitor_config_type_oneofcases envoy_config_overload_v3_ResourceMonitor_config_type_case(const envoy_config_overload_v3_ResourceMonitor* msg) { return (envoy_config_overload_v3_ResourceMonitor_config_type_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
+
+UPB_INLINE upb_strview envoy_config_overload_v3_ResourceMonitor_name(const envoy_config_overload_v3_ResourceMonitor *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE bool envoy_config_overload_v3_ResourceMonitor_has_typed_config(const envoy_config_overload_v3_ResourceMonitor *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 3; }
+UPB_INLINE const struct google_protobuf_Any* envoy_config_overload_v3_ResourceMonitor_typed_config(const envoy_config_overload_v3_ResourceMonitor *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Any*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 3, NULL); }
+
+UPB_INLINE void envoy_config_overload_v3_ResourceMonitor_set_name(envoy_config_overload_v3_ResourceMonitor *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_overload_v3_ResourceMonitor_set_typed_config(envoy_config_overload_v3_ResourceMonitor *msg, struct google_protobuf_Any* value) {
+  UPB_WRITE_ONEOF(msg, struct google_protobuf_Any*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 3);
+}
+UPB_INLINE struct google_protobuf_Any* envoy_config_overload_v3_ResourceMonitor_mutable_typed_config(envoy_config_overload_v3_ResourceMonitor *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_config_overload_v3_ResourceMonitor_typed_config(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_overload_v3_ResourceMonitor_set_typed_config(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.overload.v3.ThresholdTrigger */
+
+UPB_INLINE envoy_config_overload_v3_ThresholdTrigger *envoy_config_overload_v3_ThresholdTrigger_new(upb_arena *arena) {
+  return (envoy_config_overload_v3_ThresholdTrigger *)_upb_msg_new(&envoy_config_overload_v3_ThresholdTrigger_msginit, arena);
+}
+UPB_INLINE envoy_config_overload_v3_ThresholdTrigger *envoy_config_overload_v3_ThresholdTrigger_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_overload_v3_ThresholdTrigger *ret = envoy_config_overload_v3_ThresholdTrigger_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_overload_v3_ThresholdTrigger_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_overload_v3_ThresholdTrigger *envoy_config_overload_v3_ThresholdTrigger_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_overload_v3_ThresholdTrigger *ret = envoy_config_overload_v3_ThresholdTrigger_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_overload_v3_ThresholdTrigger_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_overload_v3_ThresholdTrigger_serialize(const envoy_config_overload_v3_ThresholdTrigger *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_overload_v3_ThresholdTrigger_msginit, arena, len);
+}
+
+UPB_INLINE double envoy_config_overload_v3_ThresholdTrigger_value(const envoy_config_overload_v3_ThresholdTrigger *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), double); }
+
+UPB_INLINE void envoy_config_overload_v3_ThresholdTrigger_set_value(envoy_config_overload_v3_ThresholdTrigger *msg, double value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), double) = value;
+}
+
+/* envoy.config.overload.v3.ScaledTrigger */
+
+UPB_INLINE envoy_config_overload_v3_ScaledTrigger *envoy_config_overload_v3_ScaledTrigger_new(upb_arena *arena) {
+  return (envoy_config_overload_v3_ScaledTrigger *)_upb_msg_new(&envoy_config_overload_v3_ScaledTrigger_msginit, arena);
+}
+UPB_INLINE envoy_config_overload_v3_ScaledTrigger *envoy_config_overload_v3_ScaledTrigger_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_overload_v3_ScaledTrigger *ret = envoy_config_overload_v3_ScaledTrigger_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_overload_v3_ScaledTrigger_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_overload_v3_ScaledTrigger *envoy_config_overload_v3_ScaledTrigger_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_overload_v3_ScaledTrigger *ret = envoy_config_overload_v3_ScaledTrigger_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_overload_v3_ScaledTrigger_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_overload_v3_ScaledTrigger_serialize(const envoy_config_overload_v3_ScaledTrigger *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_overload_v3_ScaledTrigger_msginit, arena, len);
+}
+
+UPB_INLINE double envoy_config_overload_v3_ScaledTrigger_scaling_threshold(const envoy_config_overload_v3_ScaledTrigger *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), double); }
+UPB_INLINE double envoy_config_overload_v3_ScaledTrigger_saturation_threshold(const envoy_config_overload_v3_ScaledTrigger *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), double); }
+
+UPB_INLINE void envoy_config_overload_v3_ScaledTrigger_set_scaling_threshold(envoy_config_overload_v3_ScaledTrigger *msg, double value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), double) = value;
+}
+UPB_INLINE void envoy_config_overload_v3_ScaledTrigger_set_saturation_threshold(envoy_config_overload_v3_ScaledTrigger *msg, double value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), double) = value;
+}
+
+/* envoy.config.overload.v3.Trigger */
+
+UPB_INLINE envoy_config_overload_v3_Trigger *envoy_config_overload_v3_Trigger_new(upb_arena *arena) {
+  return (envoy_config_overload_v3_Trigger *)_upb_msg_new(&envoy_config_overload_v3_Trigger_msginit, arena);
+}
+UPB_INLINE envoy_config_overload_v3_Trigger *envoy_config_overload_v3_Trigger_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_overload_v3_Trigger *ret = envoy_config_overload_v3_Trigger_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_overload_v3_Trigger_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_overload_v3_Trigger *envoy_config_overload_v3_Trigger_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_overload_v3_Trigger *ret = envoy_config_overload_v3_Trigger_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_overload_v3_Trigger_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_overload_v3_Trigger_serialize(const envoy_config_overload_v3_Trigger *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_overload_v3_Trigger_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_overload_v3_Trigger_trigger_oneof_threshold = 2,
+  envoy_config_overload_v3_Trigger_trigger_oneof_scaled = 3,
+  envoy_config_overload_v3_Trigger_trigger_oneof_NOT_SET = 0
+} envoy_config_overload_v3_Trigger_trigger_oneof_oneofcases;
+UPB_INLINE envoy_config_overload_v3_Trigger_trigger_oneof_oneofcases envoy_config_overload_v3_Trigger_trigger_oneof_case(const envoy_config_overload_v3_Trigger* msg) { return (envoy_config_overload_v3_Trigger_trigger_oneof_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
+
+UPB_INLINE upb_strview envoy_config_overload_v3_Trigger_name(const envoy_config_overload_v3_Trigger *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE bool envoy_config_overload_v3_Trigger_has_threshold(const envoy_config_overload_v3_Trigger *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 2; }
+UPB_INLINE const envoy_config_overload_v3_ThresholdTrigger* envoy_config_overload_v3_Trigger_threshold(const envoy_config_overload_v3_Trigger *msg) { return UPB_READ_ONEOF(msg, const envoy_config_overload_v3_ThresholdTrigger*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 2, NULL); }
+UPB_INLINE bool envoy_config_overload_v3_Trigger_has_scaled(const envoy_config_overload_v3_Trigger *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 3; }
+UPB_INLINE const envoy_config_overload_v3_ScaledTrigger* envoy_config_overload_v3_Trigger_scaled(const envoy_config_overload_v3_Trigger *msg) { return UPB_READ_ONEOF(msg, const envoy_config_overload_v3_ScaledTrigger*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 3, NULL); }
+
+UPB_INLINE void envoy_config_overload_v3_Trigger_set_name(envoy_config_overload_v3_Trigger *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_overload_v3_Trigger_set_threshold(envoy_config_overload_v3_Trigger *msg, envoy_config_overload_v3_ThresholdTrigger* value) {
+  UPB_WRITE_ONEOF(msg, envoy_config_overload_v3_ThresholdTrigger*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 2);
+}
+UPB_INLINE struct envoy_config_overload_v3_ThresholdTrigger* envoy_config_overload_v3_Trigger_mutable_threshold(envoy_config_overload_v3_Trigger *msg, upb_arena *arena) {
+  struct envoy_config_overload_v3_ThresholdTrigger* sub = (struct envoy_config_overload_v3_ThresholdTrigger*)envoy_config_overload_v3_Trigger_threshold(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_overload_v3_ThresholdTrigger*)_upb_msg_new(&envoy_config_overload_v3_ThresholdTrigger_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_overload_v3_Trigger_set_threshold(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_overload_v3_Trigger_set_scaled(envoy_config_overload_v3_Trigger *msg, envoy_config_overload_v3_ScaledTrigger* value) {
+  UPB_WRITE_ONEOF(msg, envoy_config_overload_v3_ScaledTrigger*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 3);
+}
+UPB_INLINE struct envoy_config_overload_v3_ScaledTrigger* envoy_config_overload_v3_Trigger_mutable_scaled(envoy_config_overload_v3_Trigger *msg, upb_arena *arena) {
+  struct envoy_config_overload_v3_ScaledTrigger* sub = (struct envoy_config_overload_v3_ScaledTrigger*)envoy_config_overload_v3_Trigger_scaled(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_overload_v3_ScaledTrigger*)_upb_msg_new(&envoy_config_overload_v3_ScaledTrigger_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_overload_v3_Trigger_set_scaled(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.overload.v3.ScaleTimersOverloadActionConfig */
+
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_new(upb_arena *arena) {
+  return (envoy_config_overload_v3_ScaleTimersOverloadActionConfig *)_upb_msg_new(&envoy_config_overload_v3_ScaleTimersOverloadActionConfig_msginit, arena);
+}
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig *ret = envoy_config_overload_v3_ScaleTimersOverloadActionConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig *ret = envoy_config_overload_v3_ScaleTimersOverloadActionConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_serialize(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_overload_v3_ScaleTimersOverloadActionConfig_has_timer_scale_factors(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer* const* envoy_config_overload_v3_ScaleTimersOverloadActionConfig_timer_scale_factors(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig *msg, size_t *len) { return (const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer** envoy_config_overload_v3_ScaleTimersOverloadActionConfig_mutable_timer_scale_factors(envoy_config_overload_v3_ScaleTimersOverloadActionConfig *msg, size_t *len) {
+  return (envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer** envoy_config_overload_v3_ScaleTimersOverloadActionConfig_resize_timer_scale_factors(envoy_config_overload_v3_ScaleTimersOverloadActionConfig *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer* envoy_config_overload_v3_ScaleTimersOverloadActionConfig_add_timer_scale_factors(envoy_config_overload_v3_ScaleTimersOverloadActionConfig *msg, upb_arena *arena) {
+  struct envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer* sub = (struct envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer*)_upb_msg_new(&envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.config.overload.v3.ScaleTimersOverloadActionConfig.ScaleTimer */
+
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_new(upb_arena *arena) {
+  return (envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *)_upb_msg_new(&envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit, arena);
+}
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *ret = envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *ret = envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_serialize(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_overload_adjust_min_timeout = 2,
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_overload_adjust_min_scale = 3,
+  envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_overload_adjust_NOT_SET = 0
+} envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_overload_adjust_oneofcases;
+UPB_INLINE envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_overload_adjust_oneofcases envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_overload_adjust_case(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer* msg) { return (envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_overload_adjust_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(8, 16), int32_t); }
+
+UPB_INLINE int32_t envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_timer(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int32_t); }
+UPB_INLINE bool envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_has_min_timeout(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 2; }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_min_timeout(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Duration*, UPB_SIZE(4, 8), UPB_SIZE(8, 16), 2, NULL); }
+UPB_INLINE bool envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_has_min_scale(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 3; }
+UPB_INLINE const struct envoy_type_v3_Percent* envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_min_scale(const envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg) { return UPB_READ_ONEOF(msg, const struct envoy_type_v3_Percent*, UPB_SIZE(4, 8), UPB_SIZE(8, 16), 3, NULL); }
+
+UPB_INLINE void envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_set_timer(envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int32_t) = value;
+}
+UPB_INLINE void envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_set_min_timeout(envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg, struct google_protobuf_Duration* value) {
+  UPB_WRITE_ONEOF(msg, struct google_protobuf_Duration*, UPB_SIZE(4, 8), value, UPB_SIZE(8, 16), 2);
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_mutable_min_timeout(envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_min_timeout(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_set_min_timeout(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_set_min_scale(envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg, struct envoy_type_v3_Percent* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_type_v3_Percent*, UPB_SIZE(4, 8), value, UPB_SIZE(8, 16), 3);
+}
+UPB_INLINE struct envoy_type_v3_Percent* envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_mutable_min_scale(envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer *msg, upb_arena *arena) {
+  struct envoy_type_v3_Percent* sub = (struct envoy_type_v3_Percent*)envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_min_scale(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_v3_Percent*)_upb_msg_new(&envoy_type_v3_Percent_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_set_min_scale(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.overload.v3.OverloadAction */
+
+UPB_INLINE envoy_config_overload_v3_OverloadAction *envoy_config_overload_v3_OverloadAction_new(upb_arena *arena) {
+  return (envoy_config_overload_v3_OverloadAction *)_upb_msg_new(&envoy_config_overload_v3_OverloadAction_msginit, arena);
+}
+UPB_INLINE envoy_config_overload_v3_OverloadAction *envoy_config_overload_v3_OverloadAction_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_overload_v3_OverloadAction *ret = envoy_config_overload_v3_OverloadAction_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_overload_v3_OverloadAction_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_overload_v3_OverloadAction *envoy_config_overload_v3_OverloadAction_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_overload_v3_OverloadAction *ret = envoy_config_overload_v3_OverloadAction_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_overload_v3_OverloadAction_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_overload_v3_OverloadAction_serialize(const envoy_config_overload_v3_OverloadAction *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_overload_v3_OverloadAction_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_overload_v3_OverloadAction_name(const envoy_config_overload_v3_OverloadAction *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_config_overload_v3_OverloadAction_has_triggers(const envoy_config_overload_v3_OverloadAction *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
+UPB_INLINE const envoy_config_overload_v3_Trigger* const* envoy_config_overload_v3_OverloadAction_triggers(const envoy_config_overload_v3_OverloadAction *msg, size_t *len) { return (const envoy_config_overload_v3_Trigger* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
+UPB_INLINE bool envoy_config_overload_v3_OverloadAction_has_typed_config(const envoy_config_overload_v3_OverloadAction *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_config_overload_v3_OverloadAction_typed_config(const envoy_config_overload_v3_OverloadAction *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct google_protobuf_Any*); }
+
+UPB_INLINE void envoy_config_overload_v3_OverloadAction_set_name(envoy_config_overload_v3_OverloadAction *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE envoy_config_overload_v3_Trigger** envoy_config_overload_v3_OverloadAction_mutable_triggers(envoy_config_overload_v3_OverloadAction *msg, size_t *len) {
+  return (envoy_config_overload_v3_Trigger**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
+}
+UPB_INLINE envoy_config_overload_v3_Trigger** envoy_config_overload_v3_OverloadAction_resize_triggers(envoy_config_overload_v3_OverloadAction *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_overload_v3_Trigger**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_overload_v3_Trigger* envoy_config_overload_v3_OverloadAction_add_triggers(envoy_config_overload_v3_OverloadAction *msg, upb_arena *arena) {
+  struct envoy_config_overload_v3_Trigger* sub = (struct envoy_config_overload_v3_Trigger*)_upb_msg_new(&envoy_config_overload_v3_Trigger_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_config_overload_v3_OverloadAction_set_typed_config(envoy_config_overload_v3_OverloadAction *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_config_overload_v3_OverloadAction_mutable_typed_config(envoy_config_overload_v3_OverloadAction *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_config_overload_v3_OverloadAction_typed_config(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_overload_v3_OverloadAction_set_typed_config(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.config.overload.v3.OverloadManager */
+
+UPB_INLINE envoy_config_overload_v3_OverloadManager *envoy_config_overload_v3_OverloadManager_new(upb_arena *arena) {
+  return (envoy_config_overload_v3_OverloadManager *)_upb_msg_new(&envoy_config_overload_v3_OverloadManager_msginit, arena);
+}
+UPB_INLINE envoy_config_overload_v3_OverloadManager *envoy_config_overload_v3_OverloadManager_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_overload_v3_OverloadManager *ret = envoy_config_overload_v3_OverloadManager_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_overload_v3_OverloadManager_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_overload_v3_OverloadManager *envoy_config_overload_v3_OverloadManager_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_overload_v3_OverloadManager *ret = envoy_config_overload_v3_OverloadManager_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_overload_v3_OverloadManager_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_overload_v3_OverloadManager_serialize(const envoy_config_overload_v3_OverloadManager *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_overload_v3_OverloadManager_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_overload_v3_OverloadManager_has_refresh_interval(const envoy_config_overload_v3_OverloadManager *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_config_overload_v3_OverloadManager_refresh_interval(const envoy_config_overload_v3_OverloadManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_config_overload_v3_OverloadManager_has_resource_monitors(const envoy_config_overload_v3_OverloadManager *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const envoy_config_overload_v3_ResourceMonitor* const* envoy_config_overload_v3_OverloadManager_resource_monitors(const envoy_config_overload_v3_OverloadManager *msg, size_t *len) { return (const envoy_config_overload_v3_ResourceMonitor* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+UPB_INLINE bool envoy_config_overload_v3_OverloadManager_has_actions(const envoy_config_overload_v3_OverloadManager *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); }
+UPB_INLINE const envoy_config_overload_v3_OverloadAction* const* envoy_config_overload_v3_OverloadManager_actions(const envoy_config_overload_v3_OverloadManager *msg, size_t *len) { return (const envoy_config_overload_v3_OverloadAction* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); }
+
+UPB_INLINE void envoy_config_overload_v3_OverloadManager_set_refresh_interval(envoy_config_overload_v3_OverloadManager *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_config_overload_v3_OverloadManager_mutable_refresh_interval(envoy_config_overload_v3_OverloadManager *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_config_overload_v3_OverloadManager_refresh_interval(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_overload_v3_OverloadManager_set_refresh_interval(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE envoy_config_overload_v3_ResourceMonitor** envoy_config_overload_v3_OverloadManager_mutable_resource_monitors(envoy_config_overload_v3_OverloadManager *msg, size_t *len) {
+  return (envoy_config_overload_v3_ResourceMonitor**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE envoy_config_overload_v3_ResourceMonitor** envoy_config_overload_v3_OverloadManager_resize_resource_monitors(envoy_config_overload_v3_OverloadManager *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_overload_v3_ResourceMonitor**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_overload_v3_ResourceMonitor* envoy_config_overload_v3_OverloadManager_add_resource_monitors(envoy_config_overload_v3_OverloadManager *msg, upb_arena *arena) {
+  struct envoy_config_overload_v3_ResourceMonitor* sub = (struct envoy_config_overload_v3_ResourceMonitor*)_upb_msg_new(&envoy_config_overload_v3_ResourceMonitor_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE envoy_config_overload_v3_OverloadAction** envoy_config_overload_v3_OverloadManager_mutable_actions(envoy_config_overload_v3_OverloadManager *msg, size_t *len) {
+  return (envoy_config_overload_v3_OverloadAction**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len);
+}
+UPB_INLINE envoy_config_overload_v3_OverloadAction** envoy_config_overload_v3_OverloadManager_resize_actions(envoy_config_overload_v3_OverloadManager *msg, size_t len, upb_arena *arena) {
+  return (envoy_config_overload_v3_OverloadAction**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_overload_v3_OverloadAction* envoy_config_overload_v3_OverloadManager_add_actions(envoy_config_overload_v3_OverloadManager *msg, upb_arena *arena) {
+  struct envoy_config_overload_v3_OverloadAction* sub = (struct envoy_config_overload_v3_OverloadAction*)_upb_msg_new(&envoy_config_overload_v3_OverloadAction_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_CONFIG_OVERLOAD_V3_OVERLOAD_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c
index 22e259c..d34e1c5 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c
@@ -19,30 +19,32 @@
 
 #include "upb/port_def.inc"
 
-static const upb_msglayout *const envoy_config_route_v3_RouteConfiguration_submsgs[4] = {
+static const upb_msglayout *const envoy_config_route_v3_RouteConfiguration_submsgs[5] = {
   &envoy_config_core_v3_HeaderValueOption_msginit,
   &envoy_config_route_v3_Vhds_msginit,
   &envoy_config_route_v3_VirtualHost_msginit,
   &google_protobuf_BoolValue_msginit,
+  &google_protobuf_UInt32Value_msginit,
 };
 
-static const upb_msglayout_field envoy_config_route_v3_RouteConfiguration__fields[10] = {
+static const upb_msglayout_field envoy_config_route_v3_RouteConfiguration__fields[11] = {
   {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
-  {2, UPB_SIZE(20, 40), 0, 2, 11, 3},
-  {3, UPB_SIZE(24, 48), 0, 0, 9, 3},
-  {4, UPB_SIZE(28, 56), 0, 0, 11, 3},
-  {5, UPB_SIZE(32, 64), 0, 0, 9, 3},
-  {6, UPB_SIZE(36, 72), 0, 0, 11, 3},
+  {2, UPB_SIZE(24, 48), 0, 2, 11, 3},
+  {3, UPB_SIZE(28, 56), 0, 0, 9, 3},
+  {4, UPB_SIZE(32, 64), 0, 0, 11, 3},
+  {5, UPB_SIZE(36, 72), 0, 0, 9, 3},
+  {6, UPB_SIZE(40, 80), 0, 0, 11, 3},
   {7, UPB_SIZE(12, 24), 1, 3, 11, 1},
-  {8, UPB_SIZE(40, 80), 0, 0, 9, 3},
+  {8, UPB_SIZE(44, 88), 0, 0, 9, 3},
   {9, UPB_SIZE(16, 32), 2, 1, 11, 1},
   {10, UPB_SIZE(1, 1), 0, 0, 8, 1},
+  {11, UPB_SIZE(20, 40), 3, 4, 11, 1},
 };
 
 const upb_msglayout envoy_config_route_v3_RouteConfiguration_msginit = {
   &envoy_config_route_v3_RouteConfiguration_submsgs[0],
   &envoy_config_route_v3_RouteConfiguration__fields[0],
-  UPB_SIZE(48, 96), 10, false, 255,
+  UPB_SIZE(48, 96), 11, false, 255,
 };
 
 static const upb_msglayout *const envoy_config_route_v3_Vhds_submsgs[1] = {
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h
index 461e8c8..b8d009f 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route.upb.h
@@ -30,10 +30,12 @@
 struct envoy_config_core_v3_HeaderValueOption;
 struct envoy_config_route_v3_VirtualHost;
 struct google_protobuf_BoolValue;
+struct google_protobuf_UInt32Value;
 extern const upb_msglayout envoy_config_core_v3_ConfigSource_msginit;
 extern const upb_msglayout envoy_config_core_v3_HeaderValueOption_msginit;
 extern const upb_msglayout envoy_config_route_v3_VirtualHost_msginit;
 extern const upb_msglayout google_protobuf_BoolValue_msginit;
+extern const upb_msglayout google_protobuf_UInt32Value_msginit;
 
 
 /* envoy.config.route.v3.RouteConfiguration */
@@ -57,80 +59,82 @@
 }
 
 UPB_INLINE upb_strview envoy_config_route_v3_RouteConfiguration_name(const envoy_config_route_v3_RouteConfiguration *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_virtual_hosts(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); }
-UPB_INLINE const struct envoy_config_route_v3_VirtualHost* const* envoy_config_route_v3_RouteConfiguration_virtual_hosts(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (const struct envoy_config_route_v3_VirtualHost* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); }
-UPB_INLINE upb_strview const* envoy_config_route_v3_RouteConfiguration_internal_only_headers(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
-UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_response_headers_to_add(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); }
-UPB_INLINE const struct envoy_config_core_v3_HeaderValueOption* const* envoy_config_route_v3_RouteConfiguration_response_headers_to_add(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (const struct envoy_config_core_v3_HeaderValueOption* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
-UPB_INLINE upb_strview const* envoy_config_route_v3_RouteConfiguration_response_headers_to_remove(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); }
-UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_request_headers_to_add(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); }
-UPB_INLINE const struct envoy_config_core_v3_HeaderValueOption* const* envoy_config_route_v3_RouteConfiguration_request_headers_to_add(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (const struct envoy_config_core_v3_HeaderValueOption* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
+UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_virtual_hosts(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); }
+UPB_INLINE const struct envoy_config_route_v3_VirtualHost* const* envoy_config_route_v3_RouteConfiguration_virtual_hosts(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (const struct envoy_config_route_v3_VirtualHost* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
+UPB_INLINE upb_strview const* envoy_config_route_v3_RouteConfiguration_internal_only_headers(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
+UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_response_headers_to_add(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); }
+UPB_INLINE const struct envoy_config_core_v3_HeaderValueOption* const* envoy_config_route_v3_RouteConfiguration_response_headers_to_add(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (const struct envoy_config_core_v3_HeaderValueOption* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); }
+UPB_INLINE upb_strview const* envoy_config_route_v3_RouteConfiguration_response_headers_to_remove(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
+UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_request_headers_to_add(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); }
+UPB_INLINE const struct envoy_config_core_v3_HeaderValueOption* const* envoy_config_route_v3_RouteConfiguration_request_headers_to_add(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (const struct envoy_config_core_v3_HeaderValueOption* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); }
 UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_validate_clusters(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct google_protobuf_BoolValue* envoy_config_route_v3_RouteConfiguration_validate_clusters(const envoy_config_route_v3_RouteConfiguration *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct google_protobuf_BoolValue*); }
-UPB_INLINE upb_strview const* envoy_config_route_v3_RouteConfiguration_request_headers_to_remove(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); }
+UPB_INLINE upb_strview const* envoy_config_route_v3_RouteConfiguration_request_headers_to_remove(const envoy_config_route_v3_RouteConfiguration *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); }
 UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_vhds(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_hasbit(msg, 2); }
 UPB_INLINE const envoy_config_route_v3_Vhds* envoy_config_route_v3_RouteConfiguration_vhds(const envoy_config_route_v3_RouteConfiguration *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const envoy_config_route_v3_Vhds*); }
 UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_most_specific_header_mutations_wins(const envoy_config_route_v3_RouteConfiguration *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
+UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_has_max_direct_response_body_size_bytes(const envoy_config_route_v3_RouteConfiguration *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const struct google_protobuf_UInt32Value* envoy_config_route_v3_RouteConfiguration_max_direct_response_body_size_bytes(const envoy_config_route_v3_RouteConfiguration *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct google_protobuf_UInt32Value*); }
 
 UPB_INLINE void envoy_config_route_v3_RouteConfiguration_set_name(envoy_config_route_v3_RouteConfiguration *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
 }
 UPB_INLINE struct envoy_config_route_v3_VirtualHost** envoy_config_route_v3_RouteConfiguration_mutable_virtual_hosts(envoy_config_route_v3_RouteConfiguration *msg, size_t *len) {
-  return (struct envoy_config_route_v3_VirtualHost**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len);
+  return (struct envoy_config_route_v3_VirtualHost**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
 }
 UPB_INLINE struct envoy_config_route_v3_VirtualHost** envoy_config_route_v3_RouteConfiguration_resize_virtual_hosts(envoy_config_route_v3_RouteConfiguration *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_route_v3_VirtualHost**)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_route_v3_VirtualHost**)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_route_v3_VirtualHost* envoy_config_route_v3_RouteConfiguration_add_virtual_hosts(envoy_config_route_v3_RouteConfiguration *msg, upb_arena *arena) {
   struct envoy_config_route_v3_VirtualHost* sub = (struct envoy_config_route_v3_VirtualHost*)_upb_msg_new(&envoy_config_route_v3_VirtualHost_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
 UPB_INLINE upb_strview* envoy_config_route_v3_RouteConfiguration_mutable_internal_only_headers(envoy_config_route_v3_RouteConfiguration *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
 }
 UPB_INLINE upb_strview* envoy_config_route_v3_RouteConfiguration_resize_internal_only_headers(envoy_config_route_v3_RouteConfiguration *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(3, 4), arena);
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena);
 }
 UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_add_internal_only_headers(envoy_config_route_v3_RouteConfiguration *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val,
+  return _upb_array_append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val,
       arena);
 }
 UPB_INLINE struct envoy_config_core_v3_HeaderValueOption** envoy_config_route_v3_RouteConfiguration_mutable_response_headers_to_add(envoy_config_route_v3_RouteConfiguration *msg, size_t *len) {
-  return (struct envoy_config_core_v3_HeaderValueOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
+  return (struct envoy_config_core_v3_HeaderValueOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len);
 }
 UPB_INLINE struct envoy_config_core_v3_HeaderValueOption** envoy_config_route_v3_RouteConfiguration_resize_response_headers_to_add(envoy_config_route_v3_RouteConfiguration *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_core_v3_HeaderValueOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_core_v3_HeaderValueOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_core_v3_HeaderValueOption* envoy_config_route_v3_RouteConfiguration_add_response_headers_to_add(envoy_config_route_v3_RouteConfiguration *msg, upb_arena *arena) {
   struct envoy_config_core_v3_HeaderValueOption* sub = (struct envoy_config_core_v3_HeaderValueOption*)_upb_msg_new(&envoy_config_core_v3_HeaderValueOption_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
 UPB_INLINE upb_strview* envoy_config_route_v3_RouteConfiguration_mutable_response_headers_to_remove(envoy_config_route_v3_RouteConfiguration *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len);
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
 }
 UPB_INLINE upb_strview* envoy_config_route_v3_RouteConfiguration_resize_response_headers_to_remove(envoy_config_route_v3_RouteConfiguration *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(3, 4), arena);
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena);
 }
 UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_add_response_headers_to_remove(envoy_config_route_v3_RouteConfiguration *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(3, 4), &val,
+  return _upb_array_append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val,
       arena);
 }
 UPB_INLINE struct envoy_config_core_v3_HeaderValueOption** envoy_config_route_v3_RouteConfiguration_mutable_request_headers_to_add(envoy_config_route_v3_RouteConfiguration *msg, size_t *len) {
-  return (struct envoy_config_core_v3_HeaderValueOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
+  return (struct envoy_config_core_v3_HeaderValueOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len);
 }
 UPB_INLINE struct envoy_config_core_v3_HeaderValueOption** envoy_config_route_v3_RouteConfiguration_resize_request_headers_to_add(envoy_config_route_v3_RouteConfiguration *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_core_v3_HeaderValueOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_core_v3_HeaderValueOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_core_v3_HeaderValueOption* envoy_config_route_v3_RouteConfiguration_add_request_headers_to_add(envoy_config_route_v3_RouteConfiguration *msg, upb_arena *arena) {
   struct envoy_config_core_v3_HeaderValueOption* sub = (struct envoy_config_core_v3_HeaderValueOption*)_upb_msg_new(&envoy_config_core_v3_HeaderValueOption_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
@@ -148,13 +152,13 @@
   return sub;
 }
 UPB_INLINE upb_strview* envoy_config_route_v3_RouteConfiguration_mutable_request_headers_to_remove(envoy_config_route_v3_RouteConfiguration *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len);
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len);
 }
 UPB_INLINE upb_strview* envoy_config_route_v3_RouteConfiguration_resize_request_headers_to_remove(envoy_config_route_v3_RouteConfiguration *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(3, 4), arena);
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(3, 4), arena);
 }
 UPB_INLINE bool envoy_config_route_v3_RouteConfiguration_add_request_headers_to_remove(envoy_config_route_v3_RouteConfiguration *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(40, 80), UPB_SIZE(3, 4), &val,
+  return _upb_array_append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val,
       arena);
 }
 UPB_INLINE void envoy_config_route_v3_RouteConfiguration_set_vhds(envoy_config_route_v3_RouteConfiguration *msg, envoy_config_route_v3_Vhds* value) {
@@ -173,6 +177,19 @@
 UPB_INLINE void envoy_config_route_v3_RouteConfiguration_set_most_specific_header_mutations_wins(envoy_config_route_v3_RouteConfiguration *msg, bool value) {
   *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value;
 }
+UPB_INLINE void envoy_config_route_v3_RouteConfiguration_set_max_direct_response_body_size_bytes(envoy_config_route_v3_RouteConfiguration *msg, struct google_protobuf_UInt32Value* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct google_protobuf_UInt32Value*) = value;
+}
+UPB_INLINE struct google_protobuf_UInt32Value* envoy_config_route_v3_RouteConfiguration_mutable_max_direct_response_body_size_bytes(envoy_config_route_v3_RouteConfiguration *msg, upb_arena *arena) {
+  struct google_protobuf_UInt32Value* sub = (struct google_protobuf_UInt32Value*)envoy_config_route_v3_RouteConfiguration_max_direct_response_body_size_bytes(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_UInt32Value*)_upb_msg_new(&google_protobuf_UInt32Value_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_route_v3_RouteConfiguration_set_max_direct_response_body_size_bytes(msg, sub);
+  }
+  return sub;
+}
 
 /* envoy.config.route.v3.Vhds */
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c
index 61efffb..a5c1d65 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.c
@@ -20,7 +20,6 @@
 #include "envoy/type/v3/range.upb.h"
 #include "google/protobuf/any.upb.h"
 #include "google/protobuf/duration.upb.h"
-#include "google/protobuf/struct.upb.h"
 #include "google/protobuf/wrappers.upb.h"
 #include "envoy/annotations/deprecation.upb.h"
 #include "udpa/annotations/migrate.upb.h"
@@ -467,14 +466,15 @@
   &envoy_config_core_v3_ProxyProtocolConfig_msginit,
 };
 
-static const upb_msglayout_field envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig__fields[1] = {
+static const upb_msglayout_field envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig__fields[2] = {
   {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(1, 1), 0, 0, 8, 1},
 };
 
 const upb_msglayout envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig_msginit = {
   &envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig_submsgs[0],
   &envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig__fields[0],
-  UPB_SIZE(8, 16), 1, false, 255,
+  UPB_SIZE(8, 16), 2, false, 255,
 };
 
 static const upb_msglayout *const envoy_config_route_v3_RouteAction_MaxStreamDuration_submsgs[1] = {
@@ -612,7 +612,11 @@
   UPB_SIZE(16, 24), 3, false, 255,
 };
 
-static const upb_msglayout_field envoy_config_route_v3_RedirectAction__fields[8] = {
+static const upb_msglayout *const envoy_config_route_v3_RedirectAction_submsgs[1] = {
+  &envoy_type_matcher_v3_RegexMatchAndSubstitute_msginit,
+};
+
+static const upb_msglayout_field envoy_config_route_v3_RedirectAction__fields[9] = {
   {1, UPB_SIZE(12, 16), 0, 0, 9, 1},
   {2, UPB_SIZE(20, 32), UPB_SIZE(-29, -49), 0, 9, 1},
   {3, UPB_SIZE(0, 0), 0, 0, 14, 1},
@@ -621,12 +625,13 @@
   {6, UPB_SIZE(8, 8), 0, 0, 8, 1},
   {7, UPB_SIZE(32, 56), UPB_SIZE(-41, -73), 0, 9, 1},
   {8, UPB_SIZE(4, 4), 0, 0, 13, 1},
+  {9, UPB_SIZE(20, 32), UPB_SIZE(-29, -49), 0, 11, 1},
 };
 
 const upb_msglayout envoy_config_route_v3_RedirectAction_msginit = {
-  NULL,
+  &envoy_config_route_v3_RedirectAction_submsgs[0],
   &envoy_config_route_v3_RedirectAction__fields[0],
-  UPB_SIZE(48, 80), 8, false, 255,
+  UPB_SIZE(48, 80), 9, false, 255,
 };
 
 static const upb_msglayout *const envoy_config_route_v3_DirectResponseAction_submsgs[1] = {
@@ -711,30 +716,34 @@
   UPB_SIZE(24, 48), 4, false, 255,
 };
 
-static const upb_msglayout *const envoy_config_route_v3_RateLimit_Action_submsgs[7] = {
+static const upb_msglayout *const envoy_config_route_v3_RateLimit_Action_submsgs[9] = {
+  &envoy_config_core_v3_TypedExtensionConfig_msginit,
   &envoy_config_route_v3_RateLimit_Action_DestinationCluster_msginit,
   &envoy_config_route_v3_RateLimit_Action_DynamicMetaData_msginit,
   &envoy_config_route_v3_RateLimit_Action_GenericKey_msginit,
   &envoy_config_route_v3_RateLimit_Action_HeaderValueMatch_msginit,
+  &envoy_config_route_v3_RateLimit_Action_MetaData_msginit,
   &envoy_config_route_v3_RateLimit_Action_RemoteAddress_msginit,
   &envoy_config_route_v3_RateLimit_Action_RequestHeaders_msginit,
   &envoy_config_route_v3_RateLimit_Action_SourceCluster_msginit,
 };
 
-static const upb_msglayout_field envoy_config_route_v3_RateLimit_Action__fields[7] = {
-  {1, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 6, 11, 1},
-  {2, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 0, 11, 1},
-  {3, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 5, 11, 1},
-  {4, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 4, 11, 1},
-  {5, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 2, 11, 1},
-  {6, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 3, 11, 1},
-  {7, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 1, 11, 1},
+static const upb_msglayout_field envoy_config_route_v3_RateLimit_Action__fields[9] = {
+  {1, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 8, 11, 1},
+  {2, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 1, 11, 1},
+  {3, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 7, 11, 1},
+  {4, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 6, 11, 1},
+  {5, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 3, 11, 1},
+  {6, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 4, 11, 1},
+  {7, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 2, 11, 1},
+  {8, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 5, 11, 1},
+  {9, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 0, 11, 1},
 };
 
 const upb_msglayout envoy_config_route_v3_RateLimit_Action_msginit = {
   &envoy_config_route_v3_RateLimit_Action_submsgs[0],
   &envoy_config_route_v3_RateLimit_Action__fields[0],
-  UPB_SIZE(8, 16), 7, false, 255,
+  UPB_SIZE(8, 16), 9, false, 255,
 };
 
 const upb_msglayout envoy_config_route_v3_RateLimit_Action_SourceCluster_msginit = {
@@ -811,6 +820,23 @@
   UPB_SIZE(24, 48), 3, false, 255,
 };
 
+static const upb_msglayout *const envoy_config_route_v3_RateLimit_Action_MetaData_submsgs[1] = {
+  &envoy_type_metadata_v3_MetadataKey_msginit,
+};
+
+static const upb_msglayout_field envoy_config_route_v3_RateLimit_Action_MetaData__fields[4] = {
+  {1, UPB_SIZE(8, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(24, 40), 1, 0, 11, 1},
+  {3, UPB_SIZE(16, 24), 0, 0, 9, 1},
+  {4, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_config_route_v3_RateLimit_Action_MetaData_msginit = {
+  &envoy_config_route_v3_RateLimit_Action_MetaData_submsgs[0],
+  &envoy_config_route_v3_RateLimit_Action_MetaData__fields[0],
+  UPB_SIZE(32, 48), 4, false, 255,
+};
+
 static const upb_msglayout *const envoy_config_route_v3_RateLimit_Override_submsgs[1] = {
   &envoy_config_route_v3_RateLimit_Override_DynamicMetadata_msginit,
 };
@@ -896,5 +922,20 @@
   UPB_SIZE(16, 32), 4, false, 255,
 };
 
+static const upb_msglayout *const envoy_config_route_v3_FilterConfig_submsgs[1] = {
+  &google_protobuf_Any_msginit,
+};
+
+static const upb_msglayout_field envoy_config_route_v3_FilterConfig__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(1, 1), 0, 0, 8, 1},
+};
+
+const upb_msglayout envoy_config_route_v3_FilterConfig_msginit = {
+  &envoy_config_route_v3_FilterConfig_submsgs[0],
+  &envoy_config_route_v3_FilterConfig__fields[0],
+  UPB_SIZE(8, 16), 2, false, 255,
+};
+
 #include "upb/port_undef.inc"
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h b/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h
index 863404e..4f98c01 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/config/route/v3/route_components.upb.h
@@ -65,11 +65,13 @@
 struct envoy_config_route_v3_RateLimit_Action_GenericKey;
 struct envoy_config_route_v3_RateLimit_Action_HeaderValueMatch;
 struct envoy_config_route_v3_RateLimit_Action_DynamicMetaData;
+struct envoy_config_route_v3_RateLimit_Action_MetaData;
 struct envoy_config_route_v3_RateLimit_Override;
 struct envoy_config_route_v3_RateLimit_Override_DynamicMetadata;
 struct envoy_config_route_v3_HeaderMatcher;
 struct envoy_config_route_v3_QueryParameterMatcher;
 struct envoy_config_route_v3_InternalRedirectPolicy;
+struct envoy_config_route_v3_FilterConfig;
 typedef struct envoy_config_route_v3_VirtualHost envoy_config_route_v3_VirtualHost;
 typedef struct envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry;
 typedef struct envoy_config_route_v3_FilterAction envoy_config_route_v3_FilterAction;
@@ -115,11 +117,13 @@
 typedef struct envoy_config_route_v3_RateLimit_Action_GenericKey envoy_config_route_v3_RateLimit_Action_GenericKey;
 typedef struct envoy_config_route_v3_RateLimit_Action_HeaderValueMatch envoy_config_route_v3_RateLimit_Action_HeaderValueMatch;
 typedef struct envoy_config_route_v3_RateLimit_Action_DynamicMetaData envoy_config_route_v3_RateLimit_Action_DynamicMetaData;
+typedef struct envoy_config_route_v3_RateLimit_Action_MetaData envoy_config_route_v3_RateLimit_Action_MetaData;
 typedef struct envoy_config_route_v3_RateLimit_Override envoy_config_route_v3_RateLimit_Override;
 typedef struct envoy_config_route_v3_RateLimit_Override_DynamicMetadata envoy_config_route_v3_RateLimit_Override_DynamicMetadata;
 typedef struct envoy_config_route_v3_HeaderMatcher envoy_config_route_v3_HeaderMatcher;
 typedef struct envoy_config_route_v3_QueryParameterMatcher envoy_config_route_v3_QueryParameterMatcher;
 typedef struct envoy_config_route_v3_InternalRedirectPolicy envoy_config_route_v3_InternalRedirectPolicy;
+typedef struct envoy_config_route_v3_FilterConfig envoy_config_route_v3_FilterConfig;
 extern const upb_msglayout envoy_config_route_v3_VirtualHost_msginit;
 extern const upb_msglayout envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry_msginit;
 extern const upb_msglayout envoy_config_route_v3_FilterAction_msginit;
@@ -165,11 +169,13 @@
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Action_GenericKey_msginit;
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Action_HeaderValueMatch_msginit;
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Action_DynamicMetaData_msginit;
+extern const upb_msglayout envoy_config_route_v3_RateLimit_Action_MetaData_msginit;
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Override_msginit;
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Override_DynamicMetadata_msginit;
 extern const upb_msglayout envoy_config_route_v3_HeaderMatcher_msginit;
 extern const upb_msglayout envoy_config_route_v3_QueryParameterMatcher_msginit;
 extern const upb_msglayout envoy_config_route_v3_InternalRedirectPolicy_msginit;
+extern const upb_msglayout envoy_config_route_v3_FilterConfig_msginit;
 struct envoy_config_core_v3_DataSource;
 struct envoy_config_core_v3_HeaderValueOption;
 struct envoy_config_core_v3_Metadata;
@@ -206,6 +212,11 @@
 extern const upb_msglayout google_protobuf_UInt32Value_msginit;
 
 typedef enum {
+  envoy_config_route_v3_RateLimit_Action_MetaData_DYNAMIC = 0,
+  envoy_config_route_v3_RateLimit_Action_MetaData_ROUTE_ENTRY = 1
+} envoy_config_route_v3_RateLimit_Action_MetaData_Source;
+
+typedef enum {
   envoy_config_route_v3_RedirectAction_MOVED_PERMANENTLY = 0,
   envoy_config_route_v3_RedirectAction_FOUND = 1,
   envoy_config_route_v3_RedirectAction_SEE_OTHER = 2,
@@ -2102,6 +2113,7 @@
 
 UPB_INLINE bool envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig_has_proxy_protocol_config(const envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct envoy_config_core_v3_ProxyProtocolConfig* envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig_proxy_protocol_config(const envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_config_core_v3_ProxyProtocolConfig*); }
+UPB_INLINE bool envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig_allow_post(const envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
 
 UPB_INLINE void envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig_set_proxy_protocol_config(envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig *msg, struct envoy_config_core_v3_ProxyProtocolConfig* value) {
   _upb_sethas(msg, 1);
@@ -2116,6 +2128,9 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig_set_allow_post(envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value;
+}
 
 /* envoy.config.route.v3.RouteAction.MaxStreamDuration */
 
@@ -2657,6 +2672,7 @@
 typedef enum {
   envoy_config_route_v3_RedirectAction_path_rewrite_specifier_path_redirect = 2,
   envoy_config_route_v3_RedirectAction_path_rewrite_specifier_prefix_rewrite = 5,
+  envoy_config_route_v3_RedirectAction_path_rewrite_specifier_regex_rewrite = 9,
   envoy_config_route_v3_RedirectAction_path_rewrite_specifier_NOT_SET = 0
 } envoy_config_route_v3_RedirectAction_path_rewrite_specifier_oneofcases;
 UPB_INLINE envoy_config_route_v3_RedirectAction_path_rewrite_specifier_oneofcases envoy_config_route_v3_RedirectAction_path_rewrite_specifier_case(const envoy_config_route_v3_RedirectAction* msg) { return (envoy_config_route_v3_RedirectAction_path_rewrite_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(28, 48), int32_t); }
@@ -2673,6 +2689,8 @@
 UPB_INLINE bool envoy_config_route_v3_RedirectAction_has_scheme_redirect(const envoy_config_route_v3_RedirectAction *msg) { return _upb_getoneofcase(msg, UPB_SIZE(40, 72)) == 7; }
 UPB_INLINE upb_strview envoy_config_route_v3_RedirectAction_scheme_redirect(const envoy_config_route_v3_RedirectAction *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(32, 56), UPB_SIZE(40, 72), 7, upb_strview_make("", strlen(""))); }
 UPB_INLINE uint32_t envoy_config_route_v3_RedirectAction_port_redirect(const envoy_config_route_v3_RedirectAction *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), uint32_t); }
+UPB_INLINE bool envoy_config_route_v3_RedirectAction_has_regex_rewrite(const envoy_config_route_v3_RedirectAction *msg) { return _upb_getoneofcase(msg, UPB_SIZE(28, 48)) == 9; }
+UPB_INLINE const struct envoy_type_matcher_v3_RegexMatchAndSubstitute* envoy_config_route_v3_RedirectAction_regex_rewrite(const envoy_config_route_v3_RedirectAction *msg) { return UPB_READ_ONEOF(msg, const struct envoy_type_matcher_v3_RegexMatchAndSubstitute*, UPB_SIZE(20, 32), UPB_SIZE(28, 48), 9, NULL); }
 
 UPB_INLINE void envoy_config_route_v3_RedirectAction_set_host_redirect(envoy_config_route_v3_RedirectAction *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_strview) = value;
@@ -2698,6 +2716,18 @@
 UPB_INLINE void envoy_config_route_v3_RedirectAction_set_port_redirect(envoy_config_route_v3_RedirectAction *msg, uint32_t value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 4), uint32_t) = value;
 }
+UPB_INLINE void envoy_config_route_v3_RedirectAction_set_regex_rewrite(envoy_config_route_v3_RedirectAction *msg, struct envoy_type_matcher_v3_RegexMatchAndSubstitute* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_type_matcher_v3_RegexMatchAndSubstitute*, UPB_SIZE(20, 32), value, UPB_SIZE(28, 48), 9);
+}
+UPB_INLINE struct envoy_type_matcher_v3_RegexMatchAndSubstitute* envoy_config_route_v3_RedirectAction_mutable_regex_rewrite(envoy_config_route_v3_RedirectAction *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_RegexMatchAndSubstitute* sub = (struct envoy_type_matcher_v3_RegexMatchAndSubstitute*)envoy_config_route_v3_RedirectAction_regex_rewrite(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_matcher_v3_RegexMatchAndSubstitute*)_upb_msg_new(&envoy_type_matcher_v3_RegexMatchAndSubstitute_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_route_v3_RedirectAction_set_regex_rewrite(msg, sub);
+  }
+  return sub;
+}
 
 /* envoy.config.route.v3.DirectResponseAction */
 
@@ -3003,6 +3033,8 @@
   envoy_config_route_v3_RateLimit_Action_action_specifier_generic_key = 5,
   envoy_config_route_v3_RateLimit_Action_action_specifier_header_value_match = 6,
   envoy_config_route_v3_RateLimit_Action_action_specifier_dynamic_metadata = 7,
+  envoy_config_route_v3_RateLimit_Action_action_specifier_metadata = 8,
+  envoy_config_route_v3_RateLimit_Action_action_specifier_extension = 9,
   envoy_config_route_v3_RateLimit_Action_action_specifier_NOT_SET = 0
 } envoy_config_route_v3_RateLimit_Action_action_specifier_oneofcases;
 UPB_INLINE envoy_config_route_v3_RateLimit_Action_action_specifier_oneofcases envoy_config_route_v3_RateLimit_Action_action_specifier_case(const envoy_config_route_v3_RateLimit_Action* msg) { return (envoy_config_route_v3_RateLimit_Action_action_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(4, 8), int32_t); }
@@ -3021,6 +3053,10 @@
 UPB_INLINE const envoy_config_route_v3_RateLimit_Action_HeaderValueMatch* envoy_config_route_v3_RateLimit_Action_header_value_match(const envoy_config_route_v3_RateLimit_Action *msg) { return UPB_READ_ONEOF(msg, const envoy_config_route_v3_RateLimit_Action_HeaderValueMatch*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 6, NULL); }
 UPB_INLINE bool envoy_config_route_v3_RateLimit_Action_has_dynamic_metadata(const envoy_config_route_v3_RateLimit_Action *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 7; }
 UPB_INLINE const envoy_config_route_v3_RateLimit_Action_DynamicMetaData* envoy_config_route_v3_RateLimit_Action_dynamic_metadata(const envoy_config_route_v3_RateLimit_Action *msg) { return UPB_READ_ONEOF(msg, const envoy_config_route_v3_RateLimit_Action_DynamicMetaData*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 7, NULL); }
+UPB_INLINE bool envoy_config_route_v3_RateLimit_Action_has_metadata(const envoy_config_route_v3_RateLimit_Action *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 8; }
+UPB_INLINE const envoy_config_route_v3_RateLimit_Action_MetaData* envoy_config_route_v3_RateLimit_Action_metadata(const envoy_config_route_v3_RateLimit_Action *msg) { return UPB_READ_ONEOF(msg, const envoy_config_route_v3_RateLimit_Action_MetaData*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 8, NULL); }
+UPB_INLINE bool envoy_config_route_v3_RateLimit_Action_has_extension(const envoy_config_route_v3_RateLimit_Action *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 9; }
+UPB_INLINE const struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_route_v3_RateLimit_Action_extension(const envoy_config_route_v3_RateLimit_Action *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_core_v3_TypedExtensionConfig*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 9, NULL); }
 
 UPB_INLINE void envoy_config_route_v3_RateLimit_Action_set_source_cluster(envoy_config_route_v3_RateLimit_Action *msg, envoy_config_route_v3_RateLimit_Action_SourceCluster* value) {
   UPB_WRITE_ONEOF(msg, envoy_config_route_v3_RateLimit_Action_SourceCluster*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 1);
@@ -3106,6 +3142,30 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_config_route_v3_RateLimit_Action_set_metadata(envoy_config_route_v3_RateLimit_Action *msg, envoy_config_route_v3_RateLimit_Action_MetaData* value) {
+  UPB_WRITE_ONEOF(msg, envoy_config_route_v3_RateLimit_Action_MetaData*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 8);
+}
+UPB_INLINE struct envoy_config_route_v3_RateLimit_Action_MetaData* envoy_config_route_v3_RateLimit_Action_mutable_metadata(envoy_config_route_v3_RateLimit_Action *msg, upb_arena *arena) {
+  struct envoy_config_route_v3_RateLimit_Action_MetaData* sub = (struct envoy_config_route_v3_RateLimit_Action_MetaData*)envoy_config_route_v3_RateLimit_Action_metadata(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_route_v3_RateLimit_Action_MetaData*)_upb_msg_new(&envoy_config_route_v3_RateLimit_Action_MetaData_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_route_v3_RateLimit_Action_set_metadata(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_route_v3_RateLimit_Action_set_extension(envoy_config_route_v3_RateLimit_Action *msg, struct envoy_config_core_v3_TypedExtensionConfig* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_config_core_v3_TypedExtensionConfig*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 9);
+}
+UPB_INLINE struct envoy_config_core_v3_TypedExtensionConfig* envoy_config_route_v3_RateLimit_Action_mutable_extension(envoy_config_route_v3_RateLimit_Action *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_TypedExtensionConfig* sub = (struct envoy_config_core_v3_TypedExtensionConfig*)envoy_config_route_v3_RateLimit_Action_extension(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_TypedExtensionConfig*)_upb_msg_new(&envoy_config_core_v3_TypedExtensionConfig_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_route_v3_RateLimit_Action_set_extension(msg, sub);
+  }
+  return sub;
+}
 
 /* envoy.config.route.v3.RateLimit.Action.SourceCluster */
 
@@ -3338,6 +3398,55 @@
   *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
 }
 
+/* envoy.config.route.v3.RateLimit.Action.MetaData */
+
+UPB_INLINE envoy_config_route_v3_RateLimit_Action_MetaData *envoy_config_route_v3_RateLimit_Action_MetaData_new(upb_arena *arena) {
+  return (envoy_config_route_v3_RateLimit_Action_MetaData *)_upb_msg_new(&envoy_config_route_v3_RateLimit_Action_MetaData_msginit, arena);
+}
+UPB_INLINE envoy_config_route_v3_RateLimit_Action_MetaData *envoy_config_route_v3_RateLimit_Action_MetaData_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_route_v3_RateLimit_Action_MetaData *ret = envoy_config_route_v3_RateLimit_Action_MetaData_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_route_v3_RateLimit_Action_MetaData_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_route_v3_RateLimit_Action_MetaData *envoy_config_route_v3_RateLimit_Action_MetaData_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_route_v3_RateLimit_Action_MetaData *ret = envoy_config_route_v3_RateLimit_Action_MetaData_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_route_v3_RateLimit_Action_MetaData_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_route_v3_RateLimit_Action_MetaData_serialize(const envoy_config_route_v3_RateLimit_Action_MetaData *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_route_v3_RateLimit_Action_MetaData_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview envoy_config_route_v3_RateLimit_Action_MetaData_descriptor_key(const envoy_config_route_v3_RateLimit_Action_MetaData *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
+UPB_INLINE bool envoy_config_route_v3_RateLimit_Action_MetaData_has_metadata_key(const envoy_config_route_v3_RateLimit_Action_MetaData *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_type_metadata_v3_MetadataKey* envoy_config_route_v3_RateLimit_Action_MetaData_metadata_key(const envoy_config_route_v3_RateLimit_Action_MetaData *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 40), const struct envoy_type_metadata_v3_MetadataKey*); }
+UPB_INLINE upb_strview envoy_config_route_v3_RateLimit_Action_MetaData_default_value(const envoy_config_route_v3_RateLimit_Action_MetaData *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_strview); }
+UPB_INLINE int32_t envoy_config_route_v3_RateLimit_Action_MetaData_source(const envoy_config_route_v3_RateLimit_Action_MetaData *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_config_route_v3_RateLimit_Action_MetaData_set_descriptor_key(envoy_config_route_v3_RateLimit_Action_MetaData *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_route_v3_RateLimit_Action_MetaData_set_metadata_key(envoy_config_route_v3_RateLimit_Action_MetaData *msg, struct envoy_type_metadata_v3_MetadataKey* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 40), struct envoy_type_metadata_v3_MetadataKey*) = value;
+}
+UPB_INLINE struct envoy_type_metadata_v3_MetadataKey* envoy_config_route_v3_RateLimit_Action_MetaData_mutable_metadata_key(envoy_config_route_v3_RateLimit_Action_MetaData *msg, upb_arena *arena) {
+  struct envoy_type_metadata_v3_MetadataKey* sub = (struct envoy_type_metadata_v3_MetadataKey*)envoy_config_route_v3_RateLimit_Action_MetaData_metadata_key(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_metadata_v3_MetadataKey*)_upb_msg_new(&envoy_type_metadata_v3_MetadataKey_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_route_v3_RateLimit_Action_MetaData_set_metadata_key(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_route_v3_RateLimit_Action_MetaData_set_default_value(envoy_config_route_v3_RateLimit_Action_MetaData *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_strview) = value;
+}
+UPB_INLINE void envoy_config_route_v3_RateLimit_Action_MetaData_set_source(envoy_config_route_v3_RateLimit_Action_MetaData *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
 /* envoy.config.route.v3.RateLimit.Override */
 
 UPB_INLINE envoy_config_route_v3_RateLimit_Override *envoy_config_route_v3_RateLimit_Override_new(upb_arena *arena) {
@@ -3631,6 +3740,47 @@
   *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value;
 }
 
+/* envoy.config.route.v3.FilterConfig */
+
+UPB_INLINE envoy_config_route_v3_FilterConfig *envoy_config_route_v3_FilterConfig_new(upb_arena *arena) {
+  return (envoy_config_route_v3_FilterConfig *)_upb_msg_new(&envoy_config_route_v3_FilterConfig_msginit, arena);
+}
+UPB_INLINE envoy_config_route_v3_FilterConfig *envoy_config_route_v3_FilterConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_config_route_v3_FilterConfig *ret = envoy_config_route_v3_FilterConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_config_route_v3_FilterConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_config_route_v3_FilterConfig *envoy_config_route_v3_FilterConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_config_route_v3_FilterConfig *ret = envoy_config_route_v3_FilterConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_config_route_v3_FilterConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_config_route_v3_FilterConfig_serialize(const envoy_config_route_v3_FilterConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_config_route_v3_FilterConfig_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_config_route_v3_FilterConfig_has_config(const envoy_config_route_v3_FilterConfig *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* envoy_config_route_v3_FilterConfig_config(const envoy_config_route_v3_FilterConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_Any*); }
+UPB_INLINE bool envoy_config_route_v3_FilterConfig_is_optional(const envoy_config_route_v3_FilterConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
+
+UPB_INLINE void envoy_config_route_v3_FilterConfig_set_config(envoy_config_route_v3_FilterConfig *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* envoy_config_route_v3_FilterConfig_mutable_config(envoy_config_route_v3_FilterConfig *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_config_route_v3_FilterConfig_config(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    envoy_config_route_v3_FilterConfig_set_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_config_route_v3_FilterConfig_set_is_optional(envoy_config_route_v3_FilterConfig *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value;
+}
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
diff --git a/grpc/src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c b/grpc/src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c
index 6729533..52cb6b7 100644
--- a/grpc/src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c
@@ -10,7 +10,6 @@
 #include "upb/msg.h"
 #include "envoy/config/trace/v3/http_tracer.upb.h"
 #include "google/protobuf/any.upb.h"
-#include "google/protobuf/struct.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
 #include "validate/validate.upb.h"
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c
new file mode 100644
index 0000000..308e8b5
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c
@@ -0,0 +1,29 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/clusters/aggregate/v3/cluster.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/extensions/clusters/aggregate/v3/cluster.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout_field envoy_extensions_clusters_aggregate_v3_ClusterConfig__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 3},
+};
+
+const upb_msglayout envoy_extensions_clusters_aggregate_v3_ClusterConfig_msginit = {
+  NULL,
+  &envoy_extensions_clusters_aggregate_v3_ClusterConfig__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h b/grpc/src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h
new file mode 100644
index 0000000..ffa4ccb
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h
@@ -0,0 +1,67 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/clusters/aggregate/v3/cluster.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_EXTENSIONS_CLUSTERS_AGGREGATE_V3_CLUSTER_PROTO_UPB_H_
+#define ENVOY_EXTENSIONS_CLUSTERS_AGGREGATE_V3_CLUSTER_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_extensions_clusters_aggregate_v3_ClusterConfig;
+typedef struct envoy_extensions_clusters_aggregate_v3_ClusterConfig envoy_extensions_clusters_aggregate_v3_ClusterConfig;
+extern const upb_msglayout envoy_extensions_clusters_aggregate_v3_ClusterConfig_msginit;
+
+
+/* envoy.extensions.clusters.aggregate.v3.ClusterConfig */
+
+UPB_INLINE envoy_extensions_clusters_aggregate_v3_ClusterConfig *envoy_extensions_clusters_aggregate_v3_ClusterConfig_new(upb_arena *arena) {
+  return (envoy_extensions_clusters_aggregate_v3_ClusterConfig *)_upb_msg_new(&envoy_extensions_clusters_aggregate_v3_ClusterConfig_msginit, arena);
+}
+UPB_INLINE envoy_extensions_clusters_aggregate_v3_ClusterConfig *envoy_extensions_clusters_aggregate_v3_ClusterConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_clusters_aggregate_v3_ClusterConfig *ret = envoy_extensions_clusters_aggregate_v3_ClusterConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_clusters_aggregate_v3_ClusterConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_clusters_aggregate_v3_ClusterConfig *envoy_extensions_clusters_aggregate_v3_ClusterConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_clusters_aggregate_v3_ClusterConfig *ret = envoy_extensions_clusters_aggregate_v3_ClusterConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_clusters_aggregate_v3_ClusterConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_clusters_aggregate_v3_ClusterConfig_serialize(const envoy_extensions_clusters_aggregate_v3_ClusterConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_clusters_aggregate_v3_ClusterConfig_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview const* envoy_extensions_clusters_aggregate_v3_ClusterConfig_clusters(const envoy_extensions_clusters_aggregate_v3_ClusterConfig *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+
+UPB_INLINE upb_strview* envoy_extensions_clusters_aggregate_v3_ClusterConfig_mutable_clusters(envoy_extensions_clusters_aggregate_v3_ClusterConfig *msg, size_t *len) {
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE upb_strview* envoy_extensions_clusters_aggregate_v3_ClusterConfig_resize_clusters(envoy_extensions_clusters_aggregate_v3_ClusterConfig *msg, size_t len, upb_arena *arena) {
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(3, 4), arena);
+}
+UPB_INLINE bool envoy_extensions_clusters_aggregate_v3_ClusterConfig_add_clusters(envoy_extensions_clusters_aggregate_v3_ClusterConfig *msg, upb_strview val, upb_arena *arena) {
+  return _upb_array_append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(3, 4), &val,
+      arena);
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_EXTENSIONS_CLUSTERS_AGGREGATE_V3_CLUSTER_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c
new file mode 100644
index 0000000..5f92b8d
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c
@@ -0,0 +1,79 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/common/fault/v3/fault.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/extensions/filters/common/fault/v3/fault.upb.h"
+#include "envoy/type/v3/percent.upb.h"
+#include "google/protobuf/duration.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_extensions_filters_common_fault_v3_FaultDelay_submsgs[3] = {
+  &envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit,
+  &envoy_type_v3_FractionalPercent_msginit,
+  &google_protobuf_Duration_msginit,
+};
+
+static const upb_msglayout_field envoy_extensions_filters_common_fault_v3_FaultDelay__fields[3] = {
+  {3, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 2, 11, 1},
+  {4, UPB_SIZE(4, 8), 1, 1, 11, 1},
+  {5, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+};
+
+const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultDelay_msginit = {
+  &envoy_extensions_filters_common_fault_v3_FaultDelay_submsgs[0],
+  &envoy_extensions_filters_common_fault_v3_FaultDelay__fields[0],
+  UPB_SIZE(16, 32), 3, false, 255,
+};
+
+const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit = {
+  NULL,
+  NULL,
+  UPB_SIZE(0, 0), 0, false, 255,
+};
+
+static const upb_msglayout *const envoy_extensions_filters_common_fault_v3_FaultRateLimit_submsgs[3] = {
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit,
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit,
+  &envoy_type_v3_FractionalPercent_msginit,
+};
+
+static const upb_msglayout_field envoy_extensions_filters_common_fault_v3_FaultRateLimit__fields[3] = {
+  {1, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+  {2, UPB_SIZE(4, 8), 1, 2, 11, 1},
+  {3, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 1, 11, 1},
+};
+
+const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit = {
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit_submsgs[0],
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit__fields[0],
+  UPB_SIZE(16, 32), 3, false, 255,
+};
+
+static const upb_msglayout_field envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 4, 1},
+};
+
+const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit = {
+  NULL,
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit = {
+  NULL,
+  NULL,
+  UPB_SIZE(0, 0), 0, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h
new file mode 100644
index 0000000..8c60917
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h
@@ -0,0 +1,268 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/common/fault/v3/fault.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_EXTENSIONS_FILTERS_COMMON_FAULT_V3_FAULT_PROTO_UPB_H_
+#define ENVOY_EXTENSIONS_FILTERS_COMMON_FAULT_V3_FAULT_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_extensions_filters_common_fault_v3_FaultDelay;
+struct envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay;
+struct envoy_extensions_filters_common_fault_v3_FaultRateLimit;
+struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit;
+struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit;
+typedef struct envoy_extensions_filters_common_fault_v3_FaultDelay envoy_extensions_filters_common_fault_v3_FaultDelay;
+typedef struct envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay;
+typedef struct envoy_extensions_filters_common_fault_v3_FaultRateLimit envoy_extensions_filters_common_fault_v3_FaultRateLimit;
+typedef struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit;
+typedef struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultDelay_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit;
+struct envoy_type_v3_FractionalPercent;
+struct google_protobuf_Duration;
+extern const upb_msglayout envoy_type_v3_FractionalPercent_msginit;
+extern const upb_msglayout google_protobuf_Duration_msginit;
+
+typedef enum {
+  envoy_extensions_filters_common_fault_v3_FaultDelay_FIXED = 0
+} envoy_extensions_filters_common_fault_v3_FaultDelay_FaultDelayType;
+
+
+/* envoy.extensions.filters.common.fault.v3.FaultDelay */
+
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultDelay *envoy_extensions_filters_common_fault_v3_FaultDelay_new(upb_arena *arena) {
+  return (envoy_extensions_filters_common_fault_v3_FaultDelay *)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultDelay_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultDelay *envoy_extensions_filters_common_fault_v3_FaultDelay_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_common_fault_v3_FaultDelay *ret = envoy_extensions_filters_common_fault_v3_FaultDelay_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultDelay_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultDelay *envoy_extensions_filters_common_fault_v3_FaultDelay_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_common_fault_v3_FaultDelay *ret = envoy_extensions_filters_common_fault_v3_FaultDelay_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultDelay_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_common_fault_v3_FaultDelay_serialize(const envoy_extensions_filters_common_fault_v3_FaultDelay *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_common_fault_v3_FaultDelay_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_extensions_filters_common_fault_v3_FaultDelay_fault_delay_secifier_fixed_delay = 3,
+  envoy_extensions_filters_common_fault_v3_FaultDelay_fault_delay_secifier_header_delay = 5,
+  envoy_extensions_filters_common_fault_v3_FaultDelay_fault_delay_secifier_NOT_SET = 0
+} envoy_extensions_filters_common_fault_v3_FaultDelay_fault_delay_secifier_oneofcases;
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultDelay_fault_delay_secifier_oneofcases envoy_extensions_filters_common_fault_v3_FaultDelay_fault_delay_secifier_case(const envoy_extensions_filters_common_fault_v3_FaultDelay* msg) { return (envoy_extensions_filters_common_fault_v3_FaultDelay_fault_delay_secifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
+
+UPB_INLINE bool envoy_extensions_filters_common_fault_v3_FaultDelay_has_fixed_delay(const envoy_extensions_filters_common_fault_v3_FaultDelay *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 3; }
+UPB_INLINE const struct google_protobuf_Duration* envoy_extensions_filters_common_fault_v3_FaultDelay_fixed_delay(const envoy_extensions_filters_common_fault_v3_FaultDelay *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Duration*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 3, NULL); }
+UPB_INLINE bool envoy_extensions_filters_common_fault_v3_FaultDelay_has_percentage(const envoy_extensions_filters_common_fault_v3_FaultDelay *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_type_v3_FractionalPercent* envoy_extensions_filters_common_fault_v3_FaultDelay_percentage(const envoy_extensions_filters_common_fault_v3_FaultDelay *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_type_v3_FractionalPercent*); }
+UPB_INLINE bool envoy_extensions_filters_common_fault_v3_FaultDelay_has_header_delay(const envoy_extensions_filters_common_fault_v3_FaultDelay *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 5; }
+UPB_INLINE const envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay* envoy_extensions_filters_common_fault_v3_FaultDelay_header_delay(const envoy_extensions_filters_common_fault_v3_FaultDelay *msg) { return UPB_READ_ONEOF(msg, const envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 5, NULL); }
+
+UPB_INLINE void envoy_extensions_filters_common_fault_v3_FaultDelay_set_fixed_delay(envoy_extensions_filters_common_fault_v3_FaultDelay *msg, struct google_protobuf_Duration* value) {
+  UPB_WRITE_ONEOF(msg, struct google_protobuf_Duration*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 3);
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_extensions_filters_common_fault_v3_FaultDelay_mutable_fixed_delay(envoy_extensions_filters_common_fault_v3_FaultDelay *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_extensions_filters_common_fault_v3_FaultDelay_fixed_delay(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_common_fault_v3_FaultDelay_set_fixed_delay(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_common_fault_v3_FaultDelay_set_percentage(envoy_extensions_filters_common_fault_v3_FaultDelay *msg, struct envoy_type_v3_FractionalPercent* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_type_v3_FractionalPercent*) = value;
+}
+UPB_INLINE struct envoy_type_v3_FractionalPercent* envoy_extensions_filters_common_fault_v3_FaultDelay_mutable_percentage(envoy_extensions_filters_common_fault_v3_FaultDelay *msg, upb_arena *arena) {
+  struct envoy_type_v3_FractionalPercent* sub = (struct envoy_type_v3_FractionalPercent*)envoy_extensions_filters_common_fault_v3_FaultDelay_percentage(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_v3_FractionalPercent*)_upb_msg_new(&envoy_type_v3_FractionalPercent_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_common_fault_v3_FaultDelay_set_percentage(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_common_fault_v3_FaultDelay_set_header_delay(envoy_extensions_filters_common_fault_v3_FaultDelay *msg, envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay* value) {
+  UPB_WRITE_ONEOF(msg, envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 5);
+}
+UPB_INLINE struct envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay* envoy_extensions_filters_common_fault_v3_FaultDelay_mutable_header_delay(envoy_extensions_filters_common_fault_v3_FaultDelay *msg, upb_arena *arena) {
+  struct envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay* sub = (struct envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay*)envoy_extensions_filters_common_fault_v3_FaultDelay_header_delay(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay*)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_common_fault_v3_FaultDelay_set_header_delay(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.extensions.filters.common.fault.v3.FaultDelay.HeaderDelay */
+
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay *envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_new(upb_arena *arena) {
+  return (envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay *)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay *envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay *ret = envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay *envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay *ret = envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_serialize(const envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit, arena, len);
+}
+
+
+
+/* envoy.extensions.filters.common.fault.v3.FaultRateLimit */
+
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_new(upb_arena *arena) {
+  return (envoy_extensions_filters_common_fault_v3_FaultRateLimit *)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit *ret = envoy_extensions_filters_common_fault_v3_FaultRateLimit_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit *ret = envoy_extensions_filters_common_fault_v3_FaultRateLimit_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_common_fault_v3_FaultRateLimit_serialize(const envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit_limit_type_fixed_limit = 1,
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit_limit_type_header_limit = 3,
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit_limit_type_NOT_SET = 0
+} envoy_extensions_filters_common_fault_v3_FaultRateLimit_limit_type_oneofcases;
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit_limit_type_oneofcases envoy_extensions_filters_common_fault_v3_FaultRateLimit_limit_type_case(const envoy_extensions_filters_common_fault_v3_FaultRateLimit* msg) { return (envoy_extensions_filters_common_fault_v3_FaultRateLimit_limit_type_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
+
+UPB_INLINE bool envoy_extensions_filters_common_fault_v3_FaultRateLimit_has_fixed_limit(const envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 1; }
+UPB_INLINE const envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit* envoy_extensions_filters_common_fault_v3_FaultRateLimit_fixed_limit(const envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg) { return UPB_READ_ONEOF(msg, const envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 1, NULL); }
+UPB_INLINE bool envoy_extensions_filters_common_fault_v3_FaultRateLimit_has_percentage(const envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_type_v3_FractionalPercent* envoy_extensions_filters_common_fault_v3_FaultRateLimit_percentage(const envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_type_v3_FractionalPercent*); }
+UPB_INLINE bool envoy_extensions_filters_common_fault_v3_FaultRateLimit_has_header_limit(const envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 3; }
+UPB_INLINE const envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit* envoy_extensions_filters_common_fault_v3_FaultRateLimit_header_limit(const envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg) { return UPB_READ_ONEOF(msg, const envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 3, NULL); }
+
+UPB_INLINE void envoy_extensions_filters_common_fault_v3_FaultRateLimit_set_fixed_limit(envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg, envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit* value) {
+  UPB_WRITE_ONEOF(msg, envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 1);
+}
+UPB_INLINE struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit* envoy_extensions_filters_common_fault_v3_FaultRateLimit_mutable_fixed_limit(envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg, upb_arena *arena) {
+  struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit* sub = (struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit*)envoy_extensions_filters_common_fault_v3_FaultRateLimit_fixed_limit(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit*)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_common_fault_v3_FaultRateLimit_set_fixed_limit(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_common_fault_v3_FaultRateLimit_set_percentage(envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg, struct envoy_type_v3_FractionalPercent* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_type_v3_FractionalPercent*) = value;
+}
+UPB_INLINE struct envoy_type_v3_FractionalPercent* envoy_extensions_filters_common_fault_v3_FaultRateLimit_mutable_percentage(envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg, upb_arena *arena) {
+  struct envoy_type_v3_FractionalPercent* sub = (struct envoy_type_v3_FractionalPercent*)envoy_extensions_filters_common_fault_v3_FaultRateLimit_percentage(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_v3_FractionalPercent*)_upb_msg_new(&envoy_type_v3_FractionalPercent_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_common_fault_v3_FaultRateLimit_set_percentage(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_common_fault_v3_FaultRateLimit_set_header_limit(envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg, envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit* value) {
+  UPB_WRITE_ONEOF(msg, envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 3);
+}
+UPB_INLINE struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit* envoy_extensions_filters_common_fault_v3_FaultRateLimit_mutable_header_limit(envoy_extensions_filters_common_fault_v3_FaultRateLimit *msg, upb_arena *arena) {
+  struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit* sub = (struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit*)envoy_extensions_filters_common_fault_v3_FaultRateLimit_header_limit(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit*)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_common_fault_v3_FaultRateLimit_set_header_limit(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.extensions.filters.common.fault.v3.FaultRateLimit.FixedLimit */
+
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_new(upb_arena *arena) {
+  return (envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *ret = envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *ret = envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_serialize(const envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit, arena, len);
+}
+
+UPB_INLINE uint64_t envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_limit_kbps(const envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), uint64_t); }
+
+UPB_INLINE void envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_set_limit_kbps(envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit *msg, uint64_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), uint64_t) = value;
+}
+
+/* envoy.extensions.filters.common.fault.v3.FaultRateLimit.HeaderLimit */
+
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_new(upb_arena *arena) {
+  return (envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit *)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit *ret = envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit *envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit *ret = envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_serialize(const envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit, arena, len);
+}
+
+
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_EXTENSIONS_FILTERS_COMMON_FAULT_V3_FAULT_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c
new file mode 100644
index 0000000..ca5144c
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c
@@ -0,0 +1,78 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/http/fault/v3/fault.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/extensions/filters/http/fault/v3/fault.upb.h"
+#include "envoy/config/route/v3/route_components.upb.h"
+#include "envoy/extensions/filters/common/fault/v3/fault.upb.h"
+#include "envoy/type/v3/percent.upb.h"
+#include "google/protobuf/wrappers.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_extensions_filters_http_fault_v3_FaultAbort_submsgs[2] = {
+  &envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit,
+  &envoy_type_v3_FractionalPercent_msginit,
+};
+
+static const upb_msglayout_field envoy_extensions_filters_http_fault_v3_FaultAbort__fields[4] = {
+  {2, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 13, 1},
+  {3, UPB_SIZE(4, 8), 1, 1, 11, 1},
+  {4, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+  {5, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 13, 1},
+};
+
+const upb_msglayout envoy_extensions_filters_http_fault_v3_FaultAbort_msginit = {
+  &envoy_extensions_filters_http_fault_v3_FaultAbort_submsgs[0],
+  &envoy_extensions_filters_http_fault_v3_FaultAbort__fields[0],
+  UPB_SIZE(16, 32), 4, false, 255,
+};
+
+const upb_msglayout envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit = {
+  NULL,
+  NULL,
+  UPB_SIZE(0, 0), 0, false, 255,
+};
+
+static const upb_msglayout *const envoy_extensions_filters_http_fault_v3_HTTPFault_submsgs[5] = {
+  &envoy_config_route_v3_HeaderMatcher_msginit,
+  &envoy_extensions_filters_common_fault_v3_FaultDelay_msginit,
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit,
+  &envoy_extensions_filters_http_fault_v3_FaultAbort_msginit,
+  &google_protobuf_UInt32Value_msginit,
+};
+
+static const upb_msglayout_field envoy_extensions_filters_http_fault_v3_HTTPFault__fields[14] = {
+  {1, UPB_SIZE(68, 136), 1, 1, 11, 1},
+  {2, UPB_SIZE(72, 144), 2, 3, 11, 1},
+  {3, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {4, UPB_SIZE(84, 168), 0, 0, 11, 3},
+  {5, UPB_SIZE(88, 176), 0, 0, 9, 3},
+  {6, UPB_SIZE(76, 152), 3, 4, 11, 1},
+  {7, UPB_SIZE(80, 160), 4, 2, 11, 1},
+  {8, UPB_SIZE(12, 24), 0, 0, 9, 1},
+  {9, UPB_SIZE(20, 40), 0, 0, 9, 1},
+  {10, UPB_SIZE(28, 56), 0, 0, 9, 1},
+  {11, UPB_SIZE(36, 72), 0, 0, 9, 1},
+  {12, UPB_SIZE(44, 88), 0, 0, 9, 1},
+  {13, UPB_SIZE(52, 104), 0, 0, 9, 1},
+  {14, UPB_SIZE(60, 120), 0, 0, 9, 1},
+};
+
+const upb_msglayout envoy_extensions_filters_http_fault_v3_HTTPFault_msginit = {
+  &envoy_extensions_filters_http_fault_v3_HTTPFault_submsgs[0],
+  &envoy_extensions_filters_http_fault_v3_HTTPFault__fields[0],
+  UPB_SIZE(96, 192), 14, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h
new file mode 100644
index 0000000..fc618c9
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h
@@ -0,0 +1,281 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/http/fault/v3/fault.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_EXTENSIONS_FILTERS_HTTP_FAULT_V3_FAULT_PROTO_UPB_H_
+#define ENVOY_EXTENSIONS_FILTERS_HTTP_FAULT_V3_FAULT_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_extensions_filters_http_fault_v3_FaultAbort;
+struct envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort;
+struct envoy_extensions_filters_http_fault_v3_HTTPFault;
+typedef struct envoy_extensions_filters_http_fault_v3_FaultAbort envoy_extensions_filters_http_fault_v3_FaultAbort;
+typedef struct envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort;
+typedef struct envoy_extensions_filters_http_fault_v3_HTTPFault envoy_extensions_filters_http_fault_v3_HTTPFault;
+extern const upb_msglayout envoy_extensions_filters_http_fault_v3_FaultAbort_msginit;
+extern const upb_msglayout envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit;
+extern const upb_msglayout envoy_extensions_filters_http_fault_v3_HTTPFault_msginit;
+struct envoy_config_route_v3_HeaderMatcher;
+struct envoy_extensions_filters_common_fault_v3_FaultDelay;
+struct envoy_extensions_filters_common_fault_v3_FaultRateLimit;
+struct envoy_type_v3_FractionalPercent;
+struct google_protobuf_UInt32Value;
+extern const upb_msglayout envoy_config_route_v3_HeaderMatcher_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultDelay_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit;
+extern const upb_msglayout envoy_type_v3_FractionalPercent_msginit;
+extern const upb_msglayout google_protobuf_UInt32Value_msginit;
+
+
+/* envoy.extensions.filters.http.fault.v3.FaultAbort */
+
+UPB_INLINE envoy_extensions_filters_http_fault_v3_FaultAbort *envoy_extensions_filters_http_fault_v3_FaultAbort_new(upb_arena *arena) {
+  return (envoy_extensions_filters_http_fault_v3_FaultAbort *)_upb_msg_new(&envoy_extensions_filters_http_fault_v3_FaultAbort_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_http_fault_v3_FaultAbort *envoy_extensions_filters_http_fault_v3_FaultAbort_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_http_fault_v3_FaultAbort *ret = envoy_extensions_filters_http_fault_v3_FaultAbort_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_http_fault_v3_FaultAbort_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_http_fault_v3_FaultAbort *envoy_extensions_filters_http_fault_v3_FaultAbort_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_http_fault_v3_FaultAbort *ret = envoy_extensions_filters_http_fault_v3_FaultAbort_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_http_fault_v3_FaultAbort_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_http_fault_v3_FaultAbort_serialize(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_http_fault_v3_FaultAbort_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_extensions_filters_http_fault_v3_FaultAbort_error_type_http_status = 2,
+  envoy_extensions_filters_http_fault_v3_FaultAbort_error_type_grpc_status = 5,
+  envoy_extensions_filters_http_fault_v3_FaultAbort_error_type_header_abort = 4,
+  envoy_extensions_filters_http_fault_v3_FaultAbort_error_type_NOT_SET = 0
+} envoy_extensions_filters_http_fault_v3_FaultAbort_error_type_oneofcases;
+UPB_INLINE envoy_extensions_filters_http_fault_v3_FaultAbort_error_type_oneofcases envoy_extensions_filters_http_fault_v3_FaultAbort_error_type_case(const envoy_extensions_filters_http_fault_v3_FaultAbort* msg) { return (envoy_extensions_filters_http_fault_v3_FaultAbort_error_type_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
+
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_FaultAbort_has_http_status(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 2; }
+UPB_INLINE uint32_t envoy_extensions_filters_http_fault_v3_FaultAbort_http_status(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg) { return UPB_READ_ONEOF(msg, uint32_t, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 2, 0); }
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_FaultAbort_has_percentage(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_type_v3_FractionalPercent* envoy_extensions_filters_http_fault_v3_FaultAbort_percentage(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_type_v3_FractionalPercent*); }
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_FaultAbort_has_header_abort(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 4; }
+UPB_INLINE const envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort* envoy_extensions_filters_http_fault_v3_FaultAbort_header_abort(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg) { return UPB_READ_ONEOF(msg, const envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 4, NULL); }
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_FaultAbort_has_grpc_status(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 5; }
+UPB_INLINE uint32_t envoy_extensions_filters_http_fault_v3_FaultAbort_grpc_status(const envoy_extensions_filters_http_fault_v3_FaultAbort *msg) { return UPB_READ_ONEOF(msg, uint32_t, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 5, 0); }
+
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_FaultAbort_set_http_status(envoy_extensions_filters_http_fault_v3_FaultAbort *msg, uint32_t value) {
+  UPB_WRITE_ONEOF(msg, uint32_t, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 2);
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_FaultAbort_set_percentage(envoy_extensions_filters_http_fault_v3_FaultAbort *msg, struct envoy_type_v3_FractionalPercent* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_type_v3_FractionalPercent*) = value;
+}
+UPB_INLINE struct envoy_type_v3_FractionalPercent* envoy_extensions_filters_http_fault_v3_FaultAbort_mutable_percentage(envoy_extensions_filters_http_fault_v3_FaultAbort *msg, upb_arena *arena) {
+  struct envoy_type_v3_FractionalPercent* sub = (struct envoy_type_v3_FractionalPercent*)envoy_extensions_filters_http_fault_v3_FaultAbort_percentage(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_v3_FractionalPercent*)_upb_msg_new(&envoy_type_v3_FractionalPercent_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_http_fault_v3_FaultAbort_set_percentage(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_FaultAbort_set_header_abort(envoy_extensions_filters_http_fault_v3_FaultAbort *msg, envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort* value) {
+  UPB_WRITE_ONEOF(msg, envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 4);
+}
+UPB_INLINE struct envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort* envoy_extensions_filters_http_fault_v3_FaultAbort_mutable_header_abort(envoy_extensions_filters_http_fault_v3_FaultAbort *msg, upb_arena *arena) {
+  struct envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort* sub = (struct envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort*)envoy_extensions_filters_http_fault_v3_FaultAbort_header_abort(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort*)_upb_msg_new(&envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_http_fault_v3_FaultAbort_set_header_abort(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_FaultAbort_set_grpc_status(envoy_extensions_filters_http_fault_v3_FaultAbort *msg, uint32_t value) {
+  UPB_WRITE_ONEOF(msg, uint32_t, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 5);
+}
+
+/* envoy.extensions.filters.http.fault.v3.FaultAbort.HeaderAbort */
+
+UPB_INLINE envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort *envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_new(upb_arena *arena) {
+  return (envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort *)_upb_msg_new(&envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort *envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort *ret = envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort *envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort *ret = envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_serialize(const envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit, arena, len);
+}
+
+
+
+/* envoy.extensions.filters.http.fault.v3.HTTPFault */
+
+UPB_INLINE envoy_extensions_filters_http_fault_v3_HTTPFault *envoy_extensions_filters_http_fault_v3_HTTPFault_new(upb_arena *arena) {
+  return (envoy_extensions_filters_http_fault_v3_HTTPFault *)_upb_msg_new(&envoy_extensions_filters_http_fault_v3_HTTPFault_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_http_fault_v3_HTTPFault *envoy_extensions_filters_http_fault_v3_HTTPFault_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_http_fault_v3_HTTPFault *ret = envoy_extensions_filters_http_fault_v3_HTTPFault_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_http_fault_v3_HTTPFault_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_http_fault_v3_HTTPFault *envoy_extensions_filters_http_fault_v3_HTTPFault_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_http_fault_v3_HTTPFault *ret = envoy_extensions_filters_http_fault_v3_HTTPFault_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_http_fault_v3_HTTPFault_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_http_fault_v3_HTTPFault_serialize(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_http_fault_v3_HTTPFault_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_HTTPFault_has_delay(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_extensions_filters_common_fault_v3_FaultDelay* envoy_extensions_filters_http_fault_v3_HTTPFault_delay(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 136), const struct envoy_extensions_filters_common_fault_v3_FaultDelay*); }
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_HTTPFault_has_abort(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const envoy_extensions_filters_http_fault_v3_FaultAbort* envoy_extensions_filters_http_fault_v3_HTTPFault_abort(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(72, 144), const envoy_extensions_filters_http_fault_v3_FaultAbort*); }
+UPB_INLINE upb_strview envoy_extensions_filters_http_fault_v3_HTTPFault_upstream_cluster(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_HTTPFault_has_headers(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(84, 168)); }
+UPB_INLINE const struct envoy_config_route_v3_HeaderMatcher* const* envoy_extensions_filters_http_fault_v3_HTTPFault_headers(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg, size_t *len) { return (const struct envoy_config_route_v3_HeaderMatcher* const*)_upb_array_accessor(msg, UPB_SIZE(84, 168), len); }
+UPB_INLINE upb_strview const* envoy_extensions_filters_http_fault_v3_HTTPFault_downstream_nodes(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(88, 176), len); }
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_HTTPFault_has_max_active_faults(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const struct google_protobuf_UInt32Value* envoy_extensions_filters_http_fault_v3_HTTPFault_max_active_faults(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 152), const struct google_protobuf_UInt32Value*); }
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_HTTPFault_has_response_rate_limit(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE const struct envoy_extensions_filters_common_fault_v3_FaultRateLimit* envoy_extensions_filters_http_fault_v3_HTTPFault_response_rate_limit(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(80, 160), const struct envoy_extensions_filters_common_fault_v3_FaultRateLimit*); }
+UPB_INLINE upb_strview envoy_extensions_filters_http_fault_v3_HTTPFault_delay_percent_runtime(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE upb_strview envoy_extensions_filters_http_fault_v3_HTTPFault_abort_percent_runtime(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
+UPB_INLINE upb_strview envoy_extensions_filters_http_fault_v3_HTTPFault_delay_duration_runtime(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), upb_strview); }
+UPB_INLINE upb_strview envoy_extensions_filters_http_fault_v3_HTTPFault_abort_http_status_runtime(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 72), upb_strview); }
+UPB_INLINE upb_strview envoy_extensions_filters_http_fault_v3_HTTPFault_max_active_faults_runtime(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 88), upb_strview); }
+UPB_INLINE upb_strview envoy_extensions_filters_http_fault_v3_HTTPFault_response_rate_limit_percent_runtime(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 104), upb_strview); }
+UPB_INLINE upb_strview envoy_extensions_filters_http_fault_v3_HTTPFault_abort_grpc_status_runtime(const envoy_extensions_filters_http_fault_v3_HTTPFault *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 120), upb_strview); }
+
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_delay(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, struct envoy_extensions_filters_common_fault_v3_FaultDelay* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(68, 136), struct envoy_extensions_filters_common_fault_v3_FaultDelay*) = value;
+}
+UPB_INLINE struct envoy_extensions_filters_common_fault_v3_FaultDelay* envoy_extensions_filters_http_fault_v3_HTTPFault_mutable_delay(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_arena *arena) {
+  struct envoy_extensions_filters_common_fault_v3_FaultDelay* sub = (struct envoy_extensions_filters_common_fault_v3_FaultDelay*)envoy_extensions_filters_http_fault_v3_HTTPFault_delay(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_extensions_filters_common_fault_v3_FaultDelay*)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultDelay_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_http_fault_v3_HTTPFault_set_delay(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_abort(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, envoy_extensions_filters_http_fault_v3_FaultAbort* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(72, 144), envoy_extensions_filters_http_fault_v3_FaultAbort*) = value;
+}
+UPB_INLINE struct envoy_extensions_filters_http_fault_v3_FaultAbort* envoy_extensions_filters_http_fault_v3_HTTPFault_mutable_abort(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_arena *arena) {
+  struct envoy_extensions_filters_http_fault_v3_FaultAbort* sub = (struct envoy_extensions_filters_http_fault_v3_FaultAbort*)envoy_extensions_filters_http_fault_v3_HTTPFault_abort(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_extensions_filters_http_fault_v3_FaultAbort*)_upb_msg_new(&envoy_extensions_filters_http_fault_v3_FaultAbort_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_http_fault_v3_HTTPFault_set_abort(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_upstream_cluster(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE struct envoy_config_route_v3_HeaderMatcher** envoy_extensions_filters_http_fault_v3_HTTPFault_mutable_headers(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, size_t *len) {
+  return (struct envoy_config_route_v3_HeaderMatcher**)_upb_array_mutable_accessor(msg, UPB_SIZE(84, 168), len);
+}
+UPB_INLINE struct envoy_config_route_v3_HeaderMatcher** envoy_extensions_filters_http_fault_v3_HTTPFault_resize_headers(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_route_v3_HeaderMatcher**)_upb_array_resize_accessor2(msg, UPB_SIZE(84, 168), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_route_v3_HeaderMatcher* envoy_extensions_filters_http_fault_v3_HTTPFault_add_headers(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_arena *arena) {
+  struct envoy_config_route_v3_HeaderMatcher* sub = (struct envoy_config_route_v3_HeaderMatcher*)_upb_msg_new(&envoy_config_route_v3_HeaderMatcher_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(84, 168), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE upb_strview* envoy_extensions_filters_http_fault_v3_HTTPFault_mutable_downstream_nodes(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, size_t *len) {
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(88, 176), len);
+}
+UPB_INLINE upb_strview* envoy_extensions_filters_http_fault_v3_HTTPFault_resize_downstream_nodes(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, size_t len, upb_arena *arena) {
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(88, 176), len, UPB_SIZE(3, 4), arena);
+}
+UPB_INLINE bool envoy_extensions_filters_http_fault_v3_HTTPFault_add_downstream_nodes(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview val, upb_arena *arena) {
+  return _upb_array_append_accessor2(msg, UPB_SIZE(88, 176), UPB_SIZE(3, 4), &val,
+      arena);
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_max_active_faults(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, struct google_protobuf_UInt32Value* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(76, 152), struct google_protobuf_UInt32Value*) = value;
+}
+UPB_INLINE struct google_protobuf_UInt32Value* envoy_extensions_filters_http_fault_v3_HTTPFault_mutable_max_active_faults(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_arena *arena) {
+  struct google_protobuf_UInt32Value* sub = (struct google_protobuf_UInt32Value*)envoy_extensions_filters_http_fault_v3_HTTPFault_max_active_faults(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_UInt32Value*)_upb_msg_new(&google_protobuf_UInt32Value_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_http_fault_v3_HTTPFault_set_max_active_faults(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_response_rate_limit(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, struct envoy_extensions_filters_common_fault_v3_FaultRateLimit* value) {
+  _upb_sethas(msg, 4);
+  *UPB_PTR_AT(msg, UPB_SIZE(80, 160), struct envoy_extensions_filters_common_fault_v3_FaultRateLimit*) = value;
+}
+UPB_INLINE struct envoy_extensions_filters_common_fault_v3_FaultRateLimit* envoy_extensions_filters_http_fault_v3_HTTPFault_mutable_response_rate_limit(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_arena *arena) {
+  struct envoy_extensions_filters_common_fault_v3_FaultRateLimit* sub = (struct envoy_extensions_filters_common_fault_v3_FaultRateLimit*)envoy_extensions_filters_http_fault_v3_HTTPFault_response_rate_limit(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_extensions_filters_common_fault_v3_FaultRateLimit*)_upb_msg_new(&envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_http_fault_v3_HTTPFault_set_response_rate_limit(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_delay_percent_runtime(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_abort_percent_runtime(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_delay_duration_runtime(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 56), upb_strview) = value;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_abort_http_status_runtime(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(36, 72), upb_strview) = value;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_max_active_faults_runtime(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(44, 88), upb_strview) = value;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_response_rate_limit_percent_runtime(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(52, 104), upb_strview) = value;
+}
+UPB_INLINE void envoy_extensions_filters_http_fault_v3_HTTPFault_set_abort_grpc_status_runtime(envoy_extensions_filters_http_fault_v3_HTTPFault *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(60, 120), upb_strview) = value;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_EXTENSIONS_FILTERS_HTTP_FAULT_V3_FAULT_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c
new file mode 100644
index 0000000..8e6ff69
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c
@@ -0,0 +1,41 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/http/router/v3/router.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/extensions/filters/http/router/v3/router.upb.h"
+#include "envoy/config/accesslog/v3/accesslog.upb.h"
+#include "google/protobuf/wrappers.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_extensions_filters_http_router_v3_Router_submsgs[2] = {
+  &envoy_config_accesslog_v3_AccessLog_msginit,
+  &google_protobuf_BoolValue_msginit,
+};
+
+static const upb_msglayout_field envoy_extensions_filters_http_router_v3_Router__fields[6] = {
+  {1, UPB_SIZE(4, 8), 1, 1, 11, 1},
+  {2, UPB_SIZE(1, 1), 0, 0, 8, 1},
+  {3, UPB_SIZE(8, 16), 0, 0, 11, 3},
+  {4, UPB_SIZE(2, 2), 0, 0, 8, 1},
+  {5, UPB_SIZE(12, 24), 0, 0, 9, 3},
+  {6, UPB_SIZE(3, 3), 0, 0, 8, 1},
+};
+
+const upb_msglayout envoy_extensions_filters_http_router_v3_Router_msginit = {
+  &envoy_extensions_filters_http_router_v3_Router_submsgs[0],
+  &envoy_extensions_filters_http_router_v3_Router__fields[0],
+  UPB_SIZE(16, 32), 6, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h
new file mode 100644
index 0000000..2e7084a
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h
@@ -0,0 +1,113 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/http/router/v3/router.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_EXTENSIONS_FILTERS_HTTP_ROUTER_V3_ROUTER_PROTO_UPB_H_
+#define ENVOY_EXTENSIONS_FILTERS_HTTP_ROUTER_V3_ROUTER_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_extensions_filters_http_router_v3_Router;
+typedef struct envoy_extensions_filters_http_router_v3_Router envoy_extensions_filters_http_router_v3_Router;
+extern const upb_msglayout envoy_extensions_filters_http_router_v3_Router_msginit;
+struct envoy_config_accesslog_v3_AccessLog;
+struct google_protobuf_BoolValue;
+extern const upb_msglayout envoy_config_accesslog_v3_AccessLog_msginit;
+extern const upb_msglayout google_protobuf_BoolValue_msginit;
+
+
+/* envoy.extensions.filters.http.router.v3.Router */
+
+UPB_INLINE envoy_extensions_filters_http_router_v3_Router *envoy_extensions_filters_http_router_v3_Router_new(upb_arena *arena) {
+  return (envoy_extensions_filters_http_router_v3_Router *)_upb_msg_new(&envoy_extensions_filters_http_router_v3_Router_msginit, arena);
+}
+UPB_INLINE envoy_extensions_filters_http_router_v3_Router *envoy_extensions_filters_http_router_v3_Router_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_extensions_filters_http_router_v3_Router *ret = envoy_extensions_filters_http_router_v3_Router_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_extensions_filters_http_router_v3_Router_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_extensions_filters_http_router_v3_Router *envoy_extensions_filters_http_router_v3_Router_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_extensions_filters_http_router_v3_Router *ret = envoy_extensions_filters_http_router_v3_Router_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_extensions_filters_http_router_v3_Router_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_extensions_filters_http_router_v3_Router_serialize(const envoy_extensions_filters_http_router_v3_Router *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_extensions_filters_http_router_v3_Router_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_extensions_filters_http_router_v3_Router_has_dynamic_stats(const envoy_extensions_filters_http_router_v3_Router *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_BoolValue* envoy_extensions_filters_http_router_v3_Router_dynamic_stats(const envoy_extensions_filters_http_router_v3_Router *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct google_protobuf_BoolValue*); }
+UPB_INLINE bool envoy_extensions_filters_http_router_v3_Router_start_child_span(const envoy_extensions_filters_http_router_v3_Router *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
+UPB_INLINE bool envoy_extensions_filters_http_router_v3_Router_has_upstream_log(const envoy_extensions_filters_http_router_v3_Router *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const struct envoy_config_accesslog_v3_AccessLog* const* envoy_extensions_filters_http_router_v3_Router_upstream_log(const envoy_extensions_filters_http_router_v3_Router *msg, size_t *len) { return (const struct envoy_config_accesslog_v3_AccessLog* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+UPB_INLINE bool envoy_extensions_filters_http_router_v3_Router_suppress_envoy_headers(const envoy_extensions_filters_http_router_v3_Router *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); }
+UPB_INLINE upb_strview const* envoy_extensions_filters_http_router_v3_Router_strict_check_headers(const envoy_extensions_filters_http_router_v3_Router *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); }
+UPB_INLINE bool envoy_extensions_filters_http_router_v3_Router_respect_expected_rq_timeout(const envoy_extensions_filters_http_router_v3_Router *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); }
+
+UPB_INLINE void envoy_extensions_filters_http_router_v3_Router_set_dynamic_stats(envoy_extensions_filters_http_router_v3_Router *msg, struct google_protobuf_BoolValue* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct google_protobuf_BoolValue*) = value;
+}
+UPB_INLINE struct google_protobuf_BoolValue* envoy_extensions_filters_http_router_v3_Router_mutable_dynamic_stats(envoy_extensions_filters_http_router_v3_Router *msg, upb_arena *arena) {
+  struct google_protobuf_BoolValue* sub = (struct google_protobuf_BoolValue*)envoy_extensions_filters_http_router_v3_Router_dynamic_stats(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_BoolValue*)_upb_msg_new(&google_protobuf_BoolValue_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_http_router_v3_Router_set_dynamic_stats(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_http_router_v3_Router_set_start_child_span(envoy_extensions_filters_http_router_v3_Router *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value;
+}
+UPB_INLINE struct envoy_config_accesslog_v3_AccessLog** envoy_extensions_filters_http_router_v3_Router_mutable_upstream_log(envoy_extensions_filters_http_router_v3_Router *msg, size_t *len) {
+  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE struct envoy_config_accesslog_v3_AccessLog** envoy_extensions_filters_http_router_v3_Router_resize_upstream_log(envoy_extensions_filters_http_router_v3_Router *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_config_accesslog_v3_AccessLog* envoy_extensions_filters_http_router_v3_Router_add_upstream_log(envoy_extensions_filters_http_router_v3_Router *msg, upb_arena *arena) {
+  struct envoy_config_accesslog_v3_AccessLog* sub = (struct envoy_config_accesslog_v3_AccessLog*)_upb_msg_new(&envoy_config_accesslog_v3_AccessLog_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_http_router_v3_Router_set_suppress_envoy_headers(envoy_extensions_filters_http_router_v3_Router *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value;
+}
+UPB_INLINE upb_strview* envoy_extensions_filters_http_router_v3_Router_mutable_strict_check_headers(envoy_extensions_filters_http_router_v3_Router *msg, size_t *len) {
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len);
+}
+UPB_INLINE upb_strview* envoy_extensions_filters_http_router_v3_Router_resize_strict_check_headers(envoy_extensions_filters_http_router_v3_Router *msg, size_t len, upb_arena *arena) {
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(3, 4), arena);
+}
+UPB_INLINE bool envoy_extensions_filters_http_router_v3_Router_add_strict_check_headers(envoy_extensions_filters_http_router_v3_Router *msg, upb_strview val, upb_arena *arena) {
+  return _upb_array_append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(3, 4), &val,
+      arena);
+}
+UPB_INLINE void envoy_extensions_filters_http_router_v3_Router_set_respect_expected_rq_timeout(envoy_extensions_filters_http_router_v3_Router *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = value;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_EXTENSIONS_FILTERS_HTTP_ROUTER_V3_ROUTER_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c
index 9d5c452..6b2b6c1 100644
--- a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c
@@ -22,10 +22,7 @@
 #include "envoy/type/v3/percent.upb.h"
 #include "google/protobuf/any.upb.h"
 #include "google/protobuf/duration.upb.h"
-#include "google/protobuf/struct.upb.h"
 #include "google/protobuf/wrappers.upb.h"
-#include "udpa/core/v1/resource_locator.upb.h"
-#include "envoy/annotations/deprecation.upb.h"
 #include "udpa/annotations/migrate.upb.h"
 #include "udpa/annotations/security.upb.h"
 #include "udpa/annotations/status.upb.h"
@@ -54,19 +51,19 @@
   &google_protobuf_UInt32Value_msginit,
 };
 
-static const upb_msglayout_field envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager__fields[38] = {
+static const upb_msglayout_field envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager__fields[40] = {
   {1, UPB_SIZE(4, 4), 0, 0, 14, 1},
   {2, UPB_SIZE(28, 32), 0, 0, 9, 1},
-  {3, UPB_SIZE(136, 248), UPB_SIZE(-141, -257), 11, 11, 1},
-  {4, UPB_SIZE(136, 248), UPB_SIZE(-141, -257), 4, 11, 1},
-  {5, UPB_SIZE(124, 224), 0, 9, 11, 3},
+  {3, UPB_SIZE(140, 256), UPB_SIZE(-145, -265), 11, 11, 1},
+  {4, UPB_SIZE(140, 256), UPB_SIZE(-145, -265), 4, 11, 1},
+  {5, UPB_SIZE(128, 232), 0, 9, 11, 3},
   {6, UPB_SIZE(52, 80), 1, 14, 11, 1},
   {7, UPB_SIZE(56, 88), 2, 7, 11, 1},
   {8, UPB_SIZE(60, 96), 3, 1, 11, 1},
   {9, UPB_SIZE(64, 104), 4, 2, 11, 1},
   {10, UPB_SIZE(36, 48), 0, 0, 9, 1},
   {12, UPB_SIZE(68, 112), 5, 15, 11, 1},
-  {13, UPB_SIZE(128, 232), 0, 0, 11, 3},
+  {13, UPB_SIZE(132, 240), 0, 0, 11, 3},
   {14, UPB_SIZE(72, 120), 6, 14, 11, 1},
   {15, UPB_SIZE(76, 128), 7, 14, 11, 1},
   {16, UPB_SIZE(8, 8), 0, 0, 14, 1},
@@ -76,14 +73,14 @@
   {20, UPB_SIZE(21, 21), 0, 0, 8, 1},
   {21, UPB_SIZE(22, 22), 0, 0, 8, 1},
   {22, UPB_SIZE(44, 64), 0, 0, 9, 1},
-  {23, UPB_SIZE(132, 240), 0, 8, 11, 3},
+  {23, UPB_SIZE(136, 248), 0, 8, 11, 3},
   {24, UPB_SIZE(84, 144), 9, 15, 11, 1},
   {25, UPB_SIZE(88, 152), 10, 5, 11, 1},
   {26, UPB_SIZE(92, 160), 11, 15, 11, 1},
   {28, UPB_SIZE(96, 168), 12, 15, 11, 1},
   {29, UPB_SIZE(100, 176), 13, 16, 11, 1},
   {30, UPB_SIZE(104, 184), 14, 14, 11, 1},
-  {31, UPB_SIZE(136, 248), UPB_SIZE(-141, -257), 13, 11, 1},
+  {31, UPB_SIZE(140, 256), UPB_SIZE(-145, -265), 13, 11, 1},
   {32, UPB_SIZE(23, 23), 0, 0, 8, 1},
   {33, UPB_SIZE(24, 24), 0, 0, 8, 1},
   {34, UPB_SIZE(12, 12), 0, 0, 14, 1},
@@ -93,12 +90,14 @@
   {38, UPB_SIZE(116, 208), 17, 10, 11, 1},
   {39, UPB_SIZE(26, 26), 0, 0, 8, 1},
   {40, UPB_SIZE(120, 216), 18, 14, 11, 1},
+  {41, UPB_SIZE(124, 224), 19, 15, 11, 1},
+  {42, UPB_SIZE(148, 268), UPB_SIZE(-153, -273), 0, 8, 1},
 };
 
 const upb_msglayout envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_msginit = {
   &envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_submsgs[0],
   &envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager__fields[0],
-  UPB_SIZE(144, 272), 38, false, 255,
+  UPB_SIZE(160, 288), 40, false, 255,
 };
 
 static const upb_msglayout *const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing_submsgs[4] = {
@@ -207,21 +206,19 @@
   UPB_SIZE(24, 48), 5, false, 255,
 };
 
-static const upb_msglayout *const envoy_extensions_filters_network_http_connection_manager_v3_Rds_submsgs[2] = {
+static const upb_msglayout *const envoy_extensions_filters_network_http_connection_manager_v3_Rds_submsgs[1] = {
   &envoy_config_core_v3_ConfigSource_msginit,
-  &udpa_core_v1_ResourceLocator_msginit,
 };
 
-static const upb_msglayout_field envoy_extensions_filters_network_http_connection_manager_v3_Rds__fields[3] = {
+static const upb_msglayout_field envoy_extensions_filters_network_http_connection_manager_v3_Rds__fields[2] = {
   {1, UPB_SIZE(12, 24), 1, 0, 11, 1},
   {2, UPB_SIZE(4, 8), 0, 0, 9, 1},
-  {3, UPB_SIZE(16, 32), 2, 1, 11, 1},
 };
 
 const upb_msglayout envoy_extensions_filters_network_http_connection_manager_v3_Rds_msginit = {
   &envoy_extensions_filters_network_http_connection_manager_v3_Rds_submsgs[0],
   &envoy_extensions_filters_network_http_connection_manager_v3_Rds__fields[0],
-  UPB_SIZE(24, 48), 3, false, 255,
+  UPB_SIZE(16, 32), 2, false, 255,
 };
 
 static const upb_msglayout *const envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList_submsgs[1] = {
@@ -334,16 +331,17 @@
   &google_protobuf_Any_msginit,
 };
 
-static const upb_msglayout_field envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter__fields[3] = {
-  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
-  {4, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 1, 11, 1},
-  {5, UPB_SIZE(8, 16), UPB_SIZE(-13, -25), 0, 11, 1},
+static const upb_msglayout_field envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter__fields[4] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {4, UPB_SIZE(12, 24), UPB_SIZE(-17, -33), 1, 11, 1},
+  {5, UPB_SIZE(12, 24), UPB_SIZE(-17, -33), 0, 11, 1},
+  {6, UPB_SIZE(0, 0), 0, 0, 8, 1},
 };
 
 const upb_msglayout envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_msginit = {
   &envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_submsgs[0],
   &envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter__fields[0],
-  UPB_SIZE(16, 32), 3, false, 255,
+  UPB_SIZE(24, 48), 4, false, 255,
 };
 
 static const upb_msglayout *const envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension_submsgs[1] = {
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h
index 7a4d971..668fa85 100644
--- a/grpc/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h
@@ -90,7 +90,6 @@
 struct google_protobuf_BoolValue;
 struct google_protobuf_Duration;
 struct google_protobuf_UInt32Value;
-struct udpa_core_v1_ResourceLocator;
 extern const upb_msglayout envoy_config_accesslog_v3_AccessLog_msginit;
 extern const upb_msglayout envoy_config_accesslog_v3_AccessLogFilter_msginit;
 extern const upb_msglayout envoy_config_core_v3_ConfigSource_msginit;
@@ -110,7 +109,6 @@
 extern const upb_msglayout google_protobuf_BoolValue_msginit;
 extern const upb_msglayout google_protobuf_Duration_msginit;
 extern const upb_msglayout google_protobuf_UInt32Value_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_msginit;
 
 typedef enum {
   envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_AUTO = 0,
@@ -165,16 +163,22 @@
   envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_scoped_routes = 31,
   envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_NOT_SET = 0
 } envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_oneofcases;
-UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_oneofcases envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_case(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager* msg) { return (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(140, 256), int32_t); }
+UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_oneofcases envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_case(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager* msg) { return (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(144, 264), int32_t); }
+
+typedef enum {
+  envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_strip_port_mode_strip_any_host_port = 42,
+  envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_strip_port_mode_NOT_SET = 0
+} envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_strip_port_mode_oneofcases;
+UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_strip_port_mode_oneofcases envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_strip_port_mode_case(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager* msg) { return (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_strip_port_mode_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(152, 272), int32_t); }
 
 UPB_INLINE int32_t envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_codec_type(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
 UPB_INLINE upb_strview envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_stat_prefix(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 32), upb_strview); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_rds(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_getoneofcase(msg, UPB_SIZE(140, 256)) == 3; }
-UPB_INLINE const envoy_extensions_filters_network_http_connection_manager_v3_Rds* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_rds(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return UPB_READ_ONEOF(msg, const envoy_extensions_filters_network_http_connection_manager_v3_Rds*, UPB_SIZE(136, 248), UPB_SIZE(140, 256), 3, NULL); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_route_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_getoneofcase(msg, UPB_SIZE(140, 256)) == 4; }
-UPB_INLINE const struct envoy_config_route_v3_RouteConfiguration* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_route_v3_RouteConfiguration*, UPB_SIZE(136, 248), UPB_SIZE(140, 256), 4, NULL); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_http_filters(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(124, 224)); }
-UPB_INLINE const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter* const* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_http_filters(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) { return (const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter* const*)_upb_array_accessor(msg, UPB_SIZE(124, 224), len); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_rds(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_getoneofcase(msg, UPB_SIZE(144, 264)) == 3; }
+UPB_INLINE const envoy_extensions_filters_network_http_connection_manager_v3_Rds* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_rds(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return UPB_READ_ONEOF(msg, const envoy_extensions_filters_network_http_connection_manager_v3_Rds*, UPB_SIZE(140, 256), UPB_SIZE(144, 264), 3, NULL); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_route_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_getoneofcase(msg, UPB_SIZE(144, 264)) == 4; }
+UPB_INLINE const struct envoy_config_route_v3_RouteConfiguration* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_route_v3_RouteConfiguration*, UPB_SIZE(140, 256), UPB_SIZE(144, 264), 4, NULL); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_http_filters(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(128, 232)); }
+UPB_INLINE const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter* const* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_http_filters(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) { return (const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter* const*)_upb_array_accessor(msg, UPB_SIZE(128, 232), len); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_add_user_agent(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct google_protobuf_BoolValue* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_add_user_agent(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 80), const struct google_protobuf_BoolValue*); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_tracing(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 2); }
@@ -186,8 +190,8 @@
 UPB_INLINE upb_strview envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_server_name(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 48), upb_strview); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_drain_timeout(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 5); }
 UPB_INLINE const struct google_protobuf_Duration* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_drain_timeout(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 112), const struct google_protobuf_Duration*); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_access_log(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(128, 232)); }
-UPB_INLINE const struct envoy_config_accesslog_v3_AccessLog* const* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_access_log(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) { return (const struct envoy_config_accesslog_v3_AccessLog* const*)_upb_array_accessor(msg, UPB_SIZE(128, 232), len); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_access_log(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(132, 240)); }
+UPB_INLINE const struct envoy_config_accesslog_v3_AccessLog* const* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_access_log(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) { return (const struct envoy_config_accesslog_v3_AccessLog* const*)_upb_array_accessor(msg, UPB_SIZE(132, 240), len); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_use_remote_address(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 6); }
 UPB_INLINE const struct google_protobuf_BoolValue* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_use_remote_address(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(72, 120), const struct google_protobuf_BoolValue*); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_generate_request_id(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 7); }
@@ -200,8 +204,8 @@
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_represent_ipv4_remote_address_as_ipv4_mapped_ipv6(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(21, 21), bool); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_skip_xff_append(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(22, 22), bool); }
 UPB_INLINE upb_strview envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_via(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 64), upb_strview); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_upgrade_configs(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(132, 240)); }
-UPB_INLINE const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig* const* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_upgrade_configs(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) { return (const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig* const*)_upb_array_accessor(msg, UPB_SIZE(132, 240), len); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_upgrade_configs(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(136, 248)); }
+UPB_INLINE const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig* const* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_upgrade_configs(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) { return (const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig* const*)_upb_array_accessor(msg, UPB_SIZE(136, 248), len); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_stream_idle_timeout(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 9); }
 UPB_INLINE const struct google_protobuf_Duration* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_stream_idle_timeout(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 144), const struct google_protobuf_Duration*); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_internal_address_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 10); }
@@ -214,8 +218,8 @@
 UPB_INLINE const struct google_protobuf_UInt32Value* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_max_request_headers_kb(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(100, 176), const struct google_protobuf_UInt32Value*); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_normalize_path(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 14); }
 UPB_INLINE const struct google_protobuf_BoolValue* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_normalize_path(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(104, 184), const struct google_protobuf_BoolValue*); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_scoped_routes(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_getoneofcase(msg, UPB_SIZE(140, 256)) == 31; }
-UPB_INLINE const envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_scoped_routes(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return UPB_READ_ONEOF(msg, const envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes*, UPB_SIZE(136, 248), UPB_SIZE(140, 256), 31, NULL); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_scoped_routes(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_getoneofcase(msg, UPB_SIZE(144, 264)) == 31; }
+UPB_INLINE const envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_scoped_routes(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return UPB_READ_ONEOF(msg, const envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes*, UPB_SIZE(140, 256), UPB_SIZE(144, 264), 31, NULL); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_preserve_external_request_id(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(23, 23), bool); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_merge_slashes(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool); }
 UPB_INLINE int32_t envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_server_header_transformation(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); }
@@ -229,6 +233,10 @@
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_strip_matching_host_port(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(26, 26), bool); }
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_stream_error_on_invalid_http_message(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 18); }
 UPB_INLINE const struct google_protobuf_BoolValue* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_stream_error_on_invalid_http_message(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(120, 216), const struct google_protobuf_BoolValue*); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_request_headers_timeout(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_hasbit(msg, 19); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_request_headers_timeout(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(124, 224), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_strip_any_host_port(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return _upb_getoneofcase(msg, UPB_SIZE(152, 272)) == 42; }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_strip_any_host_port(const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg) { return UPB_READ_ONEOF(msg, bool, UPB_SIZE(148, 268), UPB_SIZE(152, 272), 42, false); }
 
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_set_codec_type(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, int32_t value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
@@ -237,7 +245,7 @@
   *UPB_PTR_AT(msg, UPB_SIZE(28, 32), upb_strview) = value;
 }
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_set_rds(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, envoy_extensions_filters_network_http_connection_manager_v3_Rds* value) {
-  UPB_WRITE_ONEOF(msg, envoy_extensions_filters_network_http_connection_manager_v3_Rds*, UPB_SIZE(136, 248), value, UPB_SIZE(140, 256), 3);
+  UPB_WRITE_ONEOF(msg, envoy_extensions_filters_network_http_connection_manager_v3_Rds*, UPB_SIZE(140, 256), value, UPB_SIZE(144, 264), 3);
 }
 UPB_INLINE struct envoy_extensions_filters_network_http_connection_manager_v3_Rds* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_mutable_rds(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, upb_arena *arena) {
   struct envoy_extensions_filters_network_http_connection_manager_v3_Rds* sub = (struct envoy_extensions_filters_network_http_connection_manager_v3_Rds*)envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_rds(msg);
@@ -249,7 +257,7 @@
   return sub;
 }
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_set_route_config(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, struct envoy_config_route_v3_RouteConfiguration* value) {
-  UPB_WRITE_ONEOF(msg, struct envoy_config_route_v3_RouteConfiguration*, UPB_SIZE(136, 248), value, UPB_SIZE(140, 256), 4);
+  UPB_WRITE_ONEOF(msg, struct envoy_config_route_v3_RouteConfiguration*, UPB_SIZE(140, 256), value, UPB_SIZE(144, 264), 4);
 }
 UPB_INLINE struct envoy_config_route_v3_RouteConfiguration* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_mutable_route_config(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, upb_arena *arena) {
   struct envoy_config_route_v3_RouteConfiguration* sub = (struct envoy_config_route_v3_RouteConfiguration*)envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_config(msg);
@@ -261,15 +269,15 @@
   return sub;
 }
 UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter** envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_mutable_http_filters(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) {
-  return (envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter**)_upb_array_mutable_accessor(msg, UPB_SIZE(124, 224), len);
+  return (envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter**)_upb_array_mutable_accessor(msg, UPB_SIZE(128, 232), len);
 }
 UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter** envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_resize_http_filters(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t len, upb_arena *arena) {
-  return (envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter**)_upb_array_resize_accessor2(msg, UPB_SIZE(124, 224), len, UPB_SIZE(2, 3), arena);
+  return (envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter**)_upb_array_resize_accessor2(msg, UPB_SIZE(128, 232), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_add_http_filters(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, upb_arena *arena) {
   struct envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter* sub = (struct envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter*)_upb_msg_new(&envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(124, 224), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(128, 232), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
@@ -342,15 +350,15 @@
   return sub;
 }
 UPB_INLINE struct envoy_config_accesslog_v3_AccessLog** envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_mutable_access_log(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) {
-  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_mutable_accessor(msg, UPB_SIZE(128, 232), len);
+  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_mutable_accessor(msg, UPB_SIZE(132, 240), len);
 }
 UPB_INLINE struct envoy_config_accesslog_v3_AccessLog** envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_resize_access_log(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_resize_accessor2(msg, UPB_SIZE(128, 232), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_accesslog_v3_AccessLog**)_upb_array_resize_accessor2(msg, UPB_SIZE(132, 240), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_accesslog_v3_AccessLog* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_add_access_log(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, upb_arena *arena) {
   struct envoy_config_accesslog_v3_AccessLog* sub = (struct envoy_config_accesslog_v3_AccessLog*)_upb_msg_new(&envoy_config_accesslog_v3_AccessLog_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(128, 232), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(132, 240), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
@@ -412,15 +420,15 @@
   *UPB_PTR_AT(msg, UPB_SIZE(44, 64), upb_strview) = value;
 }
 UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig** envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_mutable_upgrade_configs(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t *len) {
-  return (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(132, 240), len);
+  return (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(136, 248), len);
 }
 UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig** envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_resize_upgrade_configs(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, size_t len, upb_arena *arena) {
-  return (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(132, 240), len, UPB_SIZE(2, 3), arena);
+  return (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(136, 248), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_add_upgrade_configs(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, upb_arena *arena) {
   struct envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig* sub = (struct envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig*)_upb_msg_new(&envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(132, 240), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(136, 248), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
@@ -503,7 +511,7 @@
   return sub;
 }
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_set_scoped_routes(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes* value) {
-  UPB_WRITE_ONEOF(msg, envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes*, UPB_SIZE(136, 248), value, UPB_SIZE(140, 256), 31);
+  UPB_WRITE_ONEOF(msg, envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes*, UPB_SIZE(140, 256), value, UPB_SIZE(144, 264), 31);
 }
 UPB_INLINE struct envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_mutable_scoped_routes(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, upb_arena *arena) {
   struct envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes* sub = (struct envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes*)envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_scoped_routes(msg);
@@ -581,6 +589,22 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_set_request_headers_timeout(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, struct google_protobuf_Duration* value) {
+  _upb_sethas(msg, 19);
+  *UPB_PTR_AT(msg, UPB_SIZE(124, 224), struct google_protobuf_Duration*) = value;
+}
+UPB_INLINE struct google_protobuf_Duration* envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_mutable_request_headers_timeout(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_request_headers_timeout(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_set_request_headers_timeout(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_set_strip_any_host_port(envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager *msg, bool value) {
+  UPB_WRITE_ONEOF(msg, bool, UPB_SIZE(148, 268), value, UPB_SIZE(152, 272), 42);
+}
 
 /* envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.Tracing */
 
@@ -1005,8 +1029,6 @@
 UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_Rds_has_config_source(const envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct envoy_config_core_v3_ConfigSource* envoy_extensions_filters_network_http_connection_manager_v3_Rds_config_source(const envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct envoy_config_core_v3_ConfigSource*); }
 UPB_INLINE upb_strview envoy_extensions_filters_network_http_connection_manager_v3_Rds_route_config_name(const envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_Rds_has_rds_resource_locator(const envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const struct udpa_core_v1_ResourceLocator* envoy_extensions_filters_network_http_connection_manager_v3_Rds_rds_resource_locator(const envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct udpa_core_v1_ResourceLocator*); }
 
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_Rds_set_config_source(envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg, struct envoy_config_core_v3_ConfigSource* value) {
   _upb_sethas(msg, 1);
@@ -1024,19 +1046,6 @@
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_Rds_set_route_config_name(envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
 }
-UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_Rds_set_rds_resource_locator(envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg, struct udpa_core_v1_ResourceLocator* value) {
-  _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct udpa_core_v1_ResourceLocator*) = value;
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator* envoy_extensions_filters_network_http_connection_manager_v3_Rds_mutable_rds_resource_locator(envoy_extensions_filters_network_http_connection_manager_v3_Rds *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceLocator* sub = (struct udpa_core_v1_ResourceLocator*)envoy_extensions_filters_network_http_connection_manager_v3_Rds_rds_resource_locator(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_ResourceLocator*)_upb_msg_new(&udpa_core_v1_ResourceLocator_msginit, arena);
-    if (!sub) return NULL;
-    envoy_extensions_filters_network_http_connection_manager_v3_Rds_set_rds_resource_locator(msg, sub);
-  }
-  return sub;
-}
 
 /* envoy.extensions.filters.network.http_connection_manager.v3.ScopedRouteConfigurationsList */
 
@@ -1393,19 +1402,20 @@
   envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_config_discovery = 5,
   envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_NOT_SET = 0
 } envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_oneofcases;
-UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_oneofcases envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_case(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter* msg) { return (envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 24), int32_t); }
+UPB_INLINE envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_oneofcases envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_case(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter* msg) { return (envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_type_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(16, 32), int32_t); }
 
-UPB_INLINE upb_strview envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_name(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_has_typed_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 4; }
-UPB_INLINE const struct google_protobuf_Any* envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_typed_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Any*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 4, NULL); }
-UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_has_config_discovery(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 24)) == 5; }
-UPB_INLINE const struct envoy_config_core_v3_ExtensionConfigSource* envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_discovery(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_core_v3_ExtensionConfigSource*, UPB_SIZE(8, 16), UPB_SIZE(12, 24), 5, NULL); }
+UPB_INLINE upb_strview envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_name(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_has_typed_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return _upb_getoneofcase(msg, UPB_SIZE(16, 32)) == 4; }
+UPB_INLINE const struct google_protobuf_Any* envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_typed_config(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return UPB_READ_ONEOF(msg, const struct google_protobuf_Any*, UPB_SIZE(12, 24), UPB_SIZE(16, 32), 4, NULL); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_has_config_discovery(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return _upb_getoneofcase(msg, UPB_SIZE(16, 32)) == 5; }
+UPB_INLINE const struct envoy_config_core_v3_ExtensionConfigSource* envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_discovery(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return UPB_READ_ONEOF(msg, const struct envoy_config_core_v3_ExtensionConfigSource*, UPB_SIZE(12, 24), UPB_SIZE(16, 32), 5, NULL); }
+UPB_INLINE bool envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_is_optional(const envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), bool); }
 
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_set_name(envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
 }
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_set_typed_config(envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg, struct google_protobuf_Any* value) {
-  UPB_WRITE_ONEOF(msg, struct google_protobuf_Any*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 4);
+  UPB_WRITE_ONEOF(msg, struct google_protobuf_Any*, UPB_SIZE(12, 24), value, UPB_SIZE(16, 32), 4);
 }
 UPB_INLINE struct google_protobuf_Any* envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_mutable_typed_config(envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg, upb_arena *arena) {
   struct google_protobuf_Any* sub = (struct google_protobuf_Any*)envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_typed_config(msg);
@@ -1417,7 +1427,7 @@
   return sub;
 }
 UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_set_config_discovery(envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg, struct envoy_config_core_v3_ExtensionConfigSource* value) {
-  UPB_WRITE_ONEOF(msg, struct envoy_config_core_v3_ExtensionConfigSource*, UPB_SIZE(8, 16), value, UPB_SIZE(12, 24), 5);
+  UPB_WRITE_ONEOF(msg, struct envoy_config_core_v3_ExtensionConfigSource*, UPB_SIZE(12, 24), value, UPB_SIZE(16, 32), 5);
 }
 UPB_INLINE struct envoy_config_core_v3_ExtensionConfigSource* envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_mutable_config_discovery(envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg, upb_arena *arena) {
   struct envoy_config_core_v3_ExtensionConfigSource* sub = (struct envoy_config_core_v3_ExtensionConfigSource*)envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_config_discovery(msg);
@@ -1428,6 +1438,9 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_set_is_optional(envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), bool) = value;
+}
 
 /* envoy.extensions.filters.network.http_connection_manager.v3.RequestIDExtension */
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c
index 9ae915c..44d63a4 100644
--- a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c
@@ -9,7 +9,6 @@
 #include <stddef.h>
 #include "upb/msg.h"
 #include "envoy/extensions/transport_sockets/tls/v3/cert.upb.h"
-#include "udpa/annotations/status.upb.h"
 #include "envoy/extensions/transport_sockets/tls/v3/common.upb.h"
 #include "envoy/extensions/transport_sockets/tls/v3/secret.upb.h"
 #include "envoy/extensions/transport_sockets/tls/v3/tls.upb.h"
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c
index f2dd45c..247f262 100644
--- a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.c
@@ -12,7 +12,6 @@
 #include "envoy/config/core/v3/base.upb.h"
 #include "envoy/type/matcher/v3/string.upb.h"
 #include "google/protobuf/any.upb.h"
-#include "google/protobuf/struct.upb.h"
 #include "google/protobuf/wrappers.upb.h"
 #include "udpa/annotations/sensitive.upb.h"
 #include "udpa/annotations/status.upb.h"
@@ -49,24 +48,26 @@
   UPB_SIZE(16, 32), 2, false, 255,
 };
 
-static const upb_msglayout *const envoy_extensions_transport_sockets_tls_v3_TlsCertificate_submsgs[2] = {
+static const upb_msglayout *const envoy_extensions_transport_sockets_tls_v3_TlsCertificate_submsgs[3] = {
   &envoy_config_core_v3_DataSource_msginit,
+  &envoy_config_core_v3_WatchedDirectory_msginit,
   &envoy_extensions_transport_sockets_tls_v3_PrivateKeyProvider_msginit,
 };
 
-static const upb_msglayout_field envoy_extensions_transport_sockets_tls_v3_TlsCertificate__fields[6] = {
+static const upb_msglayout_field envoy_extensions_transport_sockets_tls_v3_TlsCertificate__fields[7] = {
   {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
   {2, UPB_SIZE(8, 16), 2, 0, 11, 1},
   {3, UPB_SIZE(12, 24), 3, 0, 11, 1},
   {4, UPB_SIZE(16, 32), 4, 0, 11, 1},
-  {5, UPB_SIZE(24, 48), 0, 0, 11, 3},
-  {6, UPB_SIZE(20, 40), 5, 1, 11, 1},
+  {5, UPB_SIZE(28, 56), 0, 0, 11, 3},
+  {6, UPB_SIZE(20, 40), 5, 2, 11, 1},
+  {7, UPB_SIZE(24, 48), 6, 1, 11, 1},
 };
 
 const upb_msglayout envoy_extensions_transport_sockets_tls_v3_TlsCertificate_msginit = {
   &envoy_extensions_transport_sockets_tls_v3_TlsCertificate_submsgs[0],
   &envoy_extensions_transport_sockets_tls_v3_TlsCertificate__fields[0],
-  UPB_SIZE(32, 56), 6, false, 255,
+  UPB_SIZE(32, 64), 7, false, 255,
 };
 
 static const upb_msglayout *const envoy_extensions_transport_sockets_tls_v3_TlsSessionTicketKeys_submsgs[1] = {
@@ -83,27 +84,29 @@
   UPB_SIZE(8, 8), 1, false, 255,
 };
 
-static const upb_msglayout *const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_submsgs[3] = {
+static const upb_msglayout *const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_submsgs[4] = {
   &envoy_config_core_v3_DataSource_msginit,
+  &envoy_config_core_v3_WatchedDirectory_msginit,
   &envoy_type_matcher_v3_StringMatcher_msginit,
   &google_protobuf_BoolValue_msginit,
 };
 
-static const upb_msglayout_field envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext__fields[8] = {
+static const upb_msglayout_field envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext__fields[9] = {
   {1, UPB_SIZE(12, 16), 1, 0, 11, 1},
-  {2, UPB_SIZE(24, 40), 0, 0, 9, 3},
-  {3, UPB_SIZE(28, 48), 0, 0, 9, 3},
-  {6, UPB_SIZE(16, 24), 2, 2, 11, 1},
+  {2, UPB_SIZE(28, 48), 0, 0, 9, 3},
+  {3, UPB_SIZE(32, 56), 0, 0, 9, 3},
+  {6, UPB_SIZE(16, 24), 2, 3, 11, 1},
   {7, UPB_SIZE(20, 32), 3, 0, 11, 1},
   {8, UPB_SIZE(8, 8), 0, 0, 8, 1},
-  {9, UPB_SIZE(32, 56), 0, 1, 11, 3},
+  {9, UPB_SIZE(36, 64), 0, 2, 11, 3},
   {10, UPB_SIZE(4, 4), 0, 0, 14, 1},
+  {11, UPB_SIZE(24, 40), 4, 1, 11, 1},
 };
 
 const upb_msglayout envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_msginit = {
   &envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_submsgs[0],
   &envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext__fields[0],
-  UPB_SIZE(40, 64), 8, false, 255,
+  UPB_SIZE(40, 72), 9, false, 255,
 };
 
 #include "upb/port_undef.inc"
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h
index 59b0edb..73b534a 100644
--- a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/common.upb.h
@@ -36,10 +36,12 @@
 extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_TlsSessionTicketKeys_msginit;
 extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_msginit;
 struct envoy_config_core_v3_DataSource;
+struct envoy_config_core_v3_WatchedDirectory;
 struct envoy_type_matcher_v3_StringMatcher;
 struct google_protobuf_Any;
 struct google_protobuf_BoolValue;
 extern const upb_msglayout envoy_config_core_v3_DataSource_msginit;
+extern const upb_msglayout envoy_config_core_v3_WatchedDirectory_msginit;
 extern const upb_msglayout envoy_type_matcher_v3_StringMatcher_msginit;
 extern const upb_msglayout google_protobuf_Any_msginit;
 extern const upb_msglayout google_protobuf_BoolValue_msginit;
@@ -184,10 +186,12 @@
 UPB_INLINE const struct envoy_config_core_v3_DataSource* envoy_extensions_transport_sockets_tls_v3_TlsCertificate_password(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct envoy_config_core_v3_DataSource*); }
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_TlsCertificate_has_ocsp_staple(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return _upb_hasbit(msg, 4); }
 UPB_INLINE const struct envoy_config_core_v3_DataSource* envoy_extensions_transport_sockets_tls_v3_TlsCertificate_ocsp_staple(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct envoy_config_core_v3_DataSource*); }
-UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_TlsCertificate_has_signed_certificate_timestamp(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); }
-UPB_INLINE const struct envoy_config_core_v3_DataSource* const* envoy_extensions_transport_sockets_tls_v3_TlsCertificate_signed_certificate_timestamp(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg, size_t *len) { return (const struct envoy_config_core_v3_DataSource* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
+UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_TlsCertificate_has_signed_certificate_timestamp(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); }
+UPB_INLINE const struct envoy_config_core_v3_DataSource* const* envoy_extensions_transport_sockets_tls_v3_TlsCertificate_signed_certificate_timestamp(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg, size_t *len) { return (const struct envoy_config_core_v3_DataSource* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_TlsCertificate_has_private_key_provider(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return _upb_hasbit(msg, 5); }
 UPB_INLINE const envoy_extensions_transport_sockets_tls_v3_PrivateKeyProvider* envoy_extensions_transport_sockets_tls_v3_TlsCertificate_private_key_provider(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const envoy_extensions_transport_sockets_tls_v3_PrivateKeyProvider*); }
+UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_TlsCertificate_has_watched_directory(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE const struct envoy_config_core_v3_WatchedDirectory* envoy_extensions_transport_sockets_tls_v3_TlsCertificate_watched_directory(const envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), const struct envoy_config_core_v3_WatchedDirectory*); }
 
 UPB_INLINE void envoy_extensions_transport_sockets_tls_v3_TlsCertificate_set_certificate_chain(envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg, struct envoy_config_core_v3_DataSource* value) {
   _upb_sethas(msg, 1);
@@ -242,15 +246,15 @@
   return sub;
 }
 UPB_INLINE struct envoy_config_core_v3_DataSource** envoy_extensions_transport_sockets_tls_v3_TlsCertificate_mutable_signed_certificate_timestamp(envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg, size_t *len) {
-  return (struct envoy_config_core_v3_DataSource**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
+  return (struct envoy_config_core_v3_DataSource**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
 }
 UPB_INLINE struct envoy_config_core_v3_DataSource** envoy_extensions_transport_sockets_tls_v3_TlsCertificate_resize_signed_certificate_timestamp(envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_config_core_v3_DataSource**)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_config_core_v3_DataSource**)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_config_core_v3_DataSource* envoy_extensions_transport_sockets_tls_v3_TlsCertificate_add_signed_certificate_timestamp(envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg, upb_arena *arena) {
   struct envoy_config_core_v3_DataSource* sub = (struct envoy_config_core_v3_DataSource*)_upb_msg_new(&envoy_config_core_v3_DataSource_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
@@ -267,6 +271,19 @@
   }
   return sub;
 }
+UPB_INLINE void envoy_extensions_transport_sockets_tls_v3_TlsCertificate_set_watched_directory(envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg, struct envoy_config_core_v3_WatchedDirectory* value) {
+  _upb_sethas(msg, 6);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 48), struct envoy_config_core_v3_WatchedDirectory*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_WatchedDirectory* envoy_extensions_transport_sockets_tls_v3_TlsCertificate_mutable_watched_directory(envoy_extensions_transport_sockets_tls_v3_TlsCertificate *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_WatchedDirectory* sub = (struct envoy_config_core_v3_WatchedDirectory*)envoy_extensions_transport_sockets_tls_v3_TlsCertificate_watched_directory(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_WatchedDirectory*)_upb_msg_new(&envoy_config_core_v3_WatchedDirectory_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_transport_sockets_tls_v3_TlsCertificate_set_watched_directory(msg, sub);
+  }
+  return sub;
+}
 
 /* envoy.extensions.transport_sockets.tls.v3.TlsSessionTicketKeys */
 
@@ -327,16 +344,18 @@
 
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_has_trusted_ca(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct envoy_config_core_v3_DataSource* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_trusted_ca(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const struct envoy_config_core_v3_DataSource*); }
-UPB_INLINE upb_strview const* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_verify_certificate_hash(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(24, 40), len); }
-UPB_INLINE upb_strview const* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_verify_certificate_spki(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(28, 48), len); }
+UPB_INLINE upb_strview const* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_verify_certificate_hash(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(28, 48), len); }
+UPB_INLINE upb_strview const* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_verify_certificate_spki(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(32, 56), len); }
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_has_require_signed_certificate_timestamp(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return _upb_hasbit(msg, 2); }
 UPB_INLINE const struct google_protobuf_BoolValue* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_require_signed_certificate_timestamp(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const struct google_protobuf_BoolValue*); }
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_has_crl(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return _upb_hasbit(msg, 3); }
 UPB_INLINE const struct envoy_config_core_v3_DataSource* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_crl(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 32), const struct envoy_config_core_v3_DataSource*); }
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_allow_expired_certificate(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); }
-UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_has_match_subject_alt_names(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 56)); }
-UPB_INLINE const struct envoy_type_matcher_v3_StringMatcher* const* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_match_subject_alt_names(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) { return (const struct envoy_type_matcher_v3_StringMatcher* const*)_upb_array_accessor(msg, UPB_SIZE(32, 56), len); }
+UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_has_match_subject_alt_names(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 64)); }
+UPB_INLINE const struct envoy_type_matcher_v3_StringMatcher* const* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_match_subject_alt_names(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) { return (const struct envoy_type_matcher_v3_StringMatcher* const*)_upb_array_accessor(msg, UPB_SIZE(36, 64), len); }
 UPB_INLINE int32_t envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_trust_chain_verification(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_has_watched_directory(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE const struct envoy_config_core_v3_WatchedDirectory* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_watched_directory(const envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 40), const struct envoy_config_core_v3_WatchedDirectory*); }
 
 UPB_INLINE void envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_set_trusted_ca(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, struct envoy_config_core_v3_DataSource* value) {
   _upb_sethas(msg, 1);
@@ -352,23 +371,23 @@
   return sub;
 }
 UPB_INLINE upb_strview* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_mutable_verify_certificate_hash(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 40), len);
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 48), len);
 }
 UPB_INLINE upb_strview* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_resize_verify_certificate_hash(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 40), len, UPB_SIZE(3, 4), arena);
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 48), len, UPB_SIZE(3, 4), arena);
 }
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_add_verify_certificate_hash(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(24, 40), UPB_SIZE(3, 4), &val,
+  return _upb_array_append_accessor2(msg, UPB_SIZE(28, 48), UPB_SIZE(3, 4), &val,
       arena);
 }
 UPB_INLINE upb_strview* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_mutable_verify_certificate_spki(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 48), len);
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 56), len);
 }
 UPB_INLINE upb_strview* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_resize_verify_certificate_spki(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 48), len, UPB_SIZE(3, 4), arena);
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 56), len, UPB_SIZE(3, 4), arena);
 }
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_add_verify_certificate_spki(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(28, 48), UPB_SIZE(3, 4), &val,
+  return _upb_array_append_accessor2(msg, UPB_SIZE(32, 56), UPB_SIZE(3, 4), &val,
       arena);
 }
 UPB_INLINE void envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_set_require_signed_certificate_timestamp(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, struct google_protobuf_BoolValue* value) {
@@ -401,21 +420,34 @@
   *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value;
 }
 UPB_INLINE struct envoy_type_matcher_v3_StringMatcher** envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_mutable_match_subject_alt_names(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t *len) {
-  return (struct envoy_type_matcher_v3_StringMatcher**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 56), len);
+  return (struct envoy_type_matcher_v3_StringMatcher**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 64), len);
 }
 UPB_INLINE struct envoy_type_matcher_v3_StringMatcher** envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_resize_match_subject_alt_names(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, size_t len, upb_arena *arena) {
-  return (struct envoy_type_matcher_v3_StringMatcher**)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 56), len, UPB_SIZE(2, 3), arena);
+  return (struct envoy_type_matcher_v3_StringMatcher**)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 64), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_type_matcher_v3_StringMatcher* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_add_match_subject_alt_names(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, upb_arena *arena) {
   struct envoy_type_matcher_v3_StringMatcher* sub = (struct envoy_type_matcher_v3_StringMatcher*)_upb_msg_new(&envoy_type_matcher_v3_StringMatcher_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(32, 56), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(36, 64), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
 UPB_INLINE void envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_set_trust_chain_verification(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, int32_t value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
 }
+UPB_INLINE void envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_set_watched_directory(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, struct envoy_config_core_v3_WatchedDirectory* value) {
+  _upb_sethas(msg, 4);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 40), struct envoy_config_core_v3_WatchedDirectory*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_WatchedDirectory* envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_mutable_watched_directory(envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_WatchedDirectory* sub = (struct envoy_config_core_v3_WatchedDirectory*)envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_watched_directory(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_WatchedDirectory*)_upb_msg_new(&envoy_config_core_v3_WatchedDirectory_msginit, arena);
+    if (!sub) return NULL;
+    envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_set_watched_directory(msg, sub);
+  }
+  return sub;
+}
 
 #ifdef __cplusplus
 }  /* extern "C" */
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/secret.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/secret.upb.c
index 6dd0296..6717a17 100644
--- a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/secret.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/secret.upb.c
@@ -12,11 +12,10 @@
 #include "envoy/config/core/v3/base.upb.h"
 #include "envoy/config/core/v3/config_source.upb.h"
 #include "envoy/extensions/transport_sockets/tls/v3/common.upb.h"
-#include "udpa/core/v1/resource_locator.upb.h"
-#include "udpa/annotations/migrate.upb.h"
 #include "udpa/annotations/sensitive.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
 
 #include "upb/port_def.inc"
 
@@ -34,21 +33,19 @@
   UPB_SIZE(8, 16), 1, false, 255,
 };
 
-static const upb_msglayout *const envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_submsgs[2] = {
+static const upb_msglayout *const envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_submsgs[1] = {
   &envoy_config_core_v3_ConfigSource_msginit,
-  &udpa_core_v1_ResourceLocator_msginit,
 };
 
-static const upb_msglayout_field envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig__fields[3] = {
+static const upb_msglayout_field envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig__fields[2] = {
   {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
   {2, UPB_SIZE(12, 24), 1, 0, 11, 1},
-  {3, UPB_SIZE(16, 32), 2, 1, 11, 1},
 };
 
 const upb_msglayout envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_msginit = {
   &envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_submsgs[0],
   &envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig__fields[0],
-  UPB_SIZE(24, 48), 3, false, 255,
+  UPB_SIZE(16, 32), 2, false, 255,
 };
 
 static const upb_msglayout *const envoy_extensions_transport_sockets_tls_v3_Secret_submsgs[4] = {
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/secret.upb.h b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/secret.upb.h
index fa33aa9..c576e0a 100644
--- a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/secret.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/secret.upb.h
@@ -34,13 +34,11 @@
 struct envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext;
 struct envoy_extensions_transport_sockets_tls_v3_TlsCertificate;
 struct envoy_extensions_transport_sockets_tls_v3_TlsSessionTicketKeys;
-struct udpa_core_v1_ResourceLocator;
 extern const upb_msglayout envoy_config_core_v3_ConfigSource_msginit;
 extern const upb_msglayout envoy_config_core_v3_DataSource_msginit;
 extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_msginit;
 extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_TlsCertificate_msginit;
 extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_TlsSessionTicketKeys_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_msginit;
 
 
 /* envoy.extensions.transport_sockets.tls.v3.GenericSecret */
@@ -103,8 +101,6 @@
 UPB_INLINE upb_strview envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_name(const envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
 UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_has_sds_config(const envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct envoy_config_core_v3_ConfigSource* envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_sds_config(const envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct envoy_config_core_v3_ConfigSource*); }
-UPB_INLINE bool envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_has_sds_resource_locator(const envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const struct udpa_core_v1_ResourceLocator* envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_sds_resource_locator(const envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct udpa_core_v1_ResourceLocator*); }
 
 UPB_INLINE void envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_set_name(envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
@@ -122,19 +118,6 @@
   }
   return sub;
 }
-UPB_INLINE void envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_set_sds_resource_locator(envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig *msg, struct udpa_core_v1_ResourceLocator* value) {
-  _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct udpa_core_v1_ResourceLocator*) = value;
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator* envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_mutable_sds_resource_locator(envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceLocator* sub = (struct udpa_core_v1_ResourceLocator*)envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_sds_resource_locator(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_ResourceLocator*)_upb_msg_new(&udpa_core_v1_ResourceLocator_msginit, arena);
-    if (!sub) return NULL;
-    envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_set_sds_resource_locator(msg, sub);
-  }
-  return sub;
-}
 
 /* envoy.extensions.transport_sockets.tls.v3.Secret */
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/tls.upb.c b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/tls.upb.c
index 7a5072b..ad5494c 100644
--- a/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/tls.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/tls.upb.c
@@ -12,7 +12,6 @@
 #include "envoy/config/core/v3/extension.upb.h"
 #include "envoy/extensions/transport_sockets/tls/v3/common.upb.h"
 #include "envoy/extensions/transport_sockets/tls/v3/secret.upb.h"
-#include "google/protobuf/any.upb.h"
 #include "google/protobuf/duration.upb.h"
 #include "google/protobuf/wrappers.upb.h"
 #include "udpa/annotations/migrate.upb.h"
diff --git a/grpc/src/core/ext/upb-generated/envoy/service/discovery/v3/discovery.upb.c b/grpc/src/core/ext/upb-generated/envoy/service/discovery/v3/discovery.upb.c
index 9bed2c3..a5b6ac4 100644
--- a/grpc/src/core/ext/upb-generated/envoy/service/discovery/v3/discovery.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/service/discovery/v3/discovery.upb.c
@@ -11,10 +11,8 @@
 #include "envoy/service/discovery/v3/discovery.upb.h"
 #include "envoy/config/core/v3/base.upb.h"
 #include "google/protobuf/any.upb.h"
+#include "google/protobuf/duration.upb.h"
 #include "google/rpc/status.upb.h"
-#include "udpa/core/v1/resource_locator.upb.h"
-#include "udpa/core/v1/resource_name.upb.h"
-#include "udpa/annotations/migrate.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
 
@@ -60,14 +58,13 @@
   UPB_SIZE(40, 80), 6, false, 255,
 };
 
-static const upb_msglayout *const envoy_service_discovery_v3_DeltaDiscoveryRequest_submsgs[4] = {
+static const upb_msglayout *const envoy_service_discovery_v3_DeltaDiscoveryRequest_submsgs[3] = {
   &envoy_config_core_v3_Node_msginit,
   &envoy_service_discovery_v3_DeltaDiscoveryRequest_InitialResourceVersionsEntry_msginit,
   &google_rpc_Status_msginit,
-  &udpa_core_v1_ResourceLocator_msginit,
 };
 
-static const upb_msglayout_field envoy_service_discovery_v3_DeltaDiscoveryRequest__fields[9] = {
+static const upb_msglayout_field envoy_service_discovery_v3_DeltaDiscoveryRequest__fields[7] = {
   {1, UPB_SIZE(20, 40), 1, 0, 11, 1},
   {2, UPB_SIZE(4, 8), 0, 0, 9, 1},
   {3, UPB_SIZE(28, 56), 0, 0, 9, 3},
@@ -75,14 +72,12 @@
   {5, UPB_SIZE(36, 72), 0, 1, 11, _UPB_LABEL_MAP},
   {6, UPB_SIZE(12, 24), 0, 0, 9, 1},
   {7, UPB_SIZE(24, 48), 2, 2, 11, 1},
-  {8, UPB_SIZE(40, 80), 0, 3, 11, 3},
-  {9, UPB_SIZE(44, 88), 0, 3, 11, 3},
 };
 
 const upb_msglayout envoy_service_discovery_v3_DeltaDiscoveryRequest_msginit = {
   &envoy_service_discovery_v3_DeltaDiscoveryRequest_submsgs[0],
   &envoy_service_discovery_v3_DeltaDiscoveryRequest__fields[0],
-  UPB_SIZE(48, 96), 9, false, 255,
+  UPB_SIZE(40, 80), 7, false, 255,
 };
 
 static const upb_msglayout_field envoy_service_discovery_v3_DeltaDiscoveryRequest_InitialResourceVersionsEntry__fields[2] = {
@@ -97,17 +92,17 @@
 };
 
 static const upb_msglayout *const envoy_service_discovery_v3_DeltaDiscoveryResponse_submsgs[2] = {
+  &envoy_config_core_v3_ControlPlane_msginit,
   &envoy_service_discovery_v3_Resource_msginit,
-  &udpa_core_v1_ResourceName_msginit,
 };
 
 static const upb_msglayout_field envoy_service_discovery_v3_DeltaDiscoveryResponse__fields[6] = {
-  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
-  {2, UPB_SIZE(24, 48), 0, 0, 11, 3},
-  {4, UPB_SIZE(8, 16), 0, 0, 9, 1},
-  {5, UPB_SIZE(16, 32), 0, 0, 9, 1},
-  {6, UPB_SIZE(28, 56), 0, 0, 9, 3},
-  {7, UPB_SIZE(32, 64), 0, 1, 11, 3},
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(32, 64), 0, 1, 11, 3},
+  {4, UPB_SIZE(12, 24), 0, 0, 9, 1},
+  {5, UPB_SIZE(20, 40), 0, 0, 9, 1},
+  {6, UPB_SIZE(36, 72), 0, 0, 9, 3},
+  {7, UPB_SIZE(28, 56), 1, 0, 11, 1},
 };
 
 const upb_msglayout envoy_service_discovery_v3_DeltaDiscoveryResponse_msginit = {
@@ -116,23 +111,35 @@
   UPB_SIZE(40, 80), 6, false, 255,
 };
 
-static const upb_msglayout *const envoy_service_discovery_v3_Resource_submsgs[2] = {
+static const upb_msglayout *const envoy_service_discovery_v3_Resource_submsgs[3] = {
+  &envoy_service_discovery_v3_Resource_CacheControl_msginit,
   &google_protobuf_Any_msginit,
-  &udpa_core_v1_ResourceName_msginit,
+  &google_protobuf_Duration_msginit,
 };
 
-static const upb_msglayout_field envoy_service_discovery_v3_Resource__fields[5] = {
+static const upb_msglayout_field envoy_service_discovery_v3_Resource__fields[6] = {
   {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
-  {2, UPB_SIZE(20, 40), 1, 0, 11, 1},
+  {2, UPB_SIZE(20, 40), 1, 1, 11, 1},
   {3, UPB_SIZE(12, 24), 0, 0, 9, 1},
-  {4, UPB_SIZE(28, 56), 0, 0, 9, 3},
-  {5, UPB_SIZE(24, 48), 2, 1, 11, 1},
+  {4, UPB_SIZE(32, 64), 0, 0, 9, 3},
+  {6, UPB_SIZE(24, 48), 2, 2, 11, 1},
+  {7, UPB_SIZE(28, 56), 3, 0, 11, 1},
 };
 
 const upb_msglayout envoy_service_discovery_v3_Resource_msginit = {
   &envoy_service_discovery_v3_Resource_submsgs[0],
   &envoy_service_discovery_v3_Resource__fields[0],
-  UPB_SIZE(32, 64), 5, false, 255,
+  UPB_SIZE(40, 80), 6, false, 255,
+};
+
+static const upb_msglayout_field envoy_service_discovery_v3_Resource_CacheControl__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 8, 1},
+};
+
+const upb_msglayout envoy_service_discovery_v3_Resource_CacheControl_msginit = {
+  NULL,
+  &envoy_service_discovery_v3_Resource_CacheControl__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
 };
 
 #include "upb/port_undef.inc"
diff --git a/grpc/src/core/ext/upb-generated/envoy/service/discovery/v3/discovery.upb.h b/grpc/src/core/ext/upb-generated/envoy/service/discovery/v3/discovery.upb.h
index 715319b..def2787 100644
--- a/grpc/src/core/ext/upb-generated/envoy/service/discovery/v3/discovery.upb.h
+++ b/grpc/src/core/ext/upb-generated/envoy/service/discovery/v3/discovery.upb.h
@@ -26,30 +26,31 @@
 struct envoy_service_discovery_v3_DeltaDiscoveryRequest_InitialResourceVersionsEntry;
 struct envoy_service_discovery_v3_DeltaDiscoveryResponse;
 struct envoy_service_discovery_v3_Resource;
+struct envoy_service_discovery_v3_Resource_CacheControl;
 typedef struct envoy_service_discovery_v3_DiscoveryRequest envoy_service_discovery_v3_DiscoveryRequest;
 typedef struct envoy_service_discovery_v3_DiscoveryResponse envoy_service_discovery_v3_DiscoveryResponse;
 typedef struct envoy_service_discovery_v3_DeltaDiscoveryRequest envoy_service_discovery_v3_DeltaDiscoveryRequest;
 typedef struct envoy_service_discovery_v3_DeltaDiscoveryRequest_InitialResourceVersionsEntry envoy_service_discovery_v3_DeltaDiscoveryRequest_InitialResourceVersionsEntry;
 typedef struct envoy_service_discovery_v3_DeltaDiscoveryResponse envoy_service_discovery_v3_DeltaDiscoveryResponse;
 typedef struct envoy_service_discovery_v3_Resource envoy_service_discovery_v3_Resource;
+typedef struct envoy_service_discovery_v3_Resource_CacheControl envoy_service_discovery_v3_Resource_CacheControl;
 extern const upb_msglayout envoy_service_discovery_v3_DiscoveryRequest_msginit;
 extern const upb_msglayout envoy_service_discovery_v3_DiscoveryResponse_msginit;
 extern const upb_msglayout envoy_service_discovery_v3_DeltaDiscoveryRequest_msginit;
 extern const upb_msglayout envoy_service_discovery_v3_DeltaDiscoveryRequest_InitialResourceVersionsEntry_msginit;
 extern const upb_msglayout envoy_service_discovery_v3_DeltaDiscoveryResponse_msginit;
 extern const upb_msglayout envoy_service_discovery_v3_Resource_msginit;
+extern const upb_msglayout envoy_service_discovery_v3_Resource_CacheControl_msginit;
 struct envoy_config_core_v3_ControlPlane;
 struct envoy_config_core_v3_Node;
 struct google_protobuf_Any;
+struct google_protobuf_Duration;
 struct google_rpc_Status;
-struct udpa_core_v1_ResourceLocator;
-struct udpa_core_v1_ResourceName;
 extern const upb_msglayout envoy_config_core_v3_ControlPlane_msginit;
 extern const upb_msglayout envoy_config_core_v3_Node_msginit;
 extern const upb_msglayout google_protobuf_Any_msginit;
+extern const upb_msglayout google_protobuf_Duration_msginit;
 extern const upb_msglayout google_rpc_Status_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceName_msginit;
 
 
 /* envoy.service.discovery.v3.DiscoveryRequest */
@@ -227,10 +228,6 @@
 UPB_INLINE upb_strview envoy_service_discovery_v3_DeltaDiscoveryRequest_response_nonce(const envoy_service_discovery_v3_DeltaDiscoveryRequest *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
 UPB_INLINE bool envoy_service_discovery_v3_DeltaDiscoveryRequest_has_error_detail(const envoy_service_discovery_v3_DeltaDiscoveryRequest *msg) { return _upb_hasbit(msg, 2); }
 UPB_INLINE const struct google_rpc_Status* envoy_service_discovery_v3_DeltaDiscoveryRequest_error_detail(const envoy_service_discovery_v3_DeltaDiscoveryRequest *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), const struct google_rpc_Status*); }
-UPB_INLINE bool envoy_service_discovery_v3_DeltaDiscoveryRequest_has_udpa_resources_subscribe(const envoy_service_discovery_v3_DeltaDiscoveryRequest *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); }
-UPB_INLINE const struct udpa_core_v1_ResourceLocator* const* envoy_service_discovery_v3_DeltaDiscoveryRequest_udpa_resources_subscribe(const envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, size_t *len) { return (const struct udpa_core_v1_ResourceLocator* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); }
-UPB_INLINE bool envoy_service_discovery_v3_DeltaDiscoveryRequest_has_udpa_resources_unsubscribe(const envoy_service_discovery_v3_DeltaDiscoveryRequest *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); }
-UPB_INLINE const struct udpa_core_v1_ResourceLocator* const* envoy_service_discovery_v3_DeltaDiscoveryRequest_udpa_resources_unsubscribe(const envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, size_t *len) { return (const struct udpa_core_v1_ResourceLocator* const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); }
 
 UPB_INLINE void envoy_service_discovery_v3_DeltaDiscoveryRequest_set_node(envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, struct envoy_config_core_v3_Node* value) {
   _upb_sethas(msg, 1);
@@ -288,32 +285,6 @@
   }
   return sub;
 }
-UPB_INLINE struct udpa_core_v1_ResourceLocator** envoy_service_discovery_v3_DeltaDiscoveryRequest_mutable_udpa_resources_subscribe(envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, size_t *len) {
-  return (struct udpa_core_v1_ResourceLocator**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len);
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator** envoy_service_discovery_v3_DeltaDiscoveryRequest_resize_udpa_resources_subscribe(envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, size_t len, upb_arena *arena) {
-  return (struct udpa_core_v1_ResourceLocator**)_upb_array_resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena);
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator* envoy_service_discovery_v3_DeltaDiscoveryRequest_add_udpa_resources_subscribe(envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceLocator* sub = (struct udpa_core_v1_ResourceLocator*)_upb_msg_new(&udpa_core_v1_ResourceLocator_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena);
-  if (!ok) return NULL;
-  return sub;
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator** envoy_service_discovery_v3_DeltaDiscoveryRequest_mutable_udpa_resources_unsubscribe(envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, size_t *len) {
-  return (struct udpa_core_v1_ResourceLocator**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len);
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator** envoy_service_discovery_v3_DeltaDiscoveryRequest_resize_udpa_resources_unsubscribe(envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, size_t len, upb_arena *arena) {
-  return (struct udpa_core_v1_ResourceLocator**)_upb_array_resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena);
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator* envoy_service_discovery_v3_DeltaDiscoveryRequest_add_udpa_resources_unsubscribe(envoy_service_discovery_v3_DeltaDiscoveryRequest *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceLocator* sub = (struct udpa_core_v1_ResourceLocator*)_upb_msg_new(&udpa_core_v1_ResourceLocator_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena);
-  if (!ok) return NULL;
-  return sub;
-}
 
 /* envoy.service.discovery.v3.DeltaDiscoveryRequest.InitialResourceVersionsEntry */
 
@@ -352,58 +323,58 @@
   return upb_encode(msg, &envoy_service_discovery_v3_DeltaDiscoveryResponse_msginit, arena, len);
 }
 
-UPB_INLINE upb_strview envoy_service_discovery_v3_DeltaDiscoveryResponse_system_version_info(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
-UPB_INLINE bool envoy_service_discovery_v3_DeltaDiscoveryResponse_has_resources(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); }
-UPB_INLINE const envoy_service_discovery_v3_Resource* const* envoy_service_discovery_v3_DeltaDiscoveryResponse_resources(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t *len) { return (const envoy_service_discovery_v3_Resource* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
-UPB_INLINE upb_strview envoy_service_discovery_v3_DeltaDiscoveryResponse_type_url(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_strview); }
-UPB_INLINE upb_strview envoy_service_discovery_v3_DeltaDiscoveryResponse_nonce(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_strview); }
-UPB_INLINE upb_strview const* envoy_service_discovery_v3_DeltaDiscoveryResponse_removed_resources(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
-UPB_INLINE bool envoy_service_discovery_v3_DeltaDiscoveryResponse_has_udpa_removed_resources(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); }
-UPB_INLINE const struct udpa_core_v1_ResourceName* const* envoy_service_discovery_v3_DeltaDiscoveryResponse_udpa_removed_resources(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t *len) { return (const struct udpa_core_v1_ResourceName* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); }
+UPB_INLINE upb_strview envoy_service_discovery_v3_DeltaDiscoveryResponse_system_version_info(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool envoy_service_discovery_v3_DeltaDiscoveryResponse_has_resources(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); }
+UPB_INLINE const envoy_service_discovery_v3_Resource* const* envoy_service_discovery_v3_DeltaDiscoveryResponse_resources(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t *len) { return (const envoy_service_discovery_v3_Resource* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); }
+UPB_INLINE upb_strview envoy_service_discovery_v3_DeltaDiscoveryResponse_type_url(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE upb_strview envoy_service_discovery_v3_DeltaDiscoveryResponse_nonce(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
+UPB_INLINE upb_strview const* envoy_service_discovery_v3_DeltaDiscoveryResponse_removed_resources(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
+UPB_INLINE bool envoy_service_discovery_v3_DeltaDiscoveryResponse_has_control_plane(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_ControlPlane* envoy_service_discovery_v3_DeltaDiscoveryResponse_control_plane(const envoy_service_discovery_v3_DeltaDiscoveryResponse *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const struct envoy_config_core_v3_ControlPlane*); }
 
 UPB_INLINE void envoy_service_discovery_v3_DeltaDiscoveryResponse_set_system_version_info(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
 }
 UPB_INLINE envoy_service_discovery_v3_Resource** envoy_service_discovery_v3_DeltaDiscoveryResponse_mutable_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t *len) {
-  return (envoy_service_discovery_v3_Resource**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
+  return (envoy_service_discovery_v3_Resource**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len);
 }
 UPB_INLINE envoy_service_discovery_v3_Resource** envoy_service_discovery_v3_DeltaDiscoveryResponse_resize_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t len, upb_arena *arena) {
-  return (envoy_service_discovery_v3_Resource**)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena);
+  return (envoy_service_discovery_v3_Resource**)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena);
 }
 UPB_INLINE struct envoy_service_discovery_v3_Resource* envoy_service_discovery_v3_DeltaDiscoveryResponse_add_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, upb_arena *arena) {
   struct envoy_service_discovery_v3_Resource* sub = (struct envoy_service_discovery_v3_Resource*)_upb_msg_new(&envoy_service_discovery_v3_Resource_msginit, arena);
   bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena);
+      msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
 UPB_INLINE void envoy_service_discovery_v3_DeltaDiscoveryResponse_set_type_url(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
 }
 UPB_INLINE void envoy_service_discovery_v3_DeltaDiscoveryResponse_set_nonce(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
 }
 UPB_INLINE upb_strview* envoy_service_discovery_v3_DeltaDiscoveryResponse_mutable_removed_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
 }
 UPB_INLINE upb_strview* envoy_service_discovery_v3_DeltaDiscoveryResponse_resize_removed_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena);
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena);
 }
 UPB_INLINE bool envoy_service_discovery_v3_DeltaDiscoveryResponse_add_removed_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val,
+  return _upb_array_append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val,
       arena);
 }
-UPB_INLINE struct udpa_core_v1_ResourceName** envoy_service_discovery_v3_DeltaDiscoveryResponse_mutable_udpa_removed_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t *len) {
-  return (struct udpa_core_v1_ResourceName**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len);
+UPB_INLINE void envoy_service_discovery_v3_DeltaDiscoveryResponse_set_control_plane(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, struct envoy_config_core_v3_ControlPlane* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 56), struct envoy_config_core_v3_ControlPlane*) = value;
 }
-UPB_INLINE struct udpa_core_v1_ResourceName** envoy_service_discovery_v3_DeltaDiscoveryResponse_resize_udpa_removed_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, size_t len, upb_arena *arena) {
-  return (struct udpa_core_v1_ResourceName**)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena);
-}
-UPB_INLINE struct udpa_core_v1_ResourceName* envoy_service_discovery_v3_DeltaDiscoveryResponse_add_udpa_removed_resources(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceName* sub = (struct udpa_core_v1_ResourceName*)_upb_msg_new(&udpa_core_v1_ResourceName_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena);
-  if (!ok) return NULL;
+UPB_INLINE struct envoy_config_core_v3_ControlPlane* envoy_service_discovery_v3_DeltaDiscoveryResponse_mutable_control_plane(envoy_service_discovery_v3_DeltaDiscoveryResponse *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_ControlPlane* sub = (struct envoy_config_core_v3_ControlPlane*)envoy_service_discovery_v3_DeltaDiscoveryResponse_control_plane(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_ControlPlane*)_upb_msg_new(&envoy_config_core_v3_ControlPlane_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_discovery_v3_DeltaDiscoveryResponse_set_control_plane(msg, sub);
+  }
   return sub;
 }
 
@@ -431,9 +402,11 @@
 UPB_INLINE bool envoy_service_discovery_v3_Resource_has_resource(const envoy_service_discovery_v3_Resource *msg) { return _upb_hasbit(msg, 1); }
 UPB_INLINE const struct google_protobuf_Any* envoy_service_discovery_v3_Resource_resource(const envoy_service_discovery_v3_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct google_protobuf_Any*); }
 UPB_INLINE upb_strview envoy_service_discovery_v3_Resource_name(const envoy_service_discovery_v3_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
-UPB_INLINE upb_strview const* envoy_service_discovery_v3_Resource_aliases(const envoy_service_discovery_v3_Resource *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
-UPB_INLINE bool envoy_service_discovery_v3_Resource_has_udpa_resource_name(const envoy_service_discovery_v3_Resource *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const struct udpa_core_v1_ResourceName* envoy_service_discovery_v3_Resource_udpa_resource_name(const envoy_service_discovery_v3_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), const struct udpa_core_v1_ResourceName*); }
+UPB_INLINE upb_strview const* envoy_service_discovery_v3_Resource_aliases(const envoy_service_discovery_v3_Resource *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); }
+UPB_INLINE bool envoy_service_discovery_v3_Resource_has_ttl(const envoy_service_discovery_v3_Resource *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Duration* envoy_service_discovery_v3_Resource_ttl(const envoy_service_discovery_v3_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), const struct google_protobuf_Duration*); }
+UPB_INLINE bool envoy_service_discovery_v3_Resource_has_cache_control(const envoy_service_discovery_v3_Resource *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const envoy_service_discovery_v3_Resource_CacheControl* envoy_service_discovery_v3_Resource_cache_control(const envoy_service_discovery_v3_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const envoy_service_discovery_v3_Resource_CacheControl*); }
 
 UPB_INLINE void envoy_service_discovery_v3_Resource_set_version(envoy_service_discovery_v3_Resource *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
@@ -455,28 +428,67 @@
   *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
 }
 UPB_INLINE upb_strview* envoy_service_discovery_v3_Resource_mutable_aliases(envoy_service_discovery_v3_Resource *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len);
 }
 UPB_INLINE upb_strview* envoy_service_discovery_v3_Resource_resize_aliases(envoy_service_discovery_v3_Resource *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena);
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(3, 4), arena);
 }
 UPB_INLINE bool envoy_service_discovery_v3_Resource_add_aliases(envoy_service_discovery_v3_Resource *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val,
+  return _upb_array_append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(3, 4), &val,
       arena);
 }
-UPB_INLINE void envoy_service_discovery_v3_Resource_set_udpa_resource_name(envoy_service_discovery_v3_Resource *msg, struct udpa_core_v1_ResourceName* value) {
+UPB_INLINE void envoy_service_discovery_v3_Resource_set_ttl(envoy_service_discovery_v3_Resource *msg, struct google_protobuf_Duration* value) {
   _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(24, 48), struct udpa_core_v1_ResourceName*) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 48), struct google_protobuf_Duration*) = value;
 }
-UPB_INLINE struct udpa_core_v1_ResourceName* envoy_service_discovery_v3_Resource_mutable_udpa_resource_name(envoy_service_discovery_v3_Resource *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceName* sub = (struct udpa_core_v1_ResourceName*)envoy_service_discovery_v3_Resource_udpa_resource_name(msg);
+UPB_INLINE struct google_protobuf_Duration* envoy_service_discovery_v3_Resource_mutable_ttl(envoy_service_discovery_v3_Resource *msg, upb_arena *arena) {
+  struct google_protobuf_Duration* sub = (struct google_protobuf_Duration*)envoy_service_discovery_v3_Resource_ttl(msg);
   if (sub == NULL) {
-    sub = (struct udpa_core_v1_ResourceName*)_upb_msg_new(&udpa_core_v1_ResourceName_msginit, arena);
+    sub = (struct google_protobuf_Duration*)_upb_msg_new(&google_protobuf_Duration_msginit, arena);
     if (!sub) return NULL;
-    envoy_service_discovery_v3_Resource_set_udpa_resource_name(msg, sub);
+    envoy_service_discovery_v3_Resource_set_ttl(msg, sub);
   }
   return sub;
 }
+UPB_INLINE void envoy_service_discovery_v3_Resource_set_cache_control(envoy_service_discovery_v3_Resource *msg, envoy_service_discovery_v3_Resource_CacheControl* value) {
+  _upb_sethas(msg, 3);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 56), envoy_service_discovery_v3_Resource_CacheControl*) = value;
+}
+UPB_INLINE struct envoy_service_discovery_v3_Resource_CacheControl* envoy_service_discovery_v3_Resource_mutable_cache_control(envoy_service_discovery_v3_Resource *msg, upb_arena *arena) {
+  struct envoy_service_discovery_v3_Resource_CacheControl* sub = (struct envoy_service_discovery_v3_Resource_CacheControl*)envoy_service_discovery_v3_Resource_cache_control(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_service_discovery_v3_Resource_CacheControl*)_upb_msg_new(&envoy_service_discovery_v3_Resource_CacheControl_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_discovery_v3_Resource_set_cache_control(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.service.discovery.v3.Resource.CacheControl */
+
+UPB_INLINE envoy_service_discovery_v3_Resource_CacheControl *envoy_service_discovery_v3_Resource_CacheControl_new(upb_arena *arena) {
+  return (envoy_service_discovery_v3_Resource_CacheControl *)_upb_msg_new(&envoy_service_discovery_v3_Resource_CacheControl_msginit, arena);
+}
+UPB_INLINE envoy_service_discovery_v3_Resource_CacheControl *envoy_service_discovery_v3_Resource_CacheControl_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_service_discovery_v3_Resource_CacheControl *ret = envoy_service_discovery_v3_Resource_CacheControl_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_service_discovery_v3_Resource_CacheControl_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_service_discovery_v3_Resource_CacheControl *envoy_service_discovery_v3_Resource_CacheControl_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_service_discovery_v3_Resource_CacheControl *ret = envoy_service_discovery_v3_Resource_CacheControl_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_service_discovery_v3_Resource_CacheControl_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_service_discovery_v3_Resource_CacheControl_serialize(const envoy_service_discovery_v3_Resource_CacheControl *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_service_discovery_v3_Resource_CacheControl_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_service_discovery_v3_Resource_CacheControl_do_not_cache(const envoy_service_discovery_v3_Resource_CacheControl *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), bool); }
+
+UPB_INLINE void envoy_service_discovery_v3_Resource_CacheControl_set_do_not_cache(envoy_service_discovery_v3_Resource_CacheControl *msg, bool value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), bool) = value;
+}
 
 #ifdef __cplusplus
 }  /* extern "C" */
diff --git a/grpc/src/core/ext/upb-generated/envoy/service/endpoint/v3/eds.upb.c b/grpc/src/core/ext/upb-generated/envoy/service/endpoint/v3/eds.upb.c
index 1e22923..0af0480 100644
--- a/grpc/src/core/ext/upb-generated/envoy/service/endpoint/v3/eds.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/service/endpoint/v3/eds.upb.c
@@ -11,12 +11,9 @@
 #include "envoy/service/endpoint/v3/eds.upb.h"
 #include "envoy/service/discovery/v3/discovery.upb.h"
 #include "google/api/annotations.upb.h"
-#include "google/protobuf/duration.upb.h"
-#include "google/protobuf/wrappers.upb.h"
 #include "envoy/annotations/resource.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
-#include "validate/validate.upb.h"
 
 #include "upb/port_def.inc"
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/service/listener/v3/lds.upb.c b/grpc/src/core/ext/upb-generated/envoy/service/listener/v3/lds.upb.c
index e00bfc2..404bfa4 100644
--- a/grpc/src/core/ext/upb-generated/envoy/service/listener/v3/lds.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/service/listener/v3/lds.upb.c
@@ -11,12 +11,9 @@
 #include "envoy/service/listener/v3/lds.upb.h"
 #include "envoy/service/discovery/v3/discovery.upb.h"
 #include "google/api/annotations.upb.h"
-#include "google/protobuf/duration.upb.h"
-#include "google/protobuf/wrappers.upb.h"
 #include "envoy/annotations/resource.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
-#include "validate/validate.upb.h"
 
 #include "upb/port_def.inc"
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c b/grpc/src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c
index c806a85..68fe078 100644
--- a/grpc/src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/service/load_stats/v3/lrs.upb.c
@@ -14,7 +14,6 @@
 #include "google/protobuf/duration.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
-#include "validate/validate.upb.h"
 
 #include "upb/port_def.inc"
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c b/grpc/src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c
index 93970b1..07d17f6 100644
--- a/grpc/src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.c
@@ -11,11 +11,9 @@
 #include "envoy/service/route/v3/rds.upb.h"
 #include "envoy/service/discovery/v3/discovery.upb.h"
 #include "google/api/annotations.upb.h"
-#include "google/protobuf/wrappers.upb.h"
 #include "envoy/annotations/resource.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
-#include "validate/validate.upb.h"
 
 #include "upb/port_def.inc"
 
diff --git a/grpc/src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c b/grpc/src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c
new file mode 100644
index 0000000..40e086c
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c
@@ -0,0 +1,93 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/service/status/v3/csds.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/service/status/v3/csds.upb.h"
+#include "envoy/admin/v3/config_dump.upb.h"
+#include "envoy/config/core/v3/base.upb.h"
+#include "envoy/type/matcher/v3/node.upb.h"
+#include "google/api/annotations.upb.h"
+#include "udpa/annotations/migrate.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_service_status_v3_ClientStatusRequest_submsgs[2] = {
+  &envoy_config_core_v3_Node_msginit,
+  &envoy_type_matcher_v3_NodeMatcher_msginit,
+};
+
+static const upb_msglayout_field envoy_service_status_v3_ClientStatusRequest__fields[2] = {
+  {1, UPB_SIZE(8, 16), 0, 1, 11, 3},
+  {2, UPB_SIZE(4, 8), 1, 0, 11, 1},
+};
+
+const upb_msglayout envoy_service_status_v3_ClientStatusRequest_msginit = {
+  &envoy_service_status_v3_ClientStatusRequest_submsgs[0],
+  &envoy_service_status_v3_ClientStatusRequest__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_service_status_v3_PerXdsConfig_submsgs[5] = {
+  &envoy_admin_v3_ClustersConfigDump_msginit,
+  &envoy_admin_v3_EndpointsConfigDump_msginit,
+  &envoy_admin_v3_ListenersConfigDump_msginit,
+  &envoy_admin_v3_RoutesConfigDump_msginit,
+  &envoy_admin_v3_ScopedRoutesConfigDump_msginit,
+};
+
+static const upb_msglayout_field envoy_service_status_v3_PerXdsConfig__fields[7] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 14, 1},
+  {2, UPB_SIZE(8, 8), UPB_SIZE(-13, -17), 2, 11, 1},
+  {3, UPB_SIZE(8, 8), UPB_SIZE(-13, -17), 0, 11, 1},
+  {4, UPB_SIZE(8, 8), UPB_SIZE(-13, -17), 3, 11, 1},
+  {5, UPB_SIZE(8, 8), UPB_SIZE(-13, -17), 4, 11, 1},
+  {6, UPB_SIZE(8, 8), UPB_SIZE(-13, -17), 1, 11, 1},
+  {7, UPB_SIZE(4, 4), 0, 0, 14, 1},
+};
+
+const upb_msglayout envoy_service_status_v3_PerXdsConfig_msginit = {
+  &envoy_service_status_v3_PerXdsConfig_submsgs[0],
+  &envoy_service_status_v3_PerXdsConfig__fields[0],
+  UPB_SIZE(16, 24), 7, false, 255,
+};
+
+static const upb_msglayout *const envoy_service_status_v3_ClientConfig_submsgs[2] = {
+  &envoy_config_core_v3_Node_msginit,
+  &envoy_service_status_v3_PerXdsConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_service_status_v3_ClientConfig__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 0, 1, 11, 3},
+};
+
+const upb_msglayout envoy_service_status_v3_ClientConfig_msginit = {
+  &envoy_service_status_v3_ClientConfig_submsgs[0],
+  &envoy_service_status_v3_ClientConfig__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout *const envoy_service_status_v3_ClientStatusResponse_submsgs[1] = {
+  &envoy_service_status_v3_ClientConfig_msginit,
+};
+
+static const upb_msglayout_field envoy_service_status_v3_ClientStatusResponse__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 11, 3},
+};
+
+const upb_msglayout envoy_service_status_v3_ClientStatusResponse_msginit = {
+  &envoy_service_status_v3_ClientStatusResponse_submsgs[0],
+  &envoy_service_status_v3_ClientStatusResponse__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h b/grpc/src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h
new file mode 100644
index 0000000..87f807c
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h
@@ -0,0 +1,323 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/service/status/v3/csds.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_SERVICE_STATUS_V3_CSDS_PROTO_UPB_H_
+#define ENVOY_SERVICE_STATUS_V3_CSDS_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_service_status_v3_ClientStatusRequest;
+struct envoy_service_status_v3_PerXdsConfig;
+struct envoy_service_status_v3_ClientConfig;
+struct envoy_service_status_v3_ClientStatusResponse;
+typedef struct envoy_service_status_v3_ClientStatusRequest envoy_service_status_v3_ClientStatusRequest;
+typedef struct envoy_service_status_v3_PerXdsConfig envoy_service_status_v3_PerXdsConfig;
+typedef struct envoy_service_status_v3_ClientConfig envoy_service_status_v3_ClientConfig;
+typedef struct envoy_service_status_v3_ClientStatusResponse envoy_service_status_v3_ClientStatusResponse;
+extern const upb_msglayout envoy_service_status_v3_ClientStatusRequest_msginit;
+extern const upb_msglayout envoy_service_status_v3_PerXdsConfig_msginit;
+extern const upb_msglayout envoy_service_status_v3_ClientConfig_msginit;
+extern const upb_msglayout envoy_service_status_v3_ClientStatusResponse_msginit;
+struct envoy_admin_v3_ClustersConfigDump;
+struct envoy_admin_v3_EndpointsConfigDump;
+struct envoy_admin_v3_ListenersConfigDump;
+struct envoy_admin_v3_RoutesConfigDump;
+struct envoy_admin_v3_ScopedRoutesConfigDump;
+struct envoy_config_core_v3_Node;
+struct envoy_type_matcher_v3_NodeMatcher;
+extern const upb_msglayout envoy_admin_v3_ClustersConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_EndpointsConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_RoutesConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_msginit;
+extern const upb_msglayout envoy_config_core_v3_Node_msginit;
+extern const upb_msglayout envoy_type_matcher_v3_NodeMatcher_msginit;
+
+typedef enum {
+  envoy_service_status_v3_CLIENT_UNKNOWN = 0,
+  envoy_service_status_v3_CLIENT_REQUESTED = 1,
+  envoy_service_status_v3_CLIENT_ACKED = 2,
+  envoy_service_status_v3_CLIENT_NACKED = 3
+} envoy_service_status_v3_ClientConfigStatus;
+
+typedef enum {
+  envoy_service_status_v3_UNKNOWN = 0,
+  envoy_service_status_v3_SYNCED = 1,
+  envoy_service_status_v3_NOT_SENT = 2,
+  envoy_service_status_v3_STALE = 3,
+  envoy_service_status_v3_ERROR = 4
+} envoy_service_status_v3_ConfigStatus;
+
+
+/* envoy.service.status.v3.ClientStatusRequest */
+
+UPB_INLINE envoy_service_status_v3_ClientStatusRequest *envoy_service_status_v3_ClientStatusRequest_new(upb_arena *arena) {
+  return (envoy_service_status_v3_ClientStatusRequest *)_upb_msg_new(&envoy_service_status_v3_ClientStatusRequest_msginit, arena);
+}
+UPB_INLINE envoy_service_status_v3_ClientStatusRequest *envoy_service_status_v3_ClientStatusRequest_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_service_status_v3_ClientStatusRequest *ret = envoy_service_status_v3_ClientStatusRequest_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_service_status_v3_ClientStatusRequest_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_service_status_v3_ClientStatusRequest *envoy_service_status_v3_ClientStatusRequest_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_service_status_v3_ClientStatusRequest *ret = envoy_service_status_v3_ClientStatusRequest_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_service_status_v3_ClientStatusRequest_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_service_status_v3_ClientStatusRequest_serialize(const envoy_service_status_v3_ClientStatusRequest *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_service_status_v3_ClientStatusRequest_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_service_status_v3_ClientStatusRequest_has_node_matchers(const envoy_service_status_v3_ClientStatusRequest *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const struct envoy_type_matcher_v3_NodeMatcher* const* envoy_service_status_v3_ClientStatusRequest_node_matchers(const envoy_service_status_v3_ClientStatusRequest *msg, size_t *len) { return (const struct envoy_type_matcher_v3_NodeMatcher* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+UPB_INLINE bool envoy_service_status_v3_ClientStatusRequest_has_node(const envoy_service_status_v3_ClientStatusRequest *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_Node* envoy_service_status_v3_ClientStatusRequest_node(const envoy_service_status_v3_ClientStatusRequest *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_config_core_v3_Node*); }
+
+UPB_INLINE struct envoy_type_matcher_v3_NodeMatcher** envoy_service_status_v3_ClientStatusRequest_mutable_node_matchers(envoy_service_status_v3_ClientStatusRequest *msg, size_t *len) {
+  return (struct envoy_type_matcher_v3_NodeMatcher**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE struct envoy_type_matcher_v3_NodeMatcher** envoy_service_status_v3_ClientStatusRequest_resize_node_matchers(envoy_service_status_v3_ClientStatusRequest *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_type_matcher_v3_NodeMatcher**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_type_matcher_v3_NodeMatcher* envoy_service_status_v3_ClientStatusRequest_add_node_matchers(envoy_service_status_v3_ClientStatusRequest *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_NodeMatcher* sub = (struct envoy_type_matcher_v3_NodeMatcher*)_upb_msg_new(&envoy_type_matcher_v3_NodeMatcher_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_service_status_v3_ClientStatusRequest_set_node(envoy_service_status_v3_ClientStatusRequest *msg, struct envoy_config_core_v3_Node* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_config_core_v3_Node*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_Node* envoy_service_status_v3_ClientStatusRequest_mutable_node(envoy_service_status_v3_ClientStatusRequest *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_Node* sub = (struct envoy_config_core_v3_Node*)envoy_service_status_v3_ClientStatusRequest_node(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_Node*)_upb_msg_new(&envoy_config_core_v3_Node_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_status_v3_ClientStatusRequest_set_node(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.service.status.v3.PerXdsConfig */
+
+UPB_INLINE envoy_service_status_v3_PerXdsConfig *envoy_service_status_v3_PerXdsConfig_new(upb_arena *arena) {
+  return (envoy_service_status_v3_PerXdsConfig *)_upb_msg_new(&envoy_service_status_v3_PerXdsConfig_msginit, arena);
+}
+UPB_INLINE envoy_service_status_v3_PerXdsConfig *envoy_service_status_v3_PerXdsConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_service_status_v3_PerXdsConfig *ret = envoy_service_status_v3_PerXdsConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_service_status_v3_PerXdsConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_service_status_v3_PerXdsConfig *envoy_service_status_v3_PerXdsConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_service_status_v3_PerXdsConfig *ret = envoy_service_status_v3_PerXdsConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_service_status_v3_PerXdsConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_service_status_v3_PerXdsConfig_serialize(const envoy_service_status_v3_PerXdsConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_service_status_v3_PerXdsConfig_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_service_status_v3_PerXdsConfig_per_xds_config_listener_config = 2,
+  envoy_service_status_v3_PerXdsConfig_per_xds_config_cluster_config = 3,
+  envoy_service_status_v3_PerXdsConfig_per_xds_config_route_config = 4,
+  envoy_service_status_v3_PerXdsConfig_per_xds_config_scoped_route_config = 5,
+  envoy_service_status_v3_PerXdsConfig_per_xds_config_endpoint_config = 6,
+  envoy_service_status_v3_PerXdsConfig_per_xds_config_NOT_SET = 0
+} envoy_service_status_v3_PerXdsConfig_per_xds_config_oneofcases;
+UPB_INLINE envoy_service_status_v3_PerXdsConfig_per_xds_config_oneofcases envoy_service_status_v3_PerXdsConfig_per_xds_config_case(const envoy_service_status_v3_PerXdsConfig* msg) { return (envoy_service_status_v3_PerXdsConfig_per_xds_config_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(12, 16), int32_t); }
+
+UPB_INLINE int32_t envoy_service_status_v3_PerXdsConfig_status(const envoy_service_status_v3_PerXdsConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int32_t); }
+UPB_INLINE bool envoy_service_status_v3_PerXdsConfig_has_listener_config(const envoy_service_status_v3_PerXdsConfig *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 16)) == 2; }
+UPB_INLINE const struct envoy_admin_v3_ListenersConfigDump* envoy_service_status_v3_PerXdsConfig_listener_config(const envoy_service_status_v3_PerXdsConfig *msg) { return UPB_READ_ONEOF(msg, const struct envoy_admin_v3_ListenersConfigDump*, UPB_SIZE(8, 8), UPB_SIZE(12, 16), 2, NULL); }
+UPB_INLINE bool envoy_service_status_v3_PerXdsConfig_has_cluster_config(const envoy_service_status_v3_PerXdsConfig *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 16)) == 3; }
+UPB_INLINE const struct envoy_admin_v3_ClustersConfigDump* envoy_service_status_v3_PerXdsConfig_cluster_config(const envoy_service_status_v3_PerXdsConfig *msg) { return UPB_READ_ONEOF(msg, const struct envoy_admin_v3_ClustersConfigDump*, UPB_SIZE(8, 8), UPB_SIZE(12, 16), 3, NULL); }
+UPB_INLINE bool envoy_service_status_v3_PerXdsConfig_has_route_config(const envoy_service_status_v3_PerXdsConfig *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 16)) == 4; }
+UPB_INLINE const struct envoy_admin_v3_RoutesConfigDump* envoy_service_status_v3_PerXdsConfig_route_config(const envoy_service_status_v3_PerXdsConfig *msg) { return UPB_READ_ONEOF(msg, const struct envoy_admin_v3_RoutesConfigDump*, UPB_SIZE(8, 8), UPB_SIZE(12, 16), 4, NULL); }
+UPB_INLINE bool envoy_service_status_v3_PerXdsConfig_has_scoped_route_config(const envoy_service_status_v3_PerXdsConfig *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 16)) == 5; }
+UPB_INLINE const struct envoy_admin_v3_ScopedRoutesConfigDump* envoy_service_status_v3_PerXdsConfig_scoped_route_config(const envoy_service_status_v3_PerXdsConfig *msg) { return UPB_READ_ONEOF(msg, const struct envoy_admin_v3_ScopedRoutesConfigDump*, UPB_SIZE(8, 8), UPB_SIZE(12, 16), 5, NULL); }
+UPB_INLINE bool envoy_service_status_v3_PerXdsConfig_has_endpoint_config(const envoy_service_status_v3_PerXdsConfig *msg) { return _upb_getoneofcase(msg, UPB_SIZE(12, 16)) == 6; }
+UPB_INLINE const struct envoy_admin_v3_EndpointsConfigDump* envoy_service_status_v3_PerXdsConfig_endpoint_config(const envoy_service_status_v3_PerXdsConfig *msg) { return UPB_READ_ONEOF(msg, const struct envoy_admin_v3_EndpointsConfigDump*, UPB_SIZE(8, 8), UPB_SIZE(12, 16), 6, NULL); }
+UPB_INLINE int32_t envoy_service_status_v3_PerXdsConfig_client_status(const envoy_service_status_v3_PerXdsConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+
+UPB_INLINE void envoy_service_status_v3_PerXdsConfig_set_status(envoy_service_status_v3_PerXdsConfig *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int32_t) = value;
+}
+UPB_INLINE void envoy_service_status_v3_PerXdsConfig_set_listener_config(envoy_service_status_v3_PerXdsConfig *msg, struct envoy_admin_v3_ListenersConfigDump* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_admin_v3_ListenersConfigDump*, UPB_SIZE(8, 8), value, UPB_SIZE(12, 16), 2);
+}
+UPB_INLINE struct envoy_admin_v3_ListenersConfigDump* envoy_service_status_v3_PerXdsConfig_mutable_listener_config(envoy_service_status_v3_PerXdsConfig *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ListenersConfigDump* sub = (struct envoy_admin_v3_ListenersConfigDump*)envoy_service_status_v3_PerXdsConfig_listener_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_ListenersConfigDump*)_upb_msg_new(&envoy_admin_v3_ListenersConfigDump_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_status_v3_PerXdsConfig_set_listener_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_service_status_v3_PerXdsConfig_set_cluster_config(envoy_service_status_v3_PerXdsConfig *msg, struct envoy_admin_v3_ClustersConfigDump* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_admin_v3_ClustersConfigDump*, UPB_SIZE(8, 8), value, UPB_SIZE(12, 16), 3);
+}
+UPB_INLINE struct envoy_admin_v3_ClustersConfigDump* envoy_service_status_v3_PerXdsConfig_mutable_cluster_config(envoy_service_status_v3_PerXdsConfig *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ClustersConfigDump* sub = (struct envoy_admin_v3_ClustersConfigDump*)envoy_service_status_v3_PerXdsConfig_cluster_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_ClustersConfigDump*)_upb_msg_new(&envoy_admin_v3_ClustersConfigDump_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_status_v3_PerXdsConfig_set_cluster_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_service_status_v3_PerXdsConfig_set_route_config(envoy_service_status_v3_PerXdsConfig *msg, struct envoy_admin_v3_RoutesConfigDump* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_admin_v3_RoutesConfigDump*, UPB_SIZE(8, 8), value, UPB_SIZE(12, 16), 4);
+}
+UPB_INLINE struct envoy_admin_v3_RoutesConfigDump* envoy_service_status_v3_PerXdsConfig_mutable_route_config(envoy_service_status_v3_PerXdsConfig *msg, upb_arena *arena) {
+  struct envoy_admin_v3_RoutesConfigDump* sub = (struct envoy_admin_v3_RoutesConfigDump*)envoy_service_status_v3_PerXdsConfig_route_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_RoutesConfigDump*)_upb_msg_new(&envoy_admin_v3_RoutesConfigDump_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_status_v3_PerXdsConfig_set_route_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_service_status_v3_PerXdsConfig_set_scoped_route_config(envoy_service_status_v3_PerXdsConfig *msg, struct envoy_admin_v3_ScopedRoutesConfigDump* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_admin_v3_ScopedRoutesConfigDump*, UPB_SIZE(8, 8), value, UPB_SIZE(12, 16), 5);
+}
+UPB_INLINE struct envoy_admin_v3_ScopedRoutesConfigDump* envoy_service_status_v3_PerXdsConfig_mutable_scoped_route_config(envoy_service_status_v3_PerXdsConfig *msg, upb_arena *arena) {
+  struct envoy_admin_v3_ScopedRoutesConfigDump* sub = (struct envoy_admin_v3_ScopedRoutesConfigDump*)envoy_service_status_v3_PerXdsConfig_scoped_route_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_ScopedRoutesConfigDump*)_upb_msg_new(&envoy_admin_v3_ScopedRoutesConfigDump_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_status_v3_PerXdsConfig_set_scoped_route_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_service_status_v3_PerXdsConfig_set_endpoint_config(envoy_service_status_v3_PerXdsConfig *msg, struct envoy_admin_v3_EndpointsConfigDump* value) {
+  UPB_WRITE_ONEOF(msg, struct envoy_admin_v3_EndpointsConfigDump*, UPB_SIZE(8, 8), value, UPB_SIZE(12, 16), 6);
+}
+UPB_INLINE struct envoy_admin_v3_EndpointsConfigDump* envoy_service_status_v3_PerXdsConfig_mutable_endpoint_config(envoy_service_status_v3_PerXdsConfig *msg, upb_arena *arena) {
+  struct envoy_admin_v3_EndpointsConfigDump* sub = (struct envoy_admin_v3_EndpointsConfigDump*)envoy_service_status_v3_PerXdsConfig_endpoint_config(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_admin_v3_EndpointsConfigDump*)_upb_msg_new(&envoy_admin_v3_EndpointsConfigDump_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_status_v3_PerXdsConfig_set_endpoint_config(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void envoy_service_status_v3_PerXdsConfig_set_client_status(envoy_service_status_v3_PerXdsConfig *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value;
+}
+
+/* envoy.service.status.v3.ClientConfig */
+
+UPB_INLINE envoy_service_status_v3_ClientConfig *envoy_service_status_v3_ClientConfig_new(upb_arena *arena) {
+  return (envoy_service_status_v3_ClientConfig *)_upb_msg_new(&envoy_service_status_v3_ClientConfig_msginit, arena);
+}
+UPB_INLINE envoy_service_status_v3_ClientConfig *envoy_service_status_v3_ClientConfig_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_service_status_v3_ClientConfig *ret = envoy_service_status_v3_ClientConfig_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_service_status_v3_ClientConfig_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_service_status_v3_ClientConfig *envoy_service_status_v3_ClientConfig_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_service_status_v3_ClientConfig *ret = envoy_service_status_v3_ClientConfig_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_service_status_v3_ClientConfig_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_service_status_v3_ClientConfig_serialize(const envoy_service_status_v3_ClientConfig *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_service_status_v3_ClientConfig_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_service_status_v3_ClientConfig_has_node(const envoy_service_status_v3_ClientConfig *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_config_core_v3_Node* envoy_service_status_v3_ClientConfig_node(const envoy_service_status_v3_ClientConfig *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_config_core_v3_Node*); }
+UPB_INLINE bool envoy_service_status_v3_ClientConfig_has_xds_config(const envoy_service_status_v3_ClientConfig *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const envoy_service_status_v3_PerXdsConfig* const* envoy_service_status_v3_ClientConfig_xds_config(const envoy_service_status_v3_ClientConfig *msg, size_t *len) { return (const envoy_service_status_v3_PerXdsConfig* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+
+UPB_INLINE void envoy_service_status_v3_ClientConfig_set_node(envoy_service_status_v3_ClientConfig *msg, struct envoy_config_core_v3_Node* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_config_core_v3_Node*) = value;
+}
+UPB_INLINE struct envoy_config_core_v3_Node* envoy_service_status_v3_ClientConfig_mutable_node(envoy_service_status_v3_ClientConfig *msg, upb_arena *arena) {
+  struct envoy_config_core_v3_Node* sub = (struct envoy_config_core_v3_Node*)envoy_service_status_v3_ClientConfig_node(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_config_core_v3_Node*)_upb_msg_new(&envoy_config_core_v3_Node_msginit, arena);
+    if (!sub) return NULL;
+    envoy_service_status_v3_ClientConfig_set_node(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE envoy_service_status_v3_PerXdsConfig** envoy_service_status_v3_ClientConfig_mutable_xds_config(envoy_service_status_v3_ClientConfig *msg, size_t *len) {
+  return (envoy_service_status_v3_PerXdsConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE envoy_service_status_v3_PerXdsConfig** envoy_service_status_v3_ClientConfig_resize_xds_config(envoy_service_status_v3_ClientConfig *msg, size_t len, upb_arena *arena) {
+  return (envoy_service_status_v3_PerXdsConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_service_status_v3_PerXdsConfig* envoy_service_status_v3_ClientConfig_add_xds_config(envoy_service_status_v3_ClientConfig *msg, upb_arena *arena) {
+  struct envoy_service_status_v3_PerXdsConfig* sub = (struct envoy_service_status_v3_PerXdsConfig*)_upb_msg_new(&envoy_service_status_v3_PerXdsConfig_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* envoy.service.status.v3.ClientStatusResponse */
+
+UPB_INLINE envoy_service_status_v3_ClientStatusResponse *envoy_service_status_v3_ClientStatusResponse_new(upb_arena *arena) {
+  return (envoy_service_status_v3_ClientStatusResponse *)_upb_msg_new(&envoy_service_status_v3_ClientStatusResponse_msginit, arena);
+}
+UPB_INLINE envoy_service_status_v3_ClientStatusResponse *envoy_service_status_v3_ClientStatusResponse_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_service_status_v3_ClientStatusResponse *ret = envoy_service_status_v3_ClientStatusResponse_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_service_status_v3_ClientStatusResponse_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_service_status_v3_ClientStatusResponse *envoy_service_status_v3_ClientStatusResponse_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_service_status_v3_ClientStatusResponse *ret = envoy_service_status_v3_ClientStatusResponse_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_service_status_v3_ClientStatusResponse_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_service_status_v3_ClientStatusResponse_serialize(const envoy_service_status_v3_ClientStatusResponse *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_service_status_v3_ClientStatusResponse_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_service_status_v3_ClientStatusResponse_has_config(const envoy_service_status_v3_ClientStatusResponse *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE const envoy_service_status_v3_ClientConfig* const* envoy_service_status_v3_ClientStatusResponse_config(const envoy_service_status_v3_ClientStatusResponse *msg, size_t *len) { return (const envoy_service_status_v3_ClientConfig* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+
+UPB_INLINE envoy_service_status_v3_ClientConfig** envoy_service_status_v3_ClientStatusResponse_mutable_config(envoy_service_status_v3_ClientStatusResponse *msg, size_t *len) {
+  return (envoy_service_status_v3_ClientConfig**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE envoy_service_status_v3_ClientConfig** envoy_service_status_v3_ClientStatusResponse_resize_config(envoy_service_status_v3_ClientStatusResponse *msg, size_t len, upb_arena *arena) {
+  return (envoy_service_status_v3_ClientConfig**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_service_status_v3_ClientConfig* envoy_service_status_v3_ClientStatusResponse_add_config(envoy_service_status_v3_ClientStatusResponse *msg, upb_arena *arena) {
+  struct envoy_service_status_v3_ClientConfig* sub = (struct envoy_service_status_v3_ClientConfig*)_upb_msg_new(&envoy_service_status_v3_ClientConfig_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_SERVICE_STATUS_V3_CSDS_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c
new file mode 100644
index 0000000..8ef51fb
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c
@@ -0,0 +1,36 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/type/matcher/v3/node.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/type/matcher/v3/node.upb.h"
+#include "envoy/type/matcher/v3/string.upb.h"
+#include "envoy/type/matcher/v3/struct.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_type_matcher_v3_NodeMatcher_submsgs[2] = {
+  &envoy_type_matcher_v3_StringMatcher_msginit,
+  &envoy_type_matcher_v3_StructMatcher_msginit,
+};
+
+static const upb_msglayout_field envoy_type_matcher_v3_NodeMatcher__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 11, 1},
+  {2, UPB_SIZE(8, 16), 0, 1, 11, 3},
+};
+
+const upb_msglayout envoy_type_matcher_v3_NodeMatcher_msginit = {
+  &envoy_type_matcher_v3_NodeMatcher_submsgs[0],
+  &envoy_type_matcher_v3_NodeMatcher__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h
new file mode 100644
index 0000000..94e2257
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h
@@ -0,0 +1,90 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/type/matcher/v3/node.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_TYPE_MATCHER_V3_NODE_PROTO_UPB_H_
+#define ENVOY_TYPE_MATCHER_V3_NODE_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_type_matcher_v3_NodeMatcher;
+typedef struct envoy_type_matcher_v3_NodeMatcher envoy_type_matcher_v3_NodeMatcher;
+extern const upb_msglayout envoy_type_matcher_v3_NodeMatcher_msginit;
+struct envoy_type_matcher_v3_StringMatcher;
+struct envoy_type_matcher_v3_StructMatcher;
+extern const upb_msglayout envoy_type_matcher_v3_StringMatcher_msginit;
+extern const upb_msglayout envoy_type_matcher_v3_StructMatcher_msginit;
+
+
+/* envoy.type.matcher.v3.NodeMatcher */
+
+UPB_INLINE envoy_type_matcher_v3_NodeMatcher *envoy_type_matcher_v3_NodeMatcher_new(upb_arena *arena) {
+  return (envoy_type_matcher_v3_NodeMatcher *)_upb_msg_new(&envoy_type_matcher_v3_NodeMatcher_msginit, arena);
+}
+UPB_INLINE envoy_type_matcher_v3_NodeMatcher *envoy_type_matcher_v3_NodeMatcher_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_type_matcher_v3_NodeMatcher *ret = envoy_type_matcher_v3_NodeMatcher_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_type_matcher_v3_NodeMatcher_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_type_matcher_v3_NodeMatcher *envoy_type_matcher_v3_NodeMatcher_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_type_matcher_v3_NodeMatcher *ret = envoy_type_matcher_v3_NodeMatcher_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_type_matcher_v3_NodeMatcher_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_type_matcher_v3_NodeMatcher_serialize(const envoy_type_matcher_v3_NodeMatcher *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_type_matcher_v3_NodeMatcher_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_type_matcher_v3_NodeMatcher_has_node_id(const envoy_type_matcher_v3_NodeMatcher *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_type_matcher_v3_StringMatcher* envoy_type_matcher_v3_NodeMatcher_node_id(const envoy_type_matcher_v3_NodeMatcher *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_type_matcher_v3_StringMatcher*); }
+UPB_INLINE bool envoy_type_matcher_v3_NodeMatcher_has_node_metadatas(const envoy_type_matcher_v3_NodeMatcher *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const struct envoy_type_matcher_v3_StructMatcher* const* envoy_type_matcher_v3_NodeMatcher_node_metadatas(const envoy_type_matcher_v3_NodeMatcher *msg, size_t *len) { return (const struct envoy_type_matcher_v3_StructMatcher* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+
+UPB_INLINE void envoy_type_matcher_v3_NodeMatcher_set_node_id(envoy_type_matcher_v3_NodeMatcher *msg, struct envoy_type_matcher_v3_StringMatcher* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_type_matcher_v3_StringMatcher*) = value;
+}
+UPB_INLINE struct envoy_type_matcher_v3_StringMatcher* envoy_type_matcher_v3_NodeMatcher_mutable_node_id(envoy_type_matcher_v3_NodeMatcher *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_StringMatcher* sub = (struct envoy_type_matcher_v3_StringMatcher*)envoy_type_matcher_v3_NodeMatcher_node_id(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_matcher_v3_StringMatcher*)_upb_msg_new(&envoy_type_matcher_v3_StringMatcher_msginit, arena);
+    if (!sub) return NULL;
+    envoy_type_matcher_v3_NodeMatcher_set_node_id(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE struct envoy_type_matcher_v3_StructMatcher** envoy_type_matcher_v3_NodeMatcher_mutable_node_metadatas(envoy_type_matcher_v3_NodeMatcher *msg, size_t *len) {
+  return (struct envoy_type_matcher_v3_StructMatcher**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE struct envoy_type_matcher_v3_StructMatcher** envoy_type_matcher_v3_NodeMatcher_resize_node_metadatas(envoy_type_matcher_v3_NodeMatcher *msg, size_t len, upb_arena *arena) {
+  return (struct envoy_type_matcher_v3_StructMatcher**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_type_matcher_v3_StructMatcher* envoy_type_matcher_v3_NodeMatcher_add_node_metadatas(envoy_type_matcher_v3_NodeMatcher *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_StructMatcher* sub = (struct envoy_type_matcher_v3_StructMatcher*)_upb_msg_new(&envoy_type_matcher_v3_StructMatcher_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_TYPE_MATCHER_V3_NODE_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c
index 073e506..e84e4f7 100644
--- a/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c
+++ b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c
@@ -10,7 +10,6 @@
 #include "upb/msg.h"
 #include "envoy/type/matcher/v3/string.upb.h"
 #include "envoy/type/matcher/v3/regex.upb.h"
-#include "envoy/annotations/deprecation.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "udpa/annotations/versioning.upb.h"
 #include "validate/validate.upb.h"
diff --git a/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c
new file mode 100644
index 0000000..05ea6a3
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c
@@ -0,0 +1,46 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/type/matcher/v3/struct.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "envoy/type/matcher/v3/struct.upb.h"
+#include "envoy/type/matcher/v3/value.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "udpa/annotations/versioning.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const envoy_type_matcher_v3_StructMatcher_submsgs[2] = {
+  &envoy_type_matcher_v3_StructMatcher_PathSegment_msginit,
+  &envoy_type_matcher_v3_ValueMatcher_msginit,
+};
+
+static const upb_msglayout_field envoy_type_matcher_v3_StructMatcher__fields[2] = {
+  {2, UPB_SIZE(8, 16), 0, 0, 11, 3},
+  {3, UPB_SIZE(4, 8), 1, 1, 11, 1},
+};
+
+const upb_msglayout envoy_type_matcher_v3_StructMatcher_msginit = {
+  &envoy_type_matcher_v3_StructMatcher_submsgs[0],
+  &envoy_type_matcher_v3_StructMatcher__fields[0],
+  UPB_SIZE(16, 24), 2, false, 255,
+};
+
+static const upb_msglayout_field envoy_type_matcher_v3_StructMatcher_PathSegment__fields[1] = {
+  {1, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 9, 1},
+};
+
+const upb_msglayout envoy_type_matcher_v3_StructMatcher_PathSegment_msginit = {
+  NULL,
+  &envoy_type_matcher_v3_StructMatcher_PathSegment__fields[0],
+  UPB_SIZE(16, 32), 1, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h
new file mode 100644
index 0000000..53e5213
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h
@@ -0,0 +1,124 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/type/matcher/v3/struct.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_TYPE_MATCHER_V3_STRUCT_PROTO_UPB_H_
+#define ENVOY_TYPE_MATCHER_V3_STRUCT_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct envoy_type_matcher_v3_StructMatcher;
+struct envoy_type_matcher_v3_StructMatcher_PathSegment;
+typedef struct envoy_type_matcher_v3_StructMatcher envoy_type_matcher_v3_StructMatcher;
+typedef struct envoy_type_matcher_v3_StructMatcher_PathSegment envoy_type_matcher_v3_StructMatcher_PathSegment;
+extern const upb_msglayout envoy_type_matcher_v3_StructMatcher_msginit;
+extern const upb_msglayout envoy_type_matcher_v3_StructMatcher_PathSegment_msginit;
+struct envoy_type_matcher_v3_ValueMatcher;
+extern const upb_msglayout envoy_type_matcher_v3_ValueMatcher_msginit;
+
+
+/* envoy.type.matcher.v3.StructMatcher */
+
+UPB_INLINE envoy_type_matcher_v3_StructMatcher *envoy_type_matcher_v3_StructMatcher_new(upb_arena *arena) {
+  return (envoy_type_matcher_v3_StructMatcher *)_upb_msg_new(&envoy_type_matcher_v3_StructMatcher_msginit, arena);
+}
+UPB_INLINE envoy_type_matcher_v3_StructMatcher *envoy_type_matcher_v3_StructMatcher_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_type_matcher_v3_StructMatcher *ret = envoy_type_matcher_v3_StructMatcher_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_type_matcher_v3_StructMatcher_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_type_matcher_v3_StructMatcher *envoy_type_matcher_v3_StructMatcher_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_type_matcher_v3_StructMatcher *ret = envoy_type_matcher_v3_StructMatcher_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_type_matcher_v3_StructMatcher_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_type_matcher_v3_StructMatcher_serialize(const envoy_type_matcher_v3_StructMatcher *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_type_matcher_v3_StructMatcher_msginit, arena, len);
+}
+
+UPB_INLINE bool envoy_type_matcher_v3_StructMatcher_has_path(const envoy_type_matcher_v3_StructMatcher *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const envoy_type_matcher_v3_StructMatcher_PathSegment* const* envoy_type_matcher_v3_StructMatcher_path(const envoy_type_matcher_v3_StructMatcher *msg, size_t *len) { return (const envoy_type_matcher_v3_StructMatcher_PathSegment* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+UPB_INLINE bool envoy_type_matcher_v3_StructMatcher_has_value(const envoy_type_matcher_v3_StructMatcher *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct envoy_type_matcher_v3_ValueMatcher* envoy_type_matcher_v3_StructMatcher_value(const envoy_type_matcher_v3_StructMatcher *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), const struct envoy_type_matcher_v3_ValueMatcher*); }
+
+UPB_INLINE envoy_type_matcher_v3_StructMatcher_PathSegment** envoy_type_matcher_v3_StructMatcher_mutable_path(envoy_type_matcher_v3_StructMatcher *msg, size_t *len) {
+  return (envoy_type_matcher_v3_StructMatcher_PathSegment**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE envoy_type_matcher_v3_StructMatcher_PathSegment** envoy_type_matcher_v3_StructMatcher_resize_path(envoy_type_matcher_v3_StructMatcher *msg, size_t len, upb_arena *arena) {
+  return (envoy_type_matcher_v3_StructMatcher_PathSegment**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct envoy_type_matcher_v3_StructMatcher_PathSegment* envoy_type_matcher_v3_StructMatcher_add_path(envoy_type_matcher_v3_StructMatcher *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_StructMatcher_PathSegment* sub = (struct envoy_type_matcher_v3_StructMatcher_PathSegment*)_upb_msg_new(&envoy_type_matcher_v3_StructMatcher_PathSegment_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE void envoy_type_matcher_v3_StructMatcher_set_value(envoy_type_matcher_v3_StructMatcher *msg, struct envoy_type_matcher_v3_ValueMatcher* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), struct envoy_type_matcher_v3_ValueMatcher*) = value;
+}
+UPB_INLINE struct envoy_type_matcher_v3_ValueMatcher* envoy_type_matcher_v3_StructMatcher_mutable_value(envoy_type_matcher_v3_StructMatcher *msg, upb_arena *arena) {
+  struct envoy_type_matcher_v3_ValueMatcher* sub = (struct envoy_type_matcher_v3_ValueMatcher*)envoy_type_matcher_v3_StructMatcher_value(msg);
+  if (sub == NULL) {
+    sub = (struct envoy_type_matcher_v3_ValueMatcher*)_upb_msg_new(&envoy_type_matcher_v3_ValueMatcher_msginit, arena);
+    if (!sub) return NULL;
+    envoy_type_matcher_v3_StructMatcher_set_value(msg, sub);
+  }
+  return sub;
+}
+
+/* envoy.type.matcher.v3.StructMatcher.PathSegment */
+
+UPB_INLINE envoy_type_matcher_v3_StructMatcher_PathSegment *envoy_type_matcher_v3_StructMatcher_PathSegment_new(upb_arena *arena) {
+  return (envoy_type_matcher_v3_StructMatcher_PathSegment *)_upb_msg_new(&envoy_type_matcher_v3_StructMatcher_PathSegment_msginit, arena);
+}
+UPB_INLINE envoy_type_matcher_v3_StructMatcher_PathSegment *envoy_type_matcher_v3_StructMatcher_PathSegment_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  envoy_type_matcher_v3_StructMatcher_PathSegment *ret = envoy_type_matcher_v3_StructMatcher_PathSegment_new(arena);
+  return (ret && upb_decode(buf, size, ret, &envoy_type_matcher_v3_StructMatcher_PathSegment_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE envoy_type_matcher_v3_StructMatcher_PathSegment *envoy_type_matcher_v3_StructMatcher_PathSegment_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  envoy_type_matcher_v3_StructMatcher_PathSegment *ret = envoy_type_matcher_v3_StructMatcher_PathSegment_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &envoy_type_matcher_v3_StructMatcher_PathSegment_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *envoy_type_matcher_v3_StructMatcher_PathSegment_serialize(const envoy_type_matcher_v3_StructMatcher_PathSegment *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &envoy_type_matcher_v3_StructMatcher_PathSegment_msginit, arena, len);
+}
+
+typedef enum {
+  envoy_type_matcher_v3_StructMatcher_PathSegment_segment_key = 1,
+  envoy_type_matcher_v3_StructMatcher_PathSegment_segment_NOT_SET = 0
+} envoy_type_matcher_v3_StructMatcher_PathSegment_segment_oneofcases;
+UPB_INLINE envoy_type_matcher_v3_StructMatcher_PathSegment_segment_oneofcases envoy_type_matcher_v3_StructMatcher_PathSegment_segment_case(const envoy_type_matcher_v3_StructMatcher_PathSegment* msg) { return (envoy_type_matcher_v3_StructMatcher_PathSegment_segment_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(8, 16), int32_t); }
+
+UPB_INLINE bool envoy_type_matcher_v3_StructMatcher_PathSegment_has_key(const envoy_type_matcher_v3_StructMatcher_PathSegment *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 1; }
+UPB_INLINE upb_strview envoy_type_matcher_v3_StructMatcher_PathSegment_key(const envoy_type_matcher_v3_StructMatcher_PathSegment *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 1, upb_strview_make("", strlen(""))); }
+
+UPB_INLINE void envoy_type_matcher_v3_StructMatcher_PathSegment_set_key(envoy_type_matcher_v3_StructMatcher_PathSegment *msg, upb_strview value) {
+  UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 1);
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_TYPE_MATCHER_V3_STRUCT_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c b/grpc/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
index d3962ea..4bbf575 100644
--- a/grpc/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
+++ b/grpc/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.c
@@ -189,21 +189,23 @@
   UPB_SIZE(16, 32), 9, false, 255,
 };
 
-static const upb_msglayout *const google_api_expr_v1alpha1_SourceInfo_submsgs[1] = {
+static const upb_msglayout *const google_api_expr_v1alpha1_SourceInfo_submsgs[2] = {
+  &google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_msginit,
   &google_api_expr_v1alpha1_SourceInfo_PositionsEntry_msginit,
 };
 
-static const upb_msglayout_field google_api_expr_v1alpha1_SourceInfo__fields[4] = {
+static const upb_msglayout_field google_api_expr_v1alpha1_SourceInfo__fields[5] = {
   {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
   {2, UPB_SIZE(8, 16), 0, 0, 9, 1},
   {3, UPB_SIZE(16, 32), 0, 0, 5, _UPB_LABEL_PACKED},
-  {4, UPB_SIZE(20, 40), 0, 0, 11, _UPB_LABEL_MAP},
+  {4, UPB_SIZE(20, 40), 0, 1, 11, _UPB_LABEL_MAP},
+  {5, UPB_SIZE(24, 48), 0, 0, 11, _UPB_LABEL_MAP},
 };
 
 const upb_msglayout google_api_expr_v1alpha1_SourceInfo_msginit = {
   &google_api_expr_v1alpha1_SourceInfo_submsgs[0],
   &google_api_expr_v1alpha1_SourceInfo__fields[0],
-  UPB_SIZE(24, 48), 4, false, 255,
+  UPB_SIZE(32, 64), 5, false, 255,
 };
 
 static const upb_msglayout_field google_api_expr_v1alpha1_SourceInfo_PositionsEntry__fields[2] = {
@@ -217,6 +219,21 @@
   UPB_SIZE(16, 32), 2, false, 255,
 };
 
+static const upb_msglayout *const google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_submsgs[1] = {
+  &google_api_expr_v1alpha1_Expr_msginit,
+};
+
+static const upb_msglayout_field google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 3, 1},
+  {2, UPB_SIZE(8, 16), 0, 0, 11, 1},
+};
+
+const upb_msglayout google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_msginit = {
+  &google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_submsgs[0],
+  &google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
 static const upb_msglayout_field google_api_expr_v1alpha1_SourcePosition__fields[4] = {
   {1, UPB_SIZE(12, 16), 0, 0, 9, 1},
   {2, UPB_SIZE(0, 0), 0, 0, 5, 1},
diff --git a/grpc/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h b/grpc/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
index 861c3a5..ffa7925 100644
--- a/grpc/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
+++ b/grpc/src/core/ext/upb-generated/google/api/expr/v1alpha1/syntax.upb.h
@@ -32,6 +32,7 @@
 struct google_api_expr_v1alpha1_Constant;
 struct google_api_expr_v1alpha1_SourceInfo;
 struct google_api_expr_v1alpha1_SourceInfo_PositionsEntry;
+struct google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry;
 struct google_api_expr_v1alpha1_SourcePosition;
 typedef struct google_api_expr_v1alpha1_ParsedExpr google_api_expr_v1alpha1_ParsedExpr;
 typedef struct google_api_expr_v1alpha1_Expr google_api_expr_v1alpha1_Expr;
@@ -45,6 +46,7 @@
 typedef struct google_api_expr_v1alpha1_Constant google_api_expr_v1alpha1_Constant;
 typedef struct google_api_expr_v1alpha1_SourceInfo google_api_expr_v1alpha1_SourceInfo;
 typedef struct google_api_expr_v1alpha1_SourceInfo_PositionsEntry google_api_expr_v1alpha1_SourceInfo_PositionsEntry;
+typedef struct google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry;
 typedef struct google_api_expr_v1alpha1_SourcePosition google_api_expr_v1alpha1_SourcePosition;
 extern const upb_msglayout google_api_expr_v1alpha1_ParsedExpr_msginit;
 extern const upb_msglayout google_api_expr_v1alpha1_Expr_msginit;
@@ -58,6 +60,7 @@
 extern const upb_msglayout google_api_expr_v1alpha1_Constant_msginit;
 extern const upb_msglayout google_api_expr_v1alpha1_SourceInfo_msginit;
 extern const upb_msglayout google_api_expr_v1alpha1_SourceInfo_PositionsEntry_msginit;
+extern const upb_msglayout google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_msginit;
 extern const upb_msglayout google_api_expr_v1alpha1_SourcePosition_msginit;
 struct google_protobuf_Duration;
 struct google_protobuf_Timestamp;
@@ -756,6 +759,10 @@
 UPB_INLINE size_t google_api_expr_v1alpha1_SourceInfo_positions_size(const google_api_expr_v1alpha1_SourceInfo *msg) {return _upb_msg_map_size(msg, UPB_SIZE(20, 40)); }
 UPB_INLINE bool google_api_expr_v1alpha1_SourceInfo_positions_get(const google_api_expr_v1alpha1_SourceInfo *msg, int64_t key, int32_t *val) { return _upb_msg_map_get(msg, UPB_SIZE(20, 40), &key, sizeof(key), val, sizeof(*val)); }
 UPB_INLINE const google_api_expr_v1alpha1_SourceInfo_PositionsEntry* google_api_expr_v1alpha1_SourceInfo_positions_next(const google_api_expr_v1alpha1_SourceInfo *msg, size_t* iter) { return (const google_api_expr_v1alpha1_SourceInfo_PositionsEntry*)_upb_msg_map_next(msg, UPB_SIZE(20, 40), iter); }
+UPB_INLINE bool google_api_expr_v1alpha1_SourceInfo_has_macro_calls(const google_api_expr_v1alpha1_SourceInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); }
+UPB_INLINE size_t google_api_expr_v1alpha1_SourceInfo_macro_calls_size(const google_api_expr_v1alpha1_SourceInfo *msg) {return _upb_msg_map_size(msg, UPB_SIZE(24, 48)); }
+UPB_INLINE bool google_api_expr_v1alpha1_SourceInfo_macro_calls_get(const google_api_expr_v1alpha1_SourceInfo *msg, int64_t key, google_api_expr_v1alpha1_Expr* *val) { return _upb_msg_map_get(msg, UPB_SIZE(24, 48), &key, sizeof(key), val, sizeof(*val)); }
+UPB_INLINE const google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry* google_api_expr_v1alpha1_SourceInfo_macro_calls_next(const google_api_expr_v1alpha1_SourceInfo *msg, size_t* iter) { return (const google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry*)_upb_msg_map_next(msg, UPB_SIZE(24, 48), iter); }
 
 UPB_INLINE void google_api_expr_v1alpha1_SourceInfo_set_syntax_version(google_api_expr_v1alpha1_SourceInfo *msg, upb_strview value) {
   *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
@@ -777,6 +784,10 @@
 UPB_INLINE bool google_api_expr_v1alpha1_SourceInfo_positions_set(google_api_expr_v1alpha1_SourceInfo *msg, int64_t key, int32_t val, upb_arena *a) { return _upb_msg_map_set(msg, UPB_SIZE(20, 40), &key, sizeof(key), &val, sizeof(val), a); }
 UPB_INLINE bool google_api_expr_v1alpha1_SourceInfo_positions_delete(google_api_expr_v1alpha1_SourceInfo *msg, int64_t key) { return _upb_msg_map_delete(msg, UPB_SIZE(20, 40), &key, sizeof(key)); }
 UPB_INLINE google_api_expr_v1alpha1_SourceInfo_PositionsEntry* google_api_expr_v1alpha1_SourceInfo_positions_nextmutable(google_api_expr_v1alpha1_SourceInfo *msg, size_t* iter) { return (google_api_expr_v1alpha1_SourceInfo_PositionsEntry*)_upb_msg_map_next(msg, UPB_SIZE(20, 40), iter); }
+UPB_INLINE void google_api_expr_v1alpha1_SourceInfo_macro_calls_clear(google_api_expr_v1alpha1_SourceInfo *msg) { _upb_msg_map_clear(msg, UPB_SIZE(24, 48)); }
+UPB_INLINE bool google_api_expr_v1alpha1_SourceInfo_macro_calls_set(google_api_expr_v1alpha1_SourceInfo *msg, int64_t key, google_api_expr_v1alpha1_Expr* val, upb_arena *a) { return _upb_msg_map_set(msg, UPB_SIZE(24, 48), &key, sizeof(key), &val, sizeof(val), a); }
+UPB_INLINE bool google_api_expr_v1alpha1_SourceInfo_macro_calls_delete(google_api_expr_v1alpha1_SourceInfo *msg, int64_t key) { return _upb_msg_map_delete(msg, UPB_SIZE(24, 48), &key, sizeof(key)); }
+UPB_INLINE google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry* google_api_expr_v1alpha1_SourceInfo_macro_calls_nextmutable(google_api_expr_v1alpha1_SourceInfo *msg, size_t* iter) { return (google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry*)_upb_msg_map_next(msg, UPB_SIZE(24, 48), iter); }
 
 /* google.api.expr.v1alpha1.SourceInfo.PositionsEntry */
 
@@ -795,6 +806,24 @@
   _upb_msg_map_set_value(msg, &value, sizeof(int32_t));
 }
 
+/* google.api.expr.v1alpha1.SourceInfo.MacroCallsEntry */
+
+UPB_INLINE int64_t google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_key(const google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry *msg) {
+  int64_t ret;
+  _upb_msg_map_key(msg, &ret, sizeof(ret));
+  return ret;
+}
+UPB_INLINE bool google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_has_value(const google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const google_api_expr_v1alpha1_Expr* google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_value(const google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry *msg) {
+  google_api_expr_v1alpha1_Expr* ret;
+  _upb_msg_map_value(msg, &ret, sizeof(ret));
+  return ret;
+}
+
+UPB_INLINE void google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_set_value(google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry *msg, google_api_expr_v1alpha1_Expr* value) {
+  _upb_msg_map_set_value(msg, &value, sizeof(google_api_expr_v1alpha1_Expr*));
+}
+
 /* google.api.expr.v1alpha1.SourcePosition */
 
 UPB_INLINE google_api_expr_v1alpha1_SourcePosition *google_api_expr_v1alpha1_SourcePosition_new(upb_arena *arena) {
diff --git a/grpc/src/core/ext/upb-generated/src/proto/grpc/auth/v1/authz_policy.upb.c b/grpc/src/core/ext/upb-generated/src/proto/grpc/auth/v1/authz_policy.upb.c
new file mode 100644
index 0000000..62947d6
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/src/proto/grpc/auth/v1/authz_policy.upb.c
@@ -0,0 +1,85 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     src/proto/grpc/auth/v1/authz_policy.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "src/proto/grpc/auth/v1/authz_policy.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout_field grpc_auth_v1_Peer__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 3},
+};
+
+const upb_msglayout grpc_auth_v1_Peer_msginit = {
+  NULL,
+  &grpc_auth_v1_Peer__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout_field grpc_auth_v1_Header__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), 0, 0, 9, 3},
+};
+
+const upb_msglayout grpc_auth_v1_Header_msginit = {
+  NULL,
+  &grpc_auth_v1_Header__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+static const upb_msglayout *const grpc_auth_v1_Request_submsgs[1] = {
+  &grpc_auth_v1_Header_msginit,
+};
+
+static const upb_msglayout_field grpc_auth_v1_Request__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 3},
+  {3, UPB_SIZE(4, 8), 0, 0, 11, 3},
+};
+
+const upb_msglayout grpc_auth_v1_Request_msginit = {
+  &grpc_auth_v1_Request_submsgs[0],
+  &grpc_auth_v1_Request__fields[0],
+  UPB_SIZE(8, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const grpc_auth_v1_Rule_submsgs[2] = {
+  &grpc_auth_v1_Peer_msginit,
+  &grpc_auth_v1_Request_msginit,
+};
+
+static const upb_msglayout_field grpc_auth_v1_Rule__fields[3] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 1, 0, 11, 1},
+  {3, UPB_SIZE(16, 32), 2, 1, 11, 1},
+};
+
+const upb_msglayout grpc_auth_v1_Rule_msginit = {
+  &grpc_auth_v1_Rule_submsgs[0],
+  &grpc_auth_v1_Rule__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+static const upb_msglayout *const grpc_auth_v1_AuthorizationPolicy_submsgs[1] = {
+  &grpc_auth_v1_Rule_msginit,
+};
+
+static const upb_msglayout_field grpc_auth_v1_AuthorizationPolicy__fields[3] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), 0, 0, 11, 3},
+  {3, UPB_SIZE(12, 24), 0, 0, 11, 3},
+};
+
+const upb_msglayout grpc_auth_v1_AuthorizationPolicy_msginit = {
+  &grpc_auth_v1_AuthorizationPolicy_submsgs[0],
+  &grpc_auth_v1_AuthorizationPolicy__fields[0],
+  UPB_SIZE(16, 32), 3, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/src/proto/grpc/auth/v1/authz_policy.upb.h b/grpc/src/core/ext/upb-generated/src/proto/grpc/auth/v1/authz_policy.upb.h
new file mode 100644
index 0000000..2177b9d
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/src/proto/grpc/auth/v1/authz_policy.upb.h
@@ -0,0 +1,276 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     src/proto/grpc/auth/v1/authz_policy.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef SRC_PROTO_GRPC_AUTH_V1_AUTHZ_POLICY_PROTO_UPB_H_
+#define SRC_PROTO_GRPC_AUTH_V1_AUTHZ_POLICY_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct grpc_auth_v1_Peer;
+struct grpc_auth_v1_Header;
+struct grpc_auth_v1_Request;
+struct grpc_auth_v1_Rule;
+struct grpc_auth_v1_AuthorizationPolicy;
+typedef struct grpc_auth_v1_Peer grpc_auth_v1_Peer;
+typedef struct grpc_auth_v1_Header grpc_auth_v1_Header;
+typedef struct grpc_auth_v1_Request grpc_auth_v1_Request;
+typedef struct grpc_auth_v1_Rule grpc_auth_v1_Rule;
+typedef struct grpc_auth_v1_AuthorizationPolicy grpc_auth_v1_AuthorizationPolicy;
+extern const upb_msglayout grpc_auth_v1_Peer_msginit;
+extern const upb_msglayout grpc_auth_v1_Header_msginit;
+extern const upb_msglayout grpc_auth_v1_Request_msginit;
+extern const upb_msglayout grpc_auth_v1_Rule_msginit;
+extern const upb_msglayout grpc_auth_v1_AuthorizationPolicy_msginit;
+
+
+/* grpc.auth.v1.Peer */
+
+UPB_INLINE grpc_auth_v1_Peer *grpc_auth_v1_Peer_new(upb_arena *arena) {
+  return (grpc_auth_v1_Peer *)_upb_msg_new(&grpc_auth_v1_Peer_msginit, arena);
+}
+UPB_INLINE grpc_auth_v1_Peer *grpc_auth_v1_Peer_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  grpc_auth_v1_Peer *ret = grpc_auth_v1_Peer_new(arena);
+  return (ret && upb_decode(buf, size, ret, &grpc_auth_v1_Peer_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE grpc_auth_v1_Peer *grpc_auth_v1_Peer_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  grpc_auth_v1_Peer *ret = grpc_auth_v1_Peer_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &grpc_auth_v1_Peer_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *grpc_auth_v1_Peer_serialize(const grpc_auth_v1_Peer *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &grpc_auth_v1_Peer_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview const* grpc_auth_v1_Peer_principals(const grpc_auth_v1_Peer *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+
+UPB_INLINE upb_strview* grpc_auth_v1_Peer_mutable_principals(grpc_auth_v1_Peer *msg, size_t *len) {
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE upb_strview* grpc_auth_v1_Peer_resize_principals(grpc_auth_v1_Peer *msg, size_t len, upb_arena *arena) {
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(3, 4), arena);
+}
+UPB_INLINE bool grpc_auth_v1_Peer_add_principals(grpc_auth_v1_Peer *msg, upb_strview val, upb_arena *arena) {
+  return _upb_array_append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(3, 4), &val,
+      arena);
+}
+
+/* grpc.auth.v1.Header */
+
+UPB_INLINE grpc_auth_v1_Header *grpc_auth_v1_Header_new(upb_arena *arena) {
+  return (grpc_auth_v1_Header *)_upb_msg_new(&grpc_auth_v1_Header_msginit, arena);
+}
+UPB_INLINE grpc_auth_v1_Header *grpc_auth_v1_Header_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  grpc_auth_v1_Header *ret = grpc_auth_v1_Header_new(arena);
+  return (ret && upb_decode(buf, size, ret, &grpc_auth_v1_Header_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE grpc_auth_v1_Header *grpc_auth_v1_Header_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  grpc_auth_v1_Header *ret = grpc_auth_v1_Header_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &grpc_auth_v1_Header_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *grpc_auth_v1_Header_serialize(const grpc_auth_v1_Header *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &grpc_auth_v1_Header_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview grpc_auth_v1_Header_key(const grpc_auth_v1_Header *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE upb_strview const* grpc_auth_v1_Header_values(const grpc_auth_v1_Header *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+
+UPB_INLINE void grpc_auth_v1_Header_set_key(grpc_auth_v1_Header *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE upb_strview* grpc_auth_v1_Header_mutable_values(grpc_auth_v1_Header *msg, size_t *len) {
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE upb_strview* grpc_auth_v1_Header_resize_values(grpc_auth_v1_Header *msg, size_t len, upb_arena *arena) {
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(3, 4), arena);
+}
+UPB_INLINE bool grpc_auth_v1_Header_add_values(grpc_auth_v1_Header *msg, upb_strview val, upb_arena *arena) {
+  return _upb_array_append_accessor2(msg, UPB_SIZE(8, 16), UPB_SIZE(3, 4), &val,
+      arena);
+}
+
+/* grpc.auth.v1.Request */
+
+UPB_INLINE grpc_auth_v1_Request *grpc_auth_v1_Request_new(upb_arena *arena) {
+  return (grpc_auth_v1_Request *)_upb_msg_new(&grpc_auth_v1_Request_msginit, arena);
+}
+UPB_INLINE grpc_auth_v1_Request *grpc_auth_v1_Request_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  grpc_auth_v1_Request *ret = grpc_auth_v1_Request_new(arena);
+  return (ret && upb_decode(buf, size, ret, &grpc_auth_v1_Request_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE grpc_auth_v1_Request *grpc_auth_v1_Request_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  grpc_auth_v1_Request *ret = grpc_auth_v1_Request_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &grpc_auth_v1_Request_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *grpc_auth_v1_Request_serialize(const grpc_auth_v1_Request *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &grpc_auth_v1_Request_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview const* grpc_auth_v1_Request_paths(const grpc_auth_v1_Request *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
+UPB_INLINE bool grpc_auth_v1_Request_has_headers(const grpc_auth_v1_Request *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
+UPB_INLINE const grpc_auth_v1_Header* const* grpc_auth_v1_Request_headers(const grpc_auth_v1_Request *msg, size_t *len) { return (const grpc_auth_v1_Header* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
+
+UPB_INLINE upb_strview* grpc_auth_v1_Request_mutable_paths(grpc_auth_v1_Request *msg, size_t *len) {
+  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
+}
+UPB_INLINE upb_strview* grpc_auth_v1_Request_resize_paths(grpc_auth_v1_Request *msg, size_t len, upb_arena *arena) {
+  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(3, 4), arena);
+}
+UPB_INLINE bool grpc_auth_v1_Request_add_paths(grpc_auth_v1_Request *msg, upb_strview val, upb_arena *arena) {
+  return _upb_array_append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(3, 4), &val,
+      arena);
+}
+UPB_INLINE grpc_auth_v1_Header** grpc_auth_v1_Request_mutable_headers(grpc_auth_v1_Request *msg, size_t *len) {
+  return (grpc_auth_v1_Header**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
+}
+UPB_INLINE grpc_auth_v1_Header** grpc_auth_v1_Request_resize_headers(grpc_auth_v1_Request *msg, size_t len, upb_arena *arena) {
+  return (grpc_auth_v1_Header**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct grpc_auth_v1_Header* grpc_auth_v1_Request_add_headers(grpc_auth_v1_Request *msg, upb_arena *arena) {
+  struct grpc_auth_v1_Header* sub = (struct grpc_auth_v1_Header*)_upb_msg_new(&grpc_auth_v1_Header_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* grpc.auth.v1.Rule */
+
+UPB_INLINE grpc_auth_v1_Rule *grpc_auth_v1_Rule_new(upb_arena *arena) {
+  return (grpc_auth_v1_Rule *)_upb_msg_new(&grpc_auth_v1_Rule_msginit, arena);
+}
+UPB_INLINE grpc_auth_v1_Rule *grpc_auth_v1_Rule_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  grpc_auth_v1_Rule *ret = grpc_auth_v1_Rule_new(arena);
+  return (ret && upb_decode(buf, size, ret, &grpc_auth_v1_Rule_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE grpc_auth_v1_Rule *grpc_auth_v1_Rule_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  grpc_auth_v1_Rule *ret = grpc_auth_v1_Rule_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &grpc_auth_v1_Rule_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *grpc_auth_v1_Rule_serialize(const grpc_auth_v1_Rule *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &grpc_auth_v1_Rule_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview grpc_auth_v1_Rule_name(const grpc_auth_v1_Rule *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool grpc_auth_v1_Rule_has_source(const grpc_auth_v1_Rule *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const grpc_auth_v1_Peer* grpc_auth_v1_Rule_source(const grpc_auth_v1_Rule *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const grpc_auth_v1_Peer*); }
+UPB_INLINE bool grpc_auth_v1_Rule_has_request(const grpc_auth_v1_Rule *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const grpc_auth_v1_Request* grpc_auth_v1_Rule_request(const grpc_auth_v1_Rule *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const grpc_auth_v1_Request*); }
+
+UPB_INLINE void grpc_auth_v1_Rule_set_name(grpc_auth_v1_Rule *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void grpc_auth_v1_Rule_set_source(grpc_auth_v1_Rule *msg, grpc_auth_v1_Peer* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), grpc_auth_v1_Peer*) = value;
+}
+UPB_INLINE struct grpc_auth_v1_Peer* grpc_auth_v1_Rule_mutable_source(grpc_auth_v1_Rule *msg, upb_arena *arena) {
+  struct grpc_auth_v1_Peer* sub = (struct grpc_auth_v1_Peer*)grpc_auth_v1_Rule_source(msg);
+  if (sub == NULL) {
+    sub = (struct grpc_auth_v1_Peer*)_upb_msg_new(&grpc_auth_v1_Peer_msginit, arena);
+    if (!sub) return NULL;
+    grpc_auth_v1_Rule_set_source(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void grpc_auth_v1_Rule_set_request(grpc_auth_v1_Rule *msg, grpc_auth_v1_Request* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), grpc_auth_v1_Request*) = value;
+}
+UPB_INLINE struct grpc_auth_v1_Request* grpc_auth_v1_Rule_mutable_request(grpc_auth_v1_Rule *msg, upb_arena *arena) {
+  struct grpc_auth_v1_Request* sub = (struct grpc_auth_v1_Request*)grpc_auth_v1_Rule_request(msg);
+  if (sub == NULL) {
+    sub = (struct grpc_auth_v1_Request*)_upb_msg_new(&grpc_auth_v1_Request_msginit, arena);
+    if (!sub) return NULL;
+    grpc_auth_v1_Rule_set_request(msg, sub);
+  }
+  return sub;
+}
+
+/* grpc.auth.v1.AuthorizationPolicy */
+
+UPB_INLINE grpc_auth_v1_AuthorizationPolicy *grpc_auth_v1_AuthorizationPolicy_new(upb_arena *arena) {
+  return (grpc_auth_v1_AuthorizationPolicy *)_upb_msg_new(&grpc_auth_v1_AuthorizationPolicy_msginit, arena);
+}
+UPB_INLINE grpc_auth_v1_AuthorizationPolicy *grpc_auth_v1_AuthorizationPolicy_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  grpc_auth_v1_AuthorizationPolicy *ret = grpc_auth_v1_AuthorizationPolicy_new(arena);
+  return (ret && upb_decode(buf, size, ret, &grpc_auth_v1_AuthorizationPolicy_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE grpc_auth_v1_AuthorizationPolicy *grpc_auth_v1_AuthorizationPolicy_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  grpc_auth_v1_AuthorizationPolicy *ret = grpc_auth_v1_AuthorizationPolicy_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &grpc_auth_v1_AuthorizationPolicy_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *grpc_auth_v1_AuthorizationPolicy_serialize(const grpc_auth_v1_AuthorizationPolicy *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &grpc_auth_v1_AuthorizationPolicy_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview grpc_auth_v1_AuthorizationPolicy_name(const grpc_auth_v1_AuthorizationPolicy *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+UPB_INLINE bool grpc_auth_v1_AuthorizationPolicy_has_deny_rules(const grpc_auth_v1_AuthorizationPolicy *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 16)); }
+UPB_INLINE const grpc_auth_v1_Rule* const* grpc_auth_v1_AuthorizationPolicy_deny_rules(const grpc_auth_v1_AuthorizationPolicy *msg, size_t *len) { return (const grpc_auth_v1_Rule* const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); }
+UPB_INLINE bool grpc_auth_v1_AuthorizationPolicy_has_allow_rules(const grpc_auth_v1_AuthorizationPolicy *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); }
+UPB_INLINE const grpc_auth_v1_Rule* const* grpc_auth_v1_AuthorizationPolicy_allow_rules(const grpc_auth_v1_AuthorizationPolicy *msg, size_t *len) { return (const grpc_auth_v1_Rule* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); }
+
+UPB_INLINE void grpc_auth_v1_AuthorizationPolicy_set_name(grpc_auth_v1_AuthorizationPolicy *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+UPB_INLINE grpc_auth_v1_Rule** grpc_auth_v1_AuthorizationPolicy_mutable_deny_rules(grpc_auth_v1_AuthorizationPolicy *msg, size_t *len) {
+  return (grpc_auth_v1_Rule**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len);
+}
+UPB_INLINE grpc_auth_v1_Rule** grpc_auth_v1_AuthorizationPolicy_resize_deny_rules(grpc_auth_v1_AuthorizationPolicy *msg, size_t len, upb_arena *arena) {
+  return (grpc_auth_v1_Rule**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 16), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct grpc_auth_v1_Rule* grpc_auth_v1_AuthorizationPolicy_add_deny_rules(grpc_auth_v1_AuthorizationPolicy *msg, upb_arena *arena) {
+  struct grpc_auth_v1_Rule* sub = (struct grpc_auth_v1_Rule*)_upb_msg_new(&grpc_auth_v1_Rule_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(8, 16), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+UPB_INLINE grpc_auth_v1_Rule** grpc_auth_v1_AuthorizationPolicy_mutable_allow_rules(grpc_auth_v1_AuthorizationPolicy *msg, size_t *len) {
+  return (grpc_auth_v1_Rule**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len);
+}
+UPB_INLINE grpc_auth_v1_Rule** grpc_auth_v1_AuthorizationPolicy_resize_allow_rules(grpc_auth_v1_AuthorizationPolicy *msg, size_t len, upb_arena *arena) {
+  return (grpc_auth_v1_Rule**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct grpc_auth_v1_Rule* grpc_auth_v1_AuthorizationPolicy_add_allow_rules(grpc_auth_v1_AuthorizationPolicy *msg, upb_arena *arena) {
+  struct grpc_auth_v1_Rule* sub = (struct grpc_auth_v1_Rule*)_upb_msg_new(&grpc_auth_v1_Rule_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* SRC_PROTO_GRPC_AUTH_V1_AUTHZ_POLICY_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/authority.upb.h b/grpc/src/core/ext/upb-generated/udpa/core/v1/authority.upb.h
deleted file mode 100644
index cc7fc1b..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/authority.upb.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/authority.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_AUTHORITY_PROTO_UPB_H_
-#define UDPA_CORE_V1_AUTHORITY_PROTO_UPB_H_
-
-#include "upb/msg.h"
-#include "upb/decode.h"
-#include "upb/decode_fast.h"
-#include "upb/encode.h"
-
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct udpa_core_v1_Authority;
-typedef struct udpa_core_v1_Authority udpa_core_v1_Authority;
-extern const upb_msglayout udpa_core_v1_Authority_msginit;
-
-
-/* udpa.core.v1.Authority */
-
-UPB_INLINE udpa_core_v1_Authority *udpa_core_v1_Authority_new(upb_arena *arena) {
-  return (udpa_core_v1_Authority *)_upb_msg_new(&udpa_core_v1_Authority_msginit, arena);
-}
-UPB_INLINE udpa_core_v1_Authority *udpa_core_v1_Authority_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  udpa_core_v1_Authority *ret = udpa_core_v1_Authority_new(arena);
-  return (ret && upb_decode(buf, size, ret, &udpa_core_v1_Authority_msginit, arena)) ? ret : NULL;
-}
-UPB_INLINE udpa_core_v1_Authority *udpa_core_v1_Authority_parse_ex(const char *buf, size_t size,
-                           upb_arena *arena, int options) {
-  udpa_core_v1_Authority *ret = udpa_core_v1_Authority_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &udpa_core_v1_Authority_msginit, arena, options))
-      ? ret : NULL;
-}
-UPB_INLINE char *udpa_core_v1_Authority_serialize(const udpa_core_v1_Authority *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &udpa_core_v1_Authority_msginit, arena, len);
-}
-
-UPB_INLINE upb_strview udpa_core_v1_Authority_name(const udpa_core_v1_Authority *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
-
-UPB_INLINE void udpa_core_v1_Authority_set_name(udpa_core_v1_Authority *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_AUTHORITY_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c b/grpc/src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c
deleted file mode 100644
index f6ba895..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/collection_entry.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include <stddef.h>
-#include "upb/msg.h"
-#include "udpa/core/v1/collection_entry.upb.h"
-#include "google/protobuf/any.upb.h"
-#include "udpa/annotations/status.upb.h"
-#include "udpa/core/v1/resource_locator.upb.h"
-#include "validate/validate.upb.h"
-
-#include "upb/port_def.inc"
-
-static const upb_msglayout *const udpa_core_v1_CollectionEntry_submsgs[2] = {
-  &udpa_core_v1_CollectionEntry_InlineEntry_msginit,
-  &udpa_core_v1_ResourceLocator_msginit,
-};
-
-static const upb_msglayout_field udpa_core_v1_CollectionEntry__fields[2] = {
-  {1, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 1, 11, 1},
-  {2, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 0, 11, 1},
-};
-
-const upb_msglayout udpa_core_v1_CollectionEntry_msginit = {
-  &udpa_core_v1_CollectionEntry_submsgs[0],
-  &udpa_core_v1_CollectionEntry__fields[0],
-  UPB_SIZE(8, 16), 2, false, 255,
-};
-
-static const upb_msglayout *const udpa_core_v1_CollectionEntry_InlineEntry_submsgs[1] = {
-  &google_protobuf_Any_msginit,
-};
-
-static const upb_msglayout_field udpa_core_v1_CollectionEntry_InlineEntry__fields[3] = {
-  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
-  {2, UPB_SIZE(12, 24), 0, 0, 9, 1},
-  {3, UPB_SIZE(20, 40), 1, 0, 11, 1},
-};
-
-const upb_msglayout udpa_core_v1_CollectionEntry_InlineEntry_msginit = {
-  &udpa_core_v1_CollectionEntry_InlineEntry_submsgs[0],
-  &udpa_core_v1_CollectionEntry_InlineEntry__fields[0],
-  UPB_SIZE(24, 48), 3, false, 255,
-};
-
-#include "upb/port_undef.inc"
-
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h b/grpc/src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h
deleted file mode 100644
index bf76af4..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/collection_entry.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_COLLECTION_ENTRY_PROTO_UPB_H_
-#define UDPA_CORE_V1_COLLECTION_ENTRY_PROTO_UPB_H_
-
-#include "upb/msg.h"
-#include "upb/decode.h"
-#include "upb/decode_fast.h"
-#include "upb/encode.h"
-
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct udpa_core_v1_CollectionEntry;
-struct udpa_core_v1_CollectionEntry_InlineEntry;
-typedef struct udpa_core_v1_CollectionEntry udpa_core_v1_CollectionEntry;
-typedef struct udpa_core_v1_CollectionEntry_InlineEntry udpa_core_v1_CollectionEntry_InlineEntry;
-extern const upb_msglayout udpa_core_v1_CollectionEntry_msginit;
-extern const upb_msglayout udpa_core_v1_CollectionEntry_InlineEntry_msginit;
-struct google_protobuf_Any;
-struct udpa_core_v1_ResourceLocator;
-extern const upb_msglayout google_protobuf_Any_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_msginit;
-
-
-/* udpa.core.v1.CollectionEntry */
-
-UPB_INLINE udpa_core_v1_CollectionEntry *udpa_core_v1_CollectionEntry_new(upb_arena *arena) {
-  return (udpa_core_v1_CollectionEntry *)_upb_msg_new(&udpa_core_v1_CollectionEntry_msginit, arena);
-}
-UPB_INLINE udpa_core_v1_CollectionEntry *udpa_core_v1_CollectionEntry_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  udpa_core_v1_CollectionEntry *ret = udpa_core_v1_CollectionEntry_new(arena);
-  return (ret && upb_decode(buf, size, ret, &udpa_core_v1_CollectionEntry_msginit, arena)) ? ret : NULL;
-}
-UPB_INLINE udpa_core_v1_CollectionEntry *udpa_core_v1_CollectionEntry_parse_ex(const char *buf, size_t size,
-                           upb_arena *arena, int options) {
-  udpa_core_v1_CollectionEntry *ret = udpa_core_v1_CollectionEntry_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &udpa_core_v1_CollectionEntry_msginit, arena, options))
-      ? ret : NULL;
-}
-UPB_INLINE char *udpa_core_v1_CollectionEntry_serialize(const udpa_core_v1_CollectionEntry *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &udpa_core_v1_CollectionEntry_msginit, arena, len);
-}
-
-typedef enum {
-  udpa_core_v1_CollectionEntry_resource_specifier_locator = 1,
-  udpa_core_v1_CollectionEntry_resource_specifier_inline_entry = 2,
-  udpa_core_v1_CollectionEntry_resource_specifier_NOT_SET = 0
-} udpa_core_v1_CollectionEntry_resource_specifier_oneofcases;
-UPB_INLINE udpa_core_v1_CollectionEntry_resource_specifier_oneofcases udpa_core_v1_CollectionEntry_resource_specifier_case(const udpa_core_v1_CollectionEntry* msg) { return (udpa_core_v1_CollectionEntry_resource_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(4, 8), int32_t); }
-
-UPB_INLINE bool udpa_core_v1_CollectionEntry_has_locator(const udpa_core_v1_CollectionEntry *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 1; }
-UPB_INLINE const struct udpa_core_v1_ResourceLocator* udpa_core_v1_CollectionEntry_locator(const udpa_core_v1_CollectionEntry *msg) { return UPB_READ_ONEOF(msg, const struct udpa_core_v1_ResourceLocator*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 1, NULL); }
-UPB_INLINE bool udpa_core_v1_CollectionEntry_has_inline_entry(const udpa_core_v1_CollectionEntry *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 2; }
-UPB_INLINE const udpa_core_v1_CollectionEntry_InlineEntry* udpa_core_v1_CollectionEntry_inline_entry(const udpa_core_v1_CollectionEntry *msg) { return UPB_READ_ONEOF(msg, const udpa_core_v1_CollectionEntry_InlineEntry*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 2, NULL); }
-
-UPB_INLINE void udpa_core_v1_CollectionEntry_set_locator(udpa_core_v1_CollectionEntry *msg, struct udpa_core_v1_ResourceLocator* value) {
-  UPB_WRITE_ONEOF(msg, struct udpa_core_v1_ResourceLocator*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 1);
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator* udpa_core_v1_CollectionEntry_mutable_locator(udpa_core_v1_CollectionEntry *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceLocator* sub = (struct udpa_core_v1_ResourceLocator*)udpa_core_v1_CollectionEntry_locator(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_ResourceLocator*)_upb_msg_new(&udpa_core_v1_ResourceLocator_msginit, arena);
-    if (!sub) return NULL;
-    udpa_core_v1_CollectionEntry_set_locator(msg, sub);
-  }
-  return sub;
-}
-UPB_INLINE void udpa_core_v1_CollectionEntry_set_inline_entry(udpa_core_v1_CollectionEntry *msg, udpa_core_v1_CollectionEntry_InlineEntry* value) {
-  UPB_WRITE_ONEOF(msg, udpa_core_v1_CollectionEntry_InlineEntry*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 2);
-}
-UPB_INLINE struct udpa_core_v1_CollectionEntry_InlineEntry* udpa_core_v1_CollectionEntry_mutable_inline_entry(udpa_core_v1_CollectionEntry *msg, upb_arena *arena) {
-  struct udpa_core_v1_CollectionEntry_InlineEntry* sub = (struct udpa_core_v1_CollectionEntry_InlineEntry*)udpa_core_v1_CollectionEntry_inline_entry(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_CollectionEntry_InlineEntry*)_upb_msg_new(&udpa_core_v1_CollectionEntry_InlineEntry_msginit, arena);
-    if (!sub) return NULL;
-    udpa_core_v1_CollectionEntry_set_inline_entry(msg, sub);
-  }
-  return sub;
-}
-
-/* udpa.core.v1.CollectionEntry.InlineEntry */
-
-UPB_INLINE udpa_core_v1_CollectionEntry_InlineEntry *udpa_core_v1_CollectionEntry_InlineEntry_new(upb_arena *arena) {
-  return (udpa_core_v1_CollectionEntry_InlineEntry *)_upb_msg_new(&udpa_core_v1_CollectionEntry_InlineEntry_msginit, arena);
-}
-UPB_INLINE udpa_core_v1_CollectionEntry_InlineEntry *udpa_core_v1_CollectionEntry_InlineEntry_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  udpa_core_v1_CollectionEntry_InlineEntry *ret = udpa_core_v1_CollectionEntry_InlineEntry_new(arena);
-  return (ret && upb_decode(buf, size, ret, &udpa_core_v1_CollectionEntry_InlineEntry_msginit, arena)) ? ret : NULL;
-}
-UPB_INLINE udpa_core_v1_CollectionEntry_InlineEntry *udpa_core_v1_CollectionEntry_InlineEntry_parse_ex(const char *buf, size_t size,
-                           upb_arena *arena, int options) {
-  udpa_core_v1_CollectionEntry_InlineEntry *ret = udpa_core_v1_CollectionEntry_InlineEntry_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &udpa_core_v1_CollectionEntry_InlineEntry_msginit, arena, options))
-      ? ret : NULL;
-}
-UPB_INLINE char *udpa_core_v1_CollectionEntry_InlineEntry_serialize(const udpa_core_v1_CollectionEntry_InlineEntry *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &udpa_core_v1_CollectionEntry_InlineEntry_msginit, arena, len);
-}
-
-UPB_INLINE upb_strview udpa_core_v1_CollectionEntry_InlineEntry_name(const udpa_core_v1_CollectionEntry_InlineEntry *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE upb_strview udpa_core_v1_CollectionEntry_InlineEntry_version(const udpa_core_v1_CollectionEntry_InlineEntry *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
-UPB_INLINE bool udpa_core_v1_CollectionEntry_InlineEntry_has_resource(const udpa_core_v1_CollectionEntry_InlineEntry *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE const struct google_protobuf_Any* udpa_core_v1_CollectionEntry_InlineEntry_resource(const udpa_core_v1_CollectionEntry_InlineEntry *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct google_protobuf_Any*); }
-
-UPB_INLINE void udpa_core_v1_CollectionEntry_InlineEntry_set_name(udpa_core_v1_CollectionEntry_InlineEntry *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
-}
-UPB_INLINE void udpa_core_v1_CollectionEntry_InlineEntry_set_version(udpa_core_v1_CollectionEntry_InlineEntry *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
-}
-UPB_INLINE void udpa_core_v1_CollectionEntry_InlineEntry_set_resource(udpa_core_v1_CollectionEntry_InlineEntry *msg, struct google_protobuf_Any* value) {
-  _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct google_protobuf_Any*) = value;
-}
-UPB_INLINE struct google_protobuf_Any* udpa_core_v1_CollectionEntry_InlineEntry_mutable_resource(udpa_core_v1_CollectionEntry_InlineEntry *msg, upb_arena *arena) {
-  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)udpa_core_v1_CollectionEntry_InlineEntry_resource(msg);
-  if (sub == NULL) {
-    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
-    if (!sub) return NULL;
-    udpa_core_v1_CollectionEntry_InlineEntry_set_resource(msg, sub);
-  }
-  return sub;
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_COLLECTION_ENTRY_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c b/grpc/src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c
deleted file mode 100644
index fae1ad0..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/context_params.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include <stddef.h>
-#include "upb/msg.h"
-#include "udpa/core/v1/context_params.upb.h"
-#include "udpa/annotations/status.upb.h"
-
-#include "upb/port_def.inc"
-
-static const upb_msglayout *const udpa_core_v1_ContextParams_submsgs[1] = {
-  &udpa_core_v1_ContextParams_ParamsEntry_msginit,
-};
-
-static const upb_msglayout_field udpa_core_v1_ContextParams__fields[1] = {
-  {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_LABEL_MAP},
-};
-
-const upb_msglayout udpa_core_v1_ContextParams_msginit = {
-  &udpa_core_v1_ContextParams_submsgs[0],
-  &udpa_core_v1_ContextParams__fields[0],
-  UPB_SIZE(8, 8), 1, false, 255,
-};
-
-static const upb_msglayout_field udpa_core_v1_ContextParams_ParamsEntry__fields[2] = {
-  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
-  {2, UPB_SIZE(8, 16), 0, 0, 9, 1},
-};
-
-const upb_msglayout udpa_core_v1_ContextParams_ParamsEntry_msginit = {
-  NULL,
-  &udpa_core_v1_ContextParams_ParamsEntry__fields[0],
-  UPB_SIZE(16, 32), 2, false, 255,
-};
-
-#include "upb/port_undef.inc"
-
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h b/grpc/src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h
deleted file mode 100644
index 2d62de9..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/context_params.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_CONTEXT_PARAMS_PROTO_UPB_H_
-#define UDPA_CORE_V1_CONTEXT_PARAMS_PROTO_UPB_H_
-
-#include "upb/msg.h"
-#include "upb/decode.h"
-#include "upb/decode_fast.h"
-#include "upb/encode.h"
-
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct udpa_core_v1_ContextParams;
-struct udpa_core_v1_ContextParams_ParamsEntry;
-typedef struct udpa_core_v1_ContextParams udpa_core_v1_ContextParams;
-typedef struct udpa_core_v1_ContextParams_ParamsEntry udpa_core_v1_ContextParams_ParamsEntry;
-extern const upb_msglayout udpa_core_v1_ContextParams_msginit;
-extern const upb_msglayout udpa_core_v1_ContextParams_ParamsEntry_msginit;
-
-
-/* udpa.core.v1.ContextParams */
-
-UPB_INLINE udpa_core_v1_ContextParams *udpa_core_v1_ContextParams_new(upb_arena *arena) {
-  return (udpa_core_v1_ContextParams *)_upb_msg_new(&udpa_core_v1_ContextParams_msginit, arena);
-}
-UPB_INLINE udpa_core_v1_ContextParams *udpa_core_v1_ContextParams_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  udpa_core_v1_ContextParams *ret = udpa_core_v1_ContextParams_new(arena);
-  return (ret && upb_decode(buf, size, ret, &udpa_core_v1_ContextParams_msginit, arena)) ? ret : NULL;
-}
-UPB_INLINE udpa_core_v1_ContextParams *udpa_core_v1_ContextParams_parse_ex(const char *buf, size_t size,
-                           upb_arena *arena, int options) {
-  udpa_core_v1_ContextParams *ret = udpa_core_v1_ContextParams_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &udpa_core_v1_ContextParams_msginit, arena, options))
-      ? ret : NULL;
-}
-UPB_INLINE char *udpa_core_v1_ContextParams_serialize(const udpa_core_v1_ContextParams *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &udpa_core_v1_ContextParams_msginit, arena, len);
-}
-
-UPB_INLINE bool udpa_core_v1_ContextParams_has_params(const udpa_core_v1_ContextParams *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
-UPB_INLINE size_t udpa_core_v1_ContextParams_params_size(const udpa_core_v1_ContextParams *msg) {return _upb_msg_map_size(msg, UPB_SIZE(0, 0)); }
-UPB_INLINE bool udpa_core_v1_ContextParams_params_get(const udpa_core_v1_ContextParams *msg, upb_strview key, upb_strview *val) { return _upb_msg_map_get(msg, UPB_SIZE(0, 0), &key, 0, val, 0); }
-UPB_INLINE const udpa_core_v1_ContextParams_ParamsEntry* udpa_core_v1_ContextParams_params_next(const udpa_core_v1_ContextParams *msg, size_t* iter) { return (const udpa_core_v1_ContextParams_ParamsEntry*)_upb_msg_map_next(msg, UPB_SIZE(0, 0), iter); }
-
-UPB_INLINE void udpa_core_v1_ContextParams_params_clear(udpa_core_v1_ContextParams *msg) { _upb_msg_map_clear(msg, UPB_SIZE(0, 0)); }
-UPB_INLINE bool udpa_core_v1_ContextParams_params_set(udpa_core_v1_ContextParams *msg, upb_strview key, upb_strview val, upb_arena *a) { return _upb_msg_map_set(msg, UPB_SIZE(0, 0), &key, 0, &val, 0, a); }
-UPB_INLINE bool udpa_core_v1_ContextParams_params_delete(udpa_core_v1_ContextParams *msg, upb_strview key) { return _upb_msg_map_delete(msg, UPB_SIZE(0, 0), &key, 0); }
-UPB_INLINE udpa_core_v1_ContextParams_ParamsEntry* udpa_core_v1_ContextParams_params_nextmutable(udpa_core_v1_ContextParams *msg, size_t* iter) { return (udpa_core_v1_ContextParams_ParamsEntry*)_upb_msg_map_next(msg, UPB_SIZE(0, 0), iter); }
-
-/* udpa.core.v1.ContextParams.ParamsEntry */
-
-UPB_INLINE upb_strview udpa_core_v1_ContextParams_ParamsEntry_key(const udpa_core_v1_ContextParams_ParamsEntry *msg) {
-  upb_strview ret;
-  _upb_msg_map_key(msg, &ret, 0);
-  return ret;
-}
-UPB_INLINE upb_strview udpa_core_v1_ContextParams_ParamsEntry_value(const udpa_core_v1_ContextParams_ParamsEntry *msg) {
-  upb_strview ret;
-  _upb_msg_map_value(msg, &ret, 0);
-  return ret;
-}
-
-UPB_INLINE void udpa_core_v1_ContextParams_ParamsEntry_set_value(udpa_core_v1_ContextParams_ParamsEntry *msg, upb_strview value) {
-  _upb_msg_map_set_value(msg, &value, 0);
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_CONTEXT_PARAMS_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource.upb.c b/grpc/src/core/ext/upb-generated/udpa/core/v1/resource.upb.c
deleted file mode 100644
index 86d2cf4..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource.upb.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include <stddef.h>
-#include "upb/msg.h"
-#include "udpa/core/v1/resource.upb.h"
-#include "google/protobuf/any.upb.h"
-#include "udpa/annotations/status.upb.h"
-#include "udpa/core/v1/resource_name.upb.h"
-
-#include "upb/port_def.inc"
-
-static const upb_msglayout *const udpa_core_v1_Resource_submsgs[2] = {
-  &google_protobuf_Any_msginit,
-  &udpa_core_v1_ResourceName_msginit,
-};
-
-static const upb_msglayout_field udpa_core_v1_Resource__fields[3] = {
-  {1, UPB_SIZE(12, 24), 1, 1, 11, 1},
-  {2, UPB_SIZE(4, 8), 0, 0, 9, 1},
-  {3, UPB_SIZE(16, 32), 2, 0, 11, 1},
-};
-
-const upb_msglayout udpa_core_v1_Resource_msginit = {
-  &udpa_core_v1_Resource_submsgs[0],
-  &udpa_core_v1_Resource__fields[0],
-  UPB_SIZE(24, 48), 3, false, 255,
-};
-
-#include "upb/port_undef.inc"
-
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource.upb.h b/grpc/src/core/ext/upb-generated/udpa/core/v1/resource.upb.h
deleted file mode 100644
index cff8937..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource.upb.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_RESOURCE_PROTO_UPB_H_
-#define UDPA_CORE_V1_RESOURCE_PROTO_UPB_H_
-
-#include "upb/msg.h"
-#include "upb/decode.h"
-#include "upb/decode_fast.h"
-#include "upb/encode.h"
-
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct udpa_core_v1_Resource;
-typedef struct udpa_core_v1_Resource udpa_core_v1_Resource;
-extern const upb_msglayout udpa_core_v1_Resource_msginit;
-struct google_protobuf_Any;
-struct udpa_core_v1_ResourceName;
-extern const upb_msglayout google_protobuf_Any_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceName_msginit;
-
-
-/* udpa.core.v1.Resource */
-
-UPB_INLINE udpa_core_v1_Resource *udpa_core_v1_Resource_new(upb_arena *arena) {
-  return (udpa_core_v1_Resource *)_upb_msg_new(&udpa_core_v1_Resource_msginit, arena);
-}
-UPB_INLINE udpa_core_v1_Resource *udpa_core_v1_Resource_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  udpa_core_v1_Resource *ret = udpa_core_v1_Resource_new(arena);
-  return (ret && upb_decode(buf, size, ret, &udpa_core_v1_Resource_msginit, arena)) ? ret : NULL;
-}
-UPB_INLINE udpa_core_v1_Resource *udpa_core_v1_Resource_parse_ex(const char *buf, size_t size,
-                           upb_arena *arena, int options) {
-  udpa_core_v1_Resource *ret = udpa_core_v1_Resource_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &udpa_core_v1_Resource_msginit, arena, options))
-      ? ret : NULL;
-}
-UPB_INLINE char *udpa_core_v1_Resource_serialize(const udpa_core_v1_Resource *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &udpa_core_v1_Resource_msginit, arena, len);
-}
-
-UPB_INLINE bool udpa_core_v1_Resource_has_name(const udpa_core_v1_Resource *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE const struct udpa_core_v1_ResourceName* udpa_core_v1_Resource_name(const udpa_core_v1_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct udpa_core_v1_ResourceName*); }
-UPB_INLINE upb_strview udpa_core_v1_Resource_version(const udpa_core_v1_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool udpa_core_v1_Resource_has_resource(const udpa_core_v1_Resource *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const struct google_protobuf_Any* udpa_core_v1_Resource_resource(const udpa_core_v1_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct google_protobuf_Any*); }
-
-UPB_INLINE void udpa_core_v1_Resource_set_name(udpa_core_v1_Resource *msg, struct udpa_core_v1_ResourceName* value) {
-  _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct udpa_core_v1_ResourceName*) = value;
-}
-UPB_INLINE struct udpa_core_v1_ResourceName* udpa_core_v1_Resource_mutable_name(udpa_core_v1_Resource *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceName* sub = (struct udpa_core_v1_ResourceName*)udpa_core_v1_Resource_name(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_ResourceName*)_upb_msg_new(&udpa_core_v1_ResourceName_msginit, arena);
-    if (!sub) return NULL;
-    udpa_core_v1_Resource_set_name(msg, sub);
-  }
-  return sub;
-}
-UPB_INLINE void udpa_core_v1_Resource_set_version(udpa_core_v1_Resource *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
-}
-UPB_INLINE void udpa_core_v1_Resource_set_resource(udpa_core_v1_Resource *msg, struct google_protobuf_Any* value) {
-  _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct google_protobuf_Any*) = value;
-}
-UPB_INLINE struct google_protobuf_Any* udpa_core_v1_Resource_mutable_resource(udpa_core_v1_Resource *msg, upb_arena *arena) {
-  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)udpa_core_v1_Resource_resource(msg);
-  if (sub == NULL) {
-    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
-    if (!sub) return NULL;
-    udpa_core_v1_Resource_set_resource(msg, sub);
-  }
-  return sub;
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_RESOURCE_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c b/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c
deleted file mode 100644
index 5ceb62e..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource_locator.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include <stddef.h>
-#include "upb/msg.h"
-#include "udpa/core/v1/resource_locator.upb.h"
-#include "udpa/annotations/status.upb.h"
-#include "udpa/core/v1/context_params.upb.h"
-#include "validate/validate.upb.h"
-
-#include "upb/port_def.inc"
-
-static const upb_msglayout *const udpa_core_v1_ResourceLocator_submsgs[2] = {
-  &udpa_core_v1_ContextParams_msginit,
-  &udpa_core_v1_ResourceLocator_Directive_msginit,
-};
-
-static const upb_msglayout_field udpa_core_v1_ResourceLocator__fields[6] = {
-  {1, UPB_SIZE(0, 0), 0, 0, 14, 1},
-  {2, UPB_SIZE(20, 40), 0, 0, 9, 3},
-  {3, UPB_SIZE(4, 8), 0, 0, 9, 1},
-  {4, UPB_SIZE(12, 24), 0, 0, 9, 1},
-  {5, UPB_SIZE(28, 56), UPB_SIZE(-33, -65), 0, 11, 1},
-  {6, UPB_SIZE(24, 48), 0, 1, 11, 3},
-};
-
-const upb_msglayout udpa_core_v1_ResourceLocator_msginit = {
-  &udpa_core_v1_ResourceLocator_submsgs[0],
-  &udpa_core_v1_ResourceLocator__fields[0],
-  UPB_SIZE(40, 80), 6, false, 255,
-};
-
-static const upb_msglayout *const udpa_core_v1_ResourceLocator_Directive_submsgs[1] = {
-  &udpa_core_v1_ResourceLocator_msginit,
-};
-
-static const upb_msglayout_field udpa_core_v1_ResourceLocator_Directive__fields[2] = {
-  {1, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 11, 1},
-  {2, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 9, 1},
-};
-
-const upb_msglayout udpa_core_v1_ResourceLocator_Directive_msginit = {
-  &udpa_core_v1_ResourceLocator_Directive_submsgs[0],
-  &udpa_core_v1_ResourceLocator_Directive__fields[0],
-  UPB_SIZE(16, 32), 2, false, 255,
-};
-
-#include "upb/port_undef.inc"
-
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h b/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h
deleted file mode 100644
index ff52c58..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource_locator.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_RESOURCE_LOCATOR_PROTO_UPB_H_
-#define UDPA_CORE_V1_RESOURCE_LOCATOR_PROTO_UPB_H_
-
-#include "upb/msg.h"
-#include "upb/decode.h"
-#include "upb/decode_fast.h"
-#include "upb/encode.h"
-
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct udpa_core_v1_ResourceLocator;
-struct udpa_core_v1_ResourceLocator_Directive;
-typedef struct udpa_core_v1_ResourceLocator udpa_core_v1_ResourceLocator;
-typedef struct udpa_core_v1_ResourceLocator_Directive udpa_core_v1_ResourceLocator_Directive;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_Directive_msginit;
-struct udpa_core_v1_ContextParams;
-extern const upb_msglayout udpa_core_v1_ContextParams_msginit;
-
-typedef enum {
-  udpa_core_v1_ResourceLocator_UDPA = 0,
-  udpa_core_v1_ResourceLocator_HTTP = 1,
-  udpa_core_v1_ResourceLocator_FILE = 2
-} udpa_core_v1_ResourceLocator_Scheme;
-
-
-/* udpa.core.v1.ResourceLocator */
-
-UPB_INLINE udpa_core_v1_ResourceLocator *udpa_core_v1_ResourceLocator_new(upb_arena *arena) {
-  return (udpa_core_v1_ResourceLocator *)_upb_msg_new(&udpa_core_v1_ResourceLocator_msginit, arena);
-}
-UPB_INLINE udpa_core_v1_ResourceLocator *udpa_core_v1_ResourceLocator_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  udpa_core_v1_ResourceLocator *ret = udpa_core_v1_ResourceLocator_new(arena);
-  return (ret && upb_decode(buf, size, ret, &udpa_core_v1_ResourceLocator_msginit, arena)) ? ret : NULL;
-}
-UPB_INLINE udpa_core_v1_ResourceLocator *udpa_core_v1_ResourceLocator_parse_ex(const char *buf, size_t size,
-                           upb_arena *arena, int options) {
-  udpa_core_v1_ResourceLocator *ret = udpa_core_v1_ResourceLocator_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &udpa_core_v1_ResourceLocator_msginit, arena, options))
-      ? ret : NULL;
-}
-UPB_INLINE char *udpa_core_v1_ResourceLocator_serialize(const udpa_core_v1_ResourceLocator *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &udpa_core_v1_ResourceLocator_msginit, arena, len);
-}
-
-typedef enum {
-  udpa_core_v1_ResourceLocator_context_param_specifier_exact_context = 5,
-  udpa_core_v1_ResourceLocator_context_param_specifier_NOT_SET = 0
-} udpa_core_v1_ResourceLocator_context_param_specifier_oneofcases;
-UPB_INLINE udpa_core_v1_ResourceLocator_context_param_specifier_oneofcases udpa_core_v1_ResourceLocator_context_param_specifier_case(const udpa_core_v1_ResourceLocator* msg) { return (udpa_core_v1_ResourceLocator_context_param_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(32, 64), int32_t); }
-
-UPB_INLINE int32_t udpa_core_v1_ResourceLocator_scheme(const udpa_core_v1_ResourceLocator *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int32_t); }
-UPB_INLINE upb_strview const* udpa_core_v1_ResourceLocator_id(const udpa_core_v1_ResourceLocator *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); }
-UPB_INLINE upb_strview udpa_core_v1_ResourceLocator_authority(const udpa_core_v1_ResourceLocator *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE upb_strview udpa_core_v1_ResourceLocator_resource_type(const udpa_core_v1_ResourceLocator *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
-UPB_INLINE bool udpa_core_v1_ResourceLocator_has_exact_context(const udpa_core_v1_ResourceLocator *msg) { return _upb_getoneofcase(msg, UPB_SIZE(32, 64)) == 5; }
-UPB_INLINE const struct udpa_core_v1_ContextParams* udpa_core_v1_ResourceLocator_exact_context(const udpa_core_v1_ResourceLocator *msg) { return UPB_READ_ONEOF(msg, const struct udpa_core_v1_ContextParams*, UPB_SIZE(28, 56), UPB_SIZE(32, 64), 5, NULL); }
-UPB_INLINE bool udpa_core_v1_ResourceLocator_has_directives(const udpa_core_v1_ResourceLocator *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); }
-UPB_INLINE const udpa_core_v1_ResourceLocator_Directive* const* udpa_core_v1_ResourceLocator_directives(const udpa_core_v1_ResourceLocator *msg, size_t *len) { return (const udpa_core_v1_ResourceLocator_Directive* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
-
-UPB_INLINE void udpa_core_v1_ResourceLocator_set_scheme(udpa_core_v1_ResourceLocator *msg, int32_t value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int32_t) = value;
-}
-UPB_INLINE upb_strview* udpa_core_v1_ResourceLocator_mutable_id(udpa_core_v1_ResourceLocator *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len);
-}
-UPB_INLINE upb_strview* udpa_core_v1_ResourceLocator_resize_id(udpa_core_v1_ResourceLocator *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(3, 4), arena);
-}
-UPB_INLINE bool udpa_core_v1_ResourceLocator_add_id(udpa_core_v1_ResourceLocator *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(3, 4), &val,
-      arena);
-}
-UPB_INLINE void udpa_core_v1_ResourceLocator_set_authority(udpa_core_v1_ResourceLocator *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
-}
-UPB_INLINE void udpa_core_v1_ResourceLocator_set_resource_type(udpa_core_v1_ResourceLocator *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
-}
-UPB_INLINE void udpa_core_v1_ResourceLocator_set_exact_context(udpa_core_v1_ResourceLocator *msg, struct udpa_core_v1_ContextParams* value) {
-  UPB_WRITE_ONEOF(msg, struct udpa_core_v1_ContextParams*, UPB_SIZE(28, 56), value, UPB_SIZE(32, 64), 5);
-}
-UPB_INLINE struct udpa_core_v1_ContextParams* udpa_core_v1_ResourceLocator_mutable_exact_context(udpa_core_v1_ResourceLocator *msg, upb_arena *arena) {
-  struct udpa_core_v1_ContextParams* sub = (struct udpa_core_v1_ContextParams*)udpa_core_v1_ResourceLocator_exact_context(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_ContextParams*)_upb_msg_new(&udpa_core_v1_ContextParams_msginit, arena);
-    if (!sub) return NULL;
-    udpa_core_v1_ResourceLocator_set_exact_context(msg, sub);
-  }
-  return sub;
-}
-UPB_INLINE udpa_core_v1_ResourceLocator_Directive** udpa_core_v1_ResourceLocator_mutable_directives(udpa_core_v1_ResourceLocator *msg, size_t *len) {
-  return (udpa_core_v1_ResourceLocator_Directive**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
-}
-UPB_INLINE udpa_core_v1_ResourceLocator_Directive** udpa_core_v1_ResourceLocator_resize_directives(udpa_core_v1_ResourceLocator *msg, size_t len, upb_arena *arena) {
-  return (udpa_core_v1_ResourceLocator_Directive**)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena);
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator_Directive* udpa_core_v1_ResourceLocator_add_directives(udpa_core_v1_ResourceLocator *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceLocator_Directive* sub = (struct udpa_core_v1_ResourceLocator_Directive*)_upb_msg_new(&udpa_core_v1_ResourceLocator_Directive_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
-      msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena);
-  if (!ok) return NULL;
-  return sub;
-}
-
-/* udpa.core.v1.ResourceLocator.Directive */
-
-UPB_INLINE udpa_core_v1_ResourceLocator_Directive *udpa_core_v1_ResourceLocator_Directive_new(upb_arena *arena) {
-  return (udpa_core_v1_ResourceLocator_Directive *)_upb_msg_new(&udpa_core_v1_ResourceLocator_Directive_msginit, arena);
-}
-UPB_INLINE udpa_core_v1_ResourceLocator_Directive *udpa_core_v1_ResourceLocator_Directive_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  udpa_core_v1_ResourceLocator_Directive *ret = udpa_core_v1_ResourceLocator_Directive_new(arena);
-  return (ret && upb_decode(buf, size, ret, &udpa_core_v1_ResourceLocator_Directive_msginit, arena)) ? ret : NULL;
-}
-UPB_INLINE udpa_core_v1_ResourceLocator_Directive *udpa_core_v1_ResourceLocator_Directive_parse_ex(const char *buf, size_t size,
-                           upb_arena *arena, int options) {
-  udpa_core_v1_ResourceLocator_Directive *ret = udpa_core_v1_ResourceLocator_Directive_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &udpa_core_v1_ResourceLocator_Directive_msginit, arena, options))
-      ? ret : NULL;
-}
-UPB_INLINE char *udpa_core_v1_ResourceLocator_Directive_serialize(const udpa_core_v1_ResourceLocator_Directive *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &udpa_core_v1_ResourceLocator_Directive_msginit, arena, len);
-}
-
-typedef enum {
-  udpa_core_v1_ResourceLocator_Directive_directive_alt = 1,
-  udpa_core_v1_ResourceLocator_Directive_directive_entry = 2,
-  udpa_core_v1_ResourceLocator_Directive_directive_NOT_SET = 0
-} udpa_core_v1_ResourceLocator_Directive_directive_oneofcases;
-UPB_INLINE udpa_core_v1_ResourceLocator_Directive_directive_oneofcases udpa_core_v1_ResourceLocator_Directive_directive_case(const udpa_core_v1_ResourceLocator_Directive* msg) { return (udpa_core_v1_ResourceLocator_Directive_directive_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(8, 16), int32_t); }
-
-UPB_INLINE bool udpa_core_v1_ResourceLocator_Directive_has_alt(const udpa_core_v1_ResourceLocator_Directive *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 1; }
-UPB_INLINE const udpa_core_v1_ResourceLocator* udpa_core_v1_ResourceLocator_Directive_alt(const udpa_core_v1_ResourceLocator_Directive *msg) { return UPB_READ_ONEOF(msg, const udpa_core_v1_ResourceLocator*, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 1, NULL); }
-UPB_INLINE bool udpa_core_v1_ResourceLocator_Directive_has_entry(const udpa_core_v1_ResourceLocator_Directive *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 2; }
-UPB_INLINE upb_strview udpa_core_v1_ResourceLocator_Directive_entry(const udpa_core_v1_ResourceLocator_Directive *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 2, upb_strview_make("", strlen(""))); }
-
-UPB_INLINE void udpa_core_v1_ResourceLocator_Directive_set_alt(udpa_core_v1_ResourceLocator_Directive *msg, udpa_core_v1_ResourceLocator* value) {
-  UPB_WRITE_ONEOF(msg, udpa_core_v1_ResourceLocator*, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 1);
-}
-UPB_INLINE struct udpa_core_v1_ResourceLocator* udpa_core_v1_ResourceLocator_Directive_mutable_alt(udpa_core_v1_ResourceLocator_Directive *msg, upb_arena *arena) {
-  struct udpa_core_v1_ResourceLocator* sub = (struct udpa_core_v1_ResourceLocator*)udpa_core_v1_ResourceLocator_Directive_alt(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_ResourceLocator*)_upb_msg_new(&udpa_core_v1_ResourceLocator_msginit, arena);
-    if (!sub) return NULL;
-    udpa_core_v1_ResourceLocator_Directive_set_alt(msg, sub);
-  }
-  return sub;
-}
-UPB_INLINE void udpa_core_v1_ResourceLocator_Directive_set_entry(udpa_core_v1_ResourceLocator_Directive *msg, upb_strview value) {
-  UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 2);
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_RESOURCE_LOCATOR_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c b/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c
deleted file mode 100644
index 4bc48b4..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource_name.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include <stddef.h>
-#include "upb/msg.h"
-#include "udpa/core/v1/resource_name.upb.h"
-#include "udpa/annotations/status.upb.h"
-#include "udpa/core/v1/context_params.upb.h"
-#include "validate/validate.upb.h"
-
-#include "upb/port_def.inc"
-
-static const upb_msglayout *const udpa_core_v1_ResourceName_submsgs[1] = {
-  &udpa_core_v1_ContextParams_msginit,
-};
-
-static const upb_msglayout_field udpa_core_v1_ResourceName__fields[4] = {
-  {1, UPB_SIZE(24, 48), 0, 0, 9, 3},
-  {2, UPB_SIZE(4, 8), 0, 0, 9, 1},
-  {3, UPB_SIZE(12, 24), 0, 0, 9, 1},
-  {4, UPB_SIZE(20, 40), 1, 0, 11, 1},
-};
-
-const upb_msglayout udpa_core_v1_ResourceName_msginit = {
-  &udpa_core_v1_ResourceName_submsgs[0],
-  &udpa_core_v1_ResourceName__fields[0],
-  UPB_SIZE(32, 64), 4, false, 255,
-};
-
-#include "upb/port_undef.inc"
-
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h b/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h
deleted file mode 100644
index f631a2c..0000000
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource_name.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_RESOURCE_NAME_PROTO_UPB_H_
-#define UDPA_CORE_V1_RESOURCE_NAME_PROTO_UPB_H_
-
-#include "upb/msg.h"
-#include "upb/decode.h"
-#include "upb/decode_fast.h"
-#include "upb/encode.h"
-
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct udpa_core_v1_ResourceName;
-typedef struct udpa_core_v1_ResourceName udpa_core_v1_ResourceName;
-extern const upb_msglayout udpa_core_v1_ResourceName_msginit;
-struct udpa_core_v1_ContextParams;
-extern const upb_msglayout udpa_core_v1_ContextParams_msginit;
-
-
-/* udpa.core.v1.ResourceName */
-
-UPB_INLINE udpa_core_v1_ResourceName *udpa_core_v1_ResourceName_new(upb_arena *arena) {
-  return (udpa_core_v1_ResourceName *)_upb_msg_new(&udpa_core_v1_ResourceName_msginit, arena);
-}
-UPB_INLINE udpa_core_v1_ResourceName *udpa_core_v1_ResourceName_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  udpa_core_v1_ResourceName *ret = udpa_core_v1_ResourceName_new(arena);
-  return (ret && upb_decode(buf, size, ret, &udpa_core_v1_ResourceName_msginit, arena)) ? ret : NULL;
-}
-UPB_INLINE udpa_core_v1_ResourceName *udpa_core_v1_ResourceName_parse_ex(const char *buf, size_t size,
-                           upb_arena *arena, int options) {
-  udpa_core_v1_ResourceName *ret = udpa_core_v1_ResourceName_new(arena);
-  return (ret && _upb_decode(buf, size, ret, &udpa_core_v1_ResourceName_msginit, arena, options))
-      ? ret : NULL;
-}
-UPB_INLINE char *udpa_core_v1_ResourceName_serialize(const udpa_core_v1_ResourceName *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &udpa_core_v1_ResourceName_msginit, arena, len);
-}
-
-UPB_INLINE upb_strview const* udpa_core_v1_ResourceName_id(const udpa_core_v1_ResourceName *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
-UPB_INLINE upb_strview udpa_core_v1_ResourceName_authority(const udpa_core_v1_ResourceName *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE upb_strview udpa_core_v1_ResourceName_resource_type(const udpa_core_v1_ResourceName *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
-UPB_INLINE bool udpa_core_v1_ResourceName_has_context(const udpa_core_v1_ResourceName *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE const struct udpa_core_v1_ContextParams* udpa_core_v1_ResourceName_context(const udpa_core_v1_ResourceName *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct udpa_core_v1_ContextParams*); }
-
-UPB_INLINE upb_strview* udpa_core_v1_ResourceName_mutable_id(udpa_core_v1_ResourceName *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
-}
-UPB_INLINE upb_strview* udpa_core_v1_ResourceName_resize_id(udpa_core_v1_ResourceName *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(3, 4), arena);
-}
-UPB_INLINE bool udpa_core_v1_ResourceName_add_id(udpa_core_v1_ResourceName *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val,
-      arena);
-}
-UPB_INLINE void udpa_core_v1_ResourceName_set_authority(udpa_core_v1_ResourceName *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
-}
-UPB_INLINE void udpa_core_v1_ResourceName_set_resource_type(udpa_core_v1_ResourceName *msg, upb_strview value) {
-  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
-}
-UPB_INLINE void udpa_core_v1_ResourceName_set_context(udpa_core_v1_ResourceName *msg, struct udpa_core_v1_ContextParams* value) {
-  _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct udpa_core_v1_ContextParams*) = value;
-}
-UPB_INLINE struct udpa_core_v1_ContextParams* udpa_core_v1_ResourceName_mutable_context(udpa_core_v1_ResourceName *msg, upb_arena *arena) {
-  struct udpa_core_v1_ContextParams* sub = (struct udpa_core_v1_ContextParams*)udpa_core_v1_ResourceName_context(msg);
-  if (sub == NULL) {
-    sub = (struct udpa_core_v1_ContextParams*)_upb_msg_new(&udpa_core_v1_ContextParams_msginit, arena);
-    if (!sub) return NULL;
-    udpa_core_v1_ResourceName_set_context(msg, sub);
-  }
-  return sub;
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_RESOURCE_NAME_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c b/grpc/src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c
new file mode 100644
index 0000000..24407fa
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c
@@ -0,0 +1,33 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     udpa/type/v1/typed_struct.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "udpa/type/v1/typed_struct.upb.h"
+#include "validate/validate.upb.h"
+#include "google/protobuf/struct.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const udpa_type_v1_TypedStruct_submsgs[1] = {
+  &google_protobuf_Struct_msginit,
+};
+
+static const upb_msglayout_field udpa_type_v1_TypedStruct__fields[2] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 1, 0, 11, 1},
+};
+
+const upb_msglayout udpa_type_v1_TypedStruct_msginit = {
+  &udpa_type_v1_TypedStruct_submsgs[0],
+  &udpa_type_v1_TypedStruct__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h b/grpc/src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h
new file mode 100644
index 0000000..2dd03ff
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h
@@ -0,0 +1,77 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     udpa/type/v1/typed_struct.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef UDPA_TYPE_V1_TYPED_STRUCT_PROTO_UPB_H_
+#define UDPA_TYPE_V1_TYPED_STRUCT_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct udpa_type_v1_TypedStruct;
+typedef struct udpa_type_v1_TypedStruct udpa_type_v1_TypedStruct;
+extern const upb_msglayout udpa_type_v1_TypedStruct_msginit;
+struct google_protobuf_Struct;
+extern const upb_msglayout google_protobuf_Struct_msginit;
+
+
+/* udpa.type.v1.TypedStruct */
+
+UPB_INLINE udpa_type_v1_TypedStruct *udpa_type_v1_TypedStruct_new(upb_arena *arena) {
+  return (udpa_type_v1_TypedStruct *)_upb_msg_new(&udpa_type_v1_TypedStruct_msginit, arena);
+}
+UPB_INLINE udpa_type_v1_TypedStruct *udpa_type_v1_TypedStruct_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  udpa_type_v1_TypedStruct *ret = udpa_type_v1_TypedStruct_new(arena);
+  return (ret && upb_decode(buf, size, ret, &udpa_type_v1_TypedStruct_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE udpa_type_v1_TypedStruct *udpa_type_v1_TypedStruct_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  udpa_type_v1_TypedStruct *ret = udpa_type_v1_TypedStruct_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &udpa_type_v1_TypedStruct_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *udpa_type_v1_TypedStruct_serialize(const udpa_type_v1_TypedStruct *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &udpa_type_v1_TypedStruct_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview udpa_type_v1_TypedStruct_type_url(const udpa_type_v1_TypedStruct *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool udpa_type_v1_TypedStruct_has_value(const udpa_type_v1_TypedStruct *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Struct* udpa_type_v1_TypedStruct_value(const udpa_type_v1_TypedStruct *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct google_protobuf_Struct*); }
+
+UPB_INLINE void udpa_type_v1_TypedStruct_set_type_url(udpa_type_v1_TypedStruct *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void udpa_type_v1_TypedStruct_set_value(udpa_type_v1_TypedStruct *msg, struct google_protobuf_Struct* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct google_protobuf_Struct*) = value;
+}
+UPB_INLINE struct google_protobuf_Struct* udpa_type_v1_TypedStruct_mutable_value(udpa_type_v1_TypedStruct *msg, upb_arena *arena) {
+  struct google_protobuf_Struct* sub = (struct google_protobuf_Struct*)udpa_type_v1_TypedStruct_value(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Struct*)_upb_msg_new(&google_protobuf_Struct_msginit, arena);
+    if (!sub) return NULL;
+    udpa_type_v1_TypedStruct_set_value(msg, sub);
+  }
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* UDPA_TYPE_V1_TYPED_STRUCT_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/udpa/core/v1/authority.upb.c b/grpc/src/core/ext/upb-generated/xds/core/v3/authority.upb.c
similarity index 64%
rename from grpc/src/core/ext/upb-generated/udpa/core/v1/authority.upb.c
rename to grpc/src/core/ext/upb-generated/xds/core/v3/authority.upb.c
index a8a3877..6c6da7d 100644
--- a/grpc/src/core/ext/upb-generated/udpa/core/v1/authority.upb.c
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/authority.upb.c
@@ -1,26 +1,26 @@
 /* This file was generated by upbc (the upb compiler) from the input
  * file:
  *
- *     udpa/core/v1/authority.proto
+ *     xds/core/v3/authority.proto
  *
  * Do not edit -- your changes will be discarded when the file is
  * regenerated. */
 
 #include <stddef.h>
 #include "upb/msg.h"
-#include "udpa/core/v1/authority.upb.h"
+#include "xds/core/v3/authority.upb.h"
 #include "udpa/annotations/status.upb.h"
 #include "validate/validate.upb.h"
 
 #include "upb/port_def.inc"
 
-static const upb_msglayout_field udpa_core_v1_Authority__fields[1] = {
+static const upb_msglayout_field xds_core_v3_Authority__fields[1] = {
   {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
 };
 
-const upb_msglayout udpa_core_v1_Authority_msginit = {
+const upb_msglayout xds_core_v3_Authority_msginit = {
   NULL,
-  &udpa_core_v1_Authority__fields[0],
+  &xds_core_v3_Authority__fields[0],
   UPB_SIZE(8, 16), 1, false, 255,
 };
 
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/authority.upb.h b/grpc/src/core/ext/upb-generated/xds/core/v3/authority.upb.h
new file mode 100644
index 0000000..2f1ff44
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/authority.upb.h
@@ -0,0 +1,60 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/authority.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_AUTHORITY_PROTO_UPB_H_
+#define XDS_CORE_V3_AUTHORITY_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xds_core_v3_Authority;
+typedef struct xds_core_v3_Authority xds_core_v3_Authority;
+extern const upb_msglayout xds_core_v3_Authority_msginit;
+
+
+/* xds.core.v3.Authority */
+
+UPB_INLINE xds_core_v3_Authority *xds_core_v3_Authority_new(upb_arena *arena) {
+  return (xds_core_v3_Authority *)_upb_msg_new(&xds_core_v3_Authority_msginit, arena);
+}
+UPB_INLINE xds_core_v3_Authority *xds_core_v3_Authority_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  xds_core_v3_Authority *ret = xds_core_v3_Authority_new(arena);
+  return (ret && upb_decode(buf, size, ret, &xds_core_v3_Authority_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE xds_core_v3_Authority *xds_core_v3_Authority_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  xds_core_v3_Authority *ret = xds_core_v3_Authority_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &xds_core_v3_Authority_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *xds_core_v3_Authority_serialize(const xds_core_v3_Authority *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &xds_core_v3_Authority_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview xds_core_v3_Authority_name(const xds_core_v3_Authority *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview); }
+
+UPB_INLINE void xds_core_v3_Authority_set_name(xds_core_v3_Authority *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), upb_strview) = value;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_AUTHORITY_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c b/grpc/src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c
new file mode 100644
index 0000000..20cc297
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c
@@ -0,0 +1,52 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/collection_entry.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "xds/core/v3/collection_entry.upb.h"
+#include "google/protobuf/any.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "xds/core/v3/resource_locator.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const xds_core_v3_CollectionEntry_submsgs[2] = {
+  &xds_core_v3_CollectionEntry_InlineEntry_msginit,
+  &xds_core_v3_ResourceLocator_msginit,
+};
+
+static const upb_msglayout_field xds_core_v3_CollectionEntry__fields[2] = {
+  {1, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 1, 11, 1},
+  {2, UPB_SIZE(0, 0), UPB_SIZE(-5, -9), 0, 11, 1},
+};
+
+const upb_msglayout xds_core_v3_CollectionEntry_msginit = {
+  &xds_core_v3_CollectionEntry_submsgs[0],
+  &xds_core_v3_CollectionEntry__fields[0],
+  UPB_SIZE(8, 16), 2, false, 255,
+};
+
+static const upb_msglayout *const xds_core_v3_CollectionEntry_InlineEntry_submsgs[1] = {
+  &google_protobuf_Any_msginit,
+};
+
+static const upb_msglayout_field xds_core_v3_CollectionEntry_InlineEntry__fields[3] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 0, 0, 9, 1},
+  {3, UPB_SIZE(20, 40), 1, 0, 11, 1},
+};
+
+const upb_msglayout xds_core_v3_CollectionEntry_InlineEntry_msginit = {
+  &xds_core_v3_CollectionEntry_InlineEntry_submsgs[0],
+  &xds_core_v3_CollectionEntry_InlineEntry__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h b/grpc/src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h
new file mode 100644
index 0000000..983a345
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h
@@ -0,0 +1,143 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/collection_entry.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_COLLECTION_ENTRY_PROTO_UPB_H_
+#define XDS_CORE_V3_COLLECTION_ENTRY_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xds_core_v3_CollectionEntry;
+struct xds_core_v3_CollectionEntry_InlineEntry;
+typedef struct xds_core_v3_CollectionEntry xds_core_v3_CollectionEntry;
+typedef struct xds_core_v3_CollectionEntry_InlineEntry xds_core_v3_CollectionEntry_InlineEntry;
+extern const upb_msglayout xds_core_v3_CollectionEntry_msginit;
+extern const upb_msglayout xds_core_v3_CollectionEntry_InlineEntry_msginit;
+struct google_protobuf_Any;
+struct xds_core_v3_ResourceLocator;
+extern const upb_msglayout google_protobuf_Any_msginit;
+extern const upb_msglayout xds_core_v3_ResourceLocator_msginit;
+
+
+/* xds.core.v3.CollectionEntry */
+
+UPB_INLINE xds_core_v3_CollectionEntry *xds_core_v3_CollectionEntry_new(upb_arena *arena) {
+  return (xds_core_v3_CollectionEntry *)_upb_msg_new(&xds_core_v3_CollectionEntry_msginit, arena);
+}
+UPB_INLINE xds_core_v3_CollectionEntry *xds_core_v3_CollectionEntry_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  xds_core_v3_CollectionEntry *ret = xds_core_v3_CollectionEntry_new(arena);
+  return (ret && upb_decode(buf, size, ret, &xds_core_v3_CollectionEntry_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE xds_core_v3_CollectionEntry *xds_core_v3_CollectionEntry_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  xds_core_v3_CollectionEntry *ret = xds_core_v3_CollectionEntry_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &xds_core_v3_CollectionEntry_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *xds_core_v3_CollectionEntry_serialize(const xds_core_v3_CollectionEntry *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &xds_core_v3_CollectionEntry_msginit, arena, len);
+}
+
+typedef enum {
+  xds_core_v3_CollectionEntry_resource_specifier_locator = 1,
+  xds_core_v3_CollectionEntry_resource_specifier_inline_entry = 2,
+  xds_core_v3_CollectionEntry_resource_specifier_NOT_SET = 0
+} xds_core_v3_CollectionEntry_resource_specifier_oneofcases;
+UPB_INLINE xds_core_v3_CollectionEntry_resource_specifier_oneofcases xds_core_v3_CollectionEntry_resource_specifier_case(const xds_core_v3_CollectionEntry* msg) { return (xds_core_v3_CollectionEntry_resource_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(4, 8), int32_t); }
+
+UPB_INLINE bool xds_core_v3_CollectionEntry_has_locator(const xds_core_v3_CollectionEntry *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 1; }
+UPB_INLINE const struct xds_core_v3_ResourceLocator* xds_core_v3_CollectionEntry_locator(const xds_core_v3_CollectionEntry *msg) { return UPB_READ_ONEOF(msg, const struct xds_core_v3_ResourceLocator*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 1, NULL); }
+UPB_INLINE bool xds_core_v3_CollectionEntry_has_inline_entry(const xds_core_v3_CollectionEntry *msg) { return _upb_getoneofcase(msg, UPB_SIZE(4, 8)) == 2; }
+UPB_INLINE const xds_core_v3_CollectionEntry_InlineEntry* xds_core_v3_CollectionEntry_inline_entry(const xds_core_v3_CollectionEntry *msg) { return UPB_READ_ONEOF(msg, const xds_core_v3_CollectionEntry_InlineEntry*, UPB_SIZE(0, 0), UPB_SIZE(4, 8), 2, NULL); }
+
+UPB_INLINE void xds_core_v3_CollectionEntry_set_locator(xds_core_v3_CollectionEntry *msg, struct xds_core_v3_ResourceLocator* value) {
+  UPB_WRITE_ONEOF(msg, struct xds_core_v3_ResourceLocator*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 1);
+}
+UPB_INLINE struct xds_core_v3_ResourceLocator* xds_core_v3_CollectionEntry_mutable_locator(xds_core_v3_CollectionEntry *msg, upb_arena *arena) {
+  struct xds_core_v3_ResourceLocator* sub = (struct xds_core_v3_ResourceLocator*)xds_core_v3_CollectionEntry_locator(msg);
+  if (sub == NULL) {
+    sub = (struct xds_core_v3_ResourceLocator*)_upb_msg_new(&xds_core_v3_ResourceLocator_msginit, arena);
+    if (!sub) return NULL;
+    xds_core_v3_CollectionEntry_set_locator(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void xds_core_v3_CollectionEntry_set_inline_entry(xds_core_v3_CollectionEntry *msg, xds_core_v3_CollectionEntry_InlineEntry* value) {
+  UPB_WRITE_ONEOF(msg, xds_core_v3_CollectionEntry_InlineEntry*, UPB_SIZE(0, 0), value, UPB_SIZE(4, 8), 2);
+}
+UPB_INLINE struct xds_core_v3_CollectionEntry_InlineEntry* xds_core_v3_CollectionEntry_mutable_inline_entry(xds_core_v3_CollectionEntry *msg, upb_arena *arena) {
+  struct xds_core_v3_CollectionEntry_InlineEntry* sub = (struct xds_core_v3_CollectionEntry_InlineEntry*)xds_core_v3_CollectionEntry_inline_entry(msg);
+  if (sub == NULL) {
+    sub = (struct xds_core_v3_CollectionEntry_InlineEntry*)_upb_msg_new(&xds_core_v3_CollectionEntry_InlineEntry_msginit, arena);
+    if (!sub) return NULL;
+    xds_core_v3_CollectionEntry_set_inline_entry(msg, sub);
+  }
+  return sub;
+}
+
+/* xds.core.v3.CollectionEntry.InlineEntry */
+
+UPB_INLINE xds_core_v3_CollectionEntry_InlineEntry *xds_core_v3_CollectionEntry_InlineEntry_new(upb_arena *arena) {
+  return (xds_core_v3_CollectionEntry_InlineEntry *)_upb_msg_new(&xds_core_v3_CollectionEntry_InlineEntry_msginit, arena);
+}
+UPB_INLINE xds_core_v3_CollectionEntry_InlineEntry *xds_core_v3_CollectionEntry_InlineEntry_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  xds_core_v3_CollectionEntry_InlineEntry *ret = xds_core_v3_CollectionEntry_InlineEntry_new(arena);
+  return (ret && upb_decode(buf, size, ret, &xds_core_v3_CollectionEntry_InlineEntry_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE xds_core_v3_CollectionEntry_InlineEntry *xds_core_v3_CollectionEntry_InlineEntry_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  xds_core_v3_CollectionEntry_InlineEntry *ret = xds_core_v3_CollectionEntry_InlineEntry_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &xds_core_v3_CollectionEntry_InlineEntry_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *xds_core_v3_CollectionEntry_InlineEntry_serialize(const xds_core_v3_CollectionEntry_InlineEntry *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &xds_core_v3_CollectionEntry_InlineEntry_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview xds_core_v3_CollectionEntry_InlineEntry_name(const xds_core_v3_CollectionEntry_InlineEntry *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_strview xds_core_v3_CollectionEntry_InlineEntry_version(const xds_core_v3_CollectionEntry_InlineEntry *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE bool xds_core_v3_CollectionEntry_InlineEntry_has_resource(const xds_core_v3_CollectionEntry_InlineEntry *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct google_protobuf_Any* xds_core_v3_CollectionEntry_InlineEntry_resource(const xds_core_v3_CollectionEntry_InlineEntry *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), const struct google_protobuf_Any*); }
+
+UPB_INLINE void xds_core_v3_CollectionEntry_InlineEntry_set_name(xds_core_v3_CollectionEntry_InlineEntry *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_CollectionEntry_InlineEntry_set_version(xds_core_v3_CollectionEntry_InlineEntry *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_CollectionEntry_InlineEntry_set_resource(xds_core_v3_CollectionEntry_InlineEntry *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* xds_core_v3_CollectionEntry_InlineEntry_mutable_resource(xds_core_v3_CollectionEntry_InlineEntry *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)xds_core_v3_CollectionEntry_InlineEntry_resource(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    xds_core_v3_CollectionEntry_InlineEntry_set_resource(msg, sub);
+  }
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_COLLECTION_ENTRY_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/context_params.upb.c b/grpc/src/core/ext/upb-generated/xds/core/v3/context_params.upb.c
new file mode 100644
index 0000000..17c3c61
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/context_params.upb.c
@@ -0,0 +1,42 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/context_params.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "xds/core/v3/context_params.upb.h"
+#include "udpa/annotations/status.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const xds_core_v3_ContextParams_submsgs[1] = {
+  &xds_core_v3_ContextParams_ParamsEntry_msginit,
+};
+
+static const upb_msglayout_field xds_core_v3_ContextParams__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_LABEL_MAP},
+};
+
+const upb_msglayout xds_core_v3_ContextParams_msginit = {
+  &xds_core_v3_ContextParams_submsgs[0],
+  &xds_core_v3_ContextParams__fields[0],
+  UPB_SIZE(8, 8), 1, false, 255,
+};
+
+static const upb_msglayout_field xds_core_v3_ContextParams_ParamsEntry__fields[2] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 9, 1},
+  {2, UPB_SIZE(8, 16), 0, 0, 9, 1},
+};
+
+const upb_msglayout xds_core_v3_ContextParams_ParamsEntry_msginit = {
+  NULL,
+  &xds_core_v3_ContextParams_ParamsEntry__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/context_params.upb.h b/grpc/src/core/ext/upb-generated/xds/core/v3/context_params.upb.h
new file mode 100644
index 0000000..0bcd242
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/context_params.upb.h
@@ -0,0 +1,84 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/context_params.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_CONTEXT_PARAMS_PROTO_UPB_H_
+#define XDS_CORE_V3_CONTEXT_PARAMS_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xds_core_v3_ContextParams;
+struct xds_core_v3_ContextParams_ParamsEntry;
+typedef struct xds_core_v3_ContextParams xds_core_v3_ContextParams;
+typedef struct xds_core_v3_ContextParams_ParamsEntry xds_core_v3_ContextParams_ParamsEntry;
+extern const upb_msglayout xds_core_v3_ContextParams_msginit;
+extern const upb_msglayout xds_core_v3_ContextParams_ParamsEntry_msginit;
+
+
+/* xds.core.v3.ContextParams */
+
+UPB_INLINE xds_core_v3_ContextParams *xds_core_v3_ContextParams_new(upb_arena *arena) {
+  return (xds_core_v3_ContextParams *)_upb_msg_new(&xds_core_v3_ContextParams_msginit, arena);
+}
+UPB_INLINE xds_core_v3_ContextParams *xds_core_v3_ContextParams_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  xds_core_v3_ContextParams *ret = xds_core_v3_ContextParams_new(arena);
+  return (ret && upb_decode(buf, size, ret, &xds_core_v3_ContextParams_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE xds_core_v3_ContextParams *xds_core_v3_ContextParams_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  xds_core_v3_ContextParams *ret = xds_core_v3_ContextParams_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &xds_core_v3_ContextParams_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *xds_core_v3_ContextParams_serialize(const xds_core_v3_ContextParams *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &xds_core_v3_ContextParams_msginit, arena, len);
+}
+
+UPB_INLINE bool xds_core_v3_ContextParams_has_params(const xds_core_v3_ContextParams *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE size_t xds_core_v3_ContextParams_params_size(const xds_core_v3_ContextParams *msg) {return _upb_msg_map_size(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE bool xds_core_v3_ContextParams_params_get(const xds_core_v3_ContextParams *msg, upb_strview key, upb_strview *val) { return _upb_msg_map_get(msg, UPB_SIZE(0, 0), &key, 0, val, 0); }
+UPB_INLINE const xds_core_v3_ContextParams_ParamsEntry* xds_core_v3_ContextParams_params_next(const xds_core_v3_ContextParams *msg, size_t* iter) { return (const xds_core_v3_ContextParams_ParamsEntry*)_upb_msg_map_next(msg, UPB_SIZE(0, 0), iter); }
+
+UPB_INLINE void xds_core_v3_ContextParams_params_clear(xds_core_v3_ContextParams *msg) { _upb_msg_map_clear(msg, UPB_SIZE(0, 0)); }
+UPB_INLINE bool xds_core_v3_ContextParams_params_set(xds_core_v3_ContextParams *msg, upb_strview key, upb_strview val, upb_arena *a) { return _upb_msg_map_set(msg, UPB_SIZE(0, 0), &key, 0, &val, 0, a); }
+UPB_INLINE bool xds_core_v3_ContextParams_params_delete(xds_core_v3_ContextParams *msg, upb_strview key) { return _upb_msg_map_delete(msg, UPB_SIZE(0, 0), &key, 0); }
+UPB_INLINE xds_core_v3_ContextParams_ParamsEntry* xds_core_v3_ContextParams_params_nextmutable(xds_core_v3_ContextParams *msg, size_t* iter) { return (xds_core_v3_ContextParams_ParamsEntry*)_upb_msg_map_next(msg, UPB_SIZE(0, 0), iter); }
+
+/* xds.core.v3.ContextParams.ParamsEntry */
+
+UPB_INLINE upb_strview xds_core_v3_ContextParams_ParamsEntry_key(const xds_core_v3_ContextParams_ParamsEntry *msg) {
+  upb_strview ret;
+  _upb_msg_map_key(msg, &ret, 0);
+  return ret;
+}
+UPB_INLINE upb_strview xds_core_v3_ContextParams_ParamsEntry_value(const xds_core_v3_ContextParams_ParamsEntry *msg) {
+  upb_strview ret;
+  _upb_msg_map_value(msg, &ret, 0);
+  return ret;
+}
+
+UPB_INLINE void xds_core_v3_ContextParams_ParamsEntry_set_value(xds_core_v3_ContextParams_ParamsEntry *msg, upb_strview value) {
+  _upb_msg_map_set_value(msg, &value, 0);
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_CONTEXT_PARAMS_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/resource.upb.c b/grpc/src/core/ext/upb-generated/xds/core/v3/resource.upb.c
new file mode 100644
index 0000000..fa2375e
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/resource.upb.c
@@ -0,0 +1,36 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "xds/core/v3/resource.upb.h"
+#include "google/protobuf/any.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "xds/core/v3/resource_name.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const xds_core_v3_Resource_submsgs[2] = {
+  &google_protobuf_Any_msginit,
+  &xds_core_v3_ResourceName_msginit,
+};
+
+static const upb_msglayout_field xds_core_v3_Resource__fields[3] = {
+  {1, UPB_SIZE(12, 24), 1, 1, 11, 1},
+  {2, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {3, UPB_SIZE(16, 32), 2, 0, 11, 1},
+};
+
+const upb_msglayout xds_core_v3_Resource_msginit = {
+  &xds_core_v3_Resource_submsgs[0],
+  &xds_core_v3_Resource__fields[0],
+  UPB_SIZE(24, 48), 3, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/resource.upb.h b/grpc/src/core/ext/upb-generated/xds/core/v3/resource.upb.h
new file mode 100644
index 0000000..ab8e2df
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/resource.upb.h
@@ -0,0 +1,94 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_RESOURCE_PROTO_UPB_H_
+#define XDS_CORE_V3_RESOURCE_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xds_core_v3_Resource;
+typedef struct xds_core_v3_Resource xds_core_v3_Resource;
+extern const upb_msglayout xds_core_v3_Resource_msginit;
+struct google_protobuf_Any;
+struct xds_core_v3_ResourceName;
+extern const upb_msglayout google_protobuf_Any_msginit;
+extern const upb_msglayout xds_core_v3_ResourceName_msginit;
+
+
+/* xds.core.v3.Resource */
+
+UPB_INLINE xds_core_v3_Resource *xds_core_v3_Resource_new(upb_arena *arena) {
+  return (xds_core_v3_Resource *)_upb_msg_new(&xds_core_v3_Resource_msginit, arena);
+}
+UPB_INLINE xds_core_v3_Resource *xds_core_v3_Resource_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  xds_core_v3_Resource *ret = xds_core_v3_Resource_new(arena);
+  return (ret && upb_decode(buf, size, ret, &xds_core_v3_Resource_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE xds_core_v3_Resource *xds_core_v3_Resource_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  xds_core_v3_Resource *ret = xds_core_v3_Resource_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &xds_core_v3_Resource_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *xds_core_v3_Resource_serialize(const xds_core_v3_Resource *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &xds_core_v3_Resource_msginit, arena, len);
+}
+
+UPB_INLINE bool xds_core_v3_Resource_has_name(const xds_core_v3_Resource *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct xds_core_v3_ResourceName* xds_core_v3_Resource_name(const xds_core_v3_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const struct xds_core_v3_ResourceName*); }
+UPB_INLINE upb_strview xds_core_v3_Resource_version(const xds_core_v3_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE bool xds_core_v3_Resource_has_resource(const xds_core_v3_Resource *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const struct google_protobuf_Any* xds_core_v3_Resource_resource(const xds_core_v3_Resource *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const struct google_protobuf_Any*); }
+
+UPB_INLINE void xds_core_v3_Resource_set_name(xds_core_v3_Resource *msg, struct xds_core_v3_ResourceName* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), struct xds_core_v3_ResourceName*) = value;
+}
+UPB_INLINE struct xds_core_v3_ResourceName* xds_core_v3_Resource_mutable_name(xds_core_v3_Resource *msg, upb_arena *arena) {
+  struct xds_core_v3_ResourceName* sub = (struct xds_core_v3_ResourceName*)xds_core_v3_Resource_name(msg);
+  if (sub == NULL) {
+    sub = (struct xds_core_v3_ResourceName*)_upb_msg_new(&xds_core_v3_ResourceName_msginit, arena);
+    if (!sub) return NULL;
+    xds_core_v3_Resource_set_name(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void xds_core_v3_Resource_set_version(xds_core_v3_Resource *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_Resource_set_resource(xds_core_v3_Resource *msg, struct google_protobuf_Any* value) {
+  _upb_sethas(msg, 2);
+  *UPB_PTR_AT(msg, UPB_SIZE(16, 32), struct google_protobuf_Any*) = value;
+}
+UPB_INLINE struct google_protobuf_Any* xds_core_v3_Resource_mutable_resource(xds_core_v3_Resource *msg, upb_arena *arena) {
+  struct google_protobuf_Any* sub = (struct google_protobuf_Any*)xds_core_v3_Resource_resource(msg);
+  if (sub == NULL) {
+    sub = (struct google_protobuf_Any*)_upb_msg_new(&google_protobuf_Any_msginit, arena);
+    if (!sub) return NULL;
+    xds_core_v3_Resource_set_resource(msg, sub);
+  }
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_RESOURCE_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c b/grpc/src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c
new file mode 100644
index 0000000..2bd099a
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c
@@ -0,0 +1,54 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource_locator.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "xds/core/v3/resource_locator.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "xds/core/v3/context_params.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const xds_core_v3_ResourceLocator_submsgs[2] = {
+  &xds_core_v3_ContextParams_msginit,
+  &xds_core_v3_ResourceLocator_Directive_msginit,
+};
+
+static const upb_msglayout_field xds_core_v3_ResourceLocator__fields[6] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 14, 1},
+  {2, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {3, UPB_SIZE(12, 24), 0, 0, 9, 1},
+  {4, UPB_SIZE(20, 40), 0, 0, 9, 1},
+  {5, UPB_SIZE(32, 64), UPB_SIZE(-37, -73), 0, 11, 1},
+  {6, UPB_SIZE(28, 56), 0, 1, 11, 3},
+};
+
+const upb_msglayout xds_core_v3_ResourceLocator_msginit = {
+  &xds_core_v3_ResourceLocator_submsgs[0],
+  &xds_core_v3_ResourceLocator__fields[0],
+  UPB_SIZE(40, 80), 6, false, 255,
+};
+
+static const upb_msglayout *const xds_core_v3_ResourceLocator_Directive_submsgs[1] = {
+  &xds_core_v3_ResourceLocator_msginit,
+};
+
+static const upb_msglayout_field xds_core_v3_ResourceLocator_Directive__fields[2] = {
+  {1, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 11, 1},
+  {2, UPB_SIZE(0, 0), UPB_SIZE(-9, -17), 0, 9, 1},
+};
+
+const upb_msglayout xds_core_v3_ResourceLocator_Directive_msginit = {
+  &xds_core_v3_ResourceLocator_Directive_submsgs[0],
+  &xds_core_v3_ResourceLocator_Directive__fields[0],
+  UPB_SIZE(16, 32), 2, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h b/grpc/src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h
new file mode 100644
index 0000000..da7442b
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h
@@ -0,0 +1,166 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource_locator.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_RESOURCE_LOCATOR_PROTO_UPB_H_
+#define XDS_CORE_V3_RESOURCE_LOCATOR_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xds_core_v3_ResourceLocator;
+struct xds_core_v3_ResourceLocator_Directive;
+typedef struct xds_core_v3_ResourceLocator xds_core_v3_ResourceLocator;
+typedef struct xds_core_v3_ResourceLocator_Directive xds_core_v3_ResourceLocator_Directive;
+extern const upb_msglayout xds_core_v3_ResourceLocator_msginit;
+extern const upb_msglayout xds_core_v3_ResourceLocator_Directive_msginit;
+struct xds_core_v3_ContextParams;
+extern const upb_msglayout xds_core_v3_ContextParams_msginit;
+
+typedef enum {
+  xds_core_v3_ResourceLocator_XDSTP = 0,
+  xds_core_v3_ResourceLocator_HTTP = 1,
+  xds_core_v3_ResourceLocator_FILE = 2
+} xds_core_v3_ResourceLocator_Scheme;
+
+
+/* xds.core.v3.ResourceLocator */
+
+UPB_INLINE xds_core_v3_ResourceLocator *xds_core_v3_ResourceLocator_new(upb_arena *arena) {
+  return (xds_core_v3_ResourceLocator *)_upb_msg_new(&xds_core_v3_ResourceLocator_msginit, arena);
+}
+UPB_INLINE xds_core_v3_ResourceLocator *xds_core_v3_ResourceLocator_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  xds_core_v3_ResourceLocator *ret = xds_core_v3_ResourceLocator_new(arena);
+  return (ret && upb_decode(buf, size, ret, &xds_core_v3_ResourceLocator_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE xds_core_v3_ResourceLocator *xds_core_v3_ResourceLocator_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  xds_core_v3_ResourceLocator *ret = xds_core_v3_ResourceLocator_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &xds_core_v3_ResourceLocator_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *xds_core_v3_ResourceLocator_serialize(const xds_core_v3_ResourceLocator *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &xds_core_v3_ResourceLocator_msginit, arena, len);
+}
+
+typedef enum {
+  xds_core_v3_ResourceLocator_context_param_specifier_exact_context = 5,
+  xds_core_v3_ResourceLocator_context_param_specifier_NOT_SET = 0
+} xds_core_v3_ResourceLocator_context_param_specifier_oneofcases;
+UPB_INLINE xds_core_v3_ResourceLocator_context_param_specifier_oneofcases xds_core_v3_ResourceLocator_context_param_specifier_case(const xds_core_v3_ResourceLocator* msg) { return (xds_core_v3_ResourceLocator_context_param_specifier_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(36, 72), int32_t); }
+
+UPB_INLINE int32_t xds_core_v3_ResourceLocator_scheme(const xds_core_v3_ResourceLocator *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int32_t); }
+UPB_INLINE upb_strview xds_core_v3_ResourceLocator_id(const xds_core_v3_ResourceLocator *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_strview xds_core_v3_ResourceLocator_authority(const xds_core_v3_ResourceLocator *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE upb_strview xds_core_v3_ResourceLocator_resource_type(const xds_core_v3_ResourceLocator *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
+UPB_INLINE bool xds_core_v3_ResourceLocator_has_exact_context(const xds_core_v3_ResourceLocator *msg) { return _upb_getoneofcase(msg, UPB_SIZE(36, 72)) == 5; }
+UPB_INLINE const struct xds_core_v3_ContextParams* xds_core_v3_ResourceLocator_exact_context(const xds_core_v3_ResourceLocator *msg) { return UPB_READ_ONEOF(msg, const struct xds_core_v3_ContextParams*, UPB_SIZE(32, 64), UPB_SIZE(36, 72), 5, NULL); }
+UPB_INLINE bool xds_core_v3_ResourceLocator_has_directives(const xds_core_v3_ResourceLocator *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); }
+UPB_INLINE const xds_core_v3_ResourceLocator_Directive* const* xds_core_v3_ResourceLocator_directives(const xds_core_v3_ResourceLocator *msg, size_t *len) { return (const xds_core_v3_ResourceLocator_Directive* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
+
+UPB_INLINE void xds_core_v3_ResourceLocator_set_scheme(xds_core_v3_ResourceLocator *msg, int32_t value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(0, 0), int32_t) = value;
+}
+UPB_INLINE void xds_core_v3_ResourceLocator_set_id(xds_core_v3_ResourceLocator *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_ResourceLocator_set_authority(xds_core_v3_ResourceLocator *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_ResourceLocator_set_resource_type(xds_core_v3_ResourceLocator *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_ResourceLocator_set_exact_context(xds_core_v3_ResourceLocator *msg, struct xds_core_v3_ContextParams* value) {
+  UPB_WRITE_ONEOF(msg, struct xds_core_v3_ContextParams*, UPB_SIZE(32, 64), value, UPB_SIZE(36, 72), 5);
+}
+UPB_INLINE struct xds_core_v3_ContextParams* xds_core_v3_ResourceLocator_mutable_exact_context(xds_core_v3_ResourceLocator *msg, upb_arena *arena) {
+  struct xds_core_v3_ContextParams* sub = (struct xds_core_v3_ContextParams*)xds_core_v3_ResourceLocator_exact_context(msg);
+  if (sub == NULL) {
+    sub = (struct xds_core_v3_ContextParams*)_upb_msg_new(&xds_core_v3_ContextParams_msginit, arena);
+    if (!sub) return NULL;
+    xds_core_v3_ResourceLocator_set_exact_context(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE xds_core_v3_ResourceLocator_Directive** xds_core_v3_ResourceLocator_mutable_directives(xds_core_v3_ResourceLocator *msg, size_t *len) {
+  return (xds_core_v3_ResourceLocator_Directive**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
+}
+UPB_INLINE xds_core_v3_ResourceLocator_Directive** xds_core_v3_ResourceLocator_resize_directives(xds_core_v3_ResourceLocator *msg, size_t len, upb_arena *arena) {
+  return (xds_core_v3_ResourceLocator_Directive**)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena);
+}
+UPB_INLINE struct xds_core_v3_ResourceLocator_Directive* xds_core_v3_ResourceLocator_add_directives(xds_core_v3_ResourceLocator *msg, upb_arena *arena) {
+  struct xds_core_v3_ResourceLocator_Directive* sub = (struct xds_core_v3_ResourceLocator_Directive*)_upb_msg_new(&xds_core_v3_ResourceLocator_Directive_msginit, arena);
+  bool ok = _upb_array_append_accessor2(
+      msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena);
+  if (!ok) return NULL;
+  return sub;
+}
+
+/* xds.core.v3.ResourceLocator.Directive */
+
+UPB_INLINE xds_core_v3_ResourceLocator_Directive *xds_core_v3_ResourceLocator_Directive_new(upb_arena *arena) {
+  return (xds_core_v3_ResourceLocator_Directive *)_upb_msg_new(&xds_core_v3_ResourceLocator_Directive_msginit, arena);
+}
+UPB_INLINE xds_core_v3_ResourceLocator_Directive *xds_core_v3_ResourceLocator_Directive_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  xds_core_v3_ResourceLocator_Directive *ret = xds_core_v3_ResourceLocator_Directive_new(arena);
+  return (ret && upb_decode(buf, size, ret, &xds_core_v3_ResourceLocator_Directive_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE xds_core_v3_ResourceLocator_Directive *xds_core_v3_ResourceLocator_Directive_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  xds_core_v3_ResourceLocator_Directive *ret = xds_core_v3_ResourceLocator_Directive_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &xds_core_v3_ResourceLocator_Directive_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *xds_core_v3_ResourceLocator_Directive_serialize(const xds_core_v3_ResourceLocator_Directive *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &xds_core_v3_ResourceLocator_Directive_msginit, arena, len);
+}
+
+typedef enum {
+  xds_core_v3_ResourceLocator_Directive_directive_alt = 1,
+  xds_core_v3_ResourceLocator_Directive_directive_entry = 2,
+  xds_core_v3_ResourceLocator_Directive_directive_NOT_SET = 0
+} xds_core_v3_ResourceLocator_Directive_directive_oneofcases;
+UPB_INLINE xds_core_v3_ResourceLocator_Directive_directive_oneofcases xds_core_v3_ResourceLocator_Directive_directive_case(const xds_core_v3_ResourceLocator_Directive* msg) { return (xds_core_v3_ResourceLocator_Directive_directive_oneofcases)*UPB_PTR_AT(msg, UPB_SIZE(8, 16), int32_t); }
+
+UPB_INLINE bool xds_core_v3_ResourceLocator_Directive_has_alt(const xds_core_v3_ResourceLocator_Directive *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 1; }
+UPB_INLINE const xds_core_v3_ResourceLocator* xds_core_v3_ResourceLocator_Directive_alt(const xds_core_v3_ResourceLocator_Directive *msg) { return UPB_READ_ONEOF(msg, const xds_core_v3_ResourceLocator*, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 1, NULL); }
+UPB_INLINE bool xds_core_v3_ResourceLocator_Directive_has_entry(const xds_core_v3_ResourceLocator_Directive *msg) { return _upb_getoneofcase(msg, UPB_SIZE(8, 16)) == 2; }
+UPB_INLINE upb_strview xds_core_v3_ResourceLocator_Directive_entry(const xds_core_v3_ResourceLocator_Directive *msg) { return UPB_READ_ONEOF(msg, upb_strview, UPB_SIZE(0, 0), UPB_SIZE(8, 16), 2, upb_strview_make("", strlen(""))); }
+
+UPB_INLINE void xds_core_v3_ResourceLocator_Directive_set_alt(xds_core_v3_ResourceLocator_Directive *msg, xds_core_v3_ResourceLocator* value) {
+  UPB_WRITE_ONEOF(msg, xds_core_v3_ResourceLocator*, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 1);
+}
+UPB_INLINE struct xds_core_v3_ResourceLocator* xds_core_v3_ResourceLocator_Directive_mutable_alt(xds_core_v3_ResourceLocator_Directive *msg, upb_arena *arena) {
+  struct xds_core_v3_ResourceLocator* sub = (struct xds_core_v3_ResourceLocator*)xds_core_v3_ResourceLocator_Directive_alt(msg);
+  if (sub == NULL) {
+    sub = (struct xds_core_v3_ResourceLocator*)_upb_msg_new(&xds_core_v3_ResourceLocator_msginit, arena);
+    if (!sub) return NULL;
+    xds_core_v3_ResourceLocator_Directive_set_alt(msg, sub);
+  }
+  return sub;
+}
+UPB_INLINE void xds_core_v3_ResourceLocator_Directive_set_entry(xds_core_v3_ResourceLocator_Directive *msg, upb_strview value) {
+  UPB_WRITE_ONEOF(msg, upb_strview, UPB_SIZE(0, 0), value, UPB_SIZE(8, 16), 2);
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_RESOURCE_LOCATOR_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c b/grpc/src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c
new file mode 100644
index 0000000..ff645f6
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c
@@ -0,0 +1,36 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource_name.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+#include "upb/msg.h"
+#include "xds/core/v3/resource_name.upb.h"
+#include "udpa/annotations/status.upb.h"
+#include "xds/core/v3/context_params.upb.h"
+#include "validate/validate.upb.h"
+
+#include "upb/port_def.inc"
+
+static const upb_msglayout *const xds_core_v3_ResourceName_submsgs[1] = {
+  &xds_core_v3_ContextParams_msginit,
+};
+
+static const upb_msglayout_field xds_core_v3_ResourceName__fields[4] = {
+  {1, UPB_SIZE(4, 8), 0, 0, 9, 1},
+  {2, UPB_SIZE(12, 24), 0, 0, 9, 1},
+  {3, UPB_SIZE(20, 40), 0, 0, 9, 1},
+  {4, UPB_SIZE(28, 56), 1, 0, 11, 1},
+};
+
+const upb_msglayout xds_core_v3_ResourceName_msginit = {
+  &xds_core_v3_ResourceName_submsgs[0],
+  &xds_core_v3_ResourceName__fields[0],
+  UPB_SIZE(32, 64), 4, false, 255,
+};
+
+#include "upb/port_undef.inc"
+
diff --git a/grpc/src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h b/grpc/src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h
new file mode 100644
index 0000000..3f38cc5
--- /dev/null
+++ b/grpc/src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h
@@ -0,0 +1,85 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource_name.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_RESOURCE_NAME_PROTO_UPB_H_
+#define XDS_CORE_V3_RESOURCE_NAME_PROTO_UPB_H_
+
+#include "upb/msg.h"
+#include "upb/decode.h"
+#include "upb/decode_fast.h"
+#include "upb/encode.h"
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xds_core_v3_ResourceName;
+typedef struct xds_core_v3_ResourceName xds_core_v3_ResourceName;
+extern const upb_msglayout xds_core_v3_ResourceName_msginit;
+struct xds_core_v3_ContextParams;
+extern const upb_msglayout xds_core_v3_ContextParams_msginit;
+
+
+/* xds.core.v3.ResourceName */
+
+UPB_INLINE xds_core_v3_ResourceName *xds_core_v3_ResourceName_new(upb_arena *arena) {
+  return (xds_core_v3_ResourceName *)_upb_msg_new(&xds_core_v3_ResourceName_msginit, arena);
+}
+UPB_INLINE xds_core_v3_ResourceName *xds_core_v3_ResourceName_parse(const char *buf, size_t size,
+                        upb_arena *arena) {
+  xds_core_v3_ResourceName *ret = xds_core_v3_ResourceName_new(arena);
+  return (ret && upb_decode(buf, size, ret, &xds_core_v3_ResourceName_msginit, arena)) ? ret : NULL;
+}
+UPB_INLINE xds_core_v3_ResourceName *xds_core_v3_ResourceName_parse_ex(const char *buf, size_t size,
+                           upb_arena *arena, int options) {
+  xds_core_v3_ResourceName *ret = xds_core_v3_ResourceName_new(arena);
+  return (ret && _upb_decode(buf, size, ret, &xds_core_v3_ResourceName_msginit, arena, options))
+      ? ret : NULL;
+}
+UPB_INLINE char *xds_core_v3_ResourceName_serialize(const xds_core_v3_ResourceName *msg, upb_arena *arena, size_t *len) {
+  return upb_encode(msg, &xds_core_v3_ResourceName_msginit, arena, len);
+}
+
+UPB_INLINE upb_strview xds_core_v3_ResourceName_id(const xds_core_v3_ResourceName *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_strview xds_core_v3_ResourceName_authority(const xds_core_v3_ResourceName *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE upb_strview xds_core_v3_ResourceName_resource_type(const xds_core_v3_ResourceName *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
+UPB_INLINE bool xds_core_v3_ResourceName_has_context(const xds_core_v3_ResourceName *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE const struct xds_core_v3_ContextParams* xds_core_v3_ResourceName_context(const xds_core_v3_ResourceName *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const struct xds_core_v3_ContextParams*); }
+
+UPB_INLINE void xds_core_v3_ResourceName_set_id(xds_core_v3_ResourceName *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_ResourceName_set_authority(xds_core_v3_ResourceName *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_ResourceName_set_resource_type(xds_core_v3_ResourceName *msg, upb_strview value) {
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
+}
+UPB_INLINE void xds_core_v3_ResourceName_set_context(xds_core_v3_ResourceName *msg, struct xds_core_v3_ContextParams* value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 56), struct xds_core_v3_ContextParams*) = value;
+}
+UPB_INLINE struct xds_core_v3_ContextParams* xds_core_v3_ResourceName_mutable_context(xds_core_v3_ResourceName *msg, upb_arena *arena) {
+  struct xds_core_v3_ContextParams* sub = (struct xds_core_v3_ContextParams*)xds_core_v3_ResourceName_context(msg);
+  if (sub == NULL) {
+    sub = (struct xds_core_v3_ContextParams*)_upb_msg_new(&xds_core_v3_ContextParams_msginit, arena);
+    if (!sub) return NULL;
+    xds_core_v3_ResourceName_set_context(msg, sub);
+  }
+  return sub;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_RESOURCE_NAME_PROTO_UPB_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c
new file mode 100644
index 0000000..8418d1e
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c
@@ -0,0 +1,354 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/admin/v3/config_dump.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/admin/v3/config_dump.upbdefs.h"
+
+extern upb_def_init envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit;
+extern upb_def_init google_protobuf_any_proto_upbdefinit;
+extern upb_def_init google_protobuf_timestamp_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern const upb_msglayout envoy_admin_v3_ConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_UpdateFailureState_msginit;
+extern const upb_msglayout envoy_admin_v3_BootstrapConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_StaticListener_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit;
+extern const upb_msglayout envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit;
+extern const upb_msglayout envoy_admin_v3_ClustersConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit;
+extern const upb_msglayout envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit;
+extern const upb_msglayout envoy_admin_v3_RoutesConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit;
+extern const upb_msglayout envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit;
+extern const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit;
+extern const upb_msglayout envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit;
+extern const upb_msglayout envoy_admin_v3_SecretsConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit;
+extern const upb_msglayout envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit;
+extern const upb_msglayout envoy_admin_v3_EndpointsConfigDump_msginit;
+extern const upb_msglayout envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit;
+extern const upb_msglayout envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit;
+
+static const upb_msglayout *layouts[22] = {
+  &envoy_admin_v3_ConfigDump_msginit,
+  &envoy_admin_v3_UpdateFailureState_msginit,
+  &envoy_admin_v3_BootstrapConfigDump_msginit,
+  &envoy_admin_v3_ListenersConfigDump_msginit,
+  &envoy_admin_v3_ListenersConfigDump_StaticListener_msginit,
+  &envoy_admin_v3_ListenersConfigDump_DynamicListenerState_msginit,
+  &envoy_admin_v3_ListenersConfigDump_DynamicListener_msginit,
+  &envoy_admin_v3_ClustersConfigDump_msginit,
+  &envoy_admin_v3_ClustersConfigDump_StaticCluster_msginit,
+  &envoy_admin_v3_ClustersConfigDump_DynamicCluster_msginit,
+  &envoy_admin_v3_RoutesConfigDump_msginit,
+  &envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_msginit,
+  &envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_msginit,
+  &envoy_admin_v3_ScopedRoutesConfigDump_msginit,
+  &envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_msginit,
+  &envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_msginit,
+  &envoy_admin_v3_SecretsConfigDump_msginit,
+  &envoy_admin_v3_SecretsConfigDump_DynamicSecret_msginit,
+  &envoy_admin_v3_SecretsConfigDump_StaticSecret_msginit,
+  &envoy_admin_v3_EndpointsConfigDump_msginit,
+  &envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_msginit,
+  &envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_msginit,
+};
+
+static const char descriptor[6802] = {'\n', ' ', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'd', 'm', 'i', 'n', '/', 'v', '3', '/', 'c', 'o', 'n', 'f', 'i', 'g', '_', 'd', 
+'u', 'm', 'p', '.', 'p', 'r', 'o', 't', 'o', '\022', '\016', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', 
+'\032', ')', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '/', 
+'v', '3', '/', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 
+'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'g', 'o', 'o', 
+'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 
+'t', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 
+'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\"', 'c', '\n', '\n', 'C', 'o', 
+'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\022', '.', '\n', '\007', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\001', ' ', '\003', '(', '\013', 
+'2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\007', 'c', 
+'o', 'n', 'f', 'i', 'g', 's', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 
+'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\"', '\225', '\002', '\n', '\022', 
+'U', 'p', 'd', 'a', 't', 'e', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 'S', 't', 'a', 't', 'e', '\022', 'G', '\n', '\024', 'f', 'a', 'i', 
+'l', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', '\024', 
+'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\023', 'f', 'a', 'i', 
+'l', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\022', 'J', '\n', '\023', 'l', 'a', 's', 't', '_', 
+'u', 'p', 'd', 'a', 't', 'e', '_', 'a', 't', 't', 'e', 'm', 'p', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\021', 
+'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 'e', 'A', 't', 't', 'e', 'm', 'p', 't', '\022', '\030', '\n', '\007', 'd', 'e', 't', 'a', 
+'i', 'l', 's', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\007', 'd', 'e', 't', 'a', 'i', 'l', 's', '\022', '!', '\n', '\014', 'v', 'e', 'r', 
+'s', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\013', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'I', 
+'n', 'f', 'o', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', 
+'2', 'a', 'l', 'p', 'h', 'a', '.', 'U', 'p', 'd', 'a', 't', 'e', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 'S', 't', 'a', 't', 'e', 
+'\"', '\310', '\001', '\n', '\023', 'B', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\022', 
+'B', '\n', '\t', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '\030', '\001', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'B', 'o', 'o', 
+'t', 's', 't', 'r', 'a', 'p', 'R', '\t', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', 
+'_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
+'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 
+'d', 'a', 't', 'e', 'd', ':', '.', '\232', '\305', '\210', '\036', ')', '\n', '\'', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', 
+'.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'B', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 
+'u', 'm', 'p', '\"', '\363', '\t', '\n', '\023', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 
+'m', 'p', '\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', 
+'\013', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', ']', '\n', '\020', 's', 't', 'a', 't', 'i', 'c', '_', 'l', 'i', 
+'s', 't', 'e', 'n', 'e', 'r', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 
+'i', 'n', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', 
+'.', 'S', 't', 'a', 't', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'R', '\017', 's', 't', 'a', 't', 'i', 'c', 'L', 'i', 
+'s', 't', 'e', 'n', 'e', 'r', 's', '\022', '`', '\n', '\021', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '_', 'l', 'i', 's', 't', 'e', 'n', 
+'e', 'r', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '3', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', 
+'3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 
+'a', 'm', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'R', '\020', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'L', 'i', 's', 't', 
+'e', 'n', 'e', 'r', 's', '\032', '\300', '\001', '\n', '\016', 'S', 't', 'a', 't', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '\022', 
+'0', '\n', '\010', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 
+'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\010', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '\022', 
+'=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 
+'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', 
+'\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 'e', 'd', ':', '=', '\232', '\305', '\210', '\036', '8', '\n', '6', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 
+'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'S', 't', 'a', 't', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 
+'\032', '\357', '\001', '\n', '\024', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'S', 't', 'a', 't', 'e', 
+'\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 'v', 
+'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '0', '\n', '\010', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '\030', '\002', ' ', 
+'\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 
+'R', '\010', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 'd', 'a', 't', 'e', 
+'d', '\030', '\003', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
+'.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 'e', 'd', ':', 'C', 
+'\232', '\305', '\210', '\036', '>', '\n', '<', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 
+'a', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 
+'a', 'm', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'S', 't', 'a', 't', 'e', '\032', '\222', '\004', '\n', '\017', 'D', 'y', 'n', 
+'a', 'm', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', 
+'\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '[', '\n', '\014', 'a', 'c', 't', 'i', 'v', 'e', '_', 's', 't', 'a', 't', 'e', '\030', '\002', 
+' ', '\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'L', 'i', 's', 
+'t', 'e', 'n', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'L', 
+'i', 's', 't', 'e', 'n', 'e', 'r', 'S', 't', 'a', 't', 'e', 'R', '\013', 'a', 'c', 't', 'i', 'v', 'e', 'S', 't', 'a', 't', 'e', 
+'\022', ']', '\n', '\r', 'w', 'a', 'r', 'm', 'i', 'n', 'g', '_', 's', 't', 'a', 't', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', '8', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 
+'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 
+'r', 'S', 't', 'a', 't', 'e', 'R', '\014', 'w', 'a', 'r', 'm', 'i', 'n', 'g', 'S', 't', 'a', 't', 'e', '\022', '_', '\n', '\016', 'd', 
+'r', 'a', 'i', 'n', 'i', 'n', 'g', '_', 's', 't', 'a', 't', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 'C', 'o', 'n', 'f', 
+'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'S', 't', 'a', 
+'t', 'e', 'R', '\r', 'd', 'r', 'a', 'i', 'n', 'i', 'n', 'g', 'S', 't', 'a', 't', 'e', '\022', 'C', '\n', '\013', 'e', 'r', 'r', 'o', 
+'r', '_', 's', 't', 'a', 't', 'e', '\030', '\005', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 
+'i', 'n', '.', 'v', '3', '.', 'U', 'p', 'd', 'a', 't', 'e', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 'S', 't', 'a', 't', 'e', 'R', 
+'\n', 'e', 'r', 'r', 'o', 'r', 'S', 't', 'a', 't', 'e', '\022', 'I', '\n', '\r', 'c', 'l', 'i', 'e', 'n', 't', '_', 's', 't', 'a', 
+'t', 'u', 's', '\030', '\006', ' ', '\001', '(', '\016', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', 
+'3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'S', 't', 'a', 't', 'u', 's', 'R', '\014', 'c', 
+'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', ':', '>', '\232', '\305', '\210', '\036', '9', '\n', '7', 'e', 'n', 'v', 'o', 'y', 
+'.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 'C', 
+'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 
+':', '.', '\232', '\305', '\210', '\036', ')', '\n', '\'', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 
+'p', 'h', 'a', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\"', '\312', 
+'\007', '\n', '\022', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\022', '!', '\n', '\014', 
+'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 'v', 'e', 'r', 's', 'i', 
+'o', 'n', 'I', 'n', 'f', 'o', '\022', 'Y', '\n', '\017', 's', 't', 'a', 't', 'i', 'c', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', 
+'\030', '\002', ' ', '\003', '(', '\013', '2', '0', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'C', 
+'l', 'u', 's', 't', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'S', 't', 'a', 't', 'i', 'c', 'C', 
+'l', 'u', 's', 't', 'e', 'r', 'R', '\016', 's', 't', 'a', 't', 'i', 'c', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', '\022', 'i', '\n', 
+'\027', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '_', 'a', 'c', 't', 'i', 'v', 'e', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', '\030', 
+'\003', ' ', '\003', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'C', 'l', 
+'u', 's', 't', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'C', 
+'l', 'u', 's', 't', 'e', 'r', 'R', '\025', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'A', 'c', 't', 'i', 'v', 'e', 'C', 'l', 'u', 's', 
+'t', 'e', 'r', 's', '\022', 'k', '\n', '\030', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '_', 'w', 'a', 'r', 'm', 'i', 'n', 'g', '_', 'c', 
+'l', 'u', 's', 't', 'e', 'r', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 
+'i', 'n', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 
+'D', 'y', 'n', 'a', 'm', 'i', 'c', 'C', 'l', 'u', 's', 't', 'e', 'r', 'R', '\026', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'W', 'a', 
+'r', 'm', 'i', 'n', 'g', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', '\032', '\273', '\001', '\n', '\r', 'S', 't', 'a', 't', 'i', 'c', 'C', 
+'l', 'u', 's', 't', 'e', 'r', '\022', '.', '\n', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '\024', 
+'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\007', 'c', 'l', 'u', 
+'s', 't', 'e', 'r', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', '\002', ' ', '\001', '(', 
+'\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 
+'t', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 'e', 'd', ':', ';', '\232', '\305', '\210', '\036', '6', '\n', 
+'4', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'C', 'l', 'u', 's', 
+'t', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'S', 't', 'a', 't', 'i', 'c', 'C', 'l', 'u', 's', 
+'t', 'e', 'r', '\032', '\360', '\002', '\n', '\016', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', '!', '\n', 
+'\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 'v', 'e', 'r', 's', 
+'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '.', '\n', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', 
+'\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\007', 'c', 'l', 
+'u', 's', 't', 'e', 'r', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', 
+'(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 
+'s', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 'e', 'd', '\022', 'C', '\n', '\013', 'e', 'r', 'r', 
+'o', 'r', '_', 's', 't', 'a', 't', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 
+'m', 'i', 'n', '.', 'v', '3', '.', 'U', 'p', 'd', 'a', 't', 'e', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 'S', 't', 'a', 't', 'e', 
+'R', '\n', 'e', 'r', 'r', 'o', 'r', 'S', 't', 'a', 't', 'e', '\022', 'I', '\n', '\r', 'c', 'l', 'i', 'e', 'n', 't', '_', 's', 't', 
+'a', 't', 'u', 's', '\030', '\005', ' ', '\001', '(', '\016', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 
+'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'S', 't', 'a', 't', 'u', 's', 'R', '\014', 
+'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', ':', '<', '\232', '\305', '\210', '\036', '7', '\n', '5', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', 'C', 
+'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'C', 'l', 'u', 's', 't', 'e', 'r', ':', 
+'-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 
+'h', 'a', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\"', '\335', '\006', '\n', 
+'\020', 'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\022', 'd', '\n', '\024', 's', 't', 'a', 't', 
+'i', 'c', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '2', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 
+'i', 'g', 'D', 'u', 'm', 'p', '.', 'S', 't', 'a', 't', 'i', 'c', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'R', 
+'\022', 's', 't', 'a', 't', 'i', 'c', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', 'g', '\n', '\025', 'd', 'y', 
+'n', 'a', 'm', 'i', 'c', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\003', ' ', '\003', '(', '\013', 
+'2', '3', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 's', 'C', 
+'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 
+'f', 'i', 'g', 'R', '\023', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\032', 
+'\312', '\001', '\n', '\021', 'S', 't', 'a', 't', 'i', 'c', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '7', '\n', '\014', 
+'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 
+'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\013', 'r', 'o', 'u', 't', 'e', 'C', 'o', 'n', 
+'f', 'i', 'g', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', 
+'2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 
+'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 'e', 'd', ':', '=', '\232', '\305', '\210', '\036', '8', '\n', '6', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'R', 'o', 'u', 't', 'e', 
+'s', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'S', 't', 'a', 't', 'i', 'c', 'R', 'o', 'u', 't', 'e', 'C', 'o', 
+'n', 'f', 'i', 'g', '\032', '\377', '\002', '\n', '\022', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 
+'i', 'g', '\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', 
+'\013', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '7', '\n', '\014', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 
+'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'A', 'n', 'y', 'R', '\013', 'r', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '=', '\n', '\014', 'l', 'a', 
+'s', 't', '_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
+'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 
+'U', 'p', 'd', 'a', 't', 'e', 'd', '\022', 'C', '\n', '\013', 'e', 'r', 'r', 'o', 'r', '_', 's', 't', 'a', 't', 'e', '\030', '\004', ' ', 
+'\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'U', 'p', 'd', 'a', 
+'t', 'e', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 'S', 't', 'a', 't', 'e', 'R', '\n', 'e', 'r', 'r', 'o', 'r', 'S', 't', 'a', 't', 
+'e', '\022', 'I', '\n', '\r', 'c', 'l', 'i', 'e', 'n', 't', '_', 's', 't', 'a', 't', 'u', 's', '\030', '\005', ' ', '\001', '(', '\016', '2', 
+'$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'R', 'e', 
+'s', 'o', 'u', 'r', 'c', 'e', 'S', 't', 'a', 't', 'u', 's', 'R', '\014', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 
+'s', ':', '>', '\232', '\305', '\210', '\036', '9', '\n', '7', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 
+'l', 'p', 'h', 'a', '.', 'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 
+'a', 'm', 'i', 'c', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 
+'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'R', 'o', 'u', 't', 'e', 's', 
+'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\"', '\214', '\010', '\n', '\026', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 
+'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\022', '~', '\n', '\033', 'i', 'n', 'l', 'i', 'n', 'e', '_', 's', 'c', 
+'o', 'p', 'e', 'd', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', 
+'?', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 
+'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'I', 'n', 'l', 'i', 'n', 'e', 'S', 'c', 'o', 'p', 
+'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', 'R', '\030', 'i', 'n', 'l', 'i', 'n', 'e', 'S', 'c', 'o', 
+'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', '\201', '\001', '\n', '\034', 'd', 'y', 'n', 'a', 'm', 
+'i', 'c', '_', 's', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\002', 
+' ', '\003', '(', '\013', '2', '@', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'S', 'c', 'o', 
+'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 
+'i', 'c', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', 'R', '\031', 'd', 'y', 'n', 
+'a', 'm', 'i', 'c', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\032', '\201', '\002', 
+'\n', '\030', 'I', 'n', 'l', 'i', 'n', 'e', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 
+'s', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'F', '\n', '\024', 
+'s', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\002', ' ', '\003', '(', 
+'\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\022', 
+'s', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', '=', '\n', '\014', 'l', 'a', 's', 
+'t', '_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 
+'p', 'd', 'a', 't', 'e', 'd', ':', 'J', '\232', '\305', '\210', '\036', 'E', '\n', 'C', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 
+'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 
+'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'I', 'n', 'l', 'i', 'n', 'e', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 
+'C', 'o', 'n', 'f', 'i', 'g', 's', '\032', '\266', '\003', '\n', '\031', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'S', 'c', 'o', 'p', 'e', 'd', 
+'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', 
+'\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\002', 
+' ', '\001', '(', '\t', 'R', '\013', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', 'F', '\n', '\024', 's', 'c', 'o', 'p', 
+'e', 'd', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '\024', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\022', 's', 'c', 'o', 'p', 
+'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 
+'d', 'a', 't', 'e', 'd', '\030', '\004', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 
+'e', 'd', '\022', 'C', '\n', '\013', 'e', 'r', 'r', 'o', 'r', '_', 's', 't', 'a', 't', 'e', '\030', '\005', ' ', '\001', '(', '\013', '2', '\"', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'U', 'p', 'd', 'a', 't', 'e', 'F', 'a', 'i', 
+'l', 'u', 'r', 'e', 'S', 't', 'a', 't', 'e', 'R', '\n', 'e', 'r', 'r', 'o', 'r', 'S', 't', 'a', 't', 'e', '\022', 'I', '\n', '\r', 
+'c', 'l', 'i', 'e', 'n', 't', '_', 's', 't', 'a', 't', 'u', 's', '\030', '\006', ' ', '\001', '(', '\016', '2', '$', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'R', 'e', 's', 'o', 'u', 'r', 'c', 
+'e', 'S', 't', 'a', 't', 'u', 's', 'R', '\014', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', ':', 'K', '\232', '\305', 
+'\210', '\036', 'F', '\n', 'D', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 
+'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 
+'n', 'a', 'm', 'i', 'c', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', ':', '1', 
+'\232', '\305', '\210', '\036', ',', '\n', '*', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 
+'a', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\"', 
+'\267', '\007', '\n', '\021', 'S', 'e', 'c', 'r', 'e', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '\022', 'U', '\n', '\016', 
+'s', 't', 'a', 't', 'i', 'c', '_', 's', 'e', 'c', 'r', 'e', 't', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '.', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'S', 'e', 'c', 'r', 'e', 't', 's', 'C', 'o', 'n', 'f', 'i', 
+'g', 'D', 'u', 'm', 'p', '.', 'S', 't', 'a', 't', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', 'R', '\r', 's', 't', 'a', 't', 'i', 
+'c', 'S', 'e', 'c', 'r', 'e', 't', 's', '\022', 'e', '\n', '\026', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '_', 'a', 'c', 't', 'i', 'v', 
+'e', '_', 's', 'e', 'c', 'r', 'e', 't', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
+'d', 'm', 'i', 'n', '.', 'v', '3', '.', 'S', 'e', 'c', 'r', 'e', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', 
+'.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', 'R', '\024', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'A', 'c', 
+'t', 'i', 'v', 'e', 'S', 'e', 'c', 'r', 'e', 't', 's', '\022', 'g', '\n', '\027', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '_', 'w', 'a', 
+'r', 'm', 'i', 'n', 'g', '_', 's', 'e', 'c', 'r', 'e', 't', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'S', 'e', 'c', 'r', 'e', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 
+'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', 'R', '\025', 'd', 'y', 'n', 'a', 'm', 
+'i', 'c', 'W', 'a', 'r', 'm', 'i', 'n', 'g', 'S', 'e', 'c', 'r', 'e', 't', 's', '\032', '\377', '\002', '\n', '\r', 'D', 'y', 'n', 'a', 
+'m', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 
+'n', 'a', 'm', 'e', '\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\002', ' ', '\001', '(', 
+'\t', 'R', '\013', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 
+'d', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 
+'e', 'd', '\022', ',', '\n', '\006', 's', 'e', 'c', 'r', 'e', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 
+'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\006', 's', 'e', 'c', 'r', 'e', 't', '\022', 'C', 
+'\n', '\013', 'e', 'r', 'r', 'o', 'r', '_', 's', 't', 'a', 't', 'e', '\030', '\005', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'U', 'p', 'd', 'a', 't', 'e', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 
+'S', 't', 'a', 't', 'e', 'R', '\n', 'e', 'r', 'r', 'o', 'r', 'S', 't', 'a', 't', 'e', '\022', 'I', '\n', '\r', 'c', 'l', 'i', 'e', 
+'n', 't', '_', 's', 't', 'a', 't', 'u', 's', '\030', '\006', ' ', '\001', '(', '\016', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
+'d', 'm', 'i', 'n', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'S', 't', 'a', 
+'t', 'u', 's', 'R', '\014', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', ':', ':', '\232', '\305', '\210', '\036', '5', '\n', 
+'3', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'S', 'e', 'c', 'r', 
+'e', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'S', 'e', 'c', 'r', 
+'e', 't', '\032', '\312', '\001', '\n', '\014', 'S', 't', 'a', 't', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', '\022', '\022', '\n', '\004', 'n', 'a', 
+'m', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 
+'d', 'a', 't', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 
+'e', 'd', '\022', ',', '\n', '\006', 's', 'e', 'c', 'r', 'e', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 
+'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\006', 's', 'e', 'c', 'r', 'e', 't', ':', '9', 
+'\232', '\305', '\210', '\036', '4', '\n', '2', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 
+'a', '.', 'S', 'e', 'c', 'r', 'e', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'S', 't', 'a', 't', 'i', 
+'c', 'S', 'e', 'c', 'r', 'e', 't', ':', ',', '\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 
+'i', 'n', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'S', 'e', 'c', 'r', 'e', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 
+'u', 'm', 'p', '\"', '\336', '\005', '\n', '\023', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 
+'m', 'p', '\022', 'p', '\n', '\027', 's', 't', 'a', 't', 'i', 'c', '_', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '_', 'c', 'o', 'n', 
+'f', 'i', 'g', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 
+'v', '3', '.', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'S', 't', 
+'a', 't', 'i', 'c', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\025', 's', 't', 'a', 't', 'i', 
+'c', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', 's', '\n', '\030', 'd', 'y', 'n', 'a', 'm', 
+'i', 'c', '_', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\003', ' ', '\003', '(', '\013', 
+'2', '9', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 
+'t', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'E', 'n', 'd', 'p', 'o', 
+'i', 'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\026', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 
+'t', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\032', '\224', '\001', '\n', '\024', 'S', 't', 'a', 't', 'i', 'c', 'E', 'n', 'd', 'p', 'o', 'i', 
+'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '=', '\n', '\017', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '_', 'c', 'o', 'n', 'f', 
+'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'A', 'n', 'y', 'R', '\016', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '=', '\n', '\014', 
+'l', 'a', 's', 't', '_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 
+'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 
+'s', 't', 'U', 'p', 'd', 'a', 't', 'e', 'd', '\032', '\310', '\002', '\n', '\025', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'E', 'n', 'd', 'p', 
+'o', 'i', 'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 
+'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '=', '\n', '\017', 'e', 
+'n', 'd', 'p', 'o', 'i', 'n', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\016', 'e', 'n', 'd', 'p', 'o', 'i', 
+'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '=', '\n', '\014', 'l', 'a', 's', 't', '_', 'u', 'p', 'd', 'a', 't', 'e', 'd', '\030', 
+'\003', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 
+'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'R', '\013', 'l', 'a', 's', 't', 'U', 'p', 'd', 'a', 't', 'e', 'd', '\022', 'C', '\n', '\013', 
+'e', 'r', 'r', 'o', 'r', '_', 's', 't', 'a', 't', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'U', 'p', 'd', 'a', 't', 'e', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 'S', 't', 
+'a', 't', 'e', 'R', '\n', 'e', 'r', 'r', 'o', 'r', 'S', 't', 'a', 't', 'e', '\022', 'I', '\n', '\r', 'c', 'l', 'i', 'e', 'n', 't', 
+'_', 's', 't', 'a', 't', 'u', 's', '\030', '\005', ' ', '\001', '(', '\016', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 
+'i', 'n', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'S', 't', 'a', 't', 'u', 
+'s', 'R', '\014', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', '*', ']', '\n', '\024', 'C', 'l', 'i', 'e', 'n', 't', 
+'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'S', 't', 'a', 't', 'u', 's', '\022', '\013', '\n', '\007', 'U', 'N', 'K', 'N', 'O', 'W', 'N', 
+'\020', '\000', '\022', '\r', '\n', '\t', 'R', 'E', 'Q', 'U', 'E', 'S', 'T', 'E', 'D', '\020', '\001', '\022', '\022', '\n', '\016', 'D', 'O', 'E', 'S', 
+'_', 'N', 'O', 'T', '_', 'E', 'X', 'I', 'S', 'T', '\020', '\002', '\022', '\t', '\n', '\005', 'A', 'C', 'K', 'E', 'D', '\020', '\003', '\022', '\n', 
+'\n', '\006', 'N', 'A', 'C', 'K', 'E', 'D', '\020', '\004', 'B', '9', '\n', '\034', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 
+'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', 'B', '\017', 'C', 'o', 'n', 'f', 'i', 'g', 
+'D', 'u', 'm', 'p', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 
+'o', '3', 
+};
+
+static upb_def_init *deps[6] = {
+  &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit,
+  &google_protobuf_any_proto_upbdefinit,
+  &google_protobuf_timestamp_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_admin_v3_config_dump_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/admin/v3/config_dump.proto",
+  UPB_STRVIEW_INIT(descriptor, 6802)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h
new file mode 100644
index 0000000..8e62d4e
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h
@@ -0,0 +1,140 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/admin/v3/config_dump.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_ADMIN_V3_CONFIG_DUMP_PROTO_UPBDEFS_H_
+#define ENVOY_ADMIN_V3_CONFIG_DUMP_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_admin_v3_config_dump_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ConfigDump_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ConfigDump");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_UpdateFailureState_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.UpdateFailureState");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_BootstrapConfigDump_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.BootstrapConfigDump");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ListenersConfigDump_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ListenersConfigDump");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ListenersConfigDump_StaticListener_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ListenersConfigDump.StaticListener");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ListenersConfigDump_DynamicListenerState_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ListenersConfigDump.DynamicListenerState");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ListenersConfigDump_DynamicListener_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ListenersConfigDump.DynamicListener");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ClustersConfigDump_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ClustersConfigDump");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ClustersConfigDump_StaticCluster_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ClustersConfigDump.StaticCluster");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ClustersConfigDump_DynamicCluster_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ClustersConfigDump.DynamicCluster");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_RoutesConfigDump_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.RoutesConfigDump");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_RoutesConfigDump_StaticRouteConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.RoutesConfigDump.StaticRouteConfig");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.RoutesConfigDump.DynamicRouteConfig");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ScopedRoutesConfigDump_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ScopedRoutesConfigDump");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ScopedRoutesConfigDump.InlineScopedRouteConfigs");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.ScopedRoutesConfigDump.DynamicScopedRouteConfigs");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_SecretsConfigDump_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.SecretsConfigDump");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_SecretsConfigDump_DynamicSecret_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.SecretsConfigDump.DynamicSecret");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_SecretsConfigDump_StaticSecret_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.SecretsConfigDump.StaticSecret");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_EndpointsConfigDump_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.EndpointsConfigDump");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.EndpointsConfigDump.StaticEndpointConfig");
+}
+
+UPB_INLINE const upb_msgdef *envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_admin_v3_config_dump_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.admin.v3.EndpointsConfigDump.DynamicEndpointConfig");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_ADMIN_V3_CONFIG_DUMP_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c
index 09292b5..d9e6343 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c
@@ -14,7 +14,6 @@
 extern upb_def_init envoy_type_matcher_v3_metadata_proto_upbdefinit;
 extern upb_def_init envoy_type_v3_percent_proto_upbdefinit;
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
-extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
@@ -53,7 +52,7 @@
   &envoy_config_accesslog_v3_ExtensionFilter_msginit,
 };
 
-static const char descriptor[4418] = {'\n', ')', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '/', 
+static const char descriptor[4388] = {'\n', ')', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '/', 
 'v', '3', '/', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'p', 'r', 'o', 't', 'o', '\022', '\031', 'e', 'n', 'v', 'o', 'y', 
 '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '\032', '\037', 'e', 'n', 'v', 
 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 
@@ -62,183 +61,181 @@
 '$', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 'e', 'r', '/', 'v', '3', '/', 'm', 'e', 
 't', 'a', 'd', 'a', 't', 'a', '.', 'p', 'r', 'o', 't', 'o', '\032', '\033', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 
 'v', '3', '/', 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 
-'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 
-'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 
-'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 
-'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 
-'t', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
-'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 
-'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\356', '\001', '\n', 
-'\t', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', 
-'\004', 'n', 'a', 'm', 'e', '\022', 'B', '\n', '\006', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 
-'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\006', 'f', 'i', 'l', 't', 'e', 'r', '\022', '9', 
-'\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\004', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 
-'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 
-'d', 'C', 'o', 'n', 'f', 'i', 'g', ':', '1', '\232', '\305', '\210', '\036', ',', '\n', '*', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'A', 
-'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', 
-'\010', '\003', '\020', '\004', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\366', '\010', '\n', '\017', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 
-'g', 'F', 'i', 'l', 't', 'e', 'r', '\022', '[', '\n', '\022', 's', 't', 'a', 't', 'u', 's', '_', 'c', 'o', 'd', 'e', '_', 'f', 'i', 
-'l', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'S', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', 'F', 
-'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\020', 's', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', 'F', 'i', 'l', 't', 'e', 'r', 
-'\022', 'T', '\n', '\017', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', 
-'2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', 
-'.', 'v', '3', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\016', 'd', 'u', 'r', 
-'a', 't', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'h', '\n', '\027', 'n', 'o', 't', '_', 'h', 'e', 'a', 'l', 't', 'h', 
-'_', 'c', 'h', 'e', 'c', 'k', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'N', 'o', 
-'t', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\024', 'n', 'o', 't', 
-'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'W', '\n', '\020', 't', 'r', 'a', 'c', 
-'e', 'a', 'b', 'l', 'e', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\004', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 
-'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'T', 'r', 'a', 
-'c', 'e', 'a', 'b', 'l', 'e', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\017', 't', 'r', 'a', 'c', 'e', 'a', 'b', 'l', 'e', 
-'F', 'i', 'l', 't', 'e', 'r', '\022', 'Q', '\n', '\016', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', 
-'\005', ' ', '\001', '(', '\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 
-'s', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', 
-'\r', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'E', '\n', '\n', 'a', 'n', 'd', '_', 'f', 'i', 'l', 
-'t', 'e', 'r', '\030', '\006', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'n', 'd', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', 
-'\t', 'a', 'n', 'd', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'B', '\n', '\t', 'o', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\007', 
-' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 
-'s', 'l', 'o', 'g', '.', 'v', '3', '.', 'O', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\010', 'o', 'r', 'F', 'i', 'l', 
-'t', 'e', 'r', '\022', 'N', '\n', '\r', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\010', ' ', '\001', '(', 
-'\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 
-'g', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\014', 'h', 'e', 'a', 'd', 
-'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'a', '\n', '\024', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'f', 'l', 'a', 'g', 
-'_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\t', ' ', '\001', '(', '\013', '2', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 
-'F', 'l', 'a', 'g', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\022', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'F', 'l', 'a', 
-'g', 'F', 'i', 'l', 't', 'e', 'r', '\022', '[', '\n', '\022', 'g', 'r', 'p', 'c', '_', 's', 't', 'a', 't', 'u', 's', '_', 'f', 'i', 
-'l', 't', 'e', 'r', '\030', '\n', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'G', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'F', 
-'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\020', 'g', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'F', 'i', 'l', 't', 'e', 'r', 
-'\022', 'W', '\n', '\020', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\013', ' ', '\001', '(', 
-'\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 
-'g', '.', 'v', '3', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\017', 'e', 
-'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'T', '\n', '\017', 'm', 'e', 't', 'a', 'd', 'a', 't', 
-'a', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\014', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 
-'a', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\016', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'F', 'i', 'l', 't', 'e', 'r', 
-':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 
-'t', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 
-'g', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\027', '\n', '\020', 'f', 'i', 'l', 't', 'e', 'r', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 
-'e', 'r', '\022', '\003', '\370', 'B', '\001', '\"', '\357', '\001', '\n', '\020', 'C', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', 'F', 'i', 'l', 
-'t', 'e', 'r', '\022', 'H', '\n', '\002', 'o', 'p', '\030', '\001', ' ', '\001', '(', '\016', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'C', 'o', 'm', 'p', 'a', 'r', 
-'i', 's', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '.', 'O', 'p', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\002', 
-'o', 'p', '\022', '9', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'U', 'I', 
-'n', 't', '3', '2', 'R', '\005', 'v', 'a', 'l', 'u', 'e', '\"', '\034', '\n', '\002', 'O', 'p', '\022', '\006', '\n', '\002', 'E', 'Q', '\020', '\000', 
-'\022', '\006', '\n', '\002', 'G', 'E', '\020', '\001', '\022', '\006', '\n', '\002', 'L', 'E', '\020', '\002', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 
-'s', 'l', 'o', 'g', '.', 'v', '2', '.', 'C', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\"', 
-'\243', '\001', '\n', '\020', 'S', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'U', '\n', '\n', 'c', 
-'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'C', 'o', 'm', 'p', 'a', 'r', 
-'i', 's', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\n', 'c', 'o', 'm', 
-'p', 'a', 'r', 'i', 's', 'o', 'n', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'S', 
-'t', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\237', '\001', '\n', '\016', 'D', 'u', 'r', 'a', 't', 
-'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'U', '\n', '\n', 'c', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', '\030', '\001', 
-' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 
-'s', 'l', 'o', 'g', '.', 'v', '3', '.', 'C', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', 'B', 
-'\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\n', 'c', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', ':', '6', '\232', '\305', 
-'\210', '\036', '1', '\n', '/', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 
-'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'F', 'i', 'l', 't', 
-'e', 'r', '\"', 'T', '\n', '\024', 'N', 'o', 't', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'F', 'i', 'l', 't', 'e', 
-'r', ':', '<', '\232', '\305', '\210', '\036', '7', '\n', '5', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 
-'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'N', 'o', 't', 'H', 'e', 'a', 'l', 
-'t', 'h', 'C', 'h', 'e', 'c', 'k', 'F', 'i', 'l', 't', 'e', 'r', '\"', 'J', '\n', '\017', 'T', 'r', 'a', 'c', 'e', 'a', 'b', 'l', 
-'e', 'F', 'i', 'l', 't', 'e', 'r', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'T', 
-'r', 'a', 'c', 'e', 'a', 'b', 'l', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\371', '\001', '\n', '\r', 'R', 'u', 'n', 't', 'i', 'm', 
-'e', 'F', 'i', 'l', 't', 'e', 'r', '\022', '(', '\n', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\030', '\001', ' ', 
-'\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', '\022', 
-'I', '\n', '\017', 'p', 'e', 'r', 'c', 'e', 'n', 't', '_', 's', 'a', 'm', 'p', 'l', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', 
-' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 
-'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'p', 'e', 'r', 'c', 'e', 'n', 't', 'S', 'a', 'm', 'p', 'l', 'e', 'd', '\022', 
-'<', '\n', '\032', 'u', 's', 'e', '_', 'i', 'n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 't', '_', 'r', 'a', 'n', 'd', 'o', 'm', 
-'n', 'e', 's', 's', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\030', 'u', 's', 'e', 'I', 'n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 
-'t', 'R', 'a', 'n', 'd', 'o', 'm', 'n', 'e', 's', 's', ':', '5', '\232', '\305', '\210', '\036', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 
-'v', '2', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\216', '\001', '\n', '\t', 'A', 'n', 'd', 'F', 
-'i', 'l', 't', 'e', 'r', '\022', 'N', '\n', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '*', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', 
-'.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', 
-'\002', 'R', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', ':', '1', '\232', '\305', '\210', '\036', ',', '\n', '*', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', 
-'2', '.', 'A', 'n', 'd', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\214', '\001', '\n', '\010', 'O', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\022', 
-'N', '\n', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 
+'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', 
+'\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', 
+'.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 
+'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 
+'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\356', '\001', '\n', '\t', 'A', 'c', 'c', 'e', 
+'s', 's', 'L', 'o', 'g', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', 
+'\022', 'B', '\n', '\006', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 
 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 's', 
-'s', 'L', 'o', 'g', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\002', 'R', '\007', 'f', 'i', 'l', 
-'t', 'e', 'r', 's', ':', '0', '\232', '\305', '\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'O', 'r', 'F', 'i', 
-'l', 't', 'e', 'r', '\"', '\214', '\001', '\n', '\014', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'F', '\n', '\006', 
-'h', 'e', 'a', 'd', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 
-'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\006', 'h', 'e', 'a', 'd', 'e', 'r', ':', '4', '\232', '\305', '\210', '\036', '/', 
-'\n', '-', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 
-'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\334', '\001', 
-'\n', '\022', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'F', 'l', 'a', 'g', 'F', 'i', 'l', 't', 'e', 'r', '\022', '\211', '\001', '\n', '\005', 
-'f', 'l', 'a', 'g', 's', '\030', '\001', ' ', '\003', '(', '\t', 'B', 's', '\372', 'B', 'p', '\222', '\001', 'm', '\"', 'k', 'r', 'i', 'R', '\002', 
-'L', 'H', 'R', '\002', 'U', 'H', 'R', '\002', 'U', 'T', 'R', '\002', 'L', 'R', 'R', '\002', 'U', 'R', 'R', '\002', 'U', 'F', 'R', '\002', 'U', 
-'C', 'R', '\002', 'U', 'O', 'R', '\002', 'N', 'R', 'R', '\002', 'D', 'I', 'R', '\002', 'F', 'I', 'R', '\002', 'R', 'L', 'R', '\004', 'U', 'A', 
-'E', 'X', 'R', '\004', 'R', 'L', 'S', 'E', 'R', '\002', 'D', 'C', 'R', '\003', 'U', 'R', 'X', 'R', '\002', 'S', 'I', 'R', '\002', 'I', 'H', 
-'R', '\003', 'D', 'P', 'E', 'R', '\005', 'U', 'M', 'S', 'D', 'R', 'R', '\004', 'R', 'F', 'C', 'F', 'R', '\004', 'N', 'F', 'C', 'F', 'R', 
-'\002', 'D', 'T', 'R', '\005', 'f', 'l', 'a', 'g', 's', ':', ':', '\232', '\305', '\210', '\036', '5', '\n', '3', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', 
-'2', '.', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'F', 'l', 'a', 'g', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\200', '\004', '\n', '\020', 
-'G', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'F', 'i', 'l', 't', 'e', 'r', '\022', ']', '\n', '\010', 's', 't', 'a', 't', 'u', 
-'s', 'e', 's', '\030', '\001', ' ', '\003', '(', '\016', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'G', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'F', 'i', 
-'l', 't', 'e', 'r', '.', 'S', 't', 'a', 't', 'u', 's', 'B', '\r', '\372', 'B', '\n', '\222', '\001', '\007', '\"', '\005', '\202', '\001', '\002', '\020', 
-'\001', 'R', '\010', 's', 't', 'a', 't', 'u', 's', 'e', 's', '\022', '\030', '\n', '\007', 'e', 'x', 'c', 'l', 'u', 'd', 'e', '\030', '\002', ' ', 
-'\001', '(', '\010', 'R', '\007', 'e', 'x', 'c', 'l', 'u', 'd', 'e', '\"', '\270', '\002', '\n', '\006', 'S', 't', 'a', 't', 'u', 's', '\022', '\006', 
-'\n', '\002', 'O', 'K', '\020', '\000', '\022', '\014', '\n', '\010', 'C', 'A', 'N', 'C', 'E', 'L', 'E', 'D', '\020', '\001', '\022', '\013', '\n', '\007', 'U', 
-'N', 'K', 'N', 'O', 'W', 'N', '\020', '\002', '\022', '\024', '\n', '\020', 'I', 'N', 'V', 'A', 'L', 'I', 'D', '_', 'A', 'R', 'G', 'U', 'M', 
-'E', 'N', 'T', '\020', '\003', '\022', '\025', '\n', '\021', 'D', 'E', 'A', 'D', 'L', 'I', 'N', 'E', '_', 'E', 'X', 'C', 'E', 'E', 'D', 'E', 
-'D', '\020', '\004', '\022', '\r', '\n', '\t', 'N', 'O', 'T', '_', 'F', 'O', 'U', 'N', 'D', '\020', '\005', '\022', '\022', '\n', '\016', 'A', 'L', 'R', 
-'E', 'A', 'D', 'Y', '_', 'E', 'X', 'I', 'S', 'T', 'S', '\020', '\006', '\022', '\025', '\n', '\021', 'P', 'E', 'R', 'M', 'I', 'S', 'S', 'I', 
-'O', 'N', '_', 'D', 'E', 'N', 'I', 'E', 'D', '\020', '\007', '\022', '\026', '\n', '\022', 'R', 'E', 'S', 'O', 'U', 'R', 'C', 'E', '_', 'E', 
-'X', 'H', 'A', 'U', 'S', 'T', 'E', 'D', '\020', '\010', '\022', '\027', '\n', '\023', 'F', 'A', 'I', 'L', 'E', 'D', '_', 'P', 'R', 'E', 'C', 
-'O', 'N', 'D', 'I', 'T', 'I', 'O', 'N', '\020', '\t', '\022', '\013', '\n', '\007', 'A', 'B', 'O', 'R', 'T', 'E', 'D', '\020', '\n', '\022', '\020', 
-'\n', '\014', 'O', 'U', 'T', '_', 'O', 'F', '_', 'R', 'A', 'N', 'G', 'E', '\020', '\013', '\022', '\021', '\n', '\r', 'U', 'N', 'I', 'M', 'P', 
-'L', 'E', 'M', 'E', 'N', 'T', 'E', 'D', '\020', '\014', '\022', '\014', '\n', '\010', 'I', 'N', 'T', 'E', 'R', 'N', 'A', 'L', '\020', '\r', '\022', 
-'\017', '\n', '\013', 'U', 'N', 'A', 'V', 'A', 'I', 'L', 'A', 'B', 'L', 'E', '\020', '\016', '\022', '\r', '\n', '\t', 'D', 'A', 'T', 'A', '_', 
-'L', 'O', 'S', 'S', '\020', '\017', '\022', '\023', '\n', '\017', 'U', 'N', 'A', 'U', 'T', 'H', 'E', 'N', 'T', 'I', 'C', 'A', 'T', 'E', 'D', 
-'\020', '\020', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 
-'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'G', 'r', 'p', 'c', 'S', 't', 
-'a', 't', 'u', 's', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\332', '\001', '\n', '\016', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'F', 'i', 
-'l', 't', 'e', 'r', '\022', '@', '\n', '\007', 'm', 'a', 't', 'c', 'h', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '&', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 
-'d', 'a', 't', 'a', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\007', 'm', 'a', 't', 'c', 'h', 'e', 'r', '\022', 'N', '\n', '\026', 'm', 
-'a', 't', 'c', 'h', '_', 'i', 'f', '_', 'k', 'e', 'y', '_', 'n', 'o', 't', '_', 'f', 'o', 'u', 'n', 'd', '\030', '\002', ' ', '\001', 
-'(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 
-'V', 'a', 'l', 'u', 'e', 'R', '\022', 'm', 'a', 't', 'c', 'h', 'I', 'f', 'K', 'e', 'y', 'N', 'o', 't', 'F', 'o', 'u', 'n', 'd', 
-':', '6', '\232', '\305', '\210', '\036', '1', '\n', '/', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 
-'t', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 
-'F', 'i', 'l', 't', 'e', 'r', '\"', '\266', '\001', '\n', '\017', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 
-'r', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 
-'t', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 
-'o', 'n', 'f', 'i', 'g', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'E', 'x', 't', 
-'e', 'n', 's', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 
-'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', 'B', 'C', '\n', '\'', 'i', 'o', '.', 'e', 'n', 
-'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 
-'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', 'B', '\016', 'A', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', 'P', 'r', 'o', 't', 'o', 
-'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'s', 'L', 'o', 'g', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\006', 'f', 'i', 'l', 't', 'e', 'r', '\022', '9', '\n', '\014', 't', 'y', 'p', 
+'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\004', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 
+'i', 'g', ':', '1', '\232', '\305', '\210', '\036', ',', '\n', '*', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 
+'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'A', 'c', 'c', 'e', 's', 's', 
+'L', 'o', 'g', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\003', '\020', '\004', 'R', 
+'\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\366', '\010', '\n', '\017', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'F', 'i', 'l', 't', 
+'e', 'r', '\022', '[', '\n', '\022', 's', 't', 'a', 't', 'u', 's', '_', 'c', 'o', 'd', 'e', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', 
+'\001', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 
+'s', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'S', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', 'F', 'i', 'l', 't', 'e', 'r', 
+'H', '\000', 'R', '\020', 's', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'T', '\n', '\017', 'd', 
+'u', 'r', 'a', 't', 'i', 'o', 'n', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'D', 
+'u', 'r', 'a', 't', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\016', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', 
+'F', 'i', 'l', 't', 'e', 'r', '\022', 'h', '\n', '\027', 'n', 'o', 't', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 
+'k', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'N', 'o', 't', 'H', 'e', 'a', 'l', 
+'t', 'h', 'C', 'h', 'e', 'c', 'k', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\024', 'n', 'o', 't', 'H', 'e', 'a', 'l', 't', 
+'h', 'C', 'h', 'e', 'c', 'k', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'W', '\n', '\020', 't', 'r', 'a', 'c', 'e', 'a', 'b', 'l', 'e', 
+'_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\004', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'e', 'a', 'b', 'l', 
+'e', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\017', 't', 'r', 'a', 'c', 'e', 'a', 'b', 'l', 'e', 'F', 'i', 'l', 't', 'e', 
+'r', '\022', 'Q', '\n', '\016', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\005', ' ', '\001', '(', '\013', 
+'2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', 
+'.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\r', 'r', 'u', 'n', 't', 
+'i', 'm', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'E', '\n', '\n', 'a', 'n', 'd', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\006', 
+' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 
+'s', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'n', 'd', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\t', 'a', 'n', 'd', 'F', 
+'i', 'l', 't', 'e', 'r', '\022', 'B', '\n', '\t', 'o', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\007', ' ', '\001', '(', '\013', '2', 
+'#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 
+'v', '3', '.', 'O', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\010', 'o', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'N', 
+'\n', '\r', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\010', ' ', '\001', '(', '\013', '2', '\'', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 
+'H', 'e', 'a', 'd', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\014', 'h', 'e', 'a', 'd', 'e', 'r', 'F', 'i', 'l', 
+'t', 'e', 'r', '\022', 'a', '\n', '\024', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'f', 'l', 'a', 'g', '_', 'f', 'i', 'l', 't', 
+'e', 'r', '\030', '\t', ' ', '\001', '(', '\013', '2', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 
+'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'F', 'l', 'a', 'g', 'F', 
+'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\022', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'F', 'l', 'a', 'g', 'F', 'i', 'l', 't', 
+'e', 'r', '\022', '[', '\n', '\022', 'g', 'r', 'p', 'c', '_', 's', 't', 'a', 't', 'u', 's', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', 
+'\n', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 
+'s', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'G', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'F', 'i', 'l', 't', 'e', 'r', 
+'H', '\000', 'R', '\020', 'g', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'W', '\n', '\020', 'e', 
+'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\013', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 
+'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', 'H', '\000', 'R', '\017', 'e', 'x', 't', 'e', 'n', 's', 
+'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'T', '\n', '\017', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', 'f', 'i', 'l', 
+'t', 'e', 'r', '\030', '\014', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'F', 'i', 'l', 't', 
+'e', 'r', 'H', '\000', 'R', '\016', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'F', 'i', 'l', 't', 'e', 'r', ':', '7', '\232', '\305', '\210', 
+'\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 
+'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'F', 'i', 'l', 't', 
+'e', 'r', 'B', '\027', '\n', '\020', 'f', 'i', 'l', 't', 'e', 'r', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 
+'B', '\001', '\"', '\357', '\001', '\n', '\020', 'C', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'H', 
+'\n', '\002', 'o', 'p', '\030', '\001', ' ', '\001', '(', '\016', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'C', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', 'F', 
+'i', 'l', 't', 'e', 'r', '.', 'O', 'p', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\002', 'o', 'p', '\022', '9', '\n', 
+'\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'U', 'I', 'n', 't', '3', '2', 'R', 
+'\005', 'v', 'a', 'l', 'u', 'e', '\"', '\034', '\n', '\002', 'O', 'p', '\022', '\006', '\n', '\002', 'E', 'Q', '\020', '\000', '\022', '\006', '\n', '\002', 'G', 
+'E', '\020', '\001', '\022', '\006', '\n', '\002', 'L', 'E', '\020', '\002', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 
+'v', '2', '.', 'C', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\243', '\001', '\n', '\020', 'S', 
+'t', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'U', '\n', '\n', 'c', 'o', 'm', 'p', 'a', 'r', 
+'i', 's', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'C', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', 'F', 
+'i', 'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\n', 'c', 'o', 'm', 'p', 'a', 'r', 'i', 's', 
+'o', 'n', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 
+'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'S', 't', 'a', 't', 'u', 's', 
+'C', 'o', 'd', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\237', '\001', '\n', '\016', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'F', 'i', 
+'l', 't', 'e', 'r', '\022', 'U', '\n', '\n', 'c', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', 
+'+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 
+'v', '3', '.', 'C', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', 
+'\001', '\002', '\020', '\001', 'R', '\n', 'c', 'o', 'm', 'p', 'a', 'r', 'i', 's', 'o', 'n', ':', '6', '\232', '\305', '\210', '\036', '1', '\n', '/', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 
+'s', 'l', 'o', 'g', '.', 'v', '2', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\"', 'T', '\n', 
+'\024', 'N', 'o', 't', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'F', 'i', 'l', 't', 'e', 'r', ':', '<', '\232', '\305', 
+'\210', '\036', '7', '\n', '5', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 
+'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'N', 'o', 't', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 
+'c', 'k', 'F', 'i', 'l', 't', 'e', 'r', '\"', 'J', '\n', '\017', 'T', 'r', 'a', 'c', 'e', 'a', 'b', 'l', 'e', 'F', 'i', 'l', 't', 
+'e', 'r', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 
+'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'T', 'r', 'a', 'c', 'e', 'a', 
+'b', 'l', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\371', '\001', '\n', '\r', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'i', 'l', 't', 
+'e', 'r', '\022', '(', '\n', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', 
+'\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', '\022', 'I', '\n', '\017', 'p', 'e', 
+'r', 'c', 'e', 'n', 't', '_', 's', 'a', 'm', 'p', 'l', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 
+'e', 'n', 't', 'R', '\016', 'p', 'e', 'r', 'c', 'e', 'n', 't', 'S', 'a', 'm', 'p', 'l', 'e', 'd', '\022', '<', '\n', '\032', 'u', 's', 
+'e', '_', 'i', 'n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 't', '_', 'r', 'a', 'n', 'd', 'o', 'm', 'n', 'e', 's', 's', '\030', 
+'\003', ' ', '\001', '(', '\010', 'R', '\030', 'u', 's', 'e', 'I', 'n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 't', 'R', 'a', 'n', 'd', 
+'o', 'm', 'n', 'e', 's', 's', ':', '5', '\232', '\305', '\210', '\036', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'R', 'u', 
+'n', 't', 'i', 'm', 'e', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\216', '\001', '\n', '\t', 'A', 'n', 'd', 'F', 'i', 'l', 't', 'e', 'r', 
+'\022', 'N', '\n', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 
+'s', 's', 'L', 'o', 'g', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\002', 'R', '\007', 'f', 'i', 
+'l', 't', 'e', 'r', 's', ':', '1', '\232', '\305', '\210', '\036', ',', '\n', '*', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'A', 'n', 'd', 
+'F', 'i', 'l', 't', 'e', 'r', '\"', '\214', '\001', '\n', '\010', 'O', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'N', '\n', '\007', 'f', 'i', 
+'l', 't', 'e', 'r', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'F', 
+'i', 'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\002', 'R', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', ':', 
+'0', '\232', '\305', '\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 
+'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'O', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\"', 
+'\214', '\001', '\n', '\014', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\022', 'F', '\n', '\006', 'h', 'e', 'a', 'd', 'e', 
+'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 
+'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\010', '\372', 'B', '\005', 
+'\212', '\001', '\002', '\020', '\001', 'R', '\006', 'h', 'e', 'a', 'd', 'e', 'r', ':', '4', '\232', '\305', '\210', '\036', '/', '\n', '-', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 
+'g', '.', 'v', '2', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\334', '\001', '\n', '\022', 'R', 'e', 's', 
+'p', 'o', 'n', 's', 'e', 'F', 'l', 'a', 'g', 'F', 'i', 'l', 't', 'e', 'r', '\022', '\211', '\001', '\n', '\005', 'f', 'l', 'a', 'g', 's', 
+'\030', '\001', ' ', '\003', '(', '\t', 'B', 's', '\372', 'B', 'p', '\222', '\001', 'm', '\"', 'k', 'r', 'i', 'R', '\002', 'L', 'H', 'R', '\002', 'U', 
+'H', 'R', '\002', 'U', 'T', 'R', '\002', 'L', 'R', 'R', '\002', 'U', 'R', 'R', '\002', 'U', 'F', 'R', '\002', 'U', 'C', 'R', '\002', 'U', 'O', 
+'R', '\002', 'N', 'R', 'R', '\002', 'D', 'I', 'R', '\002', 'F', 'I', 'R', '\002', 'R', 'L', 'R', '\004', 'U', 'A', 'E', 'X', 'R', '\004', 'R', 
+'L', 'S', 'E', 'R', '\002', 'D', 'C', 'R', '\003', 'U', 'R', 'X', 'R', '\002', 'S', 'I', 'R', '\002', 'I', 'H', 'R', '\003', 'D', 'P', 'E', 
+'R', '\005', 'U', 'M', 'S', 'D', 'R', 'R', '\004', 'R', 'F', 'C', 'F', 'R', '\004', 'N', 'F', 'C', 'F', 'R', '\002', 'D', 'T', 'R', '\005', 
+'f', 'l', 'a', 'g', 's', ':', ':', '\232', '\305', '\210', '\036', '5', '\n', '3', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'R', 'e', 's', 
+'p', 'o', 'n', 's', 'e', 'F', 'l', 'a', 'g', 'F', 'i', 'l', 't', 'e', 'r', '\"', '\200', '\004', '\n', '\020', 'G', 'r', 'p', 'c', 'S', 
+'t', 'a', 't', 'u', 's', 'F', 'i', 'l', 't', 'e', 'r', '\022', ']', '\n', '\010', 's', 't', 'a', 't', 'u', 's', 'e', 's', '\030', '\001', 
+' ', '\003', '(', '\016', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 
+'s', 'l', 'o', 'g', '.', 'v', '3', '.', 'G', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'F', 'i', 'l', 't', 'e', 'r', '.', 
+'S', 't', 'a', 't', 'u', 's', 'B', '\r', '\372', 'B', '\n', '\222', '\001', '\007', '\"', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\010', 's', 't', 
+'a', 't', 'u', 's', 'e', 's', '\022', '\030', '\n', '\007', 'e', 'x', 'c', 'l', 'u', 'd', 'e', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\007', 
+'e', 'x', 'c', 'l', 'u', 'd', 'e', '\"', '\270', '\002', '\n', '\006', 'S', 't', 'a', 't', 'u', 's', '\022', '\006', '\n', '\002', 'O', 'K', '\020', 
+'\000', '\022', '\014', '\n', '\010', 'C', 'A', 'N', 'C', 'E', 'L', 'E', 'D', '\020', '\001', '\022', '\013', '\n', '\007', 'U', 'N', 'K', 'N', 'O', 'W', 
+'N', '\020', '\002', '\022', '\024', '\n', '\020', 'I', 'N', 'V', 'A', 'L', 'I', 'D', '_', 'A', 'R', 'G', 'U', 'M', 'E', 'N', 'T', '\020', '\003', 
+'\022', '\025', '\n', '\021', 'D', 'E', 'A', 'D', 'L', 'I', 'N', 'E', '_', 'E', 'X', 'C', 'E', 'E', 'D', 'E', 'D', '\020', '\004', '\022', '\r', 
+'\n', '\t', 'N', 'O', 'T', '_', 'F', 'O', 'U', 'N', 'D', '\020', '\005', '\022', '\022', '\n', '\016', 'A', 'L', 'R', 'E', 'A', 'D', 'Y', '_', 
+'E', 'X', 'I', 'S', 'T', 'S', '\020', '\006', '\022', '\025', '\n', '\021', 'P', 'E', 'R', 'M', 'I', 'S', 'S', 'I', 'O', 'N', '_', 'D', 'E', 
+'N', 'I', 'E', 'D', '\020', '\007', '\022', '\026', '\n', '\022', 'R', 'E', 'S', 'O', 'U', 'R', 'C', 'E', '_', 'E', 'X', 'H', 'A', 'U', 'S', 
+'T', 'E', 'D', '\020', '\010', '\022', '\027', '\n', '\023', 'F', 'A', 'I', 'L', 'E', 'D', '_', 'P', 'R', 'E', 'C', 'O', 'N', 'D', 'I', 'T', 
+'I', 'O', 'N', '\020', '\t', '\022', '\013', '\n', '\007', 'A', 'B', 'O', 'R', 'T', 'E', 'D', '\020', '\n', '\022', '\020', '\n', '\014', 'O', 'U', 'T', 
+'_', 'O', 'F', '_', 'R', 'A', 'N', 'G', 'E', '\020', '\013', '\022', '\021', '\n', '\r', 'U', 'N', 'I', 'M', 'P', 'L', 'E', 'M', 'E', 'N', 
+'T', 'E', 'D', '\020', '\014', '\022', '\014', '\n', '\010', 'I', 'N', 'T', 'E', 'R', 'N', 'A', 'L', '\020', '\r', '\022', '\017', '\n', '\013', 'U', 'N', 
+'A', 'V', 'A', 'I', 'L', 'A', 'B', 'L', 'E', '\020', '\016', '\022', '\r', '\n', '\t', 'D', 'A', 'T', 'A', '_', 'L', 'O', 'S', 'S', '\020', 
+'\017', '\022', '\023', '\n', '\017', 'U', 'N', 'A', 'U', 'T', 'H', 'E', 'N', 'T', 'I', 'C', 'A', 'T', 'E', 'D', '\020', '\020', ':', '8', '\232', 
+'\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', 
+'.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'G', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'F', 
+'i', 'l', 't', 'e', 'r', '\"', '\332', '\001', '\n', '\016', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'F', 'i', 'l', 't', 'e', 'r', '\022', 
+'@', '\n', '\007', 'm', 'a', 't', 'c', 'h', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'t', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'M', 
+'a', 't', 'c', 'h', 'e', 'r', 'R', '\007', 'm', 'a', 't', 'c', 'h', 'e', 'r', '\022', 'N', '\n', '\026', 'm', 'a', 't', 'c', 'h', '_', 
+'i', 'f', '_', 'k', 'e', 'y', '_', 'n', 'o', 't', '_', 'f', 'o', 'u', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 
+'R', '\022', 'm', 'a', 't', 'c', 'h', 'I', 'f', 'K', 'e', 'y', 'N', 'o', 't', 'F', 'o', 'u', 'n', 'd', ':', '6', '\232', '\305', '\210', 
+'\036', '1', '\n', '/', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'a', 
+'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'F', 'i', 'l', 't', 'e', 
+'r', '\"', '\266', '\001', '\n', '\017', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'F', 'i', 'l', 't', 'e', 'r', '\022', '\022', '\n', '\004', 
+'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', 
+'_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 
+':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 
+'t', 'e', 'r', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '2', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 
+'n', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', 
+'\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', 'B', 'C', '\n', '\'', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 
+'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 
+'g', '.', 'v', '3', 'B', '\016', 'A', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', 
+'\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[11] = {
+static upb_def_init *deps[10] = {
   &envoy_config_core_v3_base_proto_upbdefinit,
   &envoy_config_route_v3_route_components_proto_upbdefinit,
   &envoy_type_matcher_v3_metadata_proto_upbdefinit,
   &envoy_type_v3_percent_proto_upbdefinit,
   &google_protobuf_any_proto_upbdefinit,
-  &google_protobuf_struct_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
@@ -250,5 +247,5 @@
   deps,
   layouts,
   "envoy/config/accesslog/v3/accesslog.proto",
-  UPB_STRVIEW_INIT(descriptor, 4418)
+  UPB_STRVIEW_INIT(descriptor, 4388)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c
new file mode 100644
index 0000000..f86bfe7
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c
@@ -0,0 +1,383 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/bootstrap/v3/bootstrap.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/config/bootstrap/v3/bootstrap.upbdefs.h"
+
+extern upb_def_init envoy_config_cluster_v3_cluster_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_address_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_base_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_config_source_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_event_service_config_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_extension_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_socket_option_proto_upbdefinit;
+extern upb_def_init envoy_config_listener_v3_listener_proto_upbdefinit;
+extern upb_def_init envoy_config_metrics_v3_stats_proto_upbdefinit;
+extern upb_def_init envoy_config_overload_v3_overload_proto_upbdefinit;
+extern upb_def_init envoy_config_trace_v3_http_tracer_proto_upbdefinit;
+extern upb_def_init envoy_extensions_transport_sockets_tls_v3_secret_proto_upbdefinit;
+extern upb_def_init envoy_type_v3_percent_proto_upbdefinit;
+extern upb_def_init google_protobuf_duration_proto_upbdefinit;
+extern upb_def_init google_protobuf_struct_proto_upbdefinit;
+extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
+extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
+extern upb_def_init udpa_annotations_security_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Admin_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_ClusterManager_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Watchdogs_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Watchdog_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_FatalAction_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_Runtime_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit;
+extern const upb_msglayout envoy_config_bootstrap_v3_LayeredRuntime_msginit;
+
+static const upb_msglayout *layouts[17] = {
+  &envoy_config_bootstrap_v3_Bootstrap_msginit,
+  &envoy_config_bootstrap_v3_Bootstrap_StaticResources_msginit,
+  &envoy_config_bootstrap_v3_Bootstrap_DynamicResources_msginit,
+  &envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_msginit,
+  &envoy_config_bootstrap_v3_Admin_msginit,
+  &envoy_config_bootstrap_v3_ClusterManager_msginit,
+  &envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_msginit,
+  &envoy_config_bootstrap_v3_Watchdogs_msginit,
+  &envoy_config_bootstrap_v3_Watchdog_msginit,
+  &envoy_config_bootstrap_v3_Watchdog_WatchdogAction_msginit,
+  &envoy_config_bootstrap_v3_FatalAction_msginit,
+  &envoy_config_bootstrap_v3_Runtime_msginit,
+  &envoy_config_bootstrap_v3_RuntimeLayer_msginit,
+  &envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_msginit,
+  &envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_msginit,
+  &envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_msginit,
+  &envoy_config_bootstrap_v3_LayeredRuntime_msginit,
+};
+
+static const char descriptor[6993] = {'\n', ')', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '/', 
+'v', '3', '/', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'p', 'r', 'o', 't', 'o', '\022', '\031', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '\032', '%', 'e', 'n', 'v', 
+'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'l', 'u', 's', 't', 'e', 'r', '/', 'v', '3', '/', 'c', 'l', 'u', 's', 
+'t', 'e', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '\"', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 
+'o', 'r', 'e', '/', 'v', '3', '/', 'a', 'd', 'd', 'r', 'e', 's', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'e', 'n', 'v', 
+'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '(', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', 
+'/', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '/', 'e', 'n', 'v', 
+'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'e', 'v', 'e', 'n', 't', '_', 's', 
+'e', 'r', 'v', 'i', 'c', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '$', 'e', 'n', 'v', 'o', 
+'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 
+'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '(', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 
+'e', '/', 'v', '3', '/', 's', 'o', 'c', 'k', 'e', 't', '_', 'o', 'p', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', 
+'\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 'v', '3', 
+'/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 
+'n', 'f', 'i', 'g', '/', 'm', 'e', 't', 'r', 'i', 'c', 's', '/', 'v', '3', '/', 's', 't', 'a', 't', 's', '.', 'p', 'r', 'o', 
+'t', 'o', '\032', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 
+'/', 'v', '3', '/', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'p', 'r', 'o', 't', 'o', '\032', '\'', 'e', 'n', 'v', 'o', 'y', 
+'/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 't', 'r', 'a', 'c', 'e', '/', 'v', '3', '/', 'h', 't', 't', 'p', '_', 't', 'r', 'a', 
+'c', 'e', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 
+'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 
+'v', '3', '/', 's', 'e', 'c', 'r', 'e', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\033', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 
+'p', 'e', '/', 'v', '3', '/', 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 
+'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 
+'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', 
+'.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 
+'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 
+'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'u', 'd', 'p', 
+'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 'e', 'c', 'u', 'r', 'i', 't', 'y', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 
+'t', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 
+'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 
+'d', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\341', '\026', '\n', '\t', 'B', 
+'o', 'o', 't', 's', 't', 'r', 'a', 'p', '\022', '.', '\n', '\004', 'n', 'o', 'd', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'N', 'o', 'd', 'e', 
+'R', '\004', 'n', 'o', 'd', 'e', '\022', '.', '\n', '\023', 'n', 'o', 'd', 'e', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'p', 'a', 
+'r', 'a', 'm', 's', '\030', '\032', ' ', '\003', '(', '\t', 'R', '\021', 'n', 'o', 'd', 'e', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 
+'r', 'a', 'm', 's', '\022', '_', '\n', '\020', 's', 't', 'a', 't', 'i', 'c', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\030', 
+'\002', ' ', '\001', '(', '\013', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 
+'s', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'B', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'S', 't', 'a', 't', 'i', 'c', 
+'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', 'R', '\017', 's', 't', 'a', 't', 'i', 'c', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 
+'s', '\022', 'b', '\n', '\021', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\030', '\003', ' ', 
+'\001', '(', '\013', '2', '5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 
+'r', 'a', 'p', '.', 'v', '3', '.', 'B', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'R', 
+'e', 's', 'o', 'u', 'r', 'c', 'e', 's', 'R', '\020', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 
+'s', '\022', 'R', '\n', '\017', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '\030', '\004', ' ', '\001', '(', 
+'\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 
+'p', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'M', 'a', 'n', 'a', 'g', 'e', 'r', 'R', '\016', 'c', 'l', 'u', 's', 
+'t', 'e', 'r', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '\022', 'D', '\n', '\n', 'h', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', 
+'\016', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
+'.', 'v', '3', '.', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 'h', 'd', 's', 'C', 
+'o', 'n', 'f', 'i', 'g', '\022', '\035', '\n', '\n', 'f', 'l', 'a', 'g', 's', '_', 'p', 'a', 't', 'h', '\030', '\005', ' ', '\001', '(', '\t', 
+'R', '\t', 'f', 'l', 'a', 'g', 's', 'P', 'a', 't', 'h', '\022', 'C', '\n', '\013', 's', 't', 'a', 't', 's', '_', 's', 'i', 'n', 'k', 
+'s', '\030', '\006', ' ', '\003', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 'e', 
+'t', 'r', 'i', 'c', 's', '.', 'v', '3', '.', 'S', 't', 'a', 't', 's', 'S', 'i', 'n', 'k', 'R', '\n', 's', 't', 'a', 't', 's', 
+'S', 'i', 'n', 'k', 's', '\022', 'G', '\n', '\014', 's', 't', 'a', 't', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\r', ' ', '\001', 
+'(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 'e', 't', 'r', 'i', 'c', 's', 
+'.', 'v', '3', '.', 'S', 't', 'a', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\013', 's', 't', 'a', 't', 's', 'C', 'o', 'n', 
+'f', 'i', 'g', '\022', 'q', '\n', '\024', 's', 't', 'a', 't', 's', '_', 'f', 'l', 'u', 's', 'h', '_', 'i', 'n', 't', 'e', 'r', 'v', 
+'a', 'l', '\030', '\007', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '$', '\372', 'B', '\016', '\252', '\001', '\013', '\032', '\003', '\010', '\254', '\002', '2', '\004', 
+'\020', '\300', '\204', '=', '\362', '\230', '\376', '\217', '\005', '\r', '\022', '\013', 's', 't', 'a', 't', 's', '_', 'f', 'l', 'u', 's', 'h', 'R', '\022', 
+'s', 't', 'a', 't', 's', 'F', 'l', 'u', 's', 'h', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', ':', '\n', '\024', 's', 't', 'a', 
+'t', 's', '_', 'f', 'l', 'u', 's', 'h', '_', 'o', 'n', '_', 'a', 'd', 'm', 'i', 'n', '\030', '\035', ' ', '\001', '(', '\010', 'B', '\007', 
+'\372', 'B', '\004', 'j', '\002', '\010', '\001', 'H', '\000', 'R', '\021', 's', 't', 'a', 't', 's', 'F', 'l', 'u', 's', 'h', 'O', 'n', 'A', 'd', 
+'m', 'i', 'n', '\022', 'C', '\n', '\010', 'w', 'a', 't', 'c', 'h', 'd', 'o', 'g', '\030', '\010', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 
+'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 'B', '\002', '\030', '\001', 'R', '\010', 'w', 'a', 't', 'c', 'h', 'd', 'o', 'g', '\022', 'B', '\n', 
+'\t', 'w', 'a', 't', 'c', 'h', 'd', 'o', 'g', 's', '\030', '\033', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'W', 'a', 't', 'c', 'h', 
+'d', 'o', 'g', 's', 'R', '\t', 'w', 'a', 't', 'c', 'h', 'd', 'o', 'g', 's', '\022', '<', '\n', '\007', 't', 'r', 'a', 'c', 'i', 'n', 
+'g', '\030', '\t', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 
+'a', 'c', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', 'B', '\002', '\030', '\001', 'R', '\007', 't', 'r', 'a', 'c', 'i', 
+'n', 'g', '\022', 'R', '\n', '\017', 'l', 'a', 'y', 'e', 'r', 'e', 'd', '_', 'r', 'u', 'n', 't', 'i', 'm', 'e', '\030', '\021', ' ', '\001', 
+'(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 
+'a', 'p', '.', 'v', '3', '.', 'L', 'a', 'y', 'e', 'r', 'e', 'd', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'R', '\016', 'l', 'a', 'y', 
+'e', 'r', 'e', 'd', 'R', 'u', 'n', 't', 'i', 'm', 'e', '\022', '6', '\n', '\005', 'a', 'd', 'm', 'i', 'n', '\030', '\014', ' ', '\001', '(', 
+'\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 
+'p', '.', 'v', '3', '.', 'A', 'd', 'm', 'i', 'n', 'R', '\005', 'a', 'd', 'm', 'i', 'n', '\022', 'd', '\n', '\020', 'o', 'v', 'e', 'r', 
+'l', 'o', 'a', 'd', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '\030', '\017', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '3', '.', 'O', 'v', 'e', 'r', 
+'l', 'o', 'a', 'd', 'M', 'a', 'n', 'a', 'g', 'e', 'r', 'B', '\016', '\212', '\223', '\267', '*', '\002', '\010', '\001', '\212', '\223', '\267', '*', '\002', 
+'\020', '\001', 'R', '\017', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '\022', '6', '\n', '\027', 'e', 'n', 
+'a', 'b', 'l', 'e', '_', 'd', 'i', 's', 'p', 'a', 't', 'c', 'h', 'e', 'r', '_', 's', 't', 'a', 't', 's', '\030', '\020', ' ', '\001', 
+'(', '\010', 'R', '\025', 'e', 'n', 'a', 'b', 'l', 'e', 'D', 'i', 's', 'p', 'a', 't', 'c', 'h', 'e', 'r', 'S', 't', 'a', 't', 's', 
+'\022', '#', '\n', '\r', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\022', ' ', '\001', '(', '\t', 'R', '\014', 
+'h', 'e', 'a', 'd', 'e', 'r', 'P', 'r', 'e', 'f', 'i', 'x', '\022', '_', '\n', '\035', 's', 't', 'a', 't', 's', '_', 's', 'e', 'r', 
+'v', 'e', 'r', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '\030', '\023', ' ', '\001', '(', 
+'\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '6', 
+'4', 'V', 'a', 'l', 'u', 'e', 'R', '\032', 's', 't', 'a', 't', 's', 'S', 'e', 'r', 'v', 'e', 'r', 'V', 'e', 'r', 's', 'i', 'o', 
+'n', 'O', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '\022', '4', '\n', '\027', 'u', 's', 'e', '_', 't', 'c', 'p', '_', 'f', 'o', 'r', '_', 
+'d', 'n', 's', '_', 'l', 'o', 'o', 'k', 'u', 'p', 's', '\030', '\024', ' ', '\001', '(', '\010', 'R', '\023', 'u', 's', 'e', 'T', 'c', 'p', 
+'F', 'o', 'r', 'D', 'n', 's', 'L', 'o', 'o', 'k', 'u', 'p', 's', '\022', ']', '\n', '\024', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 
+'p', '_', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '\030', '\025', ' ', '\003', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 
+'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\023', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', 'E', 'x', 
+'t', 'e', 'n', 's', 'i', 'o', 'n', 's', '\022', 'K', '\n', '\r', 'f', 'a', 't', 'a', 'l', '_', 'a', 'c', 't', 'i', 'o', 'n', 's', 
+'\030', '\034', ' ', '\003', '(', '\013', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 
+'t', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'F', 'a', 't', 'a', 'l', 'A', 'c', 't', 'i', 'o', 'n', 'R', '\014', 'f', 'a', 
+'t', 'a', 'l', 'A', 'c', 't', 'i', 'o', 'n', 's', '\022', 'I', '\n', '\016', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 
+'c', 'e', 's', '\030', '\026', ' ', '\003', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\r', 'c', 'o', 'n', 
+'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 's', '\022', 'V', '\n', '\025', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'c', 'o', 'n', 
+'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\027', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 
+'c', 'e', 'R', '\023', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '8', 
+'\n', '\030', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 's', 'o', 'c', 'k', 'e', 't', '_', 'i', 'n', 't', 'e', 'r', 'f', 'a', 'c', 
+'e', '\030', '\030', ' ', '\001', '(', '\t', 'R', '\026', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'S', 'o', 'c', 'k', 'e', 't', 'I', 'n', 't', 
+'e', 'r', 'f', 'a', 'c', 'e', '\022', '\214', '\001', '\n', '\036', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 
+'o', 'v', 'i', 'd', 'e', 'r', '_', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 's', '\030', '\031', ' ', '\003', '(', '\013', '2', 'F', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', 
+'.', 'B', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 
+'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', 's', 'E', 'n', 't', 'r', 'y', 'R', '\034', 'c', 'e', 'r', 't', 
+'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', 's', '\032', 
+'\232', '\002', '\n', '\017', 'S', 't', 'a', 't', 'i', 'c', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\022', '@', '\n', '\t', 'l', 'i', 
+'s', 't', 'e', 'n', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'R', 
+'\t', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', '\022', '<', '\n', '\010', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', '\030', '\002', ' ', 
+'\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 
+'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'R', '\010', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', '\022', 'K', '\n', 
+'\007', 's', 'e', 'c', 'r', 'e', 't', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 
+'t', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 
+'s', '.', 't', 'l', 's', '.', 'v', '3', '.', 'S', 'e', 'c', 'r', 'e', 't', 'R', '\007', 's', 'e', 'c', 'r', 'e', 't', 's', ':', 
+':', '\232', '\305', '\210', '\036', '5', '\n', '3', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 
+'s', 't', 'r', 'a', 'p', '.', 'v', '2', '.', 'B', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'S', 't', 'a', 't', 'i', 'c', 
+'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\032', '\211', '\003', '\n', '\020', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'R', 'e', 's', 'o', 
+'u', 'r', 'c', 'e', 's', '\022', 'A', '\n', '\n', 'l', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', 
+'2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 
+'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 'l', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '2', '\n', 
+'\025', 'l', 'd', 's', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '\030', '\005', ' ', 
+'\001', '(', '\t', 'R', '\023', 'l', 'd', 's', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', 'L', 'o', 'c', 'a', 't', 'o', 'r', '\022', 
+'A', '\n', '\n', 'c', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 
+'o', 'u', 'r', 'c', 'e', 'R', '\t', 'c', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '2', '\n', '\025', 'c', 'd', 's', '_', 'r', 
+'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '\030', '\006', ' ', '\001', '(', '\t', 'R', '\023', 'c', 
+'d', 's', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', 'L', 'o', 'c', 'a', 't', 'o', 'r', '\022', 'D', '\n', '\n', 'a', 'd', 's', 
+'_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 
+'c', 'e', 'R', '\t', 'a', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', ':', ';', '\232', '\305', '\210', '\036', '6', '\n', '4', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '2', '.', 'B', 'o', 
+'o', 't', 's', 't', 'r', 'a', 'p', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', 'J', 
+'\004', '\010', '\004', '\020', '\005', '\032', '{', '\n', '!', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 
+'d', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', 's', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', 
+'\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '@', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', 
+'2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 
+'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\005', 'v', 'a', 'l', 'u', 
+'e', ':', '\002', '8', '\001', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '2', '.', 'B', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', 'B', 
+'\r', '\n', '\013', 's', 't', 'a', 't', 's', '_', 'f', 'l', 'u', 's', 'h', 'J', '\004', '\010', '\n', '\020', '\013', 'J', '\004', '\010', '\013', '\020', 
+'\014', 'R', '\007', 'r', 'u', 'n', 't', 'i', 'm', 'e', '\"', '\376', '\001', '\n', '\005', 'A', 'd', 'm', 'i', 'n', '\022', '&', '\n', '\017', 'a', 
+'c', 'c', 'e', 's', 's', '_', 'l', 'o', 'g', '_', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\r', 'a', 'c', 'c', 
+'e', 's', 's', 'L', 'o', 'g', 'P', 'a', 't', 'h', '\022', '!', '\n', '\014', 'p', 'r', 'o', 'f', 'i', 'l', 'e', '_', 'p', 'a', 't', 
+'h', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\013', 'p', 'r', 'o', 'f', 'i', 'l', 'e', 'P', 'a', 't', 'h', '\022', '7', '\n', '\007', 'a', 
+'d', 'd', 'r', 'e', 's', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'd', 'd', 'r', 'e', 's', 's', 'R', '\007', 'a', 'd', 'd', 'r', 'e', 
+'s', 's', '\022', 'I', '\n', '\016', 's', 'o', 'c', 'k', 'e', 't', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\004', ' ', '\003', '(', 
+'\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
+'S', 'o', 'c', 'k', 'e', 't', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\r', 's', 'o', 'c', 'k', 'e', 't', 'O', 'p', 't', 'i', 'o', 
+'n', 's', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 
+'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '2', '.', 'A', 'd', 'm', 'i', 'n', '\"', '\313', '\004', '\n', '\016', 'C', 'l', 'u', 
+'s', 't', 'e', 'r', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '\022', ',', '\n', '\022', 'l', 'o', 'c', 'a', 'l', '_', 'c', 'l', 'u', 's', 
+'t', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\020', 'l', 'o', 'c', 'a', 'l', 'C', 'l', 'u', 's', 
+'t', 'e', 'r', 'N', 'a', 'm', 'e', '\022', 'g', '\n', '\021', 'o', 'u', 't', 'l', 'i', 'e', 'r', '_', 'd', 'e', 't', 'e', 'c', 't', 
+'i', 'o', 'n', '\030', '\002', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'M', 'a', 'n', 'a', 'g', 
+'e', 'r', '.', 'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 'R', '\020', 'o', 'u', 't', 'l', 
+'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', '\022', 'R', '\n', '\024', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 
+'b', 'i', 'n', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 
+'g', 'R', '\022', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', 'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'Q', '\n', '\021', 
+'l', 'o', 'a', 'd', '_', 's', 't', 'a', 't', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\004', ' ', '\001', '(', '\013', '2', '%', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 
+'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\017', 'l', 'o', 'a', 'd', 'S', 't', 'a', 't', 's', 'C', 'o', 
+'n', 'f', 'i', 'g', '\032', '\311', '\001', '\n', '\020', 'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 
+'\022', '$', '\n', '\016', 'e', 'v', 'e', 'n', 't', '_', 'l', 'o', 'g', '_', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\001', '(', '\t', 'R', 
+'\014', 'e', 'v', 'e', 'n', 't', 'L', 'o', 'g', 'P', 'a', 't', 'h', '\022', 'M', '\n', '\r', 'e', 'v', 'e', 'n', 't', '_', 's', 'e', 
+'r', 'v', 'i', 'c', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'E', 'v', 'e', 'n', 't', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'C', 'o', 'n', 
+'f', 'i', 'g', 'R', '\014', 'e', 'v', 'e', 'n', 't', 'S', 'e', 'r', 'v', 'i', 'c', 'e', ':', '@', '\232', '\305', '\210', '\036', ';', '\n', 
+'9', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', 
+'2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 
+'e', 't', 'e', 'c', 't', 'i', 'o', 'n', ':', '/', '\232', '\305', '\210', '\036', '*', '\n', '(', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 
+'M', 'a', 'n', 'a', 'g', 'e', 'r', '\"', '\260', '\001', '\n', '\t', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 's', '\022', 'U', '\n', '\024', 
+'m', 'a', 'i', 'n', '_', 't', 'h', 'r', 'e', 'a', 'd', '_', 'w', 'a', 't', 'c', 'h', 'd', 'o', 'g', '\030', '\001', ' ', '\001', '(', 
+'\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 
+'p', '.', 'v', '3', '.', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 'R', '\022', 'm', 'a', 'i', 'n', 'T', 'h', 'r', 'e', 'a', 'd', 
+'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', '\022', 'L', '\n', '\017', 'w', 'o', 'r', 'k', 'e', 'r', '_', 'w', 'a', 't', 'c', 'h', 'd', 
+'o', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 
+'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 'R', '\016', 'w', 'o', 'r', 
+'k', 'e', 'r', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', '\"', '\272', '\006', '\n', '\010', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', '\022', 
+'L', '\n', '\007', 'a', 'c', 't', 'i', 'o', 'n', 's', '\030', '\007', ' ', '\003', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'W', 'a', 't', 'c', 'h', 
+'d', 'o', 'g', '.', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 'A', 'c', 't', 'i', 'o', 'n', 'R', '\007', 'a', 'c', 't', 'i', 'o', 
+'n', 's', '\022', '<', '\n', '\014', 'm', 'i', 's', 's', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', 
+'\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', 'R', '\013', 'm', 'i', 's', 's', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'D', '\n', '\020', 'm', 'e', 'g', 'a', 'm', 'i', 's', 
+'s', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\017', 'm', 'e', 'g', 'a', 'm', 'i', 
+'s', 's', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', '<', '\n', '\014', 'k', 'i', 'l', 'l', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', 
+'\030', '\003', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
+'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\013', 'k', 'i', 'l', 'l', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'Z', '\n', '\027', 
+'m', 'a', 'x', '_', 'k', 'i', 'l', 'l', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'j', 'i', 't', 't', 'e', 'r', '\030', '\006', 
+' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 
+'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '2', '\000', 'R', '\024', 'm', 'a', 'x', 'K', 'i', 'l', 'l', 
+'T', 'i', 'm', 'e', 'o', 'u', 't', 'J', 'i', 't', 't', 'e', 'r', '\022', 'F', '\n', '\021', 'm', 'u', 'l', 't', 'i', 'k', 'i', 'l', 
+'l', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\020', 'm', 'u', 'l', 't', 'i', 'k', 
+'i', 'l', 'l', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'G', '\n', '\023', 'm', 'u', 'l', 't', 'i', 'k', 'i', 'l', 'l', '_', 't', 
+'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\030', '\005', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 
+'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\022', 'm', 'u', 'l', 't', 'i', 'k', 'i', 'l', 'l', 'T', 
+'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\032', '\205', '\002', '\n', '\016', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 'A', 'c', 't', 'i', 
+'o', 'n', '\022', 'B', '\n', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 
+'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\022', '`', '\n', '\005', 'e', 
+'v', 'e', 'n', 't', '\030', '\002', ' ', '\001', '(', '\016', '2', '@', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', '.', 'W', 'a', 
+'t', 'c', 'h', 'd', 'o', 'g', 'A', 'c', 't', 'i', 'o', 'n', '.', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 'E', 'v', 'e', 'n', 
+'t', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\005', 'e', 'v', 'e', 'n', 't', '\"', 'M', '\n', '\r', 'W', 'a', 't', 
+'c', 'h', 'd', 'o', 'g', 'E', 'v', 'e', 'n', 't', '\022', '\013', '\n', '\007', 'U', 'N', 'K', 'N', 'O', 'W', 'N', '\020', '\000', '\022', '\010', 
+'\n', '\004', 'K', 'I', 'L', 'L', '\020', '\001', '\022', '\r', '\n', '\t', 'M', 'U', 'L', 'T', 'I', 'K', 'I', 'L', 'L', '\020', '\002', '\022', '\014', 
+'\n', '\010', 'M', 'E', 'G', 'A', 'M', 'I', 'S', 'S', '\020', '\003', '\022', '\010', '\n', '\004', 'M', 'I', 'S', 'S', '\020', '\004', ':', ')', '\232', 
+'\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 
+'r', 'a', 'p', '.', 'v', '2', '.', 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', '\"', 'Q', '\n', '\013', 'F', 'a', 't', 'a', 'l', 'A', 
+'c', 't', 'i', 'o', 'n', '\022', 'B', '\n', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 
+'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\334', 
+'\001', '\n', '\007', 'R', 'u', 'n', 't', 'i', 'm', 'e', '\022', '!', '\n', '\014', 's', 'y', 'm', 'l', 'i', 'n', 'k', '_', 'r', 'o', 'o', 
+'t', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 's', 'y', 'm', 'l', 'i', 'n', 'k', 'R', 'o', 'o', 't', '\022', '\"', '\n', '\014', 's', 
+'u', 'b', 'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\014', 's', 'u', 'b', 'd', 'i', 'r', 
+'e', 'c', 't', 'o', 'r', 'y', '\022', '3', '\n', '\025', 'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '_', 's', 'u', 'b', 'd', 'i', 'r', 
+'e', 'c', 't', 'o', 'r', 'y', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\024', 'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', 'S', 'u', 'b', 
+'d', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', '\022', '+', '\n', '\004', 'b', 'a', 's', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '\027', 
+'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\004', 
+'b', 'a', 's', 'e', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '2', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', '\"', '\333', '\006', '\n', 
+'\014', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'L', 'a', 'y', 'e', 'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', 
+'(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '<', '\n', '\014', 's', 't', 'a', 't', 
+'i', 'c', '_', 'l', 'a', 'y', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
+'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'H', '\000', 'R', '\013', 's', 't', 'a', 't', 'i', 'c', 'L', 
+'a', 'y', 'e', 'r', '\022', 'R', '\n', '\n', 'd', 'i', 's', 'k', '_', 'l', 'a', 'y', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', 
+'1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 
+'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'L', 'a', 'y', 'e', 'r', '.', 'D', 'i', 's', 'k', 'L', 'a', 'y', 'e', 'r', 
+'H', '\000', 'R', '\t', 'd', 'i', 's', 'k', 'L', 'a', 'y', 'e', 'r', '\022', 'U', '\n', '\013', 'a', 'd', 'm', 'i', 'n', '_', 'l', 'a', 
+'y', 'e', 'r', '\030', '\004', ' ', '\001', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'L', 'a', 'y', 'e', 'r', 
+'.', 'A', 'd', 'm', 'i', 'n', 'L', 'a', 'y', 'e', 'r', 'H', '\000', 'R', '\n', 'a', 'd', 'm', 'i', 'n', 'L', 'a', 'y', 'e', 'r', 
+'\022', 'R', '\n', '\n', 'r', 't', 'd', 's', '_', 'l', 'a', 'y', 'e', 'r', '\030', '\005', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'R', 
+'u', 'n', 't', 'i', 'm', 'e', 'L', 'a', 'y', 'e', 'r', '.', 'R', 't', 'd', 's', 'L', 'a', 'y', 'e', 'r', 'H', '\000', 'R', '\t', 
+'r', 't', 'd', 's', 'L', 'a', 'y', 'e', 'r', '\032', '\301', '\001', '\n', '\t', 'D', 'i', 's', 'k', 'L', 'a', 'y', 'e', 'r', '\022', '!', 
+'\n', '\014', 's', 'y', 'm', 'l', 'i', 'n', 'k', '_', 'r', 'o', 'o', 't', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 's', 'y', 'm', 
+'l', 'i', 'n', 'k', 'R', 'o', 'o', 't', '\022', '\"', '\n', '\014', 's', 'u', 'b', 'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', '\030', 
+'\003', ' ', '\001', '(', '\t', 'R', '\014', 's', 'u', 'b', 'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', '\022', '4', '\n', '\026', 'a', 'p', 
+'p', 'e', 'n', 'd', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', 
+'\010', 'R', '\024', 'a', 'p', 'p', 'e', 'n', 'd', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'C', 'l', 'u', 's', 't', 'e', 'r', ':', '7', 
+'\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 
+'t', 'r', 'a', 'p', '.', 'v', '2', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'L', 'a', 'y', 'e', 'r', '.', 'D', 'i', 's', 'k', 
+'L', 'a', 'y', 'e', 'r', '\032', 'F', '\n', '\n', 'A', 'd', 'm', 'i', 'n', 'L', 'a', 'y', 'e', 'r', ':', '8', '\232', '\305', '\210', '\036', 
+'3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', 
+'.', 'v', '2', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'L', 'a', 'y', 'e', 'r', '.', 'A', 'd', 'm', 'i', 'n', 'L', 'a', 'y', 
+'e', 'r', '\032', '\235', '\001', '\n', '\t', 'R', 't', 'd', 's', 'L', 'a', 'y', 'e', 'r', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', 
+'\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'C', '\n', '\013', 'r', 't', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 
+'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
+'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\n', 'r', 't', 'd', 's', 'C', 
+'o', 'n', 'f', 'i', 'g', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '2', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'L', 'a', 'y', 
+'e', 'r', '.', 'R', 't', 'd', 's', 'L', 'a', 'y', 'e', 'r', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '2', '.', 'R', 'u', 'n', 
+'t', 'i', 'm', 'e', 'L', 'a', 'y', 'e', 'r', 'B', '\026', '\n', '\017', 'l', 'a', 'y', 'e', 'r', '_', 's', 'p', 'e', 'c', 'i', 'f', 
+'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', '\"', '\202', '\001', '\n', '\016', 'L', 'a', 'y', 'e', 'r', 'e', 'd', 'R', 'u', 'n', 't', 'i', 
+'m', 'e', '\022', '?', '\n', '\006', 'l', 'a', 'y', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', '3', '.', 'R', 'u', 'n', 
+'t', 'i', 'm', 'e', 'L', 'a', 'y', 'e', 'r', 'R', '\006', 'l', 'a', 'y', 'e', 'r', 's', ':', '/', '\232', '\305', '\210', '\036', '*', '\n', 
+'(', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', '.', 'v', 
+'2', '.', 'L', 'a', 'y', 'e', 'r', 'e', 'd', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'B', 'C', '\n', '\'', 'i', 'o', '.', 'e', 'n', 
+'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'b', 'o', 'o', 
+'t', 's', 't', 'r', 'a', 'p', '.', 'v', '3', 'B', '\016', 'B', 'o', 'o', 't', 's', 't', 'r', 'a', 'p', 'P', 'r', 'o', 't', 'o', 
+'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[22] = {
+  &envoy_config_cluster_v3_cluster_proto_upbdefinit,
+  &envoy_config_core_v3_address_proto_upbdefinit,
+  &envoy_config_core_v3_base_proto_upbdefinit,
+  &envoy_config_core_v3_config_source_proto_upbdefinit,
+  &envoy_config_core_v3_event_service_config_proto_upbdefinit,
+  &envoy_config_core_v3_extension_proto_upbdefinit,
+  &envoy_config_core_v3_socket_option_proto_upbdefinit,
+  &envoy_config_listener_v3_listener_proto_upbdefinit,
+  &envoy_config_metrics_v3_stats_proto_upbdefinit,
+  &envoy_config_overload_v3_overload_proto_upbdefinit,
+  &envoy_config_trace_v3_http_tracer_proto_upbdefinit,
+  &envoy_extensions_transport_sockets_tls_v3_secret_proto_upbdefinit,
+  &envoy_type_v3_percent_proto_upbdefinit,
+  &google_protobuf_duration_proto_upbdefinit,
+  &google_protobuf_struct_proto_upbdefinit,
+  &google_protobuf_wrappers_proto_upbdefinit,
+  &udpa_annotations_migrate_proto_upbdefinit,
+  &udpa_annotations_security_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/config/bootstrap/v3/bootstrap.proto",
+  UPB_STRVIEW_INIT(descriptor, 6993)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h
new file mode 100644
index 0000000..666cbed
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h
@@ -0,0 +1,115 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/bootstrap/v3/bootstrap.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_CONFIG_BOOTSTRAP_V3_BOOTSTRAP_PROTO_UPBDEFS_H_
+#define ENVOY_CONFIG_BOOTSTRAP_V3_BOOTSTRAP_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Bootstrap_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Bootstrap");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Bootstrap_StaticResources_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Bootstrap.StaticResources");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Bootstrap_DynamicResources_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Bootstrap.DynamicResources");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Bootstrap_CertificateProviderInstancesEntry_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Bootstrap.CertificateProviderInstancesEntry");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Admin_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Admin");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_ClusterManager_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.ClusterManager");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_ClusterManager_OutlierDetection_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.ClusterManager.OutlierDetection");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Watchdogs_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Watchdogs");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Watchdog_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Watchdog");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Watchdog_WatchdogAction_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Watchdog.WatchdogAction");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_FatalAction_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.FatalAction");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_Runtime_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.Runtime");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_RuntimeLayer_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.RuntimeLayer");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.RuntimeLayer.DiskLayer");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.RuntimeLayer.AdminLayer");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.RuntimeLayer.RtdsLayer");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_bootstrap_v3_LayeredRuntime_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_bootstrap_v3_bootstrap_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.bootstrap.v3.LayeredRuntime");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_CONFIG_BOOTSTRAP_V3_BOOTSTRAP_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c
index 926192e..18db991 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c
@@ -24,10 +24,7 @@
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_collection_entry_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_resource_locator_proto_upbdefinit;
-extern upb_def_init envoy_annotations_deprecation_proto_upbdefinit;
-extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
+extern upb_def_init xds_core_v3_collection_entry_proto_upbdefinit;
 extern upb_def_init udpa_annotations_security_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
@@ -48,7 +45,7 @@
 extern const upb_msglayout envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_Cluster_RefreshRate_msginit;
-extern const upb_msglayout envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit;
+extern const upb_msglayout envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_Cluster_TypedExtensionProtocolOptionsEntry_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_LoadBalancingPolicy_msginit;
 extern const upb_msglayout envoy_config_cluster_v3_LoadBalancingPolicy_Policy_msginit;
@@ -73,7 +70,7 @@
   &envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig_msginit,
   &envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig_msginit,
   &envoy_config_cluster_v3_Cluster_RefreshRate_msginit,
-  &envoy_config_cluster_v3_Cluster_PrefetchPolicy_msginit,
+  &envoy_config_cluster_v3_Cluster_PreconnectPolicy_msginit,
   &envoy_config_cluster_v3_Cluster_TypedExtensionProtocolOptionsEntry_msginit,
   &envoy_config_cluster_v3_LoadBalancingPolicy_msginit,
   &envoy_config_cluster_v3_LoadBalancingPolicy_Policy_msginit,
@@ -82,7 +79,7 @@
   &envoy_config_cluster_v3_TrackClusterStats_msginit,
 };
 
-static const char descriptor[10953] = {'\n', '%', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'l', 'u', 's', 't', 'e', 'r', '/', 'v', '3', 
+static const char descriptor[10750] = {'\n', '%', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'l', 'u', 's', 't', 'e', 'r', '/', 'v', '3', 
 '/', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\027', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '\032', '-', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 
 'f', 'i', 'g', '/', 'c', 'l', 'u', 's', 't', 'e', 'r', '/', 'v', '3', '/', 'c', 'i', 'r', 'c', 'u', 'i', 't', '_', 'b', 'r', 
@@ -106,424 +103,415 @@
 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 
 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 
 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
-'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 
-'r', 'e', '/', 'v', '1', '/', 'c', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', '_', 'e', 'n', 't', 'r', 'y', '.', 'p', 'r', 
-'o', 't', 'o', '\032', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 
-'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 
-'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 
-'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 
-'n', 's', '/', 's', 'e', 'c', 'u', 'r', 'i', 't', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 
-'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 
-'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 
-'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 
-'t', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', 'L', '\n', '\021', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'l', 'l', 'e', 'c', 
-'t', 'i', 'o', 'n', '\022', '7', '\n', '\007', 'e', 'n', 't', 'r', 'i', 'e', 's', '\030', '\001', ' ', '\001', '(', '\013', '2', '\035', '.', 'u', 
-'d', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 't', 
-'r', 'y', 'R', '\007', 'e', 'n', 't', 'r', 'i', 'e', 's', '\"', '\205', 'H', '\n', '\007', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', 'o', 
-'\n', '\030', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', '_', 'm', 'a', 't', 'c', 'h', 'e', 
-'s', '\030', '+', ' ', '\003', '(', '\013', '2', '5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 
-'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 
-'t', 'S', 'o', 'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 'h', 'R', '\026', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 
-'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 'h', 'e', 's', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
-'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\"', '\n', '\r', 'a', 'l', 't', '_', 's', 't', 
-'a', 't', '_', 'n', 'a', 'm', 'e', '\030', '\034', ' ', '\001', '(', '\t', 'R', '\013', 'a', 'l', 't', 'S', 't', 'a', 't', 'N', 'a', 'm', 
-'e', '\022', 'N', '\n', '\004', 't', 'y', 'p', 'e', '\030', '\002', ' ', '\001', '(', '\016', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\"', 'x', 'd', 's', '/', 'c', 'o', 'r', 
+'e', '/', 'v', '3', '/', 'c', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', '_', 'e', 'n', 't', 'r', 'y', '.', 'p', 'r', 'o', 
+'t', 'o', '\032', '\037', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 'e', 'c', 'u', 
+'r', 'i', 't', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 
+'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 
+'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 
+'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 
+'o', '\"', 'K', '\n', '\021', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', '\022', '6', '\n', 
+'\007', 'e', 'n', 't', 'r', 'i', 'e', 's', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', 
+'.', 'v', '3', '.', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 't', 'r', 'y', 'R', '\007', 'e', 'n', 't', 'r', 
+'i', 'e', 's', '\"', '\246', 'G', '\n', '\007', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', 'o', '\n', '\030', 't', 'r', 'a', 'n', 's', 'p', 
+'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', '_', 'm', 'a', 't', 'c', 'h', 'e', 's', '\030', '+', ' ', '\003', '(', '\013', '2', 
+'5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', 
+'.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'M', 
+'a', 't', 'c', 'h', 'R', '\026', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 
+'h', 'e', 's', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', 
+'\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\"', '\n', '\r', 'a', 'l', 't', '_', 's', 't', 'a', 't', '_', 'n', 'a', 'm', 'e', '\030', 
+'\034', ' ', '\001', '(', '\t', 'R', '\013', 'a', 'l', 't', 'S', 't', 'a', 't', 'N', 'a', 'm', 'e', '\022', 'N', '\n', '\004', 't', 'y', 'p', 
+'e', '\030', '\002', ' ', '\001', '(', '\016', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 
+'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 
+'y', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'H', '\000', 'R', '\004', 't', 'y', 'p', 'e', '\022', 'W', 
+'\n', '\014', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 't', 'y', 'p', 'e', '\030', '&', ' ', '\001', '(', '\013', '2', '2', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 
+'s', 't', 'e', 'r', '.', 'C', 'u', 's', 't', 'o', 'm', 'C', 'l', 'u', 's', 't', 'e', 'r', 'T', 'y', 'p', 'e', 'H', '\000', 'R', 
+'\013', 'c', 'l', 'u', 's', 't', 'e', 'r', 'T', 'y', 'p', 'e', '\022', '_', '\n', '\022', 'e', 'd', 's', '_', 'c', 'l', 'u', 's', 't', 
+'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 
-'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'H', '\000', 
-'R', '\004', 't', 'y', 'p', 'e', '\022', 'W', '\n', '\014', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 't', 'y', 'p', 'e', '\030', '&', ' ', 
-'\001', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 
-'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'u', 's', 't', 'o', 'm', 'C', 'l', 'u', 's', 't', 'e', 
-'r', 'T', 'y', 'p', 'e', 'H', '\000', 'R', '\013', 'c', 'l', 'u', 's', 't', 'e', 'r', 'T', 'y', 'p', 'e', '\022', '_', '\n', '\022', 'e', 
-'d', 's', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '1', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 
-'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'E', 'd', 's', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'R', 
-'\020', 'e', 'd', 's', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'L', '\n', '\017', 'c', 'o', 'n', 'n', 
-'e', 'c', 't', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', 
-'\001', '\002', '*', '\000', 'R', '\016', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'o', '\n', '!', 'p', 
-'e', 'r', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'b', 'u', 'f', 'f', 'e', 'r', '_', 'l', 'i', 'm', 'i', 
-'t', '_', 'b', 'y', 't', 'e', 's', '\030', '\005', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
-'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\212', '\223', '\267', '*', '\002', 
-'\020', '\001', 'R', '\035', 'p', 'e', 'r', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'u', 'f', 'f', 'e', 'r', 'L', 'i', 
-'m', 'i', 't', 'B', 'y', 't', 'e', 's', '\022', 'R', '\n', '\t', 'l', 'b', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\006', ' ', '\001', 
-'(', '\016', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', 
-'.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'b', 'P', 'o', 'l', 'i', 'c', 'y', 'B', '\n', '\372', 'B', '\007', 
-'\202', '\001', '\004', '\020', '\001', ' ', '\007', 'R', '\010', 'l', 'b', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'X', '\n', '\017', 'l', 'o', 'a', 'd', 
-'_', 'a', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', '\030', '!', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 
-'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', 'R', '\016', 'l', 'o', 'a', 'd', 'A', 's', 's', 
-'i', 'g', 'n', 'm', 'e', 'n', 't', '\022', 'F', '\n', '\r', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', 's', '\030', 
-'\010', ' ', '\003', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
-'.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'R', '\014', 'h', 'e', 'a', 'l', 't', 'h', 'C', 'h', 
-'e', 'c', 'k', 's', '\022', '[', '\n', '\033', 'm', 'a', 'x', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', 's', '_', 'p', 'e', 'r', '_', 
-'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\030', '\t', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\030', 'm', 'a', 
-'x', 'R', 'e', 'q', 'u', 'e', 's', 't', 's', 'P', 'e', 'r', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\022', 'S', '\n', 
-'\020', 'c', 'i', 'r', 'c', 'u', 'i', 't', '_', 'b', 'r', 'e', 'a', 'k', 'e', 'r', 's', '\030', '\n', ' ', '\001', '(', '\013', '2', '(', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 
-'C', 'i', 'r', 'c', 'u', 'i', 't', 'B', 'r', 'e', 'a', 'k', 'e', 'r', 's', 'R', '\017', 'c', 'i', 'r', 'c', 'u', 'i', 't', 'B', 
-'r', 'e', 'a', 'k', 'e', 'r', 's', '\022', 'v', '\n', '\036', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'h', 't', 't', 'p', '_', 
-'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '.', ' ', '\001', '(', '\013', '2', '1', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'U', 'p', 's', 't', 
-'r', 'e', 'a', 'm', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\033', 
-'u', 'p', 's', 't', 'r', 'e', 'a', 'm', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 
-'n', 's', '\022', 'j', '\n', '\034', 'c', 'o', 'm', 'm', 'o', 'n', '_', 'h', 't', 't', 'p', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 
-'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\035', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 
-'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\031', 'c', 'o', 'm', 'm', 'o', 'n', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 
-'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '^', '\n', '\025', 'h', 't', 't', 'p', '_', 'p', 'r', 'o', 't', 'o', 'c', 
+'E', 'd', 's', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\020', 'e', 'd', 's', 'C', 'l', 'u', 's', 
+'t', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'L', '\n', '\017', 'c', 'o', 'n', 'n', 'e', 'c', 't', '_', 't', 'i', 'm', 'e', 
+'o', 'u', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\016', 'c', 'o', 
+'n', 'n', 'e', 'c', 't', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'o', '\n', '!', 'p', 'e', 'r', '_', 'c', 'o', 'n', 'n', 'e', 
+'c', 't', 'i', 'o', 'n', '_', 'b', 'u', 'f', 'f', 'e', 'r', '_', 'l', 'i', 'm', 'i', 't', '_', 'b', 'y', 't', 'e', 's', '\030', 
+'\005', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 
+'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\212', '\223', '\267', '*', '\002', '\020', '\001', 'R', '\035', 'p', 'e', 'r', 'C', 
+'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'u', 'f', 'f', 'e', 'r', 'L', 'i', 'm', 'i', 't', 'B', 'y', 't', 'e', 's', 
+'\022', 'R', '\n', '\t', 'l', 'b', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\006', ' ', '\001', '(', '\016', '2', ')', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 
+'t', 'e', 'r', '.', 'L', 'b', 'P', 'o', 'l', 'i', 'c', 'y', 'B', '\n', '\372', 'B', '\007', '\202', '\001', '\004', '\020', '\001', ' ', '\007', 'R', 
+'\010', 'l', 'b', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'X', '\n', '\017', 'l', 'o', 'a', 'd', '_', 'a', 's', 's', 'i', 'g', 'n', 'm', 
+'e', 'n', 't', '\030', '!', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 
+'s', 'i', 'g', 'n', 'm', 'e', 'n', 't', 'R', '\016', 'l', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', '\022', 
+'F', '\n', '\r', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', 's', '\030', '\010', ' ', '\003', '(', '\013', '2', '!', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 
+'t', 'h', 'C', 'h', 'e', 'c', 'k', 'R', '\014', 'h', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 's', '\022', '[', '\n', '\033', 
+'m', 'a', 'x', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', 's', '_', 'p', 'e', 'r', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
+'o', 'n', '\030', '\t', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\030', 'm', 'a', 'x', 'R', 'e', 'q', 'u', 'e', 's', 't', 
+'s', 'P', 'e', 'r', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\022', 'S', '\n', '\020', 'c', 'i', 'r', 'c', 'u', 'i', 't', 
+'_', 'b', 'r', 'e', 'a', 'k', 'e', 'r', 's', '\030', '\n', ' ', '\001', '(', '\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'i', 'r', 'c', 'u', 'i', 't', 'B', 
+'r', 'e', 'a', 'k', 'e', 'r', 's', 'R', '\017', 'c', 'i', 'r', 'c', 'u', 'i', 't', 'B', 'r', 'e', 'a', 'k', 'e', 'r', 's', '\022', 
+'z', '\n', '\036', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'h', 't', 't', 'p', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', 
+'_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '.', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'H', 't', 't', 'p', 
+'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'B', '\002', '\030', '\001', 'R', '\033', 'u', 'p', 's', 't', 
+'r', 'e', 'a', 'm', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'n', 
+'\n', '\034', 'c', 'o', 'm', 'm', 'o', 'n', '_', 'h', 't', 't', 'p', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 'p', 
+'t', 'i', 'o', 'n', 's', '\030', '\035', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 
+'i', 'o', 'n', 's', 'B', '\002', '\030', '\001', 'R', '\031', 'c', 'o', 'm', 'm', 'o', 'n', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 
+'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'b', '\n', '\025', 'h', 't', 't', 'p', '_', 'p', 'r', 'o', 't', 'o', 'c', 
 'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\r', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 
 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 'p', '1', 'P', 'r', 'o', 't', 'o', 
-'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\023', 'h', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 
-'p', 't', 'i', 'o', 'n', 's', '\022', 'i', '\n', '\026', 'h', 't', 't', 'p', '2', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 
-'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\016', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 'p', '2', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 
-'O', 'p', 't', 'i', 'o', 'n', 's', 'B', '\007', '\212', '\223', '\267', '*', '\002', '\020', '\001', 'R', '\024', 'h', 't', 't', 'p', '2', 'P', 'r', 
-'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '\214', '\001', '\n', ' ', 't', 'y', 'p', 'e', 'd', '_', 'e', 
-'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', 
-'\030', '$', ' ', '\003', '(', '\013', '2', 'C', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 
-'s', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 
-'n', 's', 'i', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', 
-'R', '\035', 't', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 
-'p', 't', 'i', 'o', 'n', 's', '\022', 'Q', '\n', '\020', 'd', 'n', 's', '_', 'r', 'e', 'f', 'r', 'e', 's', 'h', '_', 'r', 'a', 't', 
-'e', '\030', '\020', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
-'.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\014', '\372', 'B', '\t', '\252', '\001', '\006', '*', '\004', '\020', '\300', '\204', '=', 'R', '\016', 
-'d', 'n', 's', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', '\022', 'e', '\n', '\030', 'd', 'n', 's', '_', 'f', 'a', 'i', 
-'l', 'u', 'r', 'e', '_', 'r', 'e', 'f', 'r', 'e', 's', 'h', '_', 'r', 'a', 't', 'e', '\030', ',', ' ', '\001', '(', '\013', '2', ',', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 
-'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', 'R', '\025', 'd', 'n', 's', 'F', 
-'a', 'i', 'l', 'u', 'r', 'e', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', '\022', '&', '\n', '\017', 'r', 'e', 's', 'p', 
-'e', 'c', 't', '_', 'd', 'n', 's', '_', 't', 't', 'l', '\030', '\'', ' ', '\001', '(', '\010', 'R', '\r', 'r', 'e', 's', 'p', 'e', 'c', 
-'t', 'D', 'n', 's', 'T', 't', 'l', '\022', 'f', '\n', '\021', 'd', 'n', 's', '_', 'l', 'o', 'o', 'k', 'u', 'p', '_', 'f', 'a', 'm', 
-'i', 'l', 'y', '\030', '\021', ' ', '\001', '(', '\016', '2', '0', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'D', 'n', 's', 'L', 'o', 'o', 
-'k', 'u', 'p', 'F', 'a', 'm', 'i', 'l', 'y', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\017', 'd', 'n', 's', 'L', 
-'o', 'o', 'k', 'u', 'p', 'F', 'a', 'm', 'i', 'l', 'y', '\022', 'B', '\n', '\r', 'd', 'n', 's', '_', 'r', 'e', 's', 'o', 'l', 'v', 
-'e', 'r', 's', '\030', '\022', ' ', '\003', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'd', 'd', 'r', 'e', 's', 's', 'R', '\014', 'd', 'n', 's', 'R', 'e', 's', 'o', 'l', 
-'v', 'e', 'r', 's', '\022', '4', '\n', '\027', 'u', 's', 'e', '_', 't', 'c', 'p', '_', 'f', 'o', 'r', '_', 'd', 'n', 's', '_', 'l', 
-'o', 'o', 'k', 'u', 'p', 's', '\030', '-', ' ', '\001', '(', '\010', 'R', '\023', 'u', 's', 'e', 'T', 'c', 'p', 'F', 'o', 'r', 'D', 'n', 
-'s', 'L', 'o', 'o', 'k', 'u', 'p', 's', '\022', 'V', '\n', '\021', 'o', 'u', 't', 'l', 'i', 'e', 'r', '_', 'd', 'e', 't', 'e', 'c', 
-'t', 'i', 'o', 'n', '\030', '\023', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 
-'i', 'o', 'n', 'R', '\020', 'o', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', '\022', 'N', '\n', '\020', 
-'c', 'l', 'e', 'a', 'n', 'u', 'p', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\024', ' ', '\001', '(', '\013', '2', '\031', '.', 
-'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', 
-'\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\017', 'c', 'l', 'e', 'a', 'n', 'u', 'p', 'I', 'n', 't', 'e', 'r', 'v', 'a', 
-'l', '\022', 'R', '\n', '\024', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'b', 'i', 'n', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', 
-'\030', '\025', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 
-'e', '.', 'v', '3', '.', 'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\022', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', 
-'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'Y', '\n', '\020', 'l', 'b', '_', 's', 'u', 'b', 's', 'e', 't', '_', 'c', 
-'o', 'n', 'f', 'i', 'g', '\030', '\026', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'b', 'S', 'u', 
-'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'l', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 
-'g', '\022', 'b', '\n', '\023', 'r', 'i', 'n', 'g', '_', 'h', 'a', 's', 'h', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', 
-'\027', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 
-'t', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'R', 'i', 'n', 'g', 'H', 'a', 's', 'h', 'L', 'b', 
-'C', 'o', 'n', 'f', 'i', 'g', 'H', '\001', 'R', '\020', 'r', 'i', 'n', 'g', 'H', 'a', 's', 'h', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 
-'g', '\022', '[', '\n', '\020', 'm', 'a', 'g', 'l', 'e', 'v', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '4', ' ', '\001', 
-'(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', 
-'.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'M', 'a', 'g', 'l', 'e', 'v', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 
-'g', 'H', '\001', 'R', '\016', 'm', 'a', 'g', 'l', 'e', 'v', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'k', '\n', '\026', 'o', 'r', 
-'i', 'g', 'i', 'n', 'a', 'l', '_', 'd', 's', 't', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\"', ' ', '\001', '(', 
-'\013', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 
-'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'O', 'r', 'i', 'g', 'i', 'n', 'a', 'l', 'D', 's', 't', 'L', 'b', 'C', 
-'o', 'n', 'f', 'i', 'g', 'H', '\001', 'R', '\023', 'o', 'r', 'i', 'g', 'i', 'n', 'a', 'l', 'D', 's', 't', 'L', 'b', 'C', 'o', 'n', 
-'f', 'i', 'g', '\022', 'n', '\n', '\027', 'l', 'e', 'a', 's', 't', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'l', 'b', '_', 'c', 
-'o', 'n', 'f', 'i', 'g', '\030', '%', ' ', '\001', '(', '\013', '2', '5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'e', 'a', 's', 
-'t', 'R', 'e', 'q', 'u', 'e', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\001', 'R', '\024', 'l', 'e', 'a', 's', 't', 
-'R', 'e', 'q', 'u', 'e', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'Y', '\n', '\020', 'c', 'o', 'm', 'm', 'o', 'n', 
-'_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\033', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 
-'.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'c', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 
-'C', 'o', 'n', 'f', 'i', 'g', '\022', 'P', '\n', '\020', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 
-'t', '\030', '\030', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
-'r', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'R', '\017', 't', 'r', 
-'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', '\022', ':', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 
-'\030', '\031', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 
-'e', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', 'h', 
-'\n', '\022', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 's', 'e', 'l', 'e', 'c', 't', 'i', 'o', 'n', '\030', '\032', ' ', '\001', '(', 
-'\016', '2', '9', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 
-'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'c', 'o', 
-'l', 'S', 'e', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'R', '\021', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'S', 'e', 'l', 'e', 'c', 
-'t', 'i', 'o', 'n', '\022', 'r', '\n', '\033', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
-'o', 'n', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\036', ' ', '\001', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'U', 'p', 's', 't', 'r', 'e', 'a', 
-'m', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\031', 'u', 'p', 's', 't', 'r', 
-'e', 'a', 'm', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'U', '\n', '(', 'c', 
-'l', 'o', 's', 'e', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 's', '_', 'o', 'n', '_', 'h', 'o', 's', 't', '_', 
-'h', 'e', 'a', 'l', 't', 'h', '_', 'f', 'a', 'i', 'l', 'u', 'r', 'e', '\030', '\037', ' ', '\001', '(', '\010', 'R', '#', 'c', 'l', 'o', 
-'s', 'e', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 's', 'O', 'n', 'H', 'o', 's', 't', 'H', 'e', 'a', 'l', 't', 'h', 
-'F', 'a', 'i', 'l', 'u', 'r', 'e', '\022', '@', '\n', '\035', 'i', 'g', 'n', 'o', 'r', 'e', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 
-'o', 'n', '_', 'h', 'o', 's', 't', '_', 'r', 'e', 'm', 'o', 'v', 'a', 'l', '\030', ' ', ' ', '\001', '(', '\010', 'R', '\031', 'i', 'g', 
-'n', 'o', 'r', 'e', 'H', 'e', 'a', 'l', 't', 'h', 'O', 'n', 'H', 'o', 's', 't', 'R', 'e', 'm', 'o', 'v', 'a', 'l', '\022', '9', 
-'\n', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', '\030', '(', ' ', '\003', '(', '\013', '2', '\037', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\007', 
-'f', 'i', 'l', 't', 'e', 'r', 's', '\022', '`', '\n', '\025', 'l', 'o', 'a', 'd', '_', 'b', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 
-'_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', ')', ' ', '\001', '(', '\013', '2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 
-'i', 'n', 'g', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\023', 'l', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 'P', 
-'o', 'l', 'i', 'c', 'y', '\022', 'A', '\n', '\n', 'l', 'r', 's', '_', 's', 'e', 'r', 'v', 'e', 'r', '\030', '*', ' ', '\001', '(', '\013', 
-'2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 
-'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 'l', 'r', 's', 'S', 'e', 'r', 'v', 'e', 'r', '\022', '6', '\n', 
-'\025', 't', 'r', 'a', 'c', 'k', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'b', 'u', 'd', 'g', 'e', 't', 's', '\030', '/', ' ', 
-'\001', '(', '\010', 'B', '\002', '\030', '\001', 'R', '\023', 't', 'r', 'a', 'c', 'k', 'T', 'i', 'm', 'e', 'o', 'u', 't', 'B', 'u', 'd', 'g', 
-'e', 't', 's', '\022', 'S', '\n', '\017', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '0', ' ', 
-'\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
-'3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'u', 
-'p', 's', 't', 'r', 'e', 'a', 'm', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'Z', '\n', '\023', 't', 'r', 'a', 'c', 'k', '_', 'c', 'l', 
-'u', 's', 't', 'e', 'r', '_', 's', 't', 'a', 't', 's', '\030', '1', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'k', 'C', 
-'l', 'u', 's', 't', 'e', 'r', 'S', 't', 'a', 't', 's', 'R', '\021', 't', 'r', 'a', 'c', 'k', 'C', 'l', 'u', 's', 't', 'e', 'r', 
-'S', 't', 'a', 't', 's', '\022', 'X', '\n', '\017', 'p', 'r', 'e', 'f', 'e', 't', 'c', 'h', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', 
-'2', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 
-'t', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'P', 'r', 'e', 'f', 'e', 't', 'c', 'h', 'P', 'o', 
-'l', 'i', 'c', 'y', 'R', '\016', 'p', 'r', 'e', 'f', 'e', 't', 'c', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'X', '\n', ')', 'c', 
-'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'p', 'o', 'o', 'l', '_', 'p', 'e', 'r', '_', 'd', 'o', 'w', 'n', 's', 't', 
-'r', 'e', 'a', 'm', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\030', '3', ' ', '\001', '(', '\010', 'R', '%', 'c', 'o', 
-'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'o', 'o', 'l', 'P', 'e', 'r', 'D', 'o', 'w', 'n', 's', 't', 'r', 'e', 'a', 'm', 
-'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\032', '\346', '\001', '\n', '\024', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 
-'o', 'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 'h', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', 
-'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '-', '\n', '\005', 'm', 'a', 't', 'c', 'h', '\030', '\002', 
-' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 
-'r', 'u', 'c', 't', 'R', '\005', 'm', 'a', 't', 'c', 'h', '\022', 'P', '\n', '\020', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 
-'s', 'o', 'c', 'k', 'e', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 
-'t', 'R', '\017', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', ':', '0', '\232', '\305', '\210', '\036', '+', 
-'\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'T', 'r', 
-'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 'h', '\032', '\230', '\001', '\n', '\021', 'C', 'u', 
-'s', 't', 'o', 'm', 'C', 'l', 'u', 's', 't', 'e', 'r', 'T', 'y', 'p', 'e', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', 
-' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '7', '\n', '\014', 't', 'y', 
-'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 
-'g', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 
-'u', 's', 't', 'e', 'r', '.', 'C', 'u', 's', 't', 'o', 'm', 'C', 'l', 'u', 's', 't', 'e', 'r', 'T', 'y', 'p', 'e', '\032', '\247', 
-'\002', '\n', '\020', 'E', 'd', 's', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'A', '\n', '\n', 'e', 'd', 
-'s', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 
-'R', '\t', 'e', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '9', '\n', '\014', 's', 'e', 'r', 'v', 'i', 'c', 'e', '_', 'n', 'a', 
-'m', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\026', '\362', '\230', '\376', '\217', '\005', '\020', '\022', '\016', 'n', 'a', 'm', 'e', '_', 's', 'p', 
-'e', 'c', 'i', 'f', 'i', 'e', 'r', 'R', '\013', 's', 'e', 'r', 'v', 'i', 'c', 'e', 'N', 'a', 'm', 'e', '\022', 'g', '\n', '\024', 'e', 
-'d', 's', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '\030', '\003', ' ', '\001', '(', '\013', 
-'2', '\035', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 
-'o', 'c', 'a', 't', 'o', 'r', 'B', '\026', '\362', '\230', '\376', '\217', '\005', '\020', '\022', '\016', 'n', 'a', 'm', 'e', '_', 's', 'p', 'e', 'c', 
-'i', 'f', 'i', 'e', 'r', 'R', '\022', 'e', 'd', 's', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 
-':', ',', '\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 
-'s', 't', 'e', 'r', '.', 'E', 'd', 's', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\300', '\010', '\n', 
-'\016', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'y', '\n', '\017', 'f', 'a', 'l', 'l', 'b', 'a', 
-'c', 'k', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\001', ' ', '\001', '(', '\016', '2', 'F', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'B', '\002', '\030', '\001', 'R', '\023', 'h', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 
+'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'k', '\n', '\026', 'h', 't', 't', 'p', '2', '_', 'p', 'r', 'o', 't', 'o', 
+'c', 'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\016', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 'p', '2', 'P', 'r', 'o', 't', 
+'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'B', '\t', '\030', '\001', '\212', '\223', '\267', '*', '\002', '\020', '\001', 'R', '\024', 'h', 
+'t', 't', 'p', '2', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '\214', '\001', '\n', ' ', 't', 
+'y', 'p', 'e', 'd', '_', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 
+'p', 't', 'i', 'o', 'n', 's', '\030', '$', ' ', '\003', '(', '\013', '2', 'C', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'T', 'y', 'p', 
+'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 
+'s', 'E', 'n', 't', 'r', 'y', 'R', '\035', 't', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'P', 'r', 'o', 
+'t', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'Q', '\n', '\020', 'd', 'n', 's', '_', 'r', 'e', 'f', 'r', 'e', 
+'s', 'h', '_', 'r', 'a', 't', 'e', '\030', '\020', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\014', '\372', 'B', '\t', '\252', '\001', '\006', '*', '\004', 
+'\020', '\300', '\204', '=', 'R', '\016', 'd', 'n', 's', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', '\022', 'e', '\n', '\030', 'd', 
+'n', 's', '_', 'f', 'a', 'i', 'l', 'u', 'r', 'e', '_', 'r', 'e', 'f', 'r', 'e', 's', 'h', '_', 'r', 'a', 't', 'e', '\030', ',', 
+' ', '\001', '(', '\013', '2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 
+'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', 
+'R', '\025', 'd', 'n', 's', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', '\022', '&', 
+'\n', '\017', 'r', 'e', 's', 'p', 'e', 'c', 't', '_', 'd', 'n', 's', '_', 't', 't', 'l', '\030', '\'', ' ', '\001', '(', '\010', 'R', '\r', 
+'r', 'e', 's', 'p', 'e', 'c', 't', 'D', 'n', 's', 'T', 't', 'l', '\022', 'f', '\n', '\021', 'd', 'n', 's', '_', 'l', 'o', 'o', 'k', 
+'u', 'p', '_', 'f', 'a', 'm', 'i', 'l', 'y', '\030', '\021', ' ', '\001', '(', '\016', '2', '0', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 
-'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'F', 'a', 
-'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\016', 'f', 
-'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '>', '\n', '\016', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 
-'s', 'u', 'b', 's', 'e', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
-'t', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'S', 'u', 'b', 's', 
-'e', 't', '\022', 'k', '\n', '\020', 's', 'u', 'b', 's', 'e', 't', '_', 's', 'e', 'l', 'e', 'c', 't', 'o', 'r', 's', '\030', '\003', ' ', 
-'\003', '(', '\013', '2', '@', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 
-'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 
-'i', 'g', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', 'R', '\017', 's', 'u', 'b', 's', 
-'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', 's', '\022', '2', '\n', '\025', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', '_', 'w', 
-'e', 'i', 'g', 'h', 't', '_', 'a', 'w', 'a', 'r', 'e', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\023', 'l', 'o', 'c', 'a', 'l', 'i', 
-'t', 'y', 'W', 'e', 'i', 'g', 'h', 't', 'A', 'w', 'a', 'r', 'e', '\022', '2', '\n', '\025', 's', 'c', 'a', 'l', 'e', '_', 'l', 'o', 
-'c', 'a', 'l', 'i', 't', 'y', '_', 'w', 'e', 'i', 'g', 'h', 't', '\030', '\005', ' ', '\001', '(', '\010', 'R', '\023', 's', 'c', 'a', 'l', 
-'e', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 'h', 't', '\022', '$', '\n', '\016', 'p', 'a', 'n', 'i', 'c', '_', 
-'m', 'o', 'd', 'e', '_', 'a', 'n', 'y', '\030', '\006', ' ', '\001', '(', '\010', 'R', '\014', 'p', 'a', 'n', 'i', 'c', 'M', 'o', 'd', 'e', 
-'A', 'n', 'y', '\022', '\036', '\n', '\013', 'l', 'i', 's', 't', '_', 'a', 's', '_', 'a', 'n', 'y', '\030', '\007', ' ', '\001', '(', '\010', 'R', 
-'\t', 'l', 'i', 's', 't', 'A', 's', 'A', 'n', 'y', '\032', '\332', '\003', '\n', '\020', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'S', 'e', 
-'l', 'e', 'c', 't', 'o', 'r', '\022', '\022', '\n', '\004', 'k', 'e', 'y', 's', '\030', '\001', ' ', '\003', '(', '\t', 'R', '\004', 'k', 'e', 'y', 
-'s', '\022', '3', '\n', '\026', 's', 'i', 'n', 'g', 'l', 'e', '_', 'h', 'o', 's', 't', '_', 'p', 'e', 'r', '_', 's', 'u', 'b', 's', 
-'e', 't', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\023', 's', 'i', 'n', 'g', 'l', 'e', 'H', 'o', 's', 't', 'P', 'e', 'r', 'S', 'u', 
-'b', 's', 'e', 't', '\022', '\222', '\001', '\n', '\017', 'f', 'a', 'l', 'l', 'b', 'a', 'c', 'k', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', 
-'\002', ' ', '\001', '(', '\016', '2', '_', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 
-'t', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 
-'n', 'f', 'i', 'g', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', '.', 'L', 'b', 'S', 
-'u', 'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', 'F', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 
-'c', 'y', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\016', 'f', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 
-'i', 'c', 'y', '\022', '0', '\n', '\024', 'f', 'a', 'l', 'l', 'b', 'a', 'c', 'k', '_', 'k', 'e', 'y', 's', '_', 's', 'u', 'b', 's', 
-'e', 't', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\022', 'f', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'K', 'e', 'y', 's', 'S', 'u', 'b', 
-'s', 'e', 't', '\"', 'y', '\n', '\036', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', 'F', 'a', 
-'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '\017', '\n', '\013', 'N', 'O', 'T', '_', 'D', 'E', 'F', 'I', 'N', 
-'E', 'D', '\020', '\000', '\022', '\017', '\n', '\013', 'N', 'O', '_', 'F', 'A', 'L', 'L', 'B', 'A', 'C', 'K', '\020', '\001', '\022', '\020', '\n', '\014', 
-'A', 'N', 'Y', '_', 'E', 'N', 'D', 'P', 'O', 'I', 'N', 'T', '\020', '\002', '\022', '\022', '\n', '\016', 'D', 'E', 'F', 'A', 'U', 'L', 'T', 
-'_', 'S', 'U', 'B', 'S', 'E', 'T', '\020', '\003', '\022', '\017', '\n', '\013', 'K', 'E', 'Y', 'S', '_', 'S', 'U', 'B', 'S', 'E', 'T', '\020', 
-'\004', ':', ';', '\232', '\305', '\210', '\036', '6', '\n', '4', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 
-'u', 's', 't', 'e', 'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'b', 'S', 'u', 
-'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', '\"', 'O', '\n', '\026', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'F', 
-'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '\017', '\n', '\013', 'N', 'O', '_', 'F', 'A', 'L', 'L', 'B', 
-'A', 'C', 'K', '\020', '\000', '\022', '\020', '\n', '\014', 'A', 'N', 'Y', '_', 'E', 'N', 'D', 'P', 'O', 'I', 'N', 'T', '\020', '\001', '\022', '\022', 
-'\n', '\016', 'D', 'E', 'F', 'A', 'U', 'L', 'T', '_', 'S', 'U', 'B', 'S', 'E', 'T', '\020', '\002', ':', '*', '\232', '\305', '\210', '\036', '%', 
-'\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'b', 
-'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\347', '\001', '\n', '\024', 'L', 'e', 'a', 's', 't', 'R', 'e', 'q', 
-'u', 'e', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'H', '\n', '\014', 'c', 'h', 'o', 'i', 'c', 'e', '_', 'c', 'o', 
-'u', 'n', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
-'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', '(', '\002', 'R', '\013', 
-'c', 'h', 'o', 'i', 'c', 'e', 'C', 'o', 'u', 'n', 't', '\022', 'S', '\n', '\023', 'a', 'c', 't', 'i', 'v', 'e', '_', 'r', 'e', 'q', 
-'u', 'e', 's', 't', '_', 'b', 'i', 'a', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'D', 'o', 'u', 'b', 
-'l', 'e', 'R', '\021', 'a', 'c', 't', 'i', 'v', 'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'B', 'i', 'a', 's', ':', '0', '\232', '\305', 
-'\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 
-'.', 'L', 'e', 'a', 's', 't', 'R', 'e', 'q', 'u', 'e', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\221', '\003', '\n', 
-'\020', 'R', 'i', 'n', 'g', 'H', 'a', 's', 'h', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'T', '\n', '\021', 'm', 'i', 'n', 'i', 
-'m', 'u', 'm', '_', 'r', 'i', 'n', 'g', '_', 's', 'i', 'z', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 
-'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '6', '4', 'V', 'a', 'l', 'u', 'e', 'B', 
-'\n', '\372', 'B', '\007', '2', '\005', '\030', '\200', '\200', '\200', '\004', 'R', '\017', 'm', 'i', 'n', 'i', 'm', 'u', 'm', 'R', 'i', 'n', 'g', 'S', 
-'i', 'z', 'e', '\022', 'm', '\n', '\r', 'h', 'a', 's', 'h', '_', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '\030', '\003', ' ', '\001', '(', 
-'\016', '2', '>', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 
-'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'R', 'i', 'n', 'g', 'H', 'a', 's', 'h', 'L', 'b', 'C', 'o', 'n', 'f', 
-'i', 'g', '.', 'H', 'a', 's', 'h', 'F', 'u', 'n', 'c', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 
-'R', '\014', 'h', 'a', 's', 'h', 'F', 'u', 'n', 'c', 't', 'i', 'o', 'n', '\022', 'T', '\n', '\021', 'm', 'a', 'x', 'i', 'm', 'u', 'm', 
-'_', 'r', 'i', 'n', 'g', '_', 's', 'i', 'z', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '6', '4', 'V', 'a', 'l', 'u', 'e', 'B', '\n', '\372', 'B', 
-'\007', '2', '\005', '\030', '\200', '\200', '\200', '\004', 'R', '\017', 'm', 'a', 'x', 'i', 'm', 'u', 'm', 'R', 'i', 'n', 'g', 'S', 'i', 'z', 'e', 
-'\"', '.', '\n', '\014', 'H', 'a', 's', 'h', 'F', 'u', 'n', 'c', 't', 'i', 'o', 'n', '\022', '\013', '\n', '\007', 'X', 'X', '_', 'H', 'A', 
-'S', 'H', '\020', '\000', '\022', '\021', '\n', '\r', 'M', 'U', 'R', 'M', 'U', 'R', '_', 'H', 'A', 'S', 'H', '_', '2', '\020', '\001', ':', ',', 
-'\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 
-'e', 'r', '.', 'R', 'i', 'n', 'g', 'H', 'a', 's', 'h', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'J', '\004', '\010', '\002', '\020', '\003', 
-'\032', 'M', '\n', '\016', 'M', 'a', 'g', 'l', 'e', 'v', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', ';', '\n', '\n', 't', 'a', 'b', 
-'l', 'e', '_', 's', 'i', 'z', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
-'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '6', '4', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 't', 'a', 'b', 'l', 'e', 
-'S', 'i', 'z', 'e', '\032', 'n', '\n', '\023', 'O', 'r', 'i', 'g', 'i', 'n', 'a', 'l', 'D', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 
-'i', 'g', '\022', '&', '\n', '\017', 'u', 's', 'e', '_', 'h', 't', 't', 'p', '_', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\001', ' ', '\001', 
-'(', '\010', 'R', '\r', 'u', 's', 'e', 'H', 't', 't', 'p', 'H', 'e', 'a', 'd', 'e', 'r', ':', '/', '\232', '\305', '\210', '\036', '*', '\n', 
-'(', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'O', 'r', 'i', 
-'g', 'i', 'n', 'a', 'l', 'D', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\374', '\n', '\n', '\016', 'C', 'o', 'm', 'm', 
-'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'N', '\n', '\027', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 'p', 'a', 'n', 
-'i', 'c', '_', 't', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\030', '\001', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 
-'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\025', 'h', 'e', 'a', 'l', 't', 'h', 
-'y', 'P', 'a', 'n', 'i', 'c', 'T', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\022', 't', '\n', '\024', 'z', 'o', 'n', 'e', '_', 'a', 
-'w', 'a', 'r', 'e', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', 'A', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 
-'s', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'Z', 'o', 'n', 'e', 'A', 
-'w', 'a', 'r', 'e', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\000', 'R', '\021', 'z', 'o', 'n', 'e', 'A', 'w', 'a', 'r', 'e', 
-'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '\211', '\001', '\n', '\033', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', '_', 'w', 'e', 'i', 
-'g', 'h', 't', 'e', 'd', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', 'H', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 
-'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'o', 'c', 'a', 
-'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\000', 'R', '\030', 'l', 
-'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'I', 
-'\n', '\023', 'u', 'p', 'd', 'a', 't', 'e', '_', 'm', 'e', 'r', 'g', 'e', '_', 'w', 'i', 'n', 'd', 'o', 'w', '\030', '\004', ' ', '\001', 
-'(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 
-'t', 'i', 'o', 'n', 'R', '\021', 'u', 'p', 'd', 'a', 't', 'e', 'M', 'e', 'r', 'g', 'e', 'W', 'i', 'n', 'd', 'o', 'w', '\022', 'C', 
-'\n', '\037', 'i', 'g', 'n', 'o', 'r', 'e', '_', 'n', 'e', 'w', '_', 'h', 'o', 's', 't', 's', '_', 'u', 'n', 't', 'i', 'l', '_', 
-'f', 'i', 'r', 's', 't', '_', 'h', 'c', '\030', '\005', ' ', '\001', '(', '\010', 'R', '\032', 'i', 'g', 'n', 'o', 'r', 'e', 'N', 'e', 'w', 
-'H', 'o', 's', 't', 's', 'U', 'n', 't', 'i', 'l', 'F', 'i', 'r', 's', 't', 'H', 'c', '\022', 'M', '\n', '$', 'c', 'l', 'o', 's', 
-'e', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 's', '_', 'o', 'n', '_', 'h', 'o', 's', 't', '_', 's', 'e', 't', 
-'_', 'c', 'h', 'a', 'n', 'g', 'e', '\030', '\006', ' ', '\001', '(', '\010', 'R', '\037', 'c', 'l', 'o', 's', 'e', 'C', 'o', 'n', 'n', 'e', 
-'c', 't', 'i', 'o', 'n', 's', 'O', 'n', 'H', 'o', 's', 't', 'S', 'e', 't', 'C', 'h', 'a', 'n', 'g', 'e', '\022', '\212', '\001', '\n', 
-'\034', 'c', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', '_', 'h', 'a', 's', 'h', 'i', 'n', 'g', '_', 'l', 'b', '_', 'c', 'o', 
-'n', 'f', 'i', 'g', '\030', '\007', ' ', '\001', '(', '\013', '2', 'I', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 
-'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'C', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', 'H', 'a', 's', 'h', 'i', 
-'n', 'g', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\031', 'c', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', 'H', 'a', 's', 
-'h', 'i', 'n', 'g', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\215', '\002', '\n', '\021', 'Z', 'o', 'n', 'e', 'A', 'w', 'a', 'r', 
-'e', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '?', '\n', '\017', 'r', 'o', 'u', 't', 'i', 'n', 'g', '_', 'e', 'n', 'a', 'b', 
-'l', 'e', 'd', '\030', '\001', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', 
-'.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'r', 'o', 'u', 't', 'i', 'n', 'g', 'E', 'n', 'a', 'b', 'l', 'e', 'd', '\022', 
-'F', '\n', '\020', 'm', 'i', 'n', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 's', 'i', 'z', 'e', '\030', '\002', ' ', '\001', '(', '\013', 
+'D', 'n', 's', 'L', 'o', 'o', 'k', 'u', 'p', 'F', 'a', 'm', 'i', 'l', 'y', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 
+'R', '\017', 'd', 'n', 's', 'L', 'o', 'o', 'k', 'u', 'p', 'F', 'a', 'm', 'i', 'l', 'y', '\022', 'B', '\n', '\r', 'd', 'n', 's', '_', 
+'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 's', '\030', '\022', ' ', '\003', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'd', 'd', 'r', 'e', 's', 's', 'R', '\014', 'd', 'n', 
+'s', 'R', 'e', 's', 'o', 'l', 'v', 'e', 'r', 's', '\022', '4', '\n', '\027', 'u', 's', 'e', '_', 't', 'c', 'p', '_', 'f', 'o', 'r', 
+'_', 'd', 'n', 's', '_', 'l', 'o', 'o', 'k', 'u', 'p', 's', '\030', '-', ' ', '\001', '(', '\010', 'R', '\023', 'u', 's', 'e', 'T', 'c', 
+'p', 'F', 'o', 'r', 'D', 'n', 's', 'L', 'o', 'o', 'k', 'u', 'p', 's', '\022', 'V', '\n', '\021', 'o', 'u', 't', 'l', 'i', 'e', 'r', 
+'_', 'd', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', '\030', '\023', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'O', 'u', 't', 'l', 'i', 'e', 'r', 
+'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 'R', '\020', 'o', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 
+'o', 'n', '\022', 'N', '\n', '\020', 'c', 'l', 'e', 'a', 'n', 'u', 'p', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\024', ' ', 
+'\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 
+'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\017', 'c', 'l', 'e', 'a', 'n', 'u', 'p', 'I', 
+'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', 'R', '\n', '\024', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'b', 'i', 'n', 'd', '_', 
+'c', 'o', 'n', 'f', 'i', 'g', '\030', '\025', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\022', 'u', 'p', 
+'s', 't', 'r', 'e', 'a', 'm', 'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'Y', '\n', '\020', 'l', 'b', '_', 's', 'u', 
+'b', 's', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\026', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 
+'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'l', 'b', 'S', 'u', 'b', 's', 'e', 
+'t', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'b', '\n', '\023', 'r', 'i', 'n', 'g', '_', 'h', 'a', 's', 'h', '_', 'l', 'b', '_', 'c', 
+'o', 'n', 'f', 'i', 'g', '\030', '\027', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'R', 'i', 'n', 'g', 
+'H', 'a', 's', 'h', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\001', 'R', '\020', 'r', 'i', 'n', 'g', 'H', 'a', 's', 'h', 'L', 
+'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '[', '\n', '\020', 'm', 'a', 'g', 'l', 'e', 'v', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 
+'i', 'g', '\030', '4', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 
+'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'M', 'a', 'g', 'l', 'e', 'v', 'L', 
+'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\001', 'R', '\016', 'm', 'a', 'g', 'l', 'e', 'v', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 
+'\022', 'k', '\n', '\026', 'o', 'r', 'i', 'g', 'i', 'n', 'a', 'l', '_', 'd', 's', 't', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 
+'g', '\030', '\"', ' ', '\001', '(', '\013', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 
+'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'O', 'r', 'i', 'g', 'i', 'n', 'a', 'l', 
+'D', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\001', 'R', '\023', 'o', 'r', 'i', 'g', 'i', 'n', 'a', 'l', 'D', 's', 
+'t', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'n', '\n', '\027', 'l', 'e', 'a', 's', 't', '_', 'r', 'e', 'q', 'u', 'e', 's', 
+'t', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '%', ' ', '\001', '(', '\013', '2', '5', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 
+'r', '.', 'L', 'e', 'a', 's', 't', 'R', 'e', 'q', 'u', 'e', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\001', 'R', 
+'\024', 'l', 'e', 'a', 's', 't', 'R', 'e', 'q', 'u', 'e', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'Y', '\n', '\020', 
+'c', 'o', 'm', 'm', 'o', 'n', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\033', ' ', '\001', '(', '\013', '2', '/', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 
+'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'c', 'o', 
+'m', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'P', '\n', '\020', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 
+'_', 's', 'o', 'c', 'k', 'e', 't', '\030', '\030', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 
+'e', 't', 'R', '\017', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', '\022', ':', '\n', '\010', 'm', 'e', 
+'t', 'a', 'd', 'a', 't', 'a', '\030', '\031', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', '\010', 'm', 'e', 't', 'a', 
+'d', 'a', 't', 'a', '\022', 'l', '\n', '\022', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 's', 'e', 'l', 'e', 'c', 't', 'i', 'o', 
+'n', '\030', '\032', ' ', '\001', '(', '\016', '2', '9', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 
+'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'P', 
+'r', 'o', 't', 'o', 'c', 'o', 'l', 'S', 'e', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'B', '\002', '\030', '\001', 'R', '\021', 'p', 'r', 'o', 
+'t', 'o', 'c', 'o', 'l', 'S', 'e', 'l', 'e', 'c', 't', 'i', 'o', 'n', '\022', 'r', '\n', '\033', 'u', 'p', 's', 't', 'r', 'e', 'a', 
+'m', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\036', ' ', '\001', '(', 
+'\013', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 
+'v', '3', '.', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'O', 'p', 't', 'i', 
+'o', 'n', 's', 'R', '\031', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'O', 'p', 
+'t', 'i', 'o', 'n', 's', '\022', 'U', '\n', '(', 'c', 'l', 'o', 's', 'e', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
+'s', '_', 'o', 'n', '_', 'h', 'o', 's', 't', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'f', 'a', 'i', 'l', 'u', 'r', 'e', '\030', 
+'\037', ' ', '\001', '(', '\010', 'R', '#', 'c', 'l', 'o', 's', 'e', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 's', 'O', 'n', 
+'H', 'o', 's', 't', 'H', 'e', 'a', 'l', 't', 'h', 'F', 'a', 'i', 'l', 'u', 'r', 'e', '\022', '@', '\n', '\035', 'i', 'g', 'n', 'o', 
+'r', 'e', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'o', 'n', '_', 'h', 'o', 's', 't', '_', 'r', 'e', 'm', 'o', 'v', 'a', 'l', 
+'\030', ' ', ' ', '\001', '(', '\010', 'R', '\031', 'i', 'g', 'n', 'o', 'r', 'e', 'H', 'e', 'a', 'l', 't', 'h', 'O', 'n', 'H', 'o', 's', 
+'t', 'R', 'e', 'm', 'o', 'v', 'a', 'l', '\022', '9', '\n', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', '\030', '(', ' ', '\003', '(', '\013', 
+'2', '\037', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', 
+'3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', '\022', '`', '\n', '\025', 'l', 'o', 'a', 'd', 
+'_', 'b', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', ')', ' ', '\001', '(', '\013', '2', ',', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 
+'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\023', 'l', 'o', 'a', 'd', 
+'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'A', '\n', '\n', 'l', 'r', 's', '_', 's', 'e', 
+'r', 'v', 'e', 'r', '\030', '*', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 'l', 'r', 
+'s', 'S', 'e', 'r', 'v', 'e', 'r', '\022', '6', '\n', '\025', 't', 'r', 'a', 'c', 'k', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 
+'b', 'u', 'd', 'g', 'e', 't', 's', '\030', '/', ' ', '\001', '(', '\010', 'B', '\002', '\030', '\001', 'R', '\023', 't', 'r', 'a', 'c', 'k', 'T', 
+'i', 'm', 'e', 'o', 'u', 't', 'B', 'u', 'd', 'g', 'e', 't', 's', '\022', 'S', '\n', '\017', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', 
+'_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '0', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 
+'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'Z', 
+'\n', '\023', 't', 'r', 'a', 'c', 'k', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 's', 't', 'a', 't', 's', '\030', '1', ' ', '\001', 
+'(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', 
+'.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'k', 'C', 'l', 'u', 's', 't', 'e', 'r', 'S', 't', 'a', 't', 's', 'R', '\021', 't', 'r', 
+'a', 'c', 'k', 'C', 'l', 'u', 's', 't', 'e', 'r', 'S', 't', 'a', 't', 's', '\022', '^', '\n', '\021', 'p', 'r', 'e', 'c', 'o', 'n', 
+'n', 'e', 'c', 't', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '2', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 
+'r', '.', 'P', 'r', 'e', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\020', 'p', 'r', 'e', 'c', 'o', 
+'n', 'n', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'X', '\n', ')', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
+'_', 'p', 'o', 'o', 'l', '_', 'p', 'e', 'r', '_', 'd', 'o', 'w', 'n', 's', 't', 'r', 'e', 'a', 'm', '_', 'c', 'o', 'n', 'n', 
+'e', 'c', 't', 'i', 'o', 'n', '\030', '3', ' ', '\001', '(', '\010', 'R', '%', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'P', 
+'o', 'o', 'l', 'P', 'e', 'r', 'D', 'o', 'w', 'n', 's', 't', 'r', 'e', 'a', 'm', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 
+'n', '\032', '\346', '\001', '\n', '\024', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 
+'h', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', 
+'\004', 'n', 'a', 'm', 'e', '\022', '-', '\n', '\005', 'm', 'a', 't', 'c', 'h', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\005', 'm', 'a', 't', 
+'c', 'h', '\022', 'P', '\n', '\020', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', '\030', '\003', ' ', 
+'\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
+'3', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'R', '\017', 't', 'r', 'a', 'n', 's', 'p', 
+'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', ':', '0', '\232', '\305', '\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
+'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 
+'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 'h', '\032', '\230', '\001', '\n', '\021', 'C', 'u', 's', 't', 'o', 'm', 'C', 'l', 'u', 's', 't', 
+'e', 'r', 'T', 'y', 'p', 'e', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 
+'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '7', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 
+'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
+'.', 'A', 'n', 'y', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', 
+'&', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'u', 's', 
+'t', 'o', 'm', 'C', 'l', 'u', 's', 't', 'e', 'r', 'T', 'y', 'p', 'e', '\032', '\246', '\001', '\n', '\020', 'E', 'd', 's', 'C', 'l', 'u', 
+'s', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'A', '\n', '\n', 'e', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', 
+'\001', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
+'.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 'e', 'd', 's', 'C', 'o', 'n', 'f', 
+'i', 'g', '\022', '!', '\n', '\014', 's', 'e', 'r', 'v', 'i', 'c', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', 
+'\013', 's', 'e', 'r', 'v', 'i', 'c', 'e', 'N', 'a', 'm', 'e', ':', ',', '\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'E', 'd', 's', 'C', 'l', 'u', 's', 't', 
+'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\300', '\010', '\n', '\016', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 
+'i', 'g', '\022', 'y', '\n', '\017', 'f', 'a', 'l', 'l', 'b', 'a', 'c', 'k', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\001', ' ', '\001', 
+'(', '\016', '2', 'F', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', 
+'.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 
+'g', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'F', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', 'B', 
+'\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\016', 'f', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', 
+'\022', '>', '\n', '\016', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 's', 'u', 'b', 's', 'e', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', 
+'\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', 
+'\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'S', 'u', 'b', 's', 'e', 't', '\022', 'k', '\n', '\020', 's', 'u', 'b', 's', 'e', 't', '_', 
+'s', 'e', 'l', 'e', 'c', 't', 'o', 'r', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '@', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 
+'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'S', 'e', 
+'l', 'e', 'c', 't', 'o', 'r', 'R', '\017', 's', 'u', 'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', 's', '\022', '2', 
+'\n', '\025', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', '_', 'w', 'e', 'i', 'g', 'h', 't', '_', 'a', 'w', 'a', 'r', 'e', '\030', '\004', 
+' ', '\001', '(', '\010', 'R', '\023', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 'h', 't', 'A', 'w', 'a', 'r', 'e', 
+'\022', '2', '\n', '\025', 's', 'c', 'a', 'l', 'e', '_', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', '_', 'w', 'e', 'i', 'g', 'h', 't', 
+'\030', '\005', ' ', '\001', '(', '\010', 'R', '\023', 's', 'c', 'a', 'l', 'e', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 
+'h', 't', '\022', '$', '\n', '\016', 'p', 'a', 'n', 'i', 'c', '_', 'm', 'o', 'd', 'e', '_', 'a', 'n', 'y', '\030', '\006', ' ', '\001', '(', 
+'\010', 'R', '\014', 'p', 'a', 'n', 'i', 'c', 'M', 'o', 'd', 'e', 'A', 'n', 'y', '\022', '\036', '\n', '\013', 'l', 'i', 's', 't', '_', 'a', 
+'s', '_', 'a', 'n', 'y', '\030', '\007', ' ', '\001', '(', '\010', 'R', '\t', 'l', 'i', 's', 't', 'A', 's', 'A', 'n', 'y', '\032', '\332', '\003', 
+'\n', '\020', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', '\022', '\022', '\n', '\004', 'k', 'e', 'y', 
+'s', '\030', '\001', ' ', '\003', '(', '\t', 'R', '\004', 'k', 'e', 'y', 's', '\022', '3', '\n', '\026', 's', 'i', 'n', 'g', 'l', 'e', '_', 'h', 
+'o', 's', 't', '_', 'p', 'e', 'r', '_', 's', 'u', 'b', 's', 'e', 't', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\023', 's', 'i', 'n', 
+'g', 'l', 'e', 'H', 'o', 's', 't', 'P', 'e', 'r', 'S', 'u', 'b', 's', 'e', 't', '\022', '\222', '\001', '\n', '\017', 'f', 'a', 'l', 'l', 
+'b', 'a', 'c', 'k', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\002', ' ', '\001', '(', '\016', '2', '_', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 
+'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 
+'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', 
+'F', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', 
+'\016', 'f', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '0', '\n', '\024', 'f', 'a', 'l', 'l', 'b', 'a', 
+'c', 'k', '_', 'k', 'e', 'y', 's', '_', 's', 'u', 'b', 's', 'e', 't', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\022', 'f', 'a', 'l', 
+'l', 'b', 'a', 'c', 'k', 'K', 'e', 'y', 's', 'S', 'u', 'b', 's', 'e', 't', '\"', 'y', '\n', '\036', 'L', 'b', 'S', 'u', 'b', 's', 
+'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', 'F', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 
+'\017', '\n', '\013', 'N', 'O', 'T', '_', 'D', 'E', 'F', 'I', 'N', 'E', 'D', '\020', '\000', '\022', '\017', '\n', '\013', 'N', 'O', '_', 'F', 'A', 
+'L', 'L', 'B', 'A', 'C', 'K', '\020', '\001', '\022', '\020', '\n', '\014', 'A', 'N', 'Y', '_', 'E', 'N', 'D', 'P', 'O', 'I', 'N', 'T', '\020', 
+'\002', '\022', '\022', '\n', '\016', 'D', 'E', 'F', 'A', 'U', 'L', 'T', '_', 'S', 'U', 'B', 'S', 'E', 'T', '\020', '\003', '\022', '\017', '\n', '\013', 
+'K', 'E', 'Y', 'S', '_', 'S', 'U', 'B', 'S', 'E', 'T', '\020', '\004', ':', ';', '\232', '\305', '\210', '\036', '6', '\n', '4', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 
+'t', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'S', 'e', 'l', 'e', 'c', 't', 'o', 'r', '\"', 
+'O', '\n', '\026', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'F', 'a', 'l', 'l', 'b', 'a', 'c', 'k', 'P', 'o', 'l', 'i', 'c', 'y', 
+'\022', '\017', '\n', '\013', 'N', 'O', '_', 'F', 'A', 'L', 'L', 'B', 'A', 'C', 'K', '\020', '\000', '\022', '\020', '\n', '\014', 'A', 'N', 'Y', '_', 
+'E', 'N', 'D', 'P', 'O', 'I', 'N', 'T', '\020', '\001', '\022', '\022', '\n', '\016', 'D', 'E', 'F', 'A', 'U', 'L', 'T', '_', 'S', 'U', 'B', 
+'S', 'E', 'T', '\020', '\002', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', 
+'2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'b', 'S', 'u', 'b', 's', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\032', 
+'\347', '\001', '\n', '\024', 'L', 'e', 'a', 's', 't', 'R', 'e', 'q', 'u', 'e', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 
+'H', '\n', '\014', 'c', 'h', 'o', 'i', 'c', 'e', '_', 'c', 'o', 'u', 'n', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 
+'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 
+'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', '(', '\002', 'R', '\013', 'c', 'h', 'o', 'i', 'c', 'e', 'C', 'o', 'u', 'n', 't', '\022', 'S', 
+'\n', '\023', 'a', 'c', 't', 'i', 'v', 'e', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'b', 'i', 'a', 's', '\030', '\002', ' ', '\001', 
+'(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
+'.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'D', 'o', 'u', 'b', 'l', 'e', 'R', '\021', 'a', 'c', 't', 'i', 'v', 'e', 'R', 'e', 'q', 
+'u', 'e', 's', 't', 'B', 'i', 'a', 's', ':', '0', '\232', '\305', '\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'L', 'e', 'a', 's', 't', 'R', 'e', 'q', 'u', 'e', 's', 't', 
+'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\221', '\003', '\n', '\020', 'R', 'i', 'n', 'g', 'H', 'a', 's', 'h', 'L', 'b', 'C', 'o', 
+'n', 'f', 'i', 'g', '\022', 'T', '\n', '\021', 'm', 'i', 'n', 'i', 'm', 'u', 'm', '_', 'r', 'i', 'n', 'g', '_', 's', 'i', 'z', 'e', 
+'\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
+'U', 'I', 'n', 't', '6', '4', 'V', 'a', 'l', 'u', 'e', 'B', '\n', '\372', 'B', '\007', '2', '\005', '\030', '\200', '\200', '\200', '\004', 'R', '\017', 
+'m', 'i', 'n', 'i', 'm', 'u', 'm', 'R', 'i', 'n', 'g', 'S', 'i', 'z', 'e', '\022', 'm', '\n', '\r', 'h', 'a', 's', 'h', '_', 'f', 
+'u', 'n', 'c', 't', 'i', 'o', 'n', '\030', '\003', ' ', '\001', '(', '\016', '2', '>', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'R', 'i', 
+'n', 'g', 'H', 'a', 's', 'h', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'H', 'a', 's', 'h', 'F', 'u', 'n', 'c', 't', 'i', 
+'o', 'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\014', 'h', 'a', 's', 'h', 'F', 'u', 'n', 'c', 't', 'i', 'o', 
+'n', '\022', 'T', '\n', '\021', 'm', 'a', 'x', 'i', 'm', 'u', 'm', '_', 'r', 'i', 'n', 'g', '_', 's', 'i', 'z', 'e', '\030', '\004', ' ', 
+'\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 
+'t', '6', '4', 'V', 'a', 'l', 'u', 'e', 'B', '\n', '\372', 'B', '\007', '2', '\005', '\030', '\200', '\200', '\200', '\004', 'R', '\017', 'm', 'a', 'x', 
+'i', 'm', 'u', 'm', 'R', 'i', 'n', 'g', 'S', 'i', 'z', 'e', '\"', '.', '\n', '\014', 'H', 'a', 's', 'h', 'F', 'u', 'n', 'c', 't', 
+'i', 'o', 'n', '\022', '\013', '\n', '\007', 'X', 'X', '_', 'H', 'A', 'S', 'H', '\020', '\000', '\022', '\021', '\n', '\r', 'M', 'U', 'R', 'M', 'U', 
+'R', '_', 'H', 'A', 'S', 'H', '_', '2', '\020', '\001', ':', ',', '\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', '.', 
+'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'R', 'i', 'n', 'g', 'H', 'a', 's', 'h', 'L', 'b', 
+'C', 'o', 'n', 'f', 'i', 'g', 'J', '\004', '\010', '\002', '\020', '\003', '\032', 'M', '\n', '\016', 'M', 'a', 'g', 'l', 'e', 'v', 'L', 'b', 'C', 
+'o', 'n', 'f', 'i', 'g', '\022', ';', '\n', '\n', 't', 'a', 'b', 'l', 'e', '_', 's', 'i', 'z', 'e', '\030', '\001', ' ', '\001', '(', '\013', 
 '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '6', '4', 
-'V', 'a', 'l', 'u', 'e', 'R', '\016', 'm', 'i', 'n', 'C', 'l', 'u', 's', 't', 'e', 'r', 'S', 'i', 'z', 'e', '\022', '1', '\n', '\025', 
-'f', 'a', 'i', 'l', '_', 't', 'r', 'a', 'f', 'f', 'i', 'c', '_', 'o', 'n', '_', 'p', 'a', 'n', 'i', 'c', '\030', '\003', ' ', '\001', 
-'(', '\010', 'R', '\022', 'f', 'a', 'i', 'l', 'T', 'r', 'a', 'f', 'f', 'i', 'c', 'O', 'n', 'P', 'a', 'n', 'i', 'c', ':', '<', '\232', 
-'\305', '\210', '\036', '7', '\n', '5', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 
-'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'Z', 'o', 'n', 'e', 'A', 'w', 'a', 'r', 
-'e', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '_', '\n', '\030', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 
-'h', 't', 'e', 'd', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', ':', 'C', '\232', '\305', '\210', '\036', '>', '\n', '<', 'e', 'n', 'v', 'o', 
+'V', 'a', 'l', 'u', 'e', 'R', '\t', 't', 'a', 'b', 'l', 'e', 'S', 'i', 'z', 'e', '\032', 'n', '\n', '\023', 'O', 'r', 'i', 'g', 'i', 
+'n', 'a', 'l', 'D', 's', 't', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '&', '\n', '\017', 'u', 's', 'e', '_', 'h', 't', 't', 
+'p', '_', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\010', 'R', '\r', 'u', 's', 'e', 'H', 't', 't', 'p', 'H', 'e', 
+'a', 'd', 'e', 'r', ':', '/', '\232', '\305', '\210', '\036', '*', '\n', '(', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', 
+'.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'O', 'r', 'i', 'g', 'i', 'n', 'a', 'l', 'D', 's', 't', 'L', 'b', 'C', 'o', 'n', 
+'f', 'i', 'g', '\032', '\374', '\n', '\n', '\016', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'N', '\n', 
+'\027', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 'p', 'a', 'n', 'i', 'c', '_', 't', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\030', 
+'\001', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 
+'c', 'e', 'n', 't', 'R', '\025', 'h', 'e', 'a', 'l', 't', 'h', 'y', 'P', 'a', 'n', 'i', 'c', 'T', 'h', 'r', 'e', 's', 'h', 'o', 
+'l', 'd', '\022', 't', '\n', '\024', 'z', 'o', 'n', 'e', '_', 'a', 'w', 'a', 'r', 'e', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 
+'g', '\030', '\002', ' ', '\001', '(', '\013', '2', 'A', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 
+'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 
+'C', 'o', 'n', 'f', 'i', 'g', '.', 'Z', 'o', 'n', 'e', 'A', 'w', 'a', 'r', 'e', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', 
+'\000', 'R', '\021', 'z', 'o', 'n', 'e', 'A', 'w', 'a', 'r', 'e', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '\211', '\001', '\n', '\033', 
+'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', '_', 'w', 'e', 'i', 'g', 'h', 't', 'e', 'd', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 
+'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', 'H', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 
+'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 
+'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'L', 
+'b', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\000', 'R', '\030', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 'h', 't', 
+'e', 'd', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'I', '\n', '\023', 'u', 'p', 'd', 'a', 't', 'e', '_', 'm', 'e', 'r', 'g', 
+'e', '_', 'w', 'i', 'n', 'd', 'o', 'w', '\030', '\004', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
+'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\021', 'u', 'p', 'd', 'a', 't', 'e', 'M', 
+'e', 'r', 'g', 'e', 'W', 'i', 'n', 'd', 'o', 'w', '\022', 'C', '\n', '\037', 'i', 'g', 'n', 'o', 'r', 'e', '_', 'n', 'e', 'w', '_', 
+'h', 'o', 's', 't', 's', '_', 'u', 'n', 't', 'i', 'l', '_', 'f', 'i', 'r', 's', 't', '_', 'h', 'c', '\030', '\005', ' ', '\001', '(', 
+'\010', 'R', '\032', 'i', 'g', 'n', 'o', 'r', 'e', 'N', 'e', 'w', 'H', 'o', 's', 't', 's', 'U', 'n', 't', 'i', 'l', 'F', 'i', 'r', 
+'s', 't', 'H', 'c', '\022', 'M', '\n', '$', 'c', 'l', 'o', 's', 'e', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 's', 
+'_', 'o', 'n', '_', 'h', 'o', 's', 't', '_', 's', 'e', 't', '_', 'c', 'h', 'a', 'n', 'g', 'e', '\030', '\006', ' ', '\001', '(', '\010', 
+'R', '\037', 'c', 'l', 'o', 's', 'e', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 's', 'O', 'n', 'H', 'o', 's', 't', 'S', 
+'e', 't', 'C', 'h', 'a', 'n', 'g', 'e', '\022', '\212', '\001', '\n', '\034', 'c', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', '_', 'h', 
+'a', 's', 'h', 'i', 'n', 'g', '_', 'l', 'b', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\007', ' ', '\001', '(', '\013', '2', 'I', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '.', 'C', 
+'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'C', 'o', 'n', 
+'s', 'i', 's', 't', 'e', 'n', 't', 'H', 'a', 's', 'h', 'i', 'n', 'g', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\031', 'c', 
+'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', 'H', 'a', 's', 'h', 'i', 'n', 'g', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\032', 
+'\215', '\002', '\n', '\021', 'Z', 'o', 'n', 'e', 'A', 'w', 'a', 'r', 'e', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '?', '\n', '\017', 
+'r', 'o', 'u', 't', 'i', 'n', 'g', '_', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\030', '\001', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'r', 'o', 'u', 
+'t', 'i', 'n', 'g', 'E', 'n', 'a', 'b', 'l', 'e', 'd', '\022', 'F', '\n', '\020', 'm', 'i', 'n', '_', 'c', 'l', 'u', 's', 't', 'e', 
+'r', '_', 's', 'i', 'z', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '6', '4', 'V', 'a', 'l', 'u', 'e', 'R', '\016', 'm', 'i', 'n', 'C', 'l', 'u', 
+'s', 't', 'e', 'r', 'S', 'i', 'z', 'e', '\022', '1', '\n', '\025', 'f', 'a', 'i', 'l', '_', 't', 'r', 'a', 'f', 'f', 'i', 'c', '_', 
+'o', 'n', '_', 'p', 'a', 'n', 'i', 'c', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\022', 'f', 'a', 'i', 'l', 'T', 'r', 'a', 'f', 'f', 
+'i', 'c', 'O', 'n', 'P', 'a', 'n', 'i', 'c', ':', '<', '\232', '\305', '\210', '\036', '7', '\n', '5', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
+'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 
+'f', 'i', 'g', '.', 'Z', 'o', 'n', 'e', 'A', 'w', 'a', 'r', 'e', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '_', '\n', '\030', 
+'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', ':', 
+'C', '\232', '\305', '\210', '\036', '>', '\n', '<', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 
+'t', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'o', 'c', 'a', 'l', 'i', 
+'t', 'y', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\361', '\001', '\n', '\031', 'C', 'o', 
+'n', 's', 'i', 's', 't', 'e', 'n', 't', 'H', 'a', 's', 'h', 'i', 'n', 'g', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '7', 
+'\n', '\030', 'u', 's', 'e', '_', 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', '_', 'f', 'o', 'r', '_', 'h', 'a', 's', 'h', 'i', 'n', 
+'g', '\030', '\001', ' ', '\001', '(', '\010', 'R', '\025', 'u', 's', 'e', 'H', 'o', 's', 't', 'n', 'a', 'm', 'e', 'F', 'o', 'r', 'H', 'a', 
+'s', 'h', 'i', 'n', 'g', '\022', 'U', '\n', '\023', 'h', 'a', 's', 'h', '_', 'b', 'a', 'l', 'a', 'n', 'c', 'e', '_', 'f', 'a', 'c', 
+'t', 'o', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', '(', 'd', 'R', '\021', 
+'h', 'a', 's', 'h', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'F', 'a', 'c', 't', 'o', 'r', ':', 'D', '\232', '\305', '\210', '\036', '?', '\n', 
+'=', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 
+'m', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'C', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', 'H', 'a', 's', 
+'h', 'i', 'n', 'g', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 
 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 
-'C', 'o', 'n', 'f', 'i', 'g', '.', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'L', 'b', 
-'C', 'o', 'n', 'f', 'i', 'g', '\032', '\361', '\001', '\n', '\031', 'C', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', 'H', 'a', 's', 'h', 
-'i', 'n', 'g', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '7', '\n', '\030', 'u', 's', 'e', '_', 'h', 'o', 's', 't', 'n', 'a', 
-'m', 'e', '_', 'f', 'o', 'r', '_', 'h', 'a', 's', 'h', 'i', 'n', 'g', '\030', '\001', ' ', '\001', '(', '\010', 'R', '\025', 'u', 's', 'e', 
-'H', 'o', 's', 't', 'n', 'a', 'm', 'e', 'F', 'o', 'r', 'H', 'a', 's', 'h', 'i', 'n', 'g', '\022', 'U', '\n', '\023', 'h', 'a', 's', 
-'h', '_', 'b', 'a', 'l', 'a', 'n', 'c', 'e', '_', 'f', 'a', 'c', 't', 'o', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 
-'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 
-'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', '(', 'd', 'R', '\021', 'h', 'a', 's', 'h', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'F', 
-'a', 'c', 't', 'o', 'r', ':', 'D', '\232', '\305', '\210', '\036', '?', '\n', '=', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', 
-'2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', '.', 
-'C', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', 'H', 'a', 's', 'h', 'i', 'n', 'g', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 
-':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 
-'s', 't', 'e', 'r', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'L', 'b', 'C', 'o', 'n', 'f', 'i', 'g', 'B', '\033', '\n', '\031', 'l', 'o', 
-'c', 'a', 'l', 'i', 't', 'y', '_', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\032', '\322', 
-'\001', '\n', '\013', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', '\022', 'N', '\n', '\r', 'b', 'a', 's', 'e', '_', 'i', 'n', 
-'t', 'e', 'r', 'v', 'a', 'l', '\030', '\001', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
-'t', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\016', '\372', 'B', '\013', '\252', '\001', '\010', '\010', '\001', '*', 
-'\004', '\020', '\300', '\204', '=', 'R', '\014', 'b', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', 'J', '\n', '\014', 'm', 'a', 
-'x', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\014', '\372', 'B', '\t', '\252', '\001', 
-'\006', '*', '\004', '\020', '\300', '\204', '=', 'R', '\013', 'm', 'a', 'x', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', ':', '\'', '\232', '\305', '\210', 
-'\036', '\"', '\n', ' ', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 
-'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', '\032', '\371', '\001', '\n', '\016', 'P', 'r', 'e', 'f', 'e', 't', 'c', 'h', 'P', 
-'o', 'l', 'i', 'c', 'y', '\022', 't', '\n', '\033', 'p', 'e', 'r', '_', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'p', 'r', 'e', 
-'f', 'e', 't', 'c', 'h', '_', 'r', 'a', 't', 'i', 'o', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'o', 'u', 'b', 'l', 'e', 'V', 'a', 'l', 'u', 'e', 'B', '\027', '\372', 
-'B', '\024', '\022', '\022', '\031', '\000', '\000', '\000', '\000', '\000', '\000', '\010', '@', ')', '\000', '\000', '\000', '\000', '\000', '\000', '\360', '?', 'R', '\030', 'p', 
-'e', 'r', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'P', 'r', 'e', 'f', 'e', 't', 'c', 'h', 'R', 'a', 't', 'i', 'o', '\022', 'q', 
-'\n', '\031', 'p', 'r', 'e', 'd', 'i', 'c', 't', 'i', 'v', 'e', '_', 'p', 'r', 'e', 'f', 'e', 't', 'c', 'h', '_', 'r', 'a', 't', 
-'i', 'o', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'C', 'o', 'n', 'f', 'i', 'g', 'B', '\033', '\n', '\031', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', '_', 'c', 'o', 'n', 'f', 'i', 'g', 
+'_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\032', '\322', '\001', '\n', '\013', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 
+'e', '\022', 'N', '\n', '\r', 'b', 'a', 's', 'e', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\001', ' ', '\001', '(', '\013', '2', 
+'\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', 'B', '\016', '\372', 'B', '\013', '\252', '\001', '\010', '\010', '\001', '*', '\004', '\020', '\300', '\204', '=', 'R', '\014', 'b', 'a', 's', 'e', 'I', 'n', 
+'t', 'e', 'r', 'v', 'a', 'l', '\022', 'J', '\n', '\014', 'm', 'a', 'x', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\002', ' ', 
+'\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 
+'a', 't', 'i', 'o', 'n', 'B', '\014', '\372', 'B', '\t', '\252', '\001', '\006', '*', '\004', '\020', '\300', '\204', '=', 'R', '\013', 'm', 'a', 'x', 'I', 
+'n', 't', 'e', 'r', 'v', 'a', 'l', ':', '\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
+'.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'R', 'e', 'f', 'r', 'e', 's', 'h', 'R', 'a', 't', 'e', '\032', '\203', 
+'\002', '\n', '\020', 'P', 'r', 'e', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'x', '\n', '\035', 'p', 'e', 
+'r', '_', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'p', 'r', 'e', 'c', 'o', 'n', 'n', 'e', 'c', 't', '_', 'r', 'a', 't', 
+'i', 'o', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
 'f', '.', 'D', 'o', 'u', 'b', 'l', 'e', 'V', 'a', 'l', 'u', 'e', 'B', '\027', '\372', 'B', '\024', '\022', '\022', '\031', '\000', '\000', '\000', '\000', 
-'\000', '\000', '\010', '@', ')', '\000', '\000', '\000', '\000', '\000', '\000', '\360', '?', 'R', '\027', 'p', 'r', 'e', 'd', 'i', 'c', 't', 'i', 'v', 'e', 
-'P', 'r', 'e', 'f', 'e', 't', 'c', 'h', 'R', 'a', 't', 'i', 'o', '\032', 'f', '\n', '\"', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 
-'e', 'n', 's', 'i', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 
-'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '*', '\n', '\005', 'v', 'a', 
-'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
-'u', 'f', '.', 'A', 'n', 'y', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', '\"', 'W', '\n', '\r', 'D', 'i', 's', 'c', 
-'o', 'v', 'e', 'r', 'y', 'T', 'y', 'p', 'e', '\022', '\n', '\n', '\006', 'S', 'T', 'A', 'T', 'I', 'C', '\020', '\000', '\022', '\016', '\n', '\n', 
-'S', 'T', 'R', 'I', 'C', 'T', '_', 'D', 'N', 'S', '\020', '\001', '\022', '\017', '\n', '\013', 'L', 'O', 'G', 'I', 'C', 'A', 'L', '_', 'D', 
-'N', 'S', '\020', '\002', '\022', '\007', '\n', '\003', 'E', 'D', 'S', '\020', '\003', '\022', '\020', '\n', '\014', 'O', 'R', 'I', 'G', 'I', 'N', 'A', 'L', 
-'_', 'D', 'S', 'T', '\020', '\004', '\"', '\244', '\001', '\n', '\010', 'L', 'b', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '\017', '\n', '\013', 'R', 'O', 
-'U', 'N', 'D', '_', 'R', 'O', 'B', 'I', 'N', '\020', '\000', '\022', '\021', '\n', '\r', 'L', 'E', 'A', 'S', 'T', '_', 'R', 'E', 'Q', 'U', 
-'E', 'S', 'T', '\020', '\001', '\022', '\r', '\n', '\t', 'R', 'I', 'N', 'G', '_', 'H', 'A', 'S', 'H', '\020', '\002', '\022', '\n', '\n', '\006', 'R', 
-'A', 'N', 'D', 'O', 'M', '\020', '\003', '\022', '\n', '\n', '\006', 'M', 'A', 'G', 'L', 'E', 'V', '\020', '\005', '\022', '\024', '\n', '\020', 'C', 'L', 
-'U', 'S', 'T', 'E', 'R', '_', 'P', 'R', 'O', 'V', 'I', 'D', 'E', 'D', '\020', '\006', '\022', ' ', '\n', '\034', 'L', 'O', 'A', 'D', '_', 
-'B', 'A', 'L', 'A', 'N', 'C', 'I', 'N', 'G', '_', 'P', 'O', 'L', 'I', 'C', 'Y', '_', 'C', 'O', 'N', 'F', 'I', 'G', '\020', '\007', 
-'\"', '\004', '\010', '\004', '\020', '\004', '*', '\017', 'O', 'R', 'I', 'G', 'I', 'N', 'A', 'L', '_', 'D', 'S', 'T', '_', 'L', 'B', '\"', '5', 
-'\n', '\017', 'D', 'n', 's', 'L', 'o', 'o', 'k', 'u', 'p', 'F', 'a', 'm', 'i', 'l', 'y', '\022', '\010', '\n', '\004', 'A', 'U', 'T', 'O', 
-'\020', '\000', '\022', '\013', '\n', '\007', 'V', '4', '_', 'O', 'N', 'L', 'Y', '\020', '\001', '\022', '\013', '\n', '\007', 'V', '6', '_', 'O', 'N', 'L', 
-'Y', '\020', '\002', '\"', 'T', '\n', '\030', 'C', 'l', 'u', 's', 't', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'S', 'e', 'l', 
-'e', 'c', 't', 'i', 'o', 'n', '\022', '\033', '\n', '\027', 'U', 'S', 'E', '_', 'C', 'O', 'N', 'F', 'I', 'G', 'U', 'R', 'E', 'D', '_', 
-'P', 'R', 'O', 'T', 'O', 'C', 'O', 'L', '\020', '\000', '\022', '\033', '\n', '\027', 'U', 'S', 'E', '_', 'D', 'O', 'W', 'N', 'S', 'T', 'R', 
-'E', 'A', 'M', '_', 'P', 'R', 'O', 'T', 'O', 'C', 'O', 'L', '\020', '\001', ':', '\033', '\232', '\305', '\210', '\036', '\026', '\n', '\024', 'e', 'n', 
-'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'B', '\030', '\n', '\026', 'c', 'l', 'u', 
-'s', 't', 'e', 'r', '_', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '_', 't', 'y', 'p', 'e', 'B', '\013', '\n', '\t', 'l', 'b', 
-'_', 'c', 'o', 'n', 'f', 'i', 'g', 'J', '\004', '\010', '\014', '\020', '\r', 'J', '\004', '\010', '\017', '\020', '\020', 'J', '\004', '\010', '\007', '\020', '\010', 
-'J', '\004', '\010', '\013', '\020', '\014', 'J', '\004', '\010', '#', '\020', '$', 'R', '\005', 'h', 'o', 's', 't', 's', 'R', '\013', 't', 'l', 's', '_', 
-'c', 'o', 'n', 't', 'e', 'x', 't', 'R', '\032', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'p', 'r', 'o', 't', 'o', 'c', 
-'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', '\245', '\002', '\n', '\023', 'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 
-'i', 'n', 'g', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'O', '\n', '\010', 'p', 'o', 'l', 'i', 'c', 'i', 'e', 's', '\030', '\001', ' ', '\003', 
-'(', '\013', '2', '3', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', 
-'.', 'v', '3', '.', 'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'P', 
-'o', 'l', 'i', 'c', 'y', 'R', '\010', 'p', 'o', 'l', 'i', 'c', 'i', 'e', 's', '\032', '\223', '\001', '\n', '\006', 'P', 'o', 'l', 'i', 'c', 
-'y', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '7', '\n', '\014', 
-'t', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 
-'f', 'i', 'g', ':', '.', '\232', '\305', '\210', '\036', ')', '\n', '\'', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
-'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'P', 'o', 'l', 'i', 'c', 
-'y', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', ':', '\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 'e', 
-'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 
-'P', 'o', 'l', 'i', 'c', 'y', '\"', '\202', '\001', '\n', '\022', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'B', 'i', 'n', 'd', 'C', 'o', 
-'n', 'f', 'i', 'g', '\022', 'D', '\n', '\016', 's', 'o', 'u', 'r', 'c', 'e', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', '\030', '\001', ' ', 
-'\001', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
-'3', '.', 'A', 'd', 'd', 'r', 'e', 's', 's', 'R', '\r', 's', 'o', 'u', 'r', 'c', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', ':', 
-'&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'U', 'p', 's', 't', 
-'r', 'e', 'a', 'm', 'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\"', '\223', '\001', '\n', '\031', 'U', 'p', 's', 't', 'r', 'e', 
-'a', 'm', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'G', '\n', '\r', 't', 'c', 
-'p', '_', 'k', 'e', 'e', 'p', 'a', 'l', 'i', 'v', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'c', 'p', 'K', 'e', 'e', 'p', 'a', 'l', 
-'i', 'v', 'e', 'R', '\014', 't', 'c', 'p', 'K', 'e', 'e', 'p', 'a', 'l', 'i', 'v', 'e', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', 
-'&', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'C', 'o', 'n', 
-'n', 'e', 'c', 't', 'i', 'o', 'n', 'O', 'p', 't', 'i', 'o', 'n', 's', '\"', 'r', '\n', '\021', 'T', 'r', 'a', 'c', 'k', 'C', 'l', 
-'u', 's', 't', 'e', 'r', 'S', 't', 'a', 't', 's', '\022', '\'', '\n', '\017', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'b', 'u', 'd', 
-'g', 'e', 't', 's', '\030', '\001', ' ', '\001', '(', '\010', 'R', '\016', 't', 'i', 'm', 'e', 'o', 'u', 't', 'B', 'u', 'd', 'g', 'e', 't', 
-'s', '\022', '4', '\n', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 's', 'i', 'z', 
-'e', 's', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\024', 'r', 'e', 'q', 'u', 'e', 's', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 
-'S', 'i', 'z', 'e', 's', 'B', '?', '\n', '%', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', 'B', '\014', 'C', 'l', 
-'u', 's', 't', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 
-'t', 'o', '3', 
+'\000', '\000', '\010', '@', ')', '\000', '\000', '\000', '\000', '\000', '\000', '\360', '?', 'R', '\032', 'p', 'e', 'r', 'U', 'p', 's', 't', 'r', 'e', 'a', 
+'m', 'P', 'r', 'e', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'R', 'a', 't', 'i', 'o', '\022', 'u', '\n', '\033', 'p', 'r', 'e', 'd', 'i', 
+'c', 't', 'i', 'v', 'e', '_', 'p', 'r', 'e', 'c', 'o', 'n', 'n', 'e', 'c', 't', '_', 'r', 'a', 't', 'i', 'o', '\030', '\002', ' ', 
+'\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'o', 'u', 
+'b', 'l', 'e', 'V', 'a', 'l', 'u', 'e', 'B', '\027', '\372', 'B', '\024', '\022', '\022', '\031', '\000', '\000', '\000', '\000', '\000', '\000', '\010', '@', ')', 
+'\000', '\000', '\000', '\000', '\000', '\000', '\360', '?', 'R', '\031', 'p', 'r', 'e', 'd', 'i', 'c', 't', 'i', 'v', 'e', 'P', 'r', 'e', 'c', 'o', 
+'n', 'n', 'e', 'c', 't', 'R', 'a', 't', 'i', 'o', '\032', 'f', '\n', '\"', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 
+'i', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', '\022', '\020', 
+'\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '*', '\n', '\005', 'v', 'a', 'l', 'u', 'e', 
+'\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
+'A', 'n', 'y', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', '\"', 'W', '\n', '\r', 'D', 'i', 's', 'c', 'o', 'v', 'e', 
+'r', 'y', 'T', 'y', 'p', 'e', '\022', '\n', '\n', '\006', 'S', 'T', 'A', 'T', 'I', 'C', '\020', '\000', '\022', '\016', '\n', '\n', 'S', 'T', 'R', 
+'I', 'C', 'T', '_', 'D', 'N', 'S', '\020', '\001', '\022', '\017', '\n', '\013', 'L', 'O', 'G', 'I', 'C', 'A', 'L', '_', 'D', 'N', 'S', '\020', 
+'\002', '\022', '\007', '\n', '\003', 'E', 'D', 'S', '\020', '\003', '\022', '\020', '\n', '\014', 'O', 'R', 'I', 'G', 'I', 'N', 'A', 'L', '_', 'D', 'S', 
+'T', '\020', '\004', '\"', '\244', '\001', '\n', '\010', 'L', 'b', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '\017', '\n', '\013', 'R', 'O', 'U', 'N', 'D', 
+'_', 'R', 'O', 'B', 'I', 'N', '\020', '\000', '\022', '\021', '\n', '\r', 'L', 'E', 'A', 'S', 'T', '_', 'R', 'E', 'Q', 'U', 'E', 'S', 'T', 
+'\020', '\001', '\022', '\r', '\n', '\t', 'R', 'I', 'N', 'G', '_', 'H', 'A', 'S', 'H', '\020', '\002', '\022', '\n', '\n', '\006', 'R', 'A', 'N', 'D', 
+'O', 'M', '\020', '\003', '\022', '\n', '\n', '\006', 'M', 'A', 'G', 'L', 'E', 'V', '\020', '\005', '\022', '\024', '\n', '\020', 'C', 'L', 'U', 'S', 'T', 
+'E', 'R', '_', 'P', 'R', 'O', 'V', 'I', 'D', 'E', 'D', '\020', '\006', '\022', ' ', '\n', '\034', 'L', 'O', 'A', 'D', '_', 'B', 'A', 'L', 
+'A', 'N', 'C', 'I', 'N', 'G', '_', 'P', 'O', 'L', 'I', 'C', 'Y', '_', 'C', 'O', 'N', 'F', 'I', 'G', '\020', '\007', '\"', '\004', '\010', 
+'\004', '\020', '\004', '*', '\017', 'O', 'R', 'I', 'G', 'I', 'N', 'A', 'L', '_', 'D', 'S', 'T', '_', 'L', 'B', '\"', '5', '\n', '\017', 'D', 
+'n', 's', 'L', 'o', 'o', 'k', 'u', 'p', 'F', 'a', 'm', 'i', 'l', 'y', '\022', '\010', '\n', '\004', 'A', 'U', 'T', 'O', '\020', '\000', '\022', 
+'\013', '\n', '\007', 'V', '4', '_', 'O', 'N', 'L', 'Y', '\020', '\001', '\022', '\013', '\n', '\007', 'V', '6', '_', 'O', 'N', 'L', 'Y', '\020', '\002', 
+'\"', 'T', '\n', '\030', 'C', 'l', 'u', 's', 't', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'S', 'e', 'l', 'e', 'c', 't', 
+'i', 'o', 'n', '\022', '\033', '\n', '\027', 'U', 'S', 'E', '_', 'C', 'O', 'N', 'F', 'I', 'G', 'U', 'R', 'E', 'D', '_', 'P', 'R', 'O', 
+'T', 'O', 'C', 'O', 'L', '\020', '\000', '\022', '\033', '\n', '\027', 'U', 'S', 'E', '_', 'D', 'O', 'W', 'N', 'S', 'T', 'R', 'E', 'A', 'M', 
+'_', 'P', 'R', 'O', 'T', 'O', 'C', 'O', 'L', '\020', '\001', ':', '\033', '\232', '\305', '\210', '\036', '\026', '\n', '\024', 'e', 'n', 'v', 'o', 'y', 
+'.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'B', '\030', '\n', '\026', 'c', 'l', 'u', 's', 't', 'e', 
+'r', '_', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '_', 't', 'y', 'p', 'e', 'B', '\013', '\n', '\t', 'l', 'b', '_', 'c', 'o', 
+'n', 'f', 'i', 'g', 'J', '\004', '\010', '\014', '\020', '\r', 'J', '\004', '\010', '\017', '\020', '\020', 'J', '\004', '\010', '\007', '\020', '\010', 'J', '\004', '\010', 
+'\013', '\020', '\014', 'J', '\004', '\010', '#', '\020', '$', 'R', '\005', 'h', 'o', 's', 't', 's', 'R', '\013', 't', 'l', 's', '_', 'c', 'o', 'n', 
+'t', 'e', 'x', 't', 'R', '\032', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 
+'o', 'p', 't', 'i', 'o', 'n', 's', '\"', '\245', '\002', '\n', '\023', 'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 
+'P', 'o', 'l', 'i', 'c', 'y', '\022', 'O', '\n', '\010', 'p', 'o', 'l', 'i', 'c', 'i', 'e', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', 
+'3', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', 
+'.', 'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'P', 'o', 'l', 'i', 
+'c', 'y', 'R', '\010', 'p', 'o', 'l', 'i', 'c', 'i', 'e', 's', '\032', '\223', '\001', '\n', '\006', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '\022', 
+'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '7', '\n', '\014', 't', 'y', 'p', 
+'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 
+':', '.', '\232', '\305', '\210', '\036', ')', '\n', '\'', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'o', 'a', 
+'d', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'P', 'o', 'l', 'i', 'c', 'y', 'J', '\004', 
+'\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', ':', '\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'o', 'a', 'd', 'B', 'a', 'l', 'a', 'n', 'c', 'i', 'n', 'g', 'P', 'o', 'l', 
+'i', 'c', 'y', '\"', '\202', '\001', '\n', '\022', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 
+'g', '\022', 'D', '\n', '\016', 's', 'o', 'u', 'r', 'c', 'e', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', '\030', '\001', ' ', '\001', '(', '\013', 
+'2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 
+'d', 'd', 'r', 'e', 's', 's', 'R', '\r', 's', 'o', 'u', 'r', 'c', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', ':', '&', '\232', '\305', 
+'\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'U', 'p', 's', 't', 'r', 'e', 'a', 
+'m', 'B', 'i', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\"', '\223', '\001', '\n', '\031', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'C', 
+'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'G', '\n', '\r', 't', 'c', 'p', '_', 'k', 
+'e', 'e', 'p', 'a', 'l', 'i', 'v', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'c', 'p', 'K', 'e', 'e', 'p', 'a', 'l', 'i', 'v', 'e', 
+'R', '\014', 't', 'c', 'p', 'K', 'e', 'e', 'p', 'a', 'l', 'i', 'v', 'e', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 
+'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'C', 'o', 'n', 'n', 'e', 'c', 
+'t', 'i', 'o', 'n', 'O', 'p', 't', 'i', 'o', 'n', 's', '\"', 'r', '\n', '\021', 'T', 'r', 'a', 'c', 'k', 'C', 'l', 'u', 's', 't', 
+'e', 'r', 'S', 't', 'a', 't', 's', '\022', '\'', '\n', '\017', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'b', 'u', 'd', 'g', 'e', 't', 
+'s', '\030', '\001', ' ', '\001', '(', '\010', 'R', '\016', 't', 'i', 'm', 'e', 'o', 'u', 't', 'B', 'u', 'd', 'g', 'e', 't', 's', '\022', '4', 
+'\n', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 's', 'i', 'z', 'e', 's', '\030', 
+'\002', ' ', '\001', '(', '\010', 'R', '\024', 'r', 'e', 'q', 'u', 'e', 's', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'S', 'i', 'z', 
+'e', 's', 'B', '?', '\n', '%', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', 'B', '\014', 'C', 'l', 'u', 's', 't', 
+'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[24] = {
+static upb_def_init *deps[21] = {
   &envoy_config_cluster_v3_circuit_breaker_proto_upbdefinit,
   &envoy_config_cluster_v3_filter_proto_upbdefinit,
   &envoy_config_cluster_v3_outlier_detection_proto_upbdefinit,
@@ -539,10 +527,7 @@
   &google_protobuf_duration_proto_upbdefinit,
   &google_protobuf_struct_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
-  &udpa_core_v1_collection_entry_proto_upbdefinit,
-  &udpa_core_v1_resource_locator_proto_upbdefinit,
-  &envoy_annotations_deprecation_proto_upbdefinit,
-  &udpa_annotations_migrate_proto_upbdefinit,
+  &xds_core_v3_collection_entry_proto_upbdefinit,
   &udpa_annotations_security_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
@@ -554,5 +539,5 @@
   deps,
   layouts,
   "envoy/config/cluster/v3/cluster.proto",
-  UPB_STRVIEW_INIT(descriptor, 10953)
+  UPB_STRVIEW_INIT(descriptor, 10750)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h
index 5664a0a..1bbc899 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.h
@@ -101,9 +101,9 @@
   return upb_symtab_lookupmsg(s, "envoy.config.cluster.v3.Cluster.RefreshRate");
 }
 
-UPB_INLINE const upb_msgdef *envoy_config_cluster_v3_Cluster_PrefetchPolicy_getmsgdef(upb_symtab *s) {
+UPB_INLINE const upb_msgdef *envoy_config_cluster_v3_Cluster_PreconnectPolicy_getmsgdef(upb_symtab *s) {
   _upb_symtab_loaddefinit(s, &envoy_config_cluster_v3_cluster_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "envoy.config.cluster.v3.Cluster.PrefetchPolicy");
+  return upb_symtab_lookupmsg(s, "envoy.config.cluster.v3.Cluster.PreconnectPolicy");
 }
 
 UPB_INLINE const upb_msgdef *envoy_config_cluster_v3_Cluster_TypedExtensionProtocolOptionsEntry_getmsgdef(upb_symtab *s) {
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/outlier_detection.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/outlier_detection.upbdefs.c
index 3ebd234..8ab795d 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/outlier_detection.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/cluster/v3/outlier_detection.upbdefs.c
@@ -20,7 +20,7 @@
   &envoy_config_cluster_v3_OutlierDetection_msginit,
 };
 
-static const char descriptor[2342] = {'\n', '/', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'l', 'u', 's', 't', 'e', 'r', '/', 'v', '3', 
+static const char descriptor[2423] = {'\n', '/', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'l', 'u', 's', 't', 'e', 'r', '/', 'v', '3', 
 '/', 'o', 'u', 't', 'l', 'i', 'e', 'r', '_', 'd', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\022', 
 '\027', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', '3', '\032', 
 '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', 
@@ -29,7 +29,7 @@
 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', 
 '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 
 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 
-'r', 'o', 't', 'o', '\"', '\354', '\017', '\n', '\020', 'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 
+'r', 'o', 't', 'o', '\"', '\275', '\020', '\n', '\020', 'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 
 '\022', 'E', '\n', '\017', 'c', 'o', 'n', 's', 'e', 'c', 'u', 't', 'i', 'v', 'e', '_', '5', 'x', 'x', '\030', '\001', ' ', '\001', '(', '\013', 
 '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 
 'V', 'a', 'l', 'u', 'e', 'R', '\016', 'c', 'o', 'n', 's', 'e', 'c', 'u', 't', 'i', 'v', 'e', '5', 'x', 'x', '\022', '?', '\n', '\010', 
@@ -108,12 +108,15 @@
 'e', 'n', 't', 'a', 'g', 'e', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'v', 'o', 'l', 'u', 'm', 'e', '\030', '\024', ' ', '\001', 
 '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', 
 '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\036', 'f', 'a', 'i', 'l', 'u', 'r', 'e', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'a', 'g', 
-'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'V', 'o', 'l', 'u', 'm', 'e', ':', ',', '\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 
-'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'O', 'u', 't', 'l', 'i', 'e', 
-'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'H', '\n', '%', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 
-'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'v', 
-'3', 'B', '\025', 'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'P', 
-'\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'V', 'o', 'l', 'u', 'm', 'e', '\022', 'O', '\n', '\021', 'm', 'a', 'x', '_', 'e', 'j', 'e', 
+'c', 't', 'i', 'o', 'n', '_', 't', 'i', 'm', 'e', '\030', '\025', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
+'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', 
+'\002', '*', '\000', 'R', '\017', 'm', 'a', 'x', 'E', 'j', 'e', 'c', 't', 'i', 'o', 'n', 'T', 'i', 'm', 'e', ':', ',', '\232', '\305', '\210', 
+'\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 
+'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'H', '\n', '%', 'i', 'o', '.', 'e', 'n', 
+'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 
+'s', 't', 'e', 'r', '.', 'v', '3', 'B', '\025', 'O', 'u', 't', 'l', 'i', 'e', 'r', 'D', 'e', 't', 'e', 'c', 't', 'i', 'o', 'n', 
+'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
 static upb_def_init *deps[6] = {
@@ -129,5 +132,5 @@
   deps,
   layouts,
   "envoy/config/cluster/v3/outlier_detection.proto",
-  UPB_STRVIEW_INIT(descriptor, 2342)
+  UPB_STRVIEW_INIT(descriptor, 2423)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/base.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/base.upbdefs.c
index 51f8994..a91ff3d 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/base.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/base.upbdefs.c
@@ -15,7 +15,6 @@
 extern upb_def_init envoy_type_v3_percent_proto_upbdefinit;
 extern upb_def_init envoy_type_v3_semantic_version_proto_upbdefinit;
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
-extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
@@ -29,11 +28,13 @@
 extern const upb_msglayout envoy_config_core_v3_Metadata_msginit;
 extern const upb_msglayout envoy_config_core_v3_Metadata_FilterMetadataEntry_msginit;
 extern const upb_msglayout envoy_config_core_v3_RuntimeUInt32_msginit;
+extern const upb_msglayout envoy_config_core_v3_RuntimePercent_msginit;
 extern const upb_msglayout envoy_config_core_v3_RuntimeDouble_msginit;
 extern const upb_msglayout envoy_config_core_v3_RuntimeFeatureFlag_msginit;
 extern const upb_msglayout envoy_config_core_v3_HeaderValue_msginit;
 extern const upb_msglayout envoy_config_core_v3_HeaderValueOption_msginit;
 extern const upb_msglayout envoy_config_core_v3_HeaderMap_msginit;
+extern const upb_msglayout envoy_config_core_v3_WatchedDirectory_msginit;
 extern const upb_msglayout envoy_config_core_v3_DataSource_msginit;
 extern const upb_msglayout envoy_config_core_v3_RetryPolicy_msginit;
 extern const upb_msglayout envoy_config_core_v3_RemoteDataSource_msginit;
@@ -42,7 +43,7 @@
 extern const upb_msglayout envoy_config_core_v3_RuntimeFractionalPercent_msginit;
 extern const upb_msglayout envoy_config_core_v3_ControlPlane_msginit;
 
-static const upb_msglayout *layouts[19] = {
+static const upb_msglayout *layouts[21] = {
   &envoy_config_core_v3_Locality_msginit,
   &envoy_config_core_v3_BuildVersion_msginit,
   &envoy_config_core_v3_Extension_msginit,
@@ -50,11 +51,13 @@
   &envoy_config_core_v3_Metadata_msginit,
   &envoy_config_core_v3_Metadata_FilterMetadataEntry_msginit,
   &envoy_config_core_v3_RuntimeUInt32_msginit,
+  &envoy_config_core_v3_RuntimePercent_msginit,
   &envoy_config_core_v3_RuntimeDouble_msginit,
   &envoy_config_core_v3_RuntimeFeatureFlag_msginit,
   &envoy_config_core_v3_HeaderValue_msginit,
   &envoy_config_core_v3_HeaderValueOption_msginit,
   &envoy_config_core_v3_HeaderMap_msginit,
+  &envoy_config_core_v3_WatchedDirectory_msginit,
   &envoy_config_core_v3_DataSource_msginit,
   &envoy_config_core_v3_RetryPolicy_msginit,
   &envoy_config_core_v3_RemoteDataSource_msginit,
@@ -64,7 +67,7 @@
   &envoy_config_core_v3_ControlPlane_msginit,
 };
 
-static const char descriptor[4353] = {'\n', '\037', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 
+static const char descriptor[4473] = {'\n', '\037', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 
 's', 'e', '.', 'p', 'r', 'o', 't', 'o', '\022', '\024', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
 'r', 'e', '.', 'v', '3', '\032', '\"', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 
 'v', '3', '/', 'a', 'd', 'd', 'r', 'e', 's', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\"', 'e', 'n', 'v', 'o', 'y', '/', 'c', 
@@ -74,181 +77,184 @@
 'e', '/', 'v', '3', '/', 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '$', 'e', 'n', 'v', 'o', 'y', 
 '/', 't', 'y', 'p', 'e', '/', 'v', '3', '/', 's', 'e', 'm', 'a', 'n', 't', 'i', 'c', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', 
 '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 
-'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
-'/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 
-'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 
-'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 
-'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 
-'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 
-'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', 
-'\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', 
-'\"', 't', '\n', '\010', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', '\022', '\026', '\n', '\006', 'r', 'e', 'g', 'i', 'o', 'n', '\030', '\001', ' ', 
-'\001', '(', '\t', 'R', '\006', 'r', 'e', 'g', 'i', 'o', 'n', '\022', '\022', '\n', '\004', 'z', 'o', 'n', 'e', '\030', '\002', ' ', '\001', '(', '\t', 
-'R', '\004', 'z', 'o', 'n', 'e', '\022', '\031', '\n', '\010', 's', 'u', 'b', '_', 'z', 'o', 'n', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', 
-'\007', 's', 'u', 'b', 'Z', 'o', 'n', 'e', ':', '!', '\232', '\305', '\210', '\036', '\034', '\n', '\032', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', '\"', '\244', '\001', '\n', '\014', 'B', 'u', 
-'i', 'l', 'd', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', '8', '\n', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\001', ' ', '\001', 
-'(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'S', 'e', 'm', 'a', 'n', 't', 
-'i', 'c', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', '3', '\n', '\010', 'm', 'e', 't', 
-'a', 'd', 'a', 't', 'a', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
-'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', ':', '%', '\232', '\305', 
-'\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'B', 'u', 
-'i', 'l', 'd', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\"', '\342', '\001', '\n', '\t', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', 
-'\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\032', '\n', '\010', 'c', 'a', 
-'t', 'e', 'g', 'o', 'r', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\010', 'c', 'a', 't', 'e', 'g', 'o', 'r', 'y', '\022', '\'', '\n', 
-'\017', 't', 'y', 'p', 'e', '_', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\016', 't', 
-'y', 'p', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '\022', '<', '\n', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', 
-'\004', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
-'.', 'v', '3', '.', 'B', 'u', 'i', 'l', 'd', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', 
-'\022', '\032', '\n', '\010', 'd', 'i', 's', 'a', 'b', 'l', 'e', 'd', '\030', '\005', ' ', '\001', '(', '\010', 'R', '\010', 'd', 'i', 's', 'a', 'b', 
-'l', 'e', 'd', ':', '\"', '\232', '\305', '\210', '\036', '\035', '\n', '\033', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
-'c', 'o', 'r', 'e', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\"', '\345', '\004', '\n', '\004', 'N', 'o', 'd', 'e', '\022', '\016', 
-'\n', '\002', 'i', 'd', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\002', 'i', 'd', '\022', '\030', '\n', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', 
-'\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\022', '3', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 
-'t', 'a', '\030', '\003', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
-'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', ':', '\n', '\010', 'l', 'o', 'c', 
-'a', 'l', 'i', 't', 'y', '\030', '\004', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'R', '\010', 'l', 'o', 'c', 'a', 'l', 
-'i', 't', 'y', '\022', '&', '\n', '\017', 'u', 's', 'e', 'r', '_', 'a', 'g', 'e', 'n', 't', '_', 'n', 'a', 'm', 'e', '\030', '\006', ' ', 
-'\001', '(', '\t', 'R', '\r', 'u', 's', 'e', 'r', 'A', 'g', 'e', 'n', 't', 'N', 'a', 'm', 'e', '\022', '.', '\n', '\022', 'u', 's', 'e', 
-'r', '_', 'a', 'g', 'e', 'n', 't', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\007', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\020', 
-'u', 's', 'e', 'r', 'A', 'g', 'e', 'n', 't', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', ']', '\n', '\030', 'u', 's', 'e', 'r', '_', 
-'a', 'g', 'e', 'n', 't', '_', 'b', 'u', 'i', 'l', 'd', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\010', ' ', '\001', '(', '\013', 
-'2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'B', 
-'u', 'i', 'l', 'd', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'H', '\000', 'R', '\025', 'u', 's', 'e', 'r', 'A', 'g', 'e', 'n', 't', 'B', 
-'u', 'i', 'l', 'd', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', '?', '\n', '\n', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 
-'\030', '\t', ' ', '\003', '(', '\013', '2', '\037', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 
-'e', '.', 'v', '3', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', '\n', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 
-'s', '\022', '\'', '\n', '\017', 'c', 'l', 'i', 'e', 'n', 't', '_', 'f', 'e', 'a', 't', 'u', 'r', 'e', 's', '\030', '\n', ' ', '\003', '(', 
-'\t', 'R', '\016', 'c', 'l', 'i', 'e', 'n', 't', 'F', 'e', 'a', 't', 'u', 'r', 'e', 's', '\022', 'R', '\n', '\023', 'l', 'i', 's', 't', 
-'e', 'n', 'i', 'n', 'g', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', 'e', 's', '\030', '\013', ' ', '\003', '(', '\013', '2', '\035', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'd', 'd', 'r', 'e', 
-'s', 's', 'B', '\002', '\030', '\001', 'R', '\022', 'l', 'i', 's', 't', 'e', 'n', 'i', 'n', 'g', 'A', 'd', 'd', 'r', 'e', 's', 's', 'e', 
-'s', ':', '\035', '\232', '\305', '\210', '\036', '\030', '\n', '\026', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 
-'r', 'e', '.', 'N', 'o', 'd', 'e', 'B', '\031', '\n', '\027', 'u', 's', 'e', 'r', '_', 'a', 'g', 'e', 'n', 't', '_', 'v', 'e', 'r', 
-'s', 'i', 'o', 'n', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\005', '\020', '\006', 'R', '\r', 'b', 'u', 'i', 'l', 'd', '_', 'v', 'e', 
-'r', 's', 'i', 'o', 'n', '\"', '\346', '\001', '\n', '\010', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', '[', '\n', '\017', 'f', 'i', 'l', 
-'t', 'e', 'r', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\001', ' ', '\003', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 'o', 
-'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 
-'.', 'F', 'i', 'l', 't', 'e', 'r', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'E', 'n', 't', 'r', 'y', 'R', '\016', 'f', 'i', 'l', 
-'t', 'e', 'r', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\032', 'Z', '\n', '\023', 'F', 'i', 'l', 't', 'e', 'r', 'M', 'e', 't', 'a', 
-'d', 'a', 't', 'a', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 
-'e', 'y', '\022', '-', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', 
-'\002', '8', '\001', ':', '!', '\232', '\305', '\210', '\036', '\034', '\n', '\032', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
-'c', 'o', 'r', 'e', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\"', '\206', '\001', '\n', '\r', 'R', 'u', 'n', 't', 'i', 'm', 'e', 
-'U', 'I', 'n', 't', '3', '2', '\022', '#', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\002', 
-' ', '\001', '(', '\r', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '(', '\n', '\013', 'r', 'u', 'n', 
-'t', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\030', '\003', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\n', 
-'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 
-'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'U', 'I', 'n', 't', '3', '2', 
-'\"', '\206', '\001', '\n', '\r', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'D', 'o', 'u', 'b', 'l', 'e', '\022', '#', '\n', '\r', 'd', 'e', 'f', 
-'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\001', ' ', '\001', '(', '\001', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 
-'V', 'a', 'l', 'u', 'e', '\022', '(', '\n', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', 
-'\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', ':', '&', '\232', 
-'\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'R', 
-'u', 'n', 't', 'i', 'm', 'e', 'D', 'o', 'u', 'b', 'l', 'e', '\"', '\266', '\001', '\n', '\022', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 
-'e', 'a', 't', 'u', 'r', 'e', 'F', 'l', 'a', 'g', '\022', 'I', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 
-'u', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
-'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\014', 'd', 'e', 
-'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '(', '\n', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', 
-'\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 
-'e', 'y', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 
-'o', 'r', 'e', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'e', 'a', 't', 'u', 'r', 'e', 'F', 'l', 'a', 'g', '\"', '\177', '\n', 
-'\013', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', '\022', '#', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 
-'B', '\021', '\372', 'B', '\016', 'r', '\014', '\020', '\001', '(', '\200', '\200', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\003', 'k', 'e', 'y', '\022', 
-'%', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\017', '\372', 'B', '\014', 'r', '\n', '(', '\200', '\200', '\001', 
-'\300', '\001', '\002', '\310', '\001', '\000', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 
-'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 
-'e', '\"', '\270', '\001', '\n', '\021', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', '\022', 'C', 
-'\n', '\006', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'B', 
-'\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\006', 'h', 'e', 'a', 'd', 'e', 'r', '\022', '2', '\n', '\006', 'a', 'p', 'p', 'e', 
-'n', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
-'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\006', 'a', 'p', 'p', 'e', 'n', 'd', ':', '*', '\232', '\305', '\210', '\036', 
-'%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'd', 
-'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', '\"', 'l', '\n', '\t', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 
-'p', '\022', ';', '\n', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 
-'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 
-'l', 'u', 'e', 'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', ':', '\"', '\232', '\305', '\210', '\036', '\035', '\n', '\033', 'e', 'n', 'v', 'o', 
-'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 'p', '\"', '\310', 
-'\001', '\n', '\n', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '%', '\n', '\010', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', 
-'\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\010', 'f', 'i', 'l', 'e', 'n', 'a', 
-'m', 'e', '\022', ',', '\n', '\014', 'i', 'n', 'l', 'i', 'n', 'e', '_', 'b', 'y', 't', 'e', 's', '\030', '\002', ' ', '\001', '(', '\014', 'B', 
-'\007', '\372', 'B', '\004', 'z', '\002', '\020', '\001', 'H', '\000', 'R', '\013', 'i', 'n', 'l', 'i', 'n', 'e', 'B', 'y', 't', 'e', 's', '\022', '.', 
-'\n', '\r', 'i', 'n', 'l', 'i', 'n', 'e', '_', 's', 't', 'r', 'i', 'n', 'g', '\030', '\003', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', 
-'\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\014', 'i', 'n', 'l', 'i', 'n', 'e', 'S', 't', 'r', 'i', 'n', 'g', ':', '#', '\232', '\305', 
-'\210', '\036', '\036', '\n', '\034', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'D', 'a', 
-'t', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\020', '\n', '\t', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', 
-'\001', '\"', '\324', '\001', '\n', '\013', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'K', '\n', '\016', 'r', 'e', 't', 'r', 
-'y', '_', 'b', 'a', 'c', 'k', '_', 'o', 'f', 'f', '\030', '\001', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'B', 'a', 'c', 'k', 'o', 'f', 'f', 'S', 't', 'r', 
-'a', 't', 'e', 'g', 'y', 'R', '\014', 'r', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\022', 'R', '\n', '\013', 'n', 'u', 
-'m', '_', 'r', 'e', 't', 'r', 'i', 'e', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
-'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\023', '\362', '\230', '\376', 
-'\217', '\005', '\r', '\n', '\013', 'm', 'a', 'x', '_', 'r', 'e', 't', 'r', 'i', 'e', 's', 'R', '\n', 'n', 'u', 'm', 'R', 'e', 't', 'r', 
-'i', 'e', 's', ':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
-'c', 'o', 'r', 'e', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\"', '\350', '\001', '\n', '\020', 'R', 'e', 'm', 'o', 
-'t', 'e', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', '\022', 'B', '\n', '\010', 'h', 't', 't', 'p', '_', 'u', 'r', 'i', '\030', 
-'\001', ' ', '\001', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
-'.', 'v', '3', '.', 'H', 't', 't', 'p', 'U', 'r', 'i', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\007', 'h', 't', 
-'t', 'p', 'U', 'r', 'i', '\022', '\037', '\n', '\006', 's', 'h', 'a', '2', '5', '6', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', 
-'\004', 'r', '\002', '\020', '\001', 'R', '\006', 's', 'h', 'a', '2', '5', '6', '\022', 'D', '\n', '\014', 'r', 'e', 't', 'r', 'y', '_', 'p', 'o', 
-'l', 'i', 'c', 'y', '\030', '\003', ' ', '\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\013', 'r', 'e', 't', 
-'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'R', 'e', 'm', 'o', 't', 'e', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 
-'e', '\"', '\311', '\001', '\n', '\017', 'A', 's', 'y', 'n', 'c', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '8', '\n', '\005', 
-'l', 'o', 'c', 'a', 'l', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\005', 'l', 
-'o', 'c', 'a', 'l', '\022', '@', '\n', '\006', 'r', 'e', 'm', 'o', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '&', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'e', 'm', 'o', 't', 'e', 
-'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\006', 'r', 'e', 'm', 'o', 't', 'e', ':', '(', '\232', '\305', '\210', 
-'\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'A', 's', 'y', 
-'n', 'c', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\020', '\n', '\t', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 
-'\022', '\003', '\370', 'B', '\001', '\"', '\260', '\001', '\n', '\017', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 
-'\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 
-'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', 
-'\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 
-'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 
-'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 
-'o', 'c', 'k', 'e', 't', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', 
-'\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\277', '\001', '\n', '\030', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 
-'t', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', '\022', 'O', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 
-'v', 'a', 'l', 'u', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 
-'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'B', '\010', '\372', 'B', '\005', 
-'\212', '\001', '\002', '\020', '\001', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '\037', '\n', '\013', 'r', 'u', 
-'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 
-'e', 'y', ':', '1', '\232', '\305', '\210', '\036', ',', '\n', '*', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 
-'o', 'r', 'e', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 
-'e', 'n', 't', '\"', 'U', '\n', '\014', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', '\022', '\036', '\n', '\n', 'i', 'd', 
-'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\n', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 
-'r', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 
-'r', 'e', '.', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', '*', '(', '\n', '\017', 'R', 'o', 'u', 't', 'i', 'n', 
-'g', 'P', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\022', '\013', '\n', '\007', 'D', 'E', 'F', 'A', 'U', 'L', 'T', '\020', '\000', '\022', '\010', '\n', 
-'\004', 'H', 'I', 'G', 'H', '\020', '\001', '*', '\211', '\001', '\n', '\r', 'R', 'e', 'q', 'u', 'e', 's', 't', 'M', 'e', 't', 'h', 'o', 'd', 
-'\022', '\026', '\n', '\022', 'M', 'E', 'T', 'H', 'O', 'D', '_', 'U', 'N', 'S', 'P', 'E', 'C', 'I', 'F', 'I', 'E', 'D', '\020', '\000', '\022', 
-'\007', '\n', '\003', 'G', 'E', 'T', '\020', '\001', '\022', '\010', '\n', '\004', 'H', 'E', 'A', 'D', '\020', '\002', '\022', '\010', '\n', '\004', 'P', 'O', 'S', 
-'T', '\020', '\003', '\022', '\007', '\n', '\003', 'P', 'U', 'T', '\020', '\004', '\022', '\n', '\n', '\006', 'D', 'E', 'L', 'E', 'T', 'E', '\020', '\005', '\022', 
-'\013', '\n', '\007', 'C', 'O', 'N', 'N', 'E', 'C', 'T', '\020', '\006', '\022', '\013', '\n', '\007', 'O', 'P', 'T', 'I', 'O', 'N', 'S', '\020', '\007', 
-'\022', '\t', '\n', '\005', 'T', 'R', 'A', 'C', 'E', '\020', '\010', '\022', '\t', '\n', '\005', 'P', 'A', 'T', 'C', 'H', '\020', '\t', '*', '>', '\n', 
-'\020', 'T', 'r', 'a', 'f', 'f', 'i', 'c', 'D', 'i', 'r', 'e', 'c', 't', 'i', 'o', 'n', '\022', '\017', '\n', '\013', 'U', 'N', 'S', 'P', 
-'E', 'C', 'I', 'F', 'I', 'E', 'D', '\020', '\000', '\022', '\013', '\n', '\007', 'I', 'N', 'B', 'O', 'U', 'N', 'D', '\020', '\001', '\022', '\014', '\n', 
-'\010', 'O', 'U', 'T', 'B', 'O', 'U', 'N', 'D', '\020', '\002', 'B', '9', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 
-'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', 
-'\t', 'B', 'a', 's', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 
-'t', 'o', '3', 
+'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
+'/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 
+'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 
+'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 
+'s', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 
+'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', 't', '\n', '\010', 'L', 'o', 'c', 
+'a', 'l', 'i', 't', 'y', '\022', '\026', '\n', '\006', 'r', 'e', 'g', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\006', 'r', 'e', 
+'g', 'i', 'o', 'n', '\022', '\022', '\n', '\004', 'z', 'o', 'n', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\004', 'z', 'o', 'n', 'e', '\022', 
+'\031', '\n', '\010', 's', 'u', 'b', '_', 'z', 'o', 'n', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\007', 's', 'u', 'b', 'Z', 'o', 'n', 
+'e', ':', '!', '\232', '\305', '\210', '\036', '\034', '\n', '\032', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 
+'r', 'e', '.', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', '\"', '\244', '\001', '\n', '\014', 'B', 'u', 'i', 'l', 'd', 'V', 'e', 'r', 's', 
+'i', 'o', 'n', '\022', '8', '\n', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'S', 'e', 'm', 'a', 'n', 't', 'i', 'c', 'V', 'e', 'r', 's', 'i', 
+'o', 'n', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', '3', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\002', 
+' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 
+'r', 'u', 'c', 't', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 
+'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'B', 'u', 'i', 'l', 'd', 'V', 'e', 'r', 's', 
+'i', 'o', 'n', '\"', '\342', '\001', '\n', '\t', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', 
+'\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\032', '\n', '\010', 'c', 'a', 't', 'e', 'g', 'o', 'r', 'y', '\030', 
+'\002', ' ', '\001', '(', '\t', 'R', '\010', 'c', 'a', 't', 'e', 'g', 'o', 'r', 'y', '\022', '\'', '\n', '\017', 't', 'y', 'p', 'e', '_', 'd', 
+'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\016', 't', 'y', 'p', 'e', 'D', 'e', 's', 'c', 
+'r', 'i', 'p', 't', 'o', 'r', '\022', '<', '\n', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\004', ' ', '\001', '(', '\013', '2', '\"', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'B', 'u', 'i', 
+'l', 'd', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', '\032', '\n', '\010', 'd', 'i', 's', 
+'a', 'b', 'l', 'e', 'd', '\030', '\005', ' ', '\001', '(', '\010', 'R', '\010', 'd', 'i', 's', 'a', 'b', 'l', 'e', 'd', ':', '\"', '\232', '\305', 
+'\210', '\036', '\035', '\n', '\033', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'E', 'x', 
+'t', 'e', 'n', 's', 'i', 'o', 'n', '\"', '\345', '\004', '\n', '\004', 'N', 'o', 'd', 'e', '\022', '\016', '\n', '\002', 'i', 'd', '\030', '\001', ' ', 
+'\001', '(', '\t', 'R', '\002', 'i', 'd', '\022', '\030', '\n', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\t', 'R', 
+'\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\022', '3', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\003', ' ', '\001', '(', 
+'\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 
+'t', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', ':', '\n', '\010', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', '\030', '\004', 
+' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
+'v', '3', '.', 'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'R', '\010', 'l', 'o', 'c', 'a', 'l', 'i', 't', 'y', '\022', '&', '\n', '\017', 
+'u', 's', 'e', 'r', '_', 'a', 'g', 'e', 'n', 't', '_', 'n', 'a', 'm', 'e', '\030', '\006', ' ', '\001', '(', '\t', 'R', '\r', 'u', 's', 
+'e', 'r', 'A', 'g', 'e', 'n', 't', 'N', 'a', 'm', 'e', '\022', '.', '\n', '\022', 'u', 's', 'e', 'r', '_', 'a', 'g', 'e', 'n', 't', 
+'_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\007', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\020', 'u', 's', 'e', 'r', 'A', 'g', 'e', 
+'n', 't', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', ']', '\n', '\030', 'u', 's', 'e', 'r', '_', 'a', 'g', 'e', 'n', 't', '_', 'b', 
+'u', 'i', 'l', 'd', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\010', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'B', 'u', 'i', 'l', 'd', 'V', 'e', 'r', 
+'s', 'i', 'o', 'n', 'H', '\000', 'R', '\025', 'u', 's', 'e', 'r', 'A', 'g', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'V', 'e', 'r', 
+'s', 'i', 'o', 'n', '\022', '?', '\n', '\n', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '\030', '\t', ' ', '\003', '(', '\013', '2', 
+'\037', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'E', 'x', 
+'t', 'e', 'n', 's', 'i', 'o', 'n', 'R', '\n', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '\022', '\'', '\n', '\017', 'c', 'l', 
+'i', 'e', 'n', 't', '_', 'f', 'e', 'a', 't', 'u', 'r', 'e', 's', '\030', '\n', ' ', '\003', '(', '\t', 'R', '\016', 'c', 'l', 'i', 'e', 
+'n', 't', 'F', 'e', 'a', 't', 'u', 'r', 'e', 's', '\022', 'R', '\n', '\023', 'l', 'i', 's', 't', 'e', 'n', 'i', 'n', 'g', '_', 'a', 
+'d', 'd', 'r', 'e', 's', 's', 'e', 's', '\030', '\013', ' ', '\003', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'd', 'd', 'r', 'e', 's', 's', 'B', '\002', '\030', '\001', 'R', 
+'\022', 'l', 'i', 's', 't', 'e', 'n', 'i', 'n', 'g', 'A', 'd', 'd', 'r', 'e', 's', 's', 'e', 's', ':', '\035', '\232', '\305', '\210', '\036', 
+'\030', '\n', '\026', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'N', 'o', 'd', 'e', 
+'B', '\031', '\n', '\027', 'u', 's', 'e', 'r', '_', 'a', 'g', 'e', 'n', 't', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 't', 'y', 
+'p', 'e', 'J', '\004', '\010', '\005', '\020', '\006', 'R', '\r', 'b', 'u', 'i', 'l', 'd', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\"', '\346', 
+'\001', '\n', '\010', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', '[', '\n', '\017', 'f', 'i', 'l', 't', 'e', 'r', '_', 'm', 'e', 't', 
+'a', 'd', 'a', 't', 'a', '\030', '\001', ' ', '\003', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '.', 'F', 'i', 'l', 't', 'e', 'r', 
+'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'E', 'n', 't', 'r', 'y', 'R', '\016', 'f', 'i', 'l', 't', 'e', 'r', 'M', 'e', 't', 'a', 
+'d', 'a', 't', 'a', '\032', 'Z', '\n', '\023', 'F', 'i', 'l', 't', 'e', 'r', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'E', 'n', 't', 
+'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '-', '\n', '\005', 'v', 
+'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
+'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', ':', '!', '\232', '\305', 
+'\210', '\036', '\034', '\n', '\032', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'M', 'e', 
+'t', 'a', 'd', 'a', 't', 'a', '\"', '\206', '\001', '\n', '\r', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'U', 'I', 'n', 't', '3', '2', '\022', 
+'#', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\r', 'R', '\014', 'd', 
+'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '(', '\n', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 
+'y', '\030', '\003', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 
+'K', 'e', 'y', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
+'c', 'o', 'r', 'e', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'U', 'I', 'n', 't', '3', '2', '\"', 'w', '\n', '\016', 'R', 'u', 'n', 
+'t', 'i', 'm', 'e', 'P', 'e', 'r', 'c', 'e', 'n', 't', '\022', ';', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 
+'l', 'u', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', 
+'.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '(', '\n', 
+'\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', 
+'\020', '\001', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', '\"', '\206', '\001', '\n', '\r', 'R', 'u', 'n', 't', 'i', 'm', 
+'e', 'D', 'o', 'u', 'b', 'l', 'e', '\022', '#', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', 
+'\001', ' ', '\001', '(', '\001', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '(', '\n', '\013', 'r', 'u', 
+'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', 
+'\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', 
+'.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'D', 'o', 'u', 'b', 'l', 
+'e', '\"', '\266', '\001', '\n', '\022', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'e', 'a', 't', 'u', 'r', 'e', 'F', 'l', 'a', 'g', '\022', 
+'I', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 
+'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', 
+'(', '\n', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 
+'r', '\002', '\020', '\001', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 
+'F', 'e', 'a', 't', 'u', 'r', 'e', 'F', 'l', 'a', 'g', '\"', '\177', '\n', '\013', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 
+'e', '\022', '#', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\021', '\372', 'B', '\016', 'r', '\014', '\020', '\001', '(', '\200', 
+'\200', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\003', 'k', 'e', 'y', '\022', '%', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', 
+'\001', '(', '\t', 'B', '\017', '\372', 'B', '\014', 'r', '\n', '(', '\200', '\200', '\001', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\005', 'v', 'a', 'l', 
+'u', 'e', ':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 
+'o', 'r', 'e', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', '\"', '\270', '\001', '\n', '\021', 'H', 'e', 'a', 'd', 'e', 
+'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', '\022', 'C', '\n', '\006', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\001', ' ', 
+'\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
+'3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\006', 
+'h', 'e', 'a', 'd', 'e', 'r', '\022', '2', '\n', '\006', 'a', 'p', 'p', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 
+'R', '\006', 'a', 'p', 'p', 'e', 'n', 'd', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 
+'o', 'n', '\"', 'l', '\n', '\t', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 'p', '\022', ';', '\n', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 
+'s', '\030', '\001', ' ', '\003', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
+'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 
+'s', ':', '\"', '\232', '\305', '\210', '\036', '\035', '\n', '\033', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 
+'r', 'e', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 'p', '\"', '/', '\n', '\020', 'W', 'a', 't', 'c', 'h', 'e', 'd', 'D', 'i', 
+'r', 'e', 'c', 't', 'o', 'r', 'y', '\022', '\033', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', 
+'\004', 'r', '\002', '\020', '\001', 'R', '\004', 'p', 'a', 't', 'h', '\"', '\266', '\001', '\n', '\n', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 
+'e', '\022', '%', '\n', '\010', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', 
+'\002', '\020', '\001', 'H', '\000', 'R', '\010', 'f', 'i', 'l', 'e', 'n', 'a', 'm', 'e', '\022', '#', '\n', '\014', 'i', 'n', 'l', 'i', 'n', 'e', 
+'_', 'b', 'y', 't', 'e', 's', '\030', '\002', ' ', '\001', '(', '\014', 'H', '\000', 'R', '\013', 'i', 'n', 'l', 'i', 'n', 'e', 'B', 'y', 't', 
+'e', 's', '\022', '%', '\n', '\r', 'i', 'n', 'l', 'i', 'n', 'e', '_', 's', 't', 'r', 'i', 'n', 'g', '\030', '\003', ' ', '\001', '(', '\t', 
+'H', '\000', 'R', '\014', 'i', 'n', 'l', 'i', 'n', 'e', 'S', 't', 'r', 'i', 'n', 'g', ':', '#', '\232', '\305', '\210', '\036', '\036', '\n', '\034', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 
+'r', 'c', 'e', 'B', '\020', '\n', '\t', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', '\"', '\324', '\001', '\n', 
+'\013', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'K', '\n', '\016', 'r', 'e', 't', 'r', 'y', '_', 'b', 'a', 'c', 
+'k', '_', 'o', 'f', 'f', '\030', '\001', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'B', 'a', 'c', 'k', 'o', 'f', 'f', 'S', 't', 'r', 'a', 't', 'e', 'g', 'y', 
+'R', '\014', 'r', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\022', 'R', '\n', '\013', 'n', 'u', 'm', '_', 'r', 'e', 't', 
+'r', 'i', 'e', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
+'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\023', '\362', '\230', '\376', '\217', '\005', '\r', '\n', '\013', 
+'m', 'a', 'x', '_', 'r', 'e', 't', 'r', 'i', 'e', 's', 'R', '\n', 'n', 'u', 'm', 'R', 'e', 't', 'r', 'i', 'e', 's', ':', '$', 
+'\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 
+'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\"', '\350', '\001', '\n', '\020', 'R', 'e', 'm', 'o', 't', 'e', 'D', 'a', 't', 
+'a', 'S', 'o', 'u', 'r', 'c', 'e', '\022', 'B', '\n', '\010', 'h', 't', 't', 'p', '_', 'u', 'r', 'i', '\030', '\001', ' ', '\001', '(', '\013', 
+'2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 
+'t', 't', 'p', 'U', 'r', 'i', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\007', 'h', 't', 't', 'p', 'U', 'r', 'i', 
+'\022', '\037', '\n', '\006', 's', 'h', 'a', '2', '5', '6', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 
+'R', '\006', 's', 'h', 'a', '2', '5', '6', '\022', 'D', '\n', '\014', 'r', 'e', 't', 'r', 'y', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', 
+'\003', ' ', '\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
+'.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\013', 'r', 'e', 't', 'r', 'y', 'P', 'o', 'l', 
+'i', 'c', 'y', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
+'c', 'o', 'r', 'e', '.', 'R', 'e', 'm', 'o', 't', 'e', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', '\"', '\311', '\001', '\n', 
+'\017', 'A', 's', 'y', 'n', 'c', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '8', '\n', '\005', 'l', 'o', 'c', 'a', 'l', 
+'\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 
+'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\005', 'l', 'o', 'c', 'a', 'l', '\022', 
+'@', '\n', '\006', 'r', 'e', 'm', 'o', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'e', 'm', 'o', 't', 'e', 'D', 'a', 't', 'a', 'S', 
+'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\006', 'r', 'e', 'm', 'o', 't', 'e', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 
+'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'A', 's', 'y', 'n', 'c', 'D', 'a', 't', 
+'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\020', '\n', '\t', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 
+'\"', '\260', '\001', '\n', '\017', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', '\022', '\033', '\n', '\004', 'n', 
+'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 
+'9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 
+'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 
+'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 
+'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 
+'n', 'f', 'i', 'g', '\"', '\277', '\001', '\n', '\030', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 
+'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', '\022', 'O', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', 
+'\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 
+'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 
+'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '\037', '\n', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', 
+'_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\n', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', ':', '1', '\232', 
+'\305', '\210', '\036', ',', '\n', '*', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'R', 
+'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', '\"', 'U', 
+'\n', '\014', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', '\022', '\036', '\n', '\n', 'i', 'd', 'e', 'n', 't', 'i', 'f', 
+'i', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\n', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', ':', '%', '\232', '\305', 
+'\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'C', 'o', 
+'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', '*', '(', '\n', '\017', 'R', 'o', 'u', 't', 'i', 'n', 'g', 'P', 'r', 'i', 'o', 
+'r', 'i', 't', 'y', '\022', '\013', '\n', '\007', 'D', 'E', 'F', 'A', 'U', 'L', 'T', '\020', '\000', '\022', '\010', '\n', '\004', 'H', 'I', 'G', 'H', 
+'\020', '\001', '*', '\211', '\001', '\n', '\r', 'R', 'e', 'q', 'u', 'e', 's', 't', 'M', 'e', 't', 'h', 'o', 'd', '\022', '\026', '\n', '\022', 'M', 
+'E', 'T', 'H', 'O', 'D', '_', 'U', 'N', 'S', 'P', 'E', 'C', 'I', 'F', 'I', 'E', 'D', '\020', '\000', '\022', '\007', '\n', '\003', 'G', 'E', 
+'T', '\020', '\001', '\022', '\010', '\n', '\004', 'H', 'E', 'A', 'D', '\020', '\002', '\022', '\010', '\n', '\004', 'P', 'O', 'S', 'T', '\020', '\003', '\022', '\007', 
+'\n', '\003', 'P', 'U', 'T', '\020', '\004', '\022', '\n', '\n', '\006', 'D', 'E', 'L', 'E', 'T', 'E', '\020', '\005', '\022', '\013', '\n', '\007', 'C', 'O', 
+'N', 'N', 'E', 'C', 'T', '\020', '\006', '\022', '\013', '\n', '\007', 'O', 'P', 'T', 'I', 'O', 'N', 'S', '\020', '\007', '\022', '\t', '\n', '\005', 'T', 
+'R', 'A', 'C', 'E', '\020', '\010', '\022', '\t', '\n', '\005', 'P', 'A', 'T', 'C', 'H', '\020', '\t', '*', '>', '\n', '\020', 'T', 'r', 'a', 'f', 
+'f', 'i', 'c', 'D', 'i', 'r', 'e', 'c', 't', 'i', 'o', 'n', '\022', '\017', '\n', '\013', 'U', 'N', 'S', 'P', 'E', 'C', 'I', 'F', 'I', 
+'E', 'D', '\020', '\000', '\022', '\013', '\n', '\007', 'I', 'N', 'B', 'O', 'U', 'N', 'D', '\020', '\001', '\022', '\014', '\n', '\010', 'O', 'U', 'T', 'B', 
+'O', 'U', 'N', 'D', '\020', '\002', 'B', '9', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\t', 'B', 'a', 's', 'e', 
+'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[14] = {
+static upb_def_init *deps[13] = {
   &envoy_config_core_v3_address_proto_upbdefinit,
   &envoy_config_core_v3_backoff_proto_upbdefinit,
   &envoy_config_core_v3_http_uri_proto_upbdefinit,
   &envoy_type_v3_percent_proto_upbdefinit,
   &envoy_type_v3_semantic_version_proto_upbdefinit,
   &google_protobuf_any_proto_upbdefinit,
-  &google_protobuf_duration_proto_upbdefinit,
   &google_protobuf_struct_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
   &udpa_annotations_migrate_proto_upbdefinit,
@@ -262,5 +268,5 @@
   deps,
   layouts,
   "envoy/config/core/v3/base.proto",
-  UPB_STRVIEW_INIT(descriptor, 4353)
+  UPB_STRVIEW_INIT(descriptor, 4473)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/base.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/base.upbdefs.h
index 96ff806..4464eda 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/base.upbdefs.h
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/base.upbdefs.h
@@ -56,6 +56,11 @@
   return upb_symtab_lookupmsg(s, "envoy.config.core.v3.RuntimeUInt32");
 }
 
+UPB_INLINE const upb_msgdef *envoy_config_core_v3_RuntimePercent_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_core_v3_base_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.core.v3.RuntimePercent");
+}
+
 UPB_INLINE const upb_msgdef *envoy_config_core_v3_RuntimeDouble_getmsgdef(upb_symtab *s) {
   _upb_symtab_loaddefinit(s, &envoy_config_core_v3_base_proto_upbdefinit);
   return upb_symtab_lookupmsg(s, "envoy.config.core.v3.RuntimeDouble");
@@ -81,6 +86,11 @@
   return upb_symtab_lookupmsg(s, "envoy.config.core.v3.HeaderMap");
 }
 
+UPB_INLINE const upb_msgdef *envoy_config_core_v3_WatchedDirectory_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_core_v3_base_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.core.v3.WatchedDirectory");
+}
+
 UPB_INLINE const upb_msgdef *envoy_config_core_v3_DataSource_getmsgdef(upb_symtab *s) {
   _upb_symtab_loaddefinit(s, &envoy_config_core_v3_base_proto_upbdefinit);
   return upb_symtab_lookupmsg(s, "envoy.config.core.v3.DataSource");
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/config_source.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/config_source.upbdefs.c
index ff4c0fe..6eb7709 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/config_source.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/config_source.upbdefs.c
@@ -12,7 +12,7 @@
 extern upb_def_init envoy_config_core_v3_grpc_service_proto_upbdefinit;
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_authority_proto_upbdefinit;
+extern upb_def_init xds_core_v3_authority_proto_upbdefinit;
 extern upb_def_init envoy_annotations_deprecation_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
@@ -31,103 +31,103 @@
   &envoy_config_core_v3_ConfigSource_msginit,
 };
 
-static const char descriptor[2232] = {'\n', '(', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'c', 'o', 
+static const char descriptor[2238] = {'\n', '(', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'c', 'o', 
 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\022', '\024', 'e', 'n', 'v', 'o', 'y', '.', 
 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 
 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'g', 'r', 'p', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 
 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 
 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 
-'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'u', 'd', 'p', 'a', 
-'/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', 
-'#', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'd', 'e', 'p', 'r', 'e', 'c', 
-'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
-'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 
-'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 
-'t', 'o', '\"', '\233', '\006', '\n', '\017', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', 'R', '\n', 
-'\010', 'a', 'p', 'i', '_', 't', 'y', 'p', 'e', '\030', '\001', ' ', '\001', '(', '\016', '2', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 
-'u', 'r', 'c', 'e', '.', 'A', 'p', 'i', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\007', 'a', 
-'p', 'i', 'T', 'y', 'p', 'e', '\022', '^', '\n', '\025', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 'a', 'p', 'i', '_', 'v', 
-'e', 'r', 's', 'i', 'o', 'n', '\030', '\010', ' ', '\001', '(', '\016', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'B', '\010', '\372', 'B', 
-'\005', '\202', '\001', '\002', '\020', '\001', 'R', '\023', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 
-'o', 'n', '\022', '#', '\n', '\r', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'n', 'a', 'm', 'e', 's', '\030', '\002', ' ', '\003', '(', '\t', 
-'R', '\014', 'c', 'l', 'u', 's', 't', 'e', 'r', 'N', 'a', 'm', 'e', 's', '\022', 'F', '\n', '\r', 'g', 'r', 'p', 'c', '_', 's', 'e', 
-'r', 'v', 'i', 'c', 'e', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'G', 'r', 'p', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'R', '\014', 'g', 
-'r', 'p', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '>', '\n', '\r', 'r', 'e', 'f', 'r', 'e', 's', 'h', '_', 'd', 'e', 
-'l', 'a', 'y', '\030', '\003', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
-'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\014', 'r', 'e', 'f', 'r', 'e', 's', 'h', 'D', 'e', 'l', 'a', 'y', 
-'\022', 'L', '\n', '\017', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\005', ' ', '\001', '(', '\013', 
-'2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 
-'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\016', 'r', 'e', 'q', 'u', 'e', 's', 't', 'T', 'i', 'm', 'e', 
-'o', 'u', 't', '\022', 'W', '\n', '\023', 'r', 'a', 't', 'e', '_', 'l', 'i', 'm', 'i', 't', '_', 's', 'e', 't', 't', 'i', 'n', 'g', 
-'s', '\030', '\006', ' ', '\001', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
-'r', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', 'R', '\021', 
-'r', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', '\022', 'A', '\n', '\036', 's', 'e', 't', '_', 
-'n', 'o', 'd', 'e', '_', 'o', 'n', '_', 'f', 'i', 'r', 's', 't', '_', 'm', 'e', 's', 's', 'a', 'g', 'e', '_', 'o', 'n', 'l', 
-'y', '\030', '\007', ' ', '\001', '(', '\010', 'R', '\031', 's', 'e', 't', 'N', 'o', 'd', 'e', 'O', 'n', 'F', 'i', 'r', 's', 't', 'M', 'e', 
-'s', 's', 'a', 'g', 'e', 'O', 'n', 'l', 'y', '\"', '\222', '\001', '\n', '\007', 'A', 'p', 'i', 'T', 'y', 'p', 'e', '\022', '3', '\n', '%', 
-'D', 'E', 'P', 'R', 'E', 'C', 'A', 'T', 'E', 'D', '_', 'A', 'N', 'D', '_', 'U', 'N', 'A', 'V', 'A', 'I', 'L', 'A', 'B', 'L', 
-'E', '_', 'D', 'O', '_', 'N', 'O', 'T', '_', 'U', 'S', 'E', '\020', '\000', '\032', '\010', '\010', '\001', '\250', '\367', '\264', '\213', '\002', '\001', '\022', 
-'\010', '\n', '\004', 'R', 'E', 'S', 'T', '\020', '\001', '\022', '\010', '\n', '\004', 'G', 'R', 'P', 'C', '\020', '\002', '\022', '\016', '\n', '\n', 'D', 'E', 
-'L', 'T', 'A', '_', 'G', 'R', 'P', 'C', '\020', '\003', '\022', '\023', '\n', '\017', 'A', 'G', 'G', 'R', 'E', 'G', 'A', 'T', 'E', 'D', '_', 
-'G', 'R', 'P', 'C', '\020', '\005', '\022', '\031', '\n', '\025', 'A', 'G', 'G', 'R', 'E', 'G', 'A', 'T', 'E', 'D', '_', 'D', 'E', 'L', 'T', 
-'A', '_', 'G', 'R', 'P', 'C', '\020', '\006', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 
-'\"', 'I', '\n', '\026', 'A', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 
-'e', ':', '/', '\232', '\305', '\210', '\036', '*', '\n', '(', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 
-'r', 'e', '.', 'A', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 
-'\"', '\235', '\001', '\n', '\020', 'S', 'e', 'l', 'f', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '^', '\n', '\025', 
-'t', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 'a', 'p', 'i', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\001', ' ', '\001', 
-'(', '\016', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
-'.', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\023', 't', 'r', 
-'a', 'n', 's', 'p', 'o', 'r', 't', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', 
-'\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'S', 'e', 'l', 'f', 'C', 'o', 
-'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\"', '\307', '\001', '\n', '\021', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'S', 
-'e', 't', 't', 'i', 'n', 'g', 's', '\022', ';', '\n', '\n', 'm', 'a', 'x', '_', 't', 'o', 'k', 'e', 'n', 's', '\030', '\001', ' ', '\001', 
-'(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', 
-'3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 'm', 'a', 'x', 'T', 'o', 'k', 'e', 'n', 's', '\022', 'I', '\n', '\t', 'f', 'i', 'l', 
-'l', '_', 'r', 'a', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
-'t', 'o', 'b', 'u', 'f', '.', 'D', 'o', 'u', 'b', 'l', 'e', 'V', 'a', 'l', 'u', 'e', 'B', '\016', '\372', 'B', '\013', '\022', '\t', '!', 
-'\000', '\000', '\000', '\000', '\000', '\000', '\000', '\000', 'R', '\010', 'f', 'i', 'l', 'l', 'R', 'a', 't', 'e', ':', '*', '\232', '\305', '\210', '\036', '%', 
-'\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'R', 'a', 't', 'e', 'L', 
-'i', 'm', 'i', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', '\"', '\250', '\004', '\n', '\014', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 
-'u', 'r', 'c', 'e', '\022', '9', '\n', '\013', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'i', 'e', 's', '\030', '\007', ' ', '\003', '(', '\013', 
-'2', '\027', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'A', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', 
-'R', '\013', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'i', 'e', 's', '\022', '\024', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\001', 
-'(', '\t', 'H', '\000', 'R', '\004', 'p', 'a', 't', 'h', '\022', 'S', '\n', '\021', 'a', 'p', 'i', '_', 'c', 'o', 'n', 'f', 'i', 'g', '_', 
-'s', 'o', 'u', 'r', 'c', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 
-'e', 'H', '\000', 'R', '\017', 'a', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '@', '\n', '\003', 'a', 
-'d', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 
-'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 
-'u', 'r', 'c', 'e', 'H', '\000', 'R', '\003', 'a', 'd', 's', '\022', '<', '\n', '\004', 's', 'e', 'l', 'f', '\030', '\005', ' ', '\001', '(', '\013', 
-'2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'S', 
-'e', 'l', 'f', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\004', 's', 'e', 'l', 'f', '\022', 'M', 
-'\n', '\025', 'i', 'n', 'i', 't', 'i', 'a', 'l', '_', 'f', 'e', 't', 'c', 'h', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\004', 
-' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 
-'r', 'a', 't', 'i', 'o', 'n', 'R', '\023', 'i', 'n', 'i', 't', 'i', 'a', 'l', 'F', 'e', 't', 'c', 'h', 'T', 'i', 'm', 'e', 'o', 
-'u', 't', '\022', '\\', '\n', '\024', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'a', 'p', 'i', '_', 'v', 'e', 'r', 's', 'i', 'o', 
-'n', '\030', '\006', ' ', '\001', '(', '\016', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
-'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', 
-'\001', 'R', '\022', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', ':', '%', '\232', '\305', 
-'\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'C', 'o', 
-'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\036', '\n', '\027', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 
-'c', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', '*', '&', '\n', '\n', 'A', 'p', 'i', 'V', 
-'e', 'r', 's', 'i', 'o', 'n', '\022', '\010', '\n', '\004', 'A', 'U', 'T', 'O', '\020', '\000', '\022', '\006', '\n', '\002', 'V', '2', '\020', '\001', '\022', 
-'\006', '\n', '\002', 'V', '3', '\020', '\002', 'B', 'A', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\021', 'C', 'o', 'n', 
-'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', 
-'\006', 'p', 'r', 'o', 't', 'o', '3', 
+'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\033', 'x', 'd', 's', '/', 
+'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 
+'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 
+'t', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 
+'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 
+'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 
+'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 
+'o', '\"', '\233', '\006', '\n', '\017', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', 'R', '\n', '\010', 
+'a', 'p', 'i', '_', 't', 'y', 'p', 'e', '\030', '\001', ' ', '\001', '(', '\016', '2', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 
+'r', 'c', 'e', '.', 'A', 'p', 'i', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\007', 'a', 'p', 
+'i', 'T', 'y', 'p', 'e', '\022', '^', '\n', '\025', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 'a', 'p', 'i', '_', 'v', 'e', 
+'r', 's', 'i', 'o', 'n', '\030', '\010', ' ', '\001', '(', '\016', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', 
+'\202', '\001', '\002', '\020', '\001', 'R', '\023', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 
+'n', '\022', '#', '\n', '\r', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'n', 'a', 'm', 'e', 's', '\030', '\002', ' ', '\003', '(', '\t', 'R', 
+'\014', 'c', 'l', 'u', 's', 't', 'e', 'r', 'N', 'a', 'm', 'e', 's', '\022', 'F', '\n', '\r', 'g', 'r', 'p', 'c', '_', 's', 'e', 'r', 
+'v', 'i', 'c', 'e', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'G', 'r', 'p', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'R', '\014', 'g', 'r', 
+'p', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '>', '\n', '\r', 'r', 'e', 'f', 'r', 'e', 's', 'h', '_', 'd', 'e', 'l', 
+'a', 'y', '\030', '\003', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\014', 'r', 'e', 'f', 'r', 'e', 's', 'h', 'D', 'e', 'l', 'a', 'y', '\022', 
+'L', '\n', '\017', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\005', ' ', '\001', '(', '\013', '2', 
+'\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\016', 'r', 'e', 'q', 'u', 'e', 's', 't', 'T', 'i', 'm', 'e', 'o', 
+'u', 't', '\022', 'W', '\n', '\023', 'r', 'a', 't', 'e', '_', 'l', 'i', 'm', 'i', 't', '_', 's', 'e', 't', 't', 'i', 'n', 'g', 's', 
+'\030', '\006', ' ', '\001', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 
+'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', 'R', '\021', 'r', 
+'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', '\022', 'A', '\n', '\036', 's', 'e', 't', '_', 'n', 
+'o', 'd', 'e', '_', 'o', 'n', '_', 'f', 'i', 'r', 's', 't', '_', 'm', 'e', 's', 's', 'a', 'g', 'e', '_', 'o', 'n', 'l', 'y', 
+'\030', '\007', ' ', '\001', '(', '\010', 'R', '\031', 's', 'e', 't', 'N', 'o', 'd', 'e', 'O', 'n', 'F', 'i', 'r', 's', 't', 'M', 'e', 's', 
+'s', 'a', 'g', 'e', 'O', 'n', 'l', 'y', '\"', '\222', '\001', '\n', '\007', 'A', 'p', 'i', 'T', 'y', 'p', 'e', '\022', '3', '\n', '%', 'D', 
+'E', 'P', 'R', 'E', 'C', 'A', 'T', 'E', 'D', '_', 'A', 'N', 'D', '_', 'U', 'N', 'A', 'V', 'A', 'I', 'L', 'A', 'B', 'L', 'E', 
+'_', 'D', 'O', '_', 'N', 'O', 'T', '_', 'U', 'S', 'E', '\020', '\000', '\032', '\010', '\010', '\001', '\250', '\367', '\264', '\213', '\002', '\001', '\022', '\010', 
+'\n', '\004', 'R', 'E', 'S', 'T', '\020', '\001', '\022', '\010', '\n', '\004', 'G', 'R', 'P', 'C', '\020', '\002', '\022', '\016', '\n', '\n', 'D', 'E', 'L', 
+'T', 'A', '_', 'G', 'R', 'P', 'C', '\020', '\003', '\022', '\023', '\n', '\017', 'A', 'G', 'G', 'R', 'E', 'G', 'A', 'T', 'E', 'D', '_', 'G', 
+'R', 'P', 'C', '\020', '\005', '\022', '\031', '\n', '\025', 'A', 'G', 'G', 'R', 'E', 'G', 'A', 'T', 'E', 'D', '_', 'D', 'E', 'L', 'T', 'A', 
+'_', 'G', 'R', 'P', 'C', '\020', '\006', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
+'.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\"', 
+'I', '\n', '\026', 'A', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 
+':', '/', '\232', '\305', '\210', '\036', '*', '\n', '(', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 
+'e', '.', 'A', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\"', 
+'\235', '\001', '\n', '\020', 'S', 'e', 'l', 'f', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '^', '\n', '\025', 't', 
+'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 'a', 'p', 'i', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', 
+'\016', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
+'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\023', 't', 'r', 'a', 
+'n', 's', 'p', 'o', 'r', 't', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'S', 'e', 'l', 'f', 'C', 'o', 'n', 
+'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\"', '\307', '\001', '\n', '\021', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'S', 'e', 
+'t', 't', 'i', 'n', 'g', 's', '\022', ';', '\n', '\n', 'm', 'a', 'x', '_', 't', 'o', 'k', 'e', 'n', 's', '\030', '\001', ' ', '\001', '(', 
+'\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', 
+'2', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 'm', 'a', 'x', 'T', 'o', 'k', 'e', 'n', 's', '\022', 'I', '\n', '\t', 'f', 'i', 'l', 'l', 
+'_', 'r', 'a', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'D', 'o', 'u', 'b', 'l', 'e', 'V', 'a', 'l', 'u', 'e', 'B', '\016', '\372', 'B', '\013', '\022', '\t', '!', '\000', 
+'\000', '\000', '\000', '\000', '\000', '\000', '\000', 'R', '\010', 'f', 'i', 'l', 'l', 'R', 'a', 't', 'e', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', 
+'#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 
+'m', 'i', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', '\"', '\247', '\004', '\n', '\014', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 
+'r', 'c', 'e', '\022', '8', '\n', '\013', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'i', 'e', 's', '\030', '\007', ' ', '\003', '(', '\013', '2', 
+'\026', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', 'R', '\013', 
+'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'i', 'e', 's', '\022', '\024', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\001', '(', '\t', 
+'H', '\000', 'R', '\004', 'p', 'a', 't', 'h', '\022', 'S', '\n', '\021', 'a', 'p', 'i', '_', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 
+'u', 'r', 'c', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'H', 
+'\000', 'R', '\017', 'a', 'p', 'i', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '@', '\n', '\003', 'a', 'd', 's', 
+'\030', '\003', ' ', '\001', '(', '\013', '2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 
+'e', '.', 'v', '3', '.', 'A', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 
+'c', 'e', 'H', '\000', 'R', '\003', 'a', 'd', 's', '\022', '<', '\n', '\004', 's', 'e', 'l', 'f', '\030', '\005', ' ', '\001', '(', '\013', '2', '&', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'S', 'e', 'l', 
+'f', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\004', 's', 'e', 'l', 'f', '\022', 'M', '\n', '\025', 
+'i', 'n', 'i', 't', 'i', 'a', 'l', '_', 'f', 'e', 't', 'c', 'h', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\004', ' ', '\001', 
+'(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 
+'t', 'i', 'o', 'n', 'R', '\023', 'i', 'n', 'i', 't', 'i', 'a', 'l', 'F', 'e', 't', 'c', 'h', 'T', 'i', 'm', 'e', 'o', 'u', 't', 
+'\022', '\\', '\n', '\024', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'a', 'p', 'i', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', 
+'\006', ' ', '\001', '(', '\016', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
+'.', 'v', '3', '.', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', 
+'\022', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'A', 'p', 'i', 'V', 'e', 'r', 's', 'i', 'o', 'n', ':', '%', '\232', '\305', '\210', '\036', 
+' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'C', 'o', 'n', 'f', 
+'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\036', '\n', '\027', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', 
+'_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', '*', '.', '\n', '\n', 'A', 'p', 'i', 'V', 'e', 'r', 
+'s', 'i', 'o', 'n', '\022', '\014', '\n', '\004', 'A', 'U', 'T', 'O', '\020', '\000', '\032', '\002', '\010', '\001', '\022', '\n', '\n', '\002', 'V', '2', '\020', 
+'\001', '\032', '\002', '\010', '\001', '\022', '\006', '\n', '\002', 'V', '3', '\020', '\002', 'B', 'A', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 
+'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
+'3', 'B', '\021', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', 
+'\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
 static upb_def_init *deps[9] = {
   &envoy_config_core_v3_grpc_service_proto_upbdefinit,
   &google_protobuf_duration_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
-  &udpa_core_v1_authority_proto_upbdefinit,
+  &xds_core_v3_authority_proto_upbdefinit,
   &envoy_annotations_deprecation_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
@@ -139,5 +139,5 @@
   deps,
   layouts,
   "envoy/config/core/v3/config_source.proto",
-  UPB_STRVIEW_INIT(descriptor, 2232)
+  UPB_STRVIEW_INIT(descriptor, 2238)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/health_check.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/health_check.upbdefs.c
index 39924f8..469acd3 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/health_check.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/health_check.upbdefs.c
@@ -18,7 +18,6 @@
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
-extern upb_def_init envoy_annotations_deprecation_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
 extern upb_def_init validate_validate_proto_upbdefinit;
@@ -42,7 +41,7 @@
   &envoy_config_core_v3_HealthCheck_TlsOptions_msginit,
 };
 
-static const char descriptor[4084] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'h', 'e', 
+static const char descriptor[4147] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'h', 'e', 
 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '.', 'p', 'r', 'o', 't', 'o', '\022', '\024', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', '\037', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 
 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '/', 'e', 'n', 
@@ -56,159 +55,161 @@
 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 
 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 
 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 
-'p', 'r', 'o', 't', 'o', '\032', '#', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 
-'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 
-'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 
-'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 
-'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 
-'t', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\342', '\032', '\n', '\013', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', 
-'?', '\n', '\007', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\n', '\372', 'B', '\007', '\252', '\001', 
-'\004', '\010', '\001', '*', '\000', 'R', '\007', 't', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'A', '\n', '\010', 'i', 'n', 't', 'e', 'r', 'v', 'a', 
-'l', '\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
-'.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\n', '\372', 'B', '\007', '\252', '\001', '\004', '\010', '\001', '*', '\000', 'R', '\010', 'i', 'n', 
-'t', 'e', 'r', 'v', 'a', 'l', '\022', '@', '\n', '\016', 'i', 'n', 'i', 't', 'i', 'a', 'l', '_', 'j', 'i', 't', 't', 'e', 'r', '\030', 
-'\024', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 
-'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\r', 'i', 'n', 'i', 't', 'i', 'a', 'l', 'J', 'i', 't', 't', 'e', 'r', '\022', 'B', '\n', 
-'\017', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '_', 'j', 'i', 't', 't', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', '\031', '.', 
-'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', 
-'\016', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', 'J', 'i', 't', 't', 'e', 'r', '\022', '6', '\n', '\027', 'i', 'n', 't', 'e', 'r', 'v', 
-'a', 'l', '_', 'j', 'i', 't', 't', 'e', 'r', '_', 'p', 'e', 'r', 'c', 'e', 'n', 't', '\030', '\022', ' ', '\001', '(', '\r', 'R', '\025', 
-'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', 'J', 'i', 't', 't', 'e', 'r', 'P', 'e', 'r', 'c', 'e', 'n', 't', '\022', 'W', '\n', '\023', 
-'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 't', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\030', '\004', ' ', '\001', '(', '\013', 
+'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 
+'t', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
+'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 
+'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\306', '\033', '\n', 
+'\013', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '?', '\n', '\007', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\001', 
+' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 
+'r', 'a', 't', 'i', 'o', 'n', 'B', '\n', '\372', 'B', '\007', '\252', '\001', '\004', '\010', '\001', '*', '\000', 'R', '\007', 't', 'i', 'm', 'e', 'o', 
+'u', 't', '\022', 'A', '\n', '\010', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\n', '\372', 
+'B', '\007', '\252', '\001', '\004', '\010', '\001', '*', '\000', 'R', '\010', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', '@', '\n', '\016', 'i', 'n', 
+'i', 't', 'i', 'a', 'l', '_', 'j', 'i', 't', 't', 'e', 'r', '\030', '\024', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 
+'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\r', 'i', 'n', 'i', 
+'t', 'i', 'a', 'l', 'J', 'i', 't', 't', 'e', 'r', '\022', 'B', '\n', '\017', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '_', 'j', 'i', 
+'t', 't', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
+'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\016', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', 'J', 'i', 't', 
+'t', 'e', 'r', '\022', '6', '\n', '\027', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '_', 'j', 'i', 't', 't', 'e', 'r', '_', 'p', 'e', 
+'r', 'c', 'e', 'n', 't', '\030', '\022', ' ', '\001', '(', '\r', 'R', '\025', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', 'J', 'i', 't', 't', 
+'e', 'r', 'P', 'e', 'r', 'c', 'e', 'n', 't', '\022', 'W', '\n', '\023', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 't', 'h', 
+'r', 'e', 's', 'h', 'o', 'l', 'd', '\030', '\004', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', 
+'\002', '\020', '\001', 'R', '\022', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', 'T', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\022', 'S', 
+'\n', '\021', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 't', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\030', '\005', ' ', '\001', '(', '\013', 
 '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 
-'V', 'a', 'l', 'u', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\022', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 
-'y', 'T', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\022', 'S', '\n', '\021', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 't', 'h', 'r', 
-'e', 's', 'h', 'o', 'l', 'd', '\030', '\005', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
-'t', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', 
-'\020', '\001', 'R', '\020', 'h', 'e', 'a', 'l', 't', 'h', 'y', 'T', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\022', '7', '\n', '\010', 'a', 
-'l', 't', '_', 'p', 'o', 'r', 't', '\030', '\006', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
-'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\007', 'a', 'l', 't', 'P', 'o', 
-'r', 't', '\022', 'E', '\n', '\020', 'r', 'e', 'u', 's', 'e', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\030', '\007', ' ', 
-'\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 
-'l', 'V', 'a', 'l', 'u', 'e', 'R', '\017', 'r', 'e', 'u', 's', 'e', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\022', '_', 
-'\n', '\021', 'h', 't', 't', 'p', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '\030', '\010', ' ', '\001', '(', '\013', 
-'2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 
-'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'H', 't', 't', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 
-'k', 'H', '\000', 'R', '\017', 'h', 't', 't', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '\\', '\n', '\020', 't', 
-'c', 'p', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '\030', '\t', ' ', '\001', '(', '\013', '2', '0', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 
-'h', 'C', 'h', 'e', 'c', 'k', '.', 'T', 'c', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'H', '\000', 'R', '\016', 
-'t', 'c', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '_', '\n', '\021', 'g', 'r', 'p', 'c', '_', 'h', 'e', 
-'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '\030', '\013', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'V', 'a', 'l', 'u', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\020', 'h', 'e', 'a', 'l', 't', 'h', 'y', 'T', 
+'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\022', '7', '\n', '\010', 'a', 'l', 't', '_', 'p', 'o', 'r', 't', '\030', '\006', ' ', '\001', '(', 
+'\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', 
+'2', 'V', 'a', 'l', 'u', 'e', 'R', '\007', 'a', 'l', 't', 'P', 'o', 'r', 't', '\022', 'E', '\n', '\020', 'r', 'e', 'u', 's', 'e', '_', 
+'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\030', '\007', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
+'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\017', 'r', 'e', 'u', 's', 
+'e', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '\022', '_', '\n', '\021', 'h', 't', 't', 'p', '_', 'h', 'e', 'a', 'l', 't', 
+'h', '_', 'c', 'h', 'e', 'c', 'k', '\030', '\010', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'H', 
+'t', 't', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'H', '\000', 'R', '\017', 'h', 't', 't', 'p', 'H', 'e', 'a', 
+'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '\\', '\n', '\020', 't', 'c', 'p', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 
+'e', 'c', 'k', '\030', '\t', ' ', '\001', '(', '\013', '2', '0', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'T', 'c', 'p', 'H', 'e', 
+'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'H', '\000', 'R', '\016', 't', 'c', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 
+'c', 'k', '\022', '_', '\n', '\021', 'g', 'r', 'p', 'c', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '\030', '\013', 
+' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
+'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'G', 'r', 'p', 'c', 'H', 'e', 'a', 'l', 't', 'h', 
+'C', 'h', 'e', 'c', 'k', 'H', '\000', 'R', '\017', 'g', 'r', 'p', 'c', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', 
+'e', '\n', '\023', 'c', 'u', 's', 't', 'o', 'm', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '\030', '\r', ' ', 
+'\001', '(', '\013', '2', '3', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
+'3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'C', 'u', 's', 't', 'o', 'm', 'H', 'e', 'a', 'l', 't', 
+'h', 'C', 'h', 'e', 'c', 'k', 'H', '\000', 'R', '\021', 'c', 'u', 's', 't', 'o', 'm', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 
+'c', 'k', '\022', 'S', '\n', '\023', 'n', 'o', '_', 't', 'r', 'a', 'f', 'f', 'i', 'c', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', 
+'\030', '\014', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
+'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\021', 'n', 'o', 'T', 'r', 'a', 
+'f', 'f', 'i', 'c', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', 'b', '\n', '\033', 'n', 'o', '_', 't', 'r', 'a', 'f', 'f', 'i', 
+'c', '_', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\030', ' ', '\001', '(', '\013', '2', 
+'\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\030', 'n', 'o', 'T', 'r', 'a', 'f', 'f', 'i', 'c', 'H', 'e', 'a', 
+'l', 't', 'h', 'y', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', 'R', '\n', '\022', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', 
+'_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\016', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', 
+'*', '\000', 'R', '\021', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', '[', '\n', '\027', 
+'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 'e', 'd', 'g', 'e', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\017', 
+' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 
+'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\025', 'u', 'n', 'h', 'e', 'a', 'l', 't', 
+'h', 'y', 'E', 'd', 'g', 'e', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', 'W', '\n', '\025', 'h', 'e', 'a', 'l', 't', 'h', 'y', 
+'_', 'e', 'd', 'g', 'e', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\020', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 
+'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\023', 'h', 'e', 'a', 'l', 't', 'h', 'y', 'E', 'd', 'g', 'e', 'I', 'n', 't', 'e', 'r', 
+'v', 'a', 'l', '\022', '$', '\n', '\016', 'e', 'v', 'e', 'n', 't', '_', 'l', 'o', 'g', '_', 'p', 'a', 't', 'h', '\030', '\021', ' ', '\001', 
+'(', '\t', 'R', '\014', 'e', 'v', 'e', 'n', 't', 'L', 'o', 'g', 'P', 'a', 't', 'h', '\022', 'M', '\n', '\r', 'e', 'v', 'e', 'n', 't', 
+'_', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\030', '\026', ' ', '\001', '(', '\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'E', 'v', 'e', 'n', 't', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 
+'C', 'o', 'n', 'f', 'i', 'g', 'R', '\014', 'e', 'v', 'e', 'n', 't', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 'F', '\n', ' ', 'a', 
+'l', 'w', 'a', 'y', 's', '_', 'l', 'o', 'g', '_', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '_', 'f', 'a', 
+'i', 'l', 'u', 'r', 'e', 's', '\030', '\023', ' ', '\001', '(', '\010', 'R', '\034', 'a', 'l', 'w', 'a', 'y', 's', 'L', 'o', 'g', 'H', 'e', 
+'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'F', 'a', 'i', 'l', 'u', 'r', 'e', 's', '\022', 'M', '\n', '\013', 't', 'l', 's', '_', 
+'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\025', ' ', '\001', '(', '\013', '2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'T', 
+'l', 's', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\n', 't', 'l', 's', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '^', '\n', '\037', 
+'t', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', '_', 'm', 'a', 't', 'c', 'h', '_', 'c', 'r', 
+'i', 't', 'e', 'r', 'i', 'a', '\030', '\027', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\034', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 
+'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 'h', 'C', 'r', 'i', 't', 'e', 'r', 'i', 'a', '\032', '\200', '\001', '\n', '\007', 'P', 'a', 'y', 
+'l', 'o', 'a', 'd', '\022', '\035', '\n', '\004', 't', 'e', 'x', 't', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', 
+'\020', '\001', 'H', '\000', 'R', '\004', 't', 'e', 'x', 't', '\022', '\030', '\n', '\006', 'b', 'i', 'n', 'a', 'r', 'y', '\030', '\002', ' ', '\001', '(', 
+'\014', 'H', '\000', 'R', '\006', 'b', 'i', 'n', 'a', 'r', 'y', ':', ',', '\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', 
+'.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 
+'P', 'a', 'y', 'l', 'o', 'a', 'd', 'B', '\016', '\n', '\007', 'p', 'a', 'y', 'l', 'o', 'a', 'd', '\022', '\003', '\370', 'B', '\001', '\032', '\340', 
+'\005', '\n', '\017', 'H', 't', 't', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '\037', '\n', '\004', 'h', 'o', 's', 
+'t', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\004', 'h', 'o', 's', 
+'t', '\022', '!', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', 
+'\001', '\002', '\310', '\001', '\000', 'R', '\004', 'p', 'a', 't', 'h', '\022', '=', '\n', '\004', 's', 'e', 'n', 'd', '\030', '\003', ' ', '\001', '(', '\013', 
+'2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 
+'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'P', 'a', 'y', 'l', 'o', 'a', 'd', 'R', '\004', 's', 'e', 'n', 'd', '\022', 
+'C', '\n', '\007', 'r', 'e', 'c', 'e', 'i', 'v', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 
 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 
-'k', '.', 'G', 'r', 'p', 'c', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'H', '\000', 'R', '\017', 'g', 'r', 'p', 'c', 
-'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', 'e', '\n', '\023', 'c', 'u', 's', 't', 'o', 'm', '_', 'h', 'e', 'a', 
-'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '\030', '\r', ' ', '\001', '(', '\013', '2', '3', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 
-'.', 'C', 'u', 's', 't', 'o', 'm', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'H', '\000', 'R', '\021', 'c', 'u', 's', 
-'t', 'o', 'm', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', 'S', '\n', '\023', 'n', 'o', '_', 't', 'r', 'a', 'f', 
-'f', 'i', 'c', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\014', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', 
-'\252', '\001', '\002', '*', '\000', 'R', '\021', 'n', 'o', 'T', 'r', 'a', 'f', 'f', 'i', 'c', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', 
-'R', '\n', '\022', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\016', ' ', '\001', 
-'(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 
-'t', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\021', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', 
-'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', '[', '\n', '\027', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 'e', 'd', 'g', 
-'e', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\017', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', 
-'\002', '*', '\000', 'R', '\025', 'u', 'n', 'h', 'e', 'a', 'l', 't', 'h', 'y', 'E', 'd', 'g', 'e', 'I', 'n', 't', 'e', 'r', 'v', 'a', 
-'l', '\022', 'W', '\n', '\025', 'h', 'e', 'a', 'l', 't', 'h', 'y', '_', 'e', 'd', 'g', 'e', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 
-'l', '\030', '\020', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
-'.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\023', 'h', 'e', 'a', 'l', 
-'t', 'h', 'y', 'E', 'd', 'g', 'e', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', '$', '\n', '\016', 'e', 'v', 'e', 'n', 't', '_', 
-'l', 'o', 'g', '_', 'p', 'a', 't', 'h', '\030', '\021', ' ', '\001', '(', '\t', 'R', '\014', 'e', 'v', 'e', 'n', 't', 'L', 'o', 'g', 'P', 
-'a', 't', 'h', '\022', 'M', '\n', '\r', 'e', 'v', 'e', 'n', 't', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\030', '\026', ' ', '\001', '(', 
-'\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
-'E', 'v', 'e', 'n', 't', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\014', 'e', 'v', 'e', 'n', 't', 
-'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 'F', '\n', ' ', 'a', 'l', 'w', 'a', 'y', 's', '_', 'l', 'o', 'g', '_', 'h', 'e', 'a', 
-'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', '_', 'f', 'a', 'i', 'l', 'u', 'r', 'e', 's', '\030', '\023', ' ', '\001', '(', '\010', 'R', 
-'\034', 'a', 'l', 'w', 'a', 'y', 's', 'L', 'o', 'g', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'F', 'a', 'i', 'l', 
-'u', 'r', 'e', 's', '\022', 'M', '\n', '\013', 't', 'l', 's', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\025', ' ', '\001', '(', '\013', 
-'2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 
-'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'T', 'l', 's', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\n', 't', 'l', 
-'s', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '^', '\n', '\037', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 
-'k', 'e', 't', '_', 'm', 'a', 't', 'c', 'h', '_', 'c', 'r', 'i', 't', 'e', 'r', 'i', 'a', '\030', '\027', ' ', '\001', '(', '\013', '2', 
-'\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', 
-'\034', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'M', 'a', 't', 'c', 'h', 'C', 'r', 'i', 't', 
-'e', 'r', 'i', 'a', '\032', '\200', '\001', '\n', '\007', 'P', 'a', 'y', 'l', 'o', 'a', 'd', '\022', '\035', '\n', '\004', 't', 'e', 'x', 't', '\030', 
-'\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\004', 't', 'e', 'x', 't', '\022', '\030', '\n', 
-'\006', 'b', 'i', 'n', 'a', 'r', 'y', '\030', '\002', ' ', '\001', '(', '\014', 'H', '\000', 'R', '\006', 'b', 'i', 'n', 'a', 'r', 'y', ':', ',', 
-'\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 
-'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'P', 'a', 'y', 'l', 'o', 'a', 'd', 'B', '\016', '\n', '\007', 'p', 'a', 
-'y', 'l', 'o', 'a', 'd', '\022', '\003', '\370', 'B', '\001', '\032', '\340', '\005', '\n', '\017', 'H', 't', 't', 'p', 'H', 'e', 'a', 'l', 't', 'h', 
-'C', 'h', 'e', 'c', 'k', '\022', '\037', '\n', '\004', 'h', 'o', 's', 't', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', 
-'\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\004', 'h', 'o', 's', 't', '\022', '!', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\002', ' ', '\001', 
-'(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\004', 'p', 'a', 't', 'h', '\022', '=', 
-'\n', '\004', 's', 'e', 'n', 'd', '\030', '\003', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'P', 'a', 
-'y', 'l', 'o', 'a', 'd', 'R', '\004', 's', 'e', 'n', 'd', '\022', 'C', '\n', '\007', 'r', 'e', 'c', 'e', 'i', 'v', 'e', '\030', '\004', ' ', 
-'\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
-'3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'P', 'a', 'y', 'l', 'o', 'a', 'd', 'R', '\007', 'r', 'e', 
-'c', 'e', 'i', 'v', 'e', '\022', 'g', '\n', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 
-'t', 'o', '_', 'a', 'd', 'd', '\030', '\006', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 
-'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\023', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 
-'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'K', '\n', '\031', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 
-'d', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\010', ' ', '\003', '(', '\t', 'B', '\020', '\372', 'B', '\r', 
-'\222', '\001', '\n', '\"', '\010', 'r', '\006', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 
-'d', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', 'F', '\n', '\021', 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd', '_', 
-'s', 't', 'a', 't', 'u', 's', 'e', 's', '\030', '\t', ' ', '\003', '(', '\013', '2', '\031', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 
-'p', 'e', '.', 'v', '3', '.', 'I', 'n', 't', '6', '4', 'R', 'a', 'n', 'g', 'e', 'R', '\020', 'e', 'x', 'p', 'e', 'c', 't', 'e', 
-'d', 'S', 't', 'a', 't', 'u', 's', 'e', 's', '\022', 'T', '\n', '\021', 'c', 'o', 'd', 'e', 'c', '_', 'c', 'l', 'i', 'e', 'n', 't', 
-'_', 't', 'y', 'p', 'e', '\030', '\n', ' ', '\001', '(', '\016', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 
-'v', '3', '.', 'C', 'o', 'd', 'e', 'c', 'C', 'l', 'i', 'e', 'n', 't', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', 
-'\002', '\020', '\001', 'R', '\017', 'c', 'o', 'd', 'e', 'c', 'C', 'l', 'i', 'e', 'n', 't', 'T', 'y', 'p', 'e', '\022', 'V', '\n', '\024', 's', 
-'e', 'r', 'v', 'i', 'c', 'e', '_', 'n', 'a', 'm', 'e', '_', 'm', 'a', 't', 'c', 'h', 'e', 'r', '\030', '\013', ' ', '\001', '(', '\013', 
-'2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 
-'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\022', 's', 'e', 'r', 'v', 'i', 'c', 'e', 'N', 'a', 'm', 
-'e', 'M', 'a', 't', 'c', 'h', 'e', 'r', ':', '4', '\232', '\305', '\210', '\036', '/', '\n', '-', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'H', 't', 't', 
-'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'J', '\004', '\010', '\005', '\020', '\006', 'J', '\004', '\010', '\007', '\020', '\010', 'R', 
-'\014', 's', 'e', 'r', 'v', 'i', 'c', 'e', '_', 'n', 'a', 'm', 'e', 'R', '\t', 'u', 's', 'e', '_', 'h', 't', 't', 'p', '2', '\032', 
-'\311', '\001', '\n', '\016', 'T', 'c', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '=', '\n', '\004', 's', 'e', 'n', 
-'d', '\030', '\001', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
-'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'P', 'a', 'y', 'l', 'o', 'a', 'd', 
-'R', '\004', 's', 'e', 'n', 'd', '\022', 'C', '\n', '\007', 'r', 'e', 'c', 'e', 'i', 'v', 'e', '\030', '\002', ' ', '\003', '(', '\013', '2', ')', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 
-'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'P', 'a', 'y', 'l', 'o', 'a', 'd', 'R', '\007', 'r', 'e', 'c', 'e', 'i', 'v', 'e', 
-':', '3', '\232', '\305', '\210', '\036', '.', '\n', ',', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 
-'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'T', 'c', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 
-'e', 'c', 'k', '\032', '[', '\n', '\020', 'R', 'e', 'd', 'i', 's', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '\020', 
-'\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', ':', '5', '\232', '\305', '\210', '\036', '0', '\n', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 
-'h', 'e', 'c', 'k', '.', 'R', 'e', 'd', 'i', 's', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\032', '\225', '\001', '\n', 
-'\017', 'G', 'r', 'p', 'c', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '!', '\n', '\014', 's', 'e', 'r', 'v', 'i', 
-'c', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 's', 'e', 'r', 'v', 'i', 'c', 'e', 'N', 'a', 'm', 
-'e', '\022', ')', '\n', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 
-'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', ':', '4', '\232', '\305', '\210', '\036', 
-'/', '\n', '-', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 
-'t', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'G', 'r', 'p', 'c', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\032', '\300', 
-'\001', '\n', '\021', 'C', 'u', 's', 't', 'o', 'm', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '\033', '\n', '\004', 'n', 
-'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 
-'9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 
-'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 
-'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '6', '\232', '\305', '\210', '\036', '1', '\n', '/', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'C', 'u', 's', 
-'t', 'o', 'm', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 
-'t', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\032', 'd', '\n', '\n', 'T', 'l', 's', 
-'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', '\016', 'a', 'l', 'p', 'n', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', 
-'\030', '\001', ' ', '\003', '(', '\t', 'R', '\r', 'a', 'l', 'p', 'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', ':', '/', '\232', '\305', 
-'\210', '\036', '*', '\n', '(', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 
-'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'T', 'l', 's', 'O', 'p', 't', 'i', 'o', 'n', 's', ':', '$', '\232', '\305', '\210', 
-'\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 
-'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'B', '\025', '\n', '\016', 'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', 'e', 
-'r', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\n', '\020', '\013', '*', '`', '\n', '\014', 'H', 'e', 'a', 'l', 't', 'h', 'S', 't', 'a', 
-'t', 'u', 's', '\022', '\013', '\n', '\007', 'U', 'N', 'K', 'N', 'O', 'W', 'N', '\020', '\000', '\022', '\013', '\n', '\007', 'H', 'E', 'A', 'L', 'T', 
-'H', 'Y', '\020', '\001', '\022', '\r', '\n', '\t', 'U', 'N', 'H', 'E', 'A', 'L', 'T', 'H', 'Y', '\020', '\002', '\022', '\014', '\n', '\010', 'D', 'R', 
-'A', 'I', 'N', 'I', 'N', 'G', '\020', '\003', '\022', '\013', '\n', '\007', 'T', 'I', 'M', 'E', 'O', 'U', 'T', '\020', '\004', '\022', '\014', '\n', '\010', 
-'D', 'E', 'G', 'R', 'A', 'D', 'E', 'D', '\020', '\005', 'B', '@', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 
-'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\020', 
-'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', 
-'\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'k', '.', 'P', 'a', 'y', 'l', 'o', 'a', 'd', 'R', '\007', 'r', 'e', 'c', 'e', 'i', 'v', 'e', '\022', 'g', '\n', '\026', 'r', 'e', 'q', 
+'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\006', ' ', '\003', '(', '\013', 
+'2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 
+'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', 
+'\350', '\007', 'R', '\023', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'K', 
+'\n', '\031', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 
+'v', 'e', '\030', '\010', ' ', '\003', '(', '\t', 'B', '\020', '\372', 'B', '\r', '\222', '\001', '\n', '\"', '\010', 'r', '\006', '\300', '\001', '\001', '\310', '\001', 
+'\000', 'R', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', 
+'\022', 'F', '\n', '\021', 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd', '_', 's', 't', 'a', 't', 'u', 's', 'e', 's', '\030', '\t', ' ', '\003', 
+'(', '\013', '2', '\031', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'I', 'n', 't', '6', '4', 'R', 
+'a', 'n', 'g', 'e', 'R', '\020', 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd', 'S', 't', 'a', 't', 'u', 's', 'e', 's', '\022', 'T', '\n', 
+'\021', 'c', 'o', 'd', 'e', 'c', '_', 'c', 'l', 'i', 'e', 'n', 't', '_', 't', 'y', 'p', 'e', '\030', '\n', ' ', '\001', '(', '\016', '2', 
+'\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'C', 'o', 'd', 'e', 'c', 'C', 'l', 'i', 'e', 
+'n', 't', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\017', 'c', 'o', 'd', 'e', 'c', 'C', 'l', 
+'i', 'e', 'n', 't', 'T', 'y', 'p', 'e', '\022', 'V', '\n', '\024', 's', 'e', 'r', 'v', 'i', 'c', 'e', '_', 'n', 'a', 'm', 'e', '_', 
+'m', 'a', 't', 'c', 'h', 'e', 'r', '\030', '\013', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 
+'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 
+'r', 'R', '\022', 's', 'e', 'r', 'v', 'i', 'c', 'e', 'N', 'a', 'm', 'e', 'M', 'a', 't', 'c', 'h', 'e', 'r', ':', '4', '\232', '\305', 
+'\210', '\036', '/', '\n', '-', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 
+'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'H', 't', 't', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 
+'J', '\004', '\010', '\005', '\020', '\006', 'J', '\004', '\010', '\007', '\020', '\010', 'R', '\014', 's', 'e', 'r', 'v', 'i', 'c', 'e', '_', 'n', 'a', 'm', 
+'e', 'R', '\t', 'u', 's', 'e', '_', 'h', 't', 't', 'p', '2', '\032', '\311', '\001', '\n', '\016', 'T', 'c', 'p', 'H', 'e', 'a', 'l', 't', 
+'h', 'C', 'h', 'e', 'c', 'k', '\022', '=', '\n', '\004', 's', 'e', 'n', 'd', '\030', '\001', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 
+'C', 'h', 'e', 'c', 'k', '.', 'P', 'a', 'y', 'l', 'o', 'a', 'd', 'R', '\004', 's', 'e', 'n', 'd', '\022', 'C', '\n', '\007', 'r', 'e', 
+'c', 'e', 'i', 'v', 'e', '\030', '\002', ' ', '\003', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'P', 'a', 'y', 
+'l', 'o', 'a', 'd', 'R', '\007', 'r', 'e', 'c', 'e', 'i', 'v', 'e', ':', '3', '\232', '\305', '\210', '\036', '.', '\n', ',', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 
+'k', '.', 'T', 'c', 'p', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\032', '[', '\n', '\020', 'R', 'e', 'd', 'i', 's', 
+'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', 
+'\003', 'k', 'e', 'y', ':', '5', '\232', '\305', '\210', '\036', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', 
+'.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'R', 'e', 'd', 'i', 's', 'H', 'e', 
+'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\032', '\225', '\001', '\n', '\017', 'G', 'r', 'p', 'c', 'H', 'e', 'a', 'l', 't', 'h', 'C', 
+'h', 'e', 'c', 'k', '\022', '!', '\n', '\014', 's', 'e', 'r', 'v', 'i', 'c', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', 
+'\t', 'R', '\013', 's', 'e', 'r', 'v', 'i', 'c', 'e', 'N', 'a', 'm', 'e', '\022', ')', '\n', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 
+'t', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\t', 'a', 'u', 
+'t', 'h', 'o', 'r', 'i', 't', 'y', ':', '4', '\232', '\305', '\210', '\036', '/', '\n', '-', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
+'.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'G', 'r', 'p', 'c', 
+'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\032', '\300', '\001', '\n', '\021', 'C', 'u', 's', 't', 'o', 'm', 'H', 'e', 'a', 
+'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 
+'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 
+'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '6', '\232', '\305', 
+'\210', '\036', '1', '\n', '/', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 
+'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'C', 'u', 's', 't', 'o', 'm', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 
+'c', 'k', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 
+'c', 'o', 'n', 'f', 'i', 'g', '\032', 'd', '\n', '\n', 'T', 'l', 's', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', '\016', 'a', 
+'l', 'p', 'n', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\030', '\001', ' ', '\003', '(', '\t', 'R', '\r', 'a', 'l', 'p', 'n', 
+'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', ':', '/', '\232', '\305', '\210', '\036', '*', '\n', '(', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
+'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', '.', 'T', 'l', 
+'s', 'O', 'p', 't', 'i', 'o', 'n', 's', ':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'B', '\025', '\n', '\016', 
+'h', 'e', 'a', 'l', 't', 'h', '_', 'c', 'h', 'e', 'c', 'k', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\n', '\020', '\013', 
+'*', '`', '\n', '\014', 'H', 'e', 'a', 'l', 't', 'h', 'S', 't', 'a', 't', 'u', 's', '\022', '\013', '\n', '\007', 'U', 'N', 'K', 'N', 'O', 
+'W', 'N', '\020', '\000', '\022', '\013', '\n', '\007', 'H', 'E', 'A', 'L', 'T', 'H', 'Y', '\020', '\001', '\022', '\r', '\n', '\t', 'U', 'N', 'H', 'E', 
+'A', 'L', 'T', 'H', 'Y', '\020', '\002', '\022', '\014', '\n', '\010', 'D', 'R', 'A', 'I', 'N', 'I', 'N', 'G', '\020', '\003', '\022', '\013', '\n', '\007', 
+'T', 'I', 'M', 'E', 'O', 'U', 'T', '\020', '\004', '\022', '\014', '\n', '\010', 'D', 'E', 'G', 'R', 'A', 'D', 'E', 'D', '\020', '\005', 'B', '@', 
+'\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\020', 'H', 'e', 'a', 'l', 't', 'h', 'C', 'h', 'e', 'c', 'k', 'P', 
+'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[14] = {
+static upb_def_init *deps[13] = {
   &envoy_config_core_v3_base_proto_upbdefinit,
   &envoy_config_core_v3_event_service_config_proto_upbdefinit,
   &envoy_type_matcher_v3_string_proto_upbdefinit,
@@ -218,7 +219,6 @@
   &google_protobuf_duration_proto_upbdefinit,
   &google_protobuf_struct_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
-  &envoy_annotations_deprecation_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
   &validate_validate_proto_upbdefinit,
@@ -229,5 +229,5 @@
   deps,
   layouts,
   "envoy/config/core/v3/health_check.proto",
-  UPB_STRVIEW_INIT(descriptor, 4084)
+  UPB_STRVIEW_INIT(descriptor, 4147)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/protocol.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/protocol.upbdefs.c
index 0a3b829..0f1096b 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/protocol.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/protocol.upbdefs.c
@@ -25,8 +25,9 @@
 extern const upb_msglayout envoy_config_core_v3_Http2ProtocolOptions_msginit;
 extern const upb_msglayout envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter_msginit;
 extern const upb_msglayout envoy_config_core_v3_GrpcProtocolOptions_msginit;
+extern const upb_msglayout envoy_config_core_v3_Http3ProtocolOptions_msginit;
 
-static const upb_msglayout *layouts[10] = {
+static const upb_msglayout *layouts[11] = {
   &envoy_config_core_v3_TcpProtocolOptions_msginit,
   &envoy_config_core_v3_UpstreamHttpProtocolOptions_msginit,
   &envoy_config_core_v3_HttpProtocolOptions_msginit,
@@ -37,9 +38,10 @@
   &envoy_config_core_v3_Http2ProtocolOptions_msginit,
   &envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter_msginit,
   &envoy_config_core_v3_GrpcProtocolOptions_msginit,
+  &envoy_config_core_v3_Http3ProtocolOptions_msginit,
 };
 
-static const char descriptor[4205] = {'\n', '#', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'p', 'r', 
+static const char descriptor[4229] = {'\n', '#', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'p', 'r', 
 'o', 't', 'o', 'c', 'o', 'l', '.', 'p', 'r', 'o', 't', 'o', '\022', '\024', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', '\033', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'v', '3', '/', 
 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 
@@ -204,10 +206,11 @@
 '2', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\024', 'h', 't', 't', 'p', '2', 'P', 'r', 
 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', ':', ',', '\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 
 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'c', 'o', 'r', 'e', '.', 'G', 'r', 'p', 'c', 'P', 'r', 'o', 't', 'o', 'c', 
-'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'B', '=', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 
-'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\r', 'P', 
-'r', 'o', 't', 'o', 'c', 'o', 'l', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 
-'r', 'o', 't', 'o', '3', 
+'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\"', '\026', '\n', '\024', 'H', 't', 't', 'p', '3', 'P', 'r', 'o', 't', 'o', 'c', 'o', 
+'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'B', '=', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\r', 'P', 'r', 
+'o', 't', 'o', 'c', 'o', 'l', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 
+'o', 't', 'o', '3', 
 };
 
 static upb_def_init *deps[7] = {
@@ -224,5 +227,5 @@
   deps,
   layouts,
   "envoy/config/core/v3/protocol.proto",
-  UPB_STRVIEW_INIT(descriptor, 4205)
+  UPB_STRVIEW_INIT(descriptor, 4229)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/protocol.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/protocol.upbdefs.h
index 61be0ed..ddc5457 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/protocol.upbdefs.h
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/protocol.upbdefs.h
@@ -71,6 +71,11 @@
   return upb_symtab_lookupmsg(s, "envoy.config.core.v3.GrpcProtocolOptions");
 }
 
+UPB_INLINE const upb_msgdef *envoy_config_core_v3_Http3ProtocolOptions_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_core_v3_protocol_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.core.v3.Http3ProtocolOptions");
+}
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/proxy_protocol.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/proxy_protocol.upbdefs.c
index 72d27a8..f1c19dc 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/proxy_protocol.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/proxy_protocol.upbdefs.c
@@ -10,18 +10,16 @@
 #include "envoy/config/core/v3/proxy_protocol.upbdefs.h"
 
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
 extern const upb_msglayout envoy_config_core_v3_ProxyProtocolConfig_msginit;
 
 static const upb_msglayout *layouts[1] = {
   &envoy_config_core_v3_ProxyProtocolConfig_msginit,
 };
 
-static const char descriptor[324] = {'\n', ')', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'p', 'r', 
+static const char descriptor[299] = {'\n', ')', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'p', 'r', 
 'o', 'x', 'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '.', 'p', 'r', 'o', 't', 'o', '\022', '\024', 'e', 'n', 'v', 'o', 'y', 
 '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 
-'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 
-'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '}', '\n', '\023', 
+'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\"', '}', '\n', '\023', 
 'P', 'r', 'o', 'x', 'y', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'K', '\n', '\007', 'v', 'e', 
 'r', 's', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\016', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'P', 'r', 'o', 'x', 'y', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'C', 'o', 
@@ -32,9 +30,8 @@
 'l', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[3] = {
+static upb_def_init *deps[2] = {
   &udpa_annotations_status_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
   NULL
 };
 
@@ -42,5 +39,5 @@
   deps,
   layouts,
   "envoy/config/core/v3/proxy_protocol.proto",
-  UPB_STRVIEW_INIT(descriptor, 324)
+  UPB_STRVIEW_INIT(descriptor, 299)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/substitution_format_string.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/substitution_format_string.upbdefs.c
index 3d4a59a..82062b6 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/substitution_format_string.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/core/v3/substitution_format_string.upbdefs.c
@@ -9,6 +9,8 @@
 #include "upb/def.h"
 #include "envoy/config/core/v3/substitution_format_string.upbdefs.h"
 
+extern upb_def_init envoy_config_core_v3_base_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_extension_proto_upbdefinit;
 extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init validate_validate_proto_upbdefinit;
@@ -18,29 +20,40 @@
   &envoy_config_core_v3_SubstitutionFormatString_msginit,
 };
 
-static const char descriptor[487] = {'\n', '5', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 's', 'u', 
+static const char descriptor[711] = {'\n', '5', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 's', 'u', 
 'b', 's', 't', 'i', 't', 'u', 't', 'i', 'o', 'n', '_', 'f', 'o', 'r', 'm', 'a', 't', '_', 's', 't', 'r', 'i', 'n', 'g', '.', 
 'p', 'r', 'o', 't', 'o', '\022', '\024', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
-'v', '3', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 
-'t', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', 
-'/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 
-'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\352', '\001', '\n', '\030', 'S', 'u', 'b', 's', 't', 'i', 't', 
-'u', 't', 'i', 'o', 'n', 'F', 'o', 'r', 'm', 'a', 't', 'S', 't', 'r', 'i', 'n', 'g', '\022', '*', '\n', '\013', 't', 'e', 'x', 't', 
-'_', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', 
-'\n', 't', 'e', 'x', 't', 'F', 'o', 'r', 'm', 'a', 't', '\022', 'D', '\n', '\013', 'j', 's', 'o', 'n', '_', 'f', 'o', 'r', 'm', 'a', 
-'t', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
-'.', 'S', 't', 'r', 'u', 'c', 't', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'H', '\000', 'R', '\n', 'j', 's', 'o', 'n', 
-'F', 'o', 'r', 'm', 'a', 't', '\022', '*', '\n', '\021', 'o', 'm', 'i', 't', '_', 'e', 'm', 'p', 't', 'y', '_', 'v', 'a', 'l', 'u', 
-'e', 's', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\017', 'o', 'm', 'i', 't', 'E', 'm', 'p', 't', 'y', 'V', 'a', 'l', 'u', 'e', 's', 
-'\022', '!', '\n', '\014', 'c', 'o', 'n', 't', 'e', 'n', 't', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\013', 'c', 
-'o', 'n', 't', 'e', 'n', 't', 'T', 'y', 'p', 'e', 'B', '\r', '\n', '\006', 'f', 'o', 'r', 'm', 'a', 't', '\022', '\003', '\370', 'B', '\001', 
-'B', 'M', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\035', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 'i', 
-'o', 'n', 'F', 'o', 'r', 'm', 'a', 't', 'S', 't', 'r', 'i', 'n', 'g', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', 
-'\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'v', '3', '\032', '\037', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 
+'b', 'a', 's', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '$', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 
+'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 
+'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 
+'t', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 
+'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\203', '\003', '\n', '\030', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 'i', 'o', 
+'n', 'F', 'o', 'r', 'm', 'a', 't', 'S', 't', 'r', 'i', 'n', 'g', '\022', '%', '\n', '\013', 't', 'e', 'x', 't', '_', 'f', 'o', 'r', 
+'m', 'a', 't', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\002', '\030', '\001', 'H', '\000', 'R', '\n', 't', 'e', 'x', 't', 'F', 'o', 'r', 'm', 
+'a', 't', '\022', 'D', '\n', '\013', 'j', 's', 'o', 'n', '_', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', 
+'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'B', '\010', 
+'\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'H', '\000', 'R', '\n', 'j', 's', 'o', 'n', 'F', 'o', 'r', 'm', 'a', 't', '\022', 'P', '\n', 
+'\022', 't', 'e', 'x', 't', '_', 'f', 'o', 'r', 'm', 'a', 't', '_', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\005', ' ', '\001', '(', '\013', 
+'2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 
+'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\020', 't', 'e', 'x', 't', 'F', 'o', 'r', 'm', 'a', 't', 'S', 'o', 
+'u', 'r', 'c', 'e', '\022', '*', '\n', '\021', 'o', 'm', 'i', 't', '_', 'e', 'm', 'p', 't', 'y', '_', 'v', 'a', 'l', 'u', 'e', 's', 
+'\030', '\003', ' ', '\001', '(', '\010', 'R', '\017', 'o', 'm', 'i', 't', 'E', 'm', 'p', 't', 'y', 'V', 'a', 'l', 'u', 'e', 's', '\022', '!', 
+'\n', '\014', 'c', 'o', 'n', 't', 'e', 'n', 't', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\013', 'c', 'o', 'n', 
+'t', 'e', 'n', 't', 'T', 'y', 'p', 'e', '\022', 'J', '\n', '\n', 'f', 'o', 'r', 'm', 'a', 't', 't', 'e', 'r', 's', '\030', '\006', ' ', 
+'\003', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
+'3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\n', 'f', 
+'o', 'r', 'm', 'a', 't', 't', 'e', 'r', 's', 'B', '\r', '\n', '\006', 'f', 'o', 'r', 'm', 'a', 't', '\022', '\003', '\370', 'B', '\001', 'B', 
+'M', '\n', '\"', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\035', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 'i', 'o', 
+'n', 'F', 'o', 'r', 'm', 'a', 't', 'S', 't', 'r', 'i', 'n', 'g', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', 
+'\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[4] = {
+static upb_def_init *deps[6] = {
+  &envoy_config_core_v3_base_proto_upbdefinit,
+  &envoy_config_core_v3_extension_proto_upbdefinit,
   &google_protobuf_struct_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &validate_validate_proto_upbdefinit,
@@ -51,5 +64,5 @@
   deps,
   layouts,
   "envoy/config/core/v3/substitution_format_string.proto",
-  UPB_STRVIEW_INIT(descriptor, 487)
+  UPB_STRVIEW_INIT(descriptor, 711)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/endpoint/v3/endpoint.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/endpoint/v3/endpoint.upbdefs.c
index 9c1247c..a140da4 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/endpoint/v3/endpoint.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/endpoint/v3/endpoint.upbdefs.c
@@ -11,7 +11,6 @@
 
 extern upb_def_init envoy_config_endpoint_v3_endpoint_components_proto_upbdefinit;
 extern upb_def_init envoy_type_v3_percent_proto_upbdefinit;
-extern upb_def_init google_api_annotations_proto_upbdefinit;
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
@@ -29,71 +28,69 @@
   &envoy_config_endpoint_v3_ClusterLoadAssignment_NamedEndpointsEntry_msginit,
 };
 
-static const char descriptor[1473] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '/', 'v', 
+static const char descriptor[1443] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '/', 'v', 
 '3', '/', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\022', '\030', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', '\032', '2', 'e', 'n', 'v', 'o', 'y', '/', 
 'c', 'o', 'n', 'f', 'i', 'g', '/', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '/', 'v', '3', '/', 'e', 'n', 'd', 'p', 'o', 'i', 
 'n', 't', '_', 'c', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\033', 'e', 'n', 'v', 'o', 
-'y', '/', 't', 'y', 'p', 'e', '/', 'v', '3', '/', 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 
-'g', 'o', 'o', 'g', 'l', 'e', '/', 'a', 'p', 'i', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '.', 'p', 'r', 
-'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 
-'t', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 
-'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 
-'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 
-'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 
-'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 
-'t', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\246', '\010', '\n', '\025', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 
-'s', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', '\022', '*', '\n', '\014', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'n', 'a', 'm', 'e', 
-'\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\013', 'c', 'l', 'u', 's', 't', 'e', 'r', 'N', 
-'a', 'm', 'e', '\022', 'K', '\n', '\t', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '-', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', '.', 
-'L', 'o', 'c', 'a', 'l', 'i', 't', 'y', 'L', 'b', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'R', '\t', 'e', 'n', 'd', 'p', 
-'o', 'i', 'n', 't', 's', '\022', 'l', '\n', '\017', 'n', 'a', 'm', 'e', 'd', '_', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\030', 
-'\005', ' ', '\003', '(', '\013', '2', 'C', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 
-'o', 'i', 'n', 't', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 
-'m', 'e', 'n', 't', '.', 'N', 'a', 'm', 'e', 'd', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'E', 'n', 't', 'r', 'y', 'R', 
-'\016', 'n', 'a', 'm', 'e', 'd', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\022', 'N', '\n', '\006', 'p', 'o', 'l', 'i', 'c', 'y', 
-'\030', '\004', ' ', '\001', '(', '\013', '2', '6', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 
-'p', 'o', 'i', 'n', 't', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 
-'n', 'm', 'e', 'n', 't', '.', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\006', 'p', 'o', 'l', 'i', 'c', 'y', '\032', '\303', '\004', '\n', '\006', 
-'P', 'o', 'l', 'i', 'c', 'y', '\022', 'j', '\n', '\016', 'd', 'r', 'o', 'p', '_', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 's', '\030', 
-'\002', ' ', '\003', '(', '\013', '2', 'C', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 
-'o', 'i', 'n', 't', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 
-'m', 'e', 'n', 't', '.', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'D', 'r', 'o', 'p', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'R', 
-'\r', 'd', 'r', 'o', 'p', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 's', '\022', '^', '\n', '\027', 'o', 'v', 'e', 'r', 'p', 'r', 'o', 
-'v', 'i', 's', 'i', 'o', 'n', 'i', 'n', 'g', '_', 'f', 'a', 'c', 't', 'o', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', '\034', '.', 
-'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 
-'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', ' ', '\000', 'R', '\026', 'o', 'v', 'e', 'r', 'p', 'r', 'o', 'v', 'i', 's', 'i', 'o', 
-'n', 'i', 'n', 'g', 'F', 'a', 'c', 't', 'o', 'r', '\022', 'U', '\n', '\024', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '_', 's', 't', 
-'a', 'l', 'e', '_', 'a', 'f', 't', 'e', 'r', '\030', '\004', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
-'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', 
-'*', '\000', 'R', '\022', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'S', 't', 'a', 'l', 'e', 'A', 'f', 't', 'e', 'r', '\032', '\275', '\001', 
-'\n', '\014', 'D', 'r', 'o', 'p', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '\022', '#', '\n', '\010', 'c', 'a', 't', 'e', 'g', 'o', 'r', 
-'y', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\010', 'c', 'a', 't', 'e', 'g', 'o', 'r', 
-'y', '\022', 'I', '\n', '\017', 'd', 'r', 'o', 'p', '_', 'p', 'e', 'r', 'c', 'e', 'n', 't', 'a', 'g', 'e', '\030', '\002', ' ', '\001', '(', 
-'\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 
-'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'd', 'r', 'o', 'p', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'a', 'g', 
-'e', ':', '=', '\232', '\305', '\210', '\036', '8', '\n', '6', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 
-'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', '.', 'P', 'o', 'l', 'i', 'c', 
-'y', '.', 'D', 'r', 'o', 'p', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', ':', '0', '\232', '\305', '\210', '\036', '+', '\n', ')', 'e', 'n', 
-'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 
-'i', 'g', 'n', 'm', 'e', 'n', 't', '.', 'P', 'o', 'l', 'i', 'c', 'y', 'J', '\004', '\010', '\001', '\020', '\002', 'J', '\004', '\010', '\005', '\020', 
-'\006', 'R', '\030', 'd', 'i', 's', 'a', 'b', 'l', 'e', '_', 'o', 'v', 'e', 'r', 'p', 'r', 'o', 'v', 'i', 's', 'i', 'o', 'n', 'i', 
-'n', 'g', '\032', 'e', '\n', '\023', 'N', 'a', 'm', 'e', 'd', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'E', 'n', 't', 'r', 'y', 
-'\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '8', '\n', '\005', 'v', 'a', 'l', 
-'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 
-'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', '.', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'R', '\005', 'v', 'a', 'l', 'u', 
-'e', ':', '\002', '8', '\001', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', 
-'2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', 'B', 'A', 
-'\n', '&', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', 'B', '\r', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 
-'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'y', '/', 't', 'y', 'p', 'e', '/', 'v', '3', '/', 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 
+'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 
+'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 
+'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 
+'t', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 
+'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 
+'o', 't', 'o', '\"', '\246', '\010', '\n', '\025', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 
+'m', 'e', 'n', 't', '\022', '*', '\n', '\014', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', 
+'\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\013', 'c', 'l', 'u', 's', 't', 'e', 'r', 'N', 'a', 'm', 'e', '\022', 'K', 
+'\n', '\t', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '-', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', '.', 'L', 'o', 'c', 'a', 'l', 
+'i', 't', 'y', 'L', 'b', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'R', '\t', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 
+'\022', 'l', '\n', '\017', 'n', 'a', 'm', 'e', 'd', '_', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\030', '\005', ' ', '\003', '(', '\013', 
+'2', 'C', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 
+'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', '.', 
+'N', 'a', 'm', 'e', 'd', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'E', 'n', 't', 'r', 'y', 'R', '\016', 'n', 'a', 'm', 'e', 
+'d', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\022', 'N', '\n', '\006', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\004', ' ', '\001', '(', 
+'\013', '2', '6', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 
+'.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', 
+'.', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\006', 'p', 'o', 'l', 'i', 'c', 'y', '\032', '\303', '\004', '\n', '\006', 'P', 'o', 'l', 'i', 'c', 
+'y', '\022', 'j', '\n', '\016', 'd', 'r', 'o', 'p', '_', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 's', '\030', '\002', ' ', '\003', '(', '\013', 
+'2', 'C', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 
+'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', '.', 
+'P', 'o', 'l', 'i', 'c', 'y', '.', 'D', 'r', 'o', 'p', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'R', '\r', 'd', 'r', 'o', 'p', 
+'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 's', '\022', '^', '\n', '\027', 'o', 'v', 'e', 'r', 'p', 'r', 'o', 'v', 'i', 's', 'i', 'o', 
+'n', 'i', 'n', 'g', '_', 'f', 'a', 'c', 't', 'o', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 
+'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 
+'B', '\004', '*', '\002', ' ', '\000', 'R', '\026', 'o', 'v', 'e', 'r', 'p', 'r', 'o', 'v', 'i', 's', 'i', 'o', 'n', 'i', 'n', 'g', 'F', 
+'a', 'c', 't', 'o', 'r', '\022', 'U', '\n', '\024', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '_', 's', 't', 'a', 'l', 'e', '_', 'a', 
+'f', 't', 'e', 'r', '\030', '\004', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
+'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\022', 'e', 
+'n', 'd', 'p', 'o', 'i', 'n', 't', 'S', 't', 'a', 'l', 'e', 'A', 'f', 't', 'e', 'r', '\032', '\275', '\001', '\n', '\014', 'D', 'r', 'o', 
+'p', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '\022', '#', '\n', '\010', 'c', 'a', 't', 'e', 'g', 'o', 'r', 'y', '\030', '\001', ' ', '\001', 
+'(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\010', 'c', 'a', 't', 'e', 'g', 'o', 'r', 'y', '\022', 'I', '\n', '\017', 
+'d', 'r', 'o', 'p', '_', 'p', 'e', 'r', 'c', 'e', 'n', 't', 'a', 'g', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 
+'r', 'c', 'e', 'n', 't', 'R', '\016', 'd', 'r', 'o', 'p', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'a', 'g', 'e', ':', '=', '\232', '\305', 
+'\210', '\036', '8', '\n', '6', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 
+'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', '.', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'D', 'r', 'o', 
+'p', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', ':', '0', '\232', '\305', '\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
+'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 
+'n', 't', '.', 'P', 'o', 'l', 'i', 'c', 'y', 'J', '\004', '\010', '\001', '\020', '\002', 'J', '\004', '\010', '\005', '\020', '\006', 'R', '\030', 'd', 'i', 
+'s', 'a', 'b', 'l', 'e', '_', 'o', 'v', 'e', 'r', 'p', 'r', 'o', 'v', 'i', 's', 'i', 'o', 'n', 'i', 'n', 'g', '\032', 'e', '\n', 
+'\023', 'N', 'a', 'm', 'e', 'd', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 
+'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '8', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', 
+'\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 
+'n', 't', '.', 'v', '3', '.', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', 
+':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'C', 'l', 'u', 
+'s', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', 'B', 'A', '\n', '&', 'i', 'o', '.', 
+'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 
+'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', 'B', '\r', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'P', 'r', 'o', 't', 'o', 
+'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[9] = {
+static upb_def_init *deps[8] = {
   &envoy_config_endpoint_v3_endpoint_components_proto_upbdefinit,
   &envoy_type_v3_percent_proto_upbdefinit,
-  &google_api_annotations_proto_upbdefinit,
   &google_protobuf_duration_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
@@ -106,5 +103,5 @@
   deps,
   layouts,
   "envoy/config/endpoint/v3/endpoint.proto",
-  UPB_STRVIEW_INIT(descriptor, 1473)
+  UPB_STRVIEW_INIT(descriptor, 1443)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c
index 9ab5e14..f1d684a 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener.upbdefs.c
@@ -17,10 +17,9 @@
 extern upb_def_init envoy_config_listener_v3_api_listener_proto_upbdefinit;
 extern upb_def_init envoy_config_listener_v3_listener_components_proto_upbdefinit;
 extern upb_def_init envoy_config_listener_v3_udp_listener_config_proto_upbdefinit;
-extern upb_def_init google_api_annotations_proto_upbdefinit;
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_collection_entry_proto_upbdefinit;
+extern upb_def_init xds_core_v3_collection_entry_proto_upbdefinit;
 extern upb_def_init udpa_annotations_security_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
@@ -39,7 +38,7 @@
   &envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance_msginit,
 };
 
-static const char descriptor[3016] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 'v', 
+static const char descriptor[3185] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 'v', 
 '3', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\030', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '\032', ')', 'e', 'n', 'v', 'o', 'y', '/', 
 'c', 'o', 'n', 'f', 'i', 'g', '/', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '/', 'v', '3', '/', 'a', 'c', 'c', 'e', 's', 
@@ -55,114 +54,121 @@
 'e', 'r', '/', 'v', '3', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'c', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', 
 '.', 'p', 'r', 'o', 't', 'o', '\032', '2', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'l', 'i', 's', 't', 
 'e', 'n', 'e', 'r', '/', 'v', '3', '/', 'u', 'd', 'p', '_', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'a', 'p', 'i', '/', 'a', 'n', 'n', 'o', 
-'t', 'a', 't', 'i', 'o', 'n', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 
-'t', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 
-'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'c', 'o', 'l', 'l', 'e', 'c', 't', 'i', 
-'o', 'n', '_', 'e', 'n', 't', 'r', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 
-'t', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 'e', 'c', 'u', 'r', 'i', 't', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 
-'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 
-'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 
-'s', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 
-'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', 'M', '\n', '\022', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 
-'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', '\022', '7', '\n', '\007', 'e', 'n', 't', 'r', 'i', 'e', 's', '\030', '\001', ' ', '\003', 
-'(', '\013', '2', '\035', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'C', 'o', 'l', 'l', 'e', 'c', 't', 
-'i', 'o', 'n', 'E', 'n', 't', 'r', 'y', 'R', '\007', 'e', 'n', 't', 'r', 'i', 'e', 's', '\"', '\224', '\021', '\n', '\010', 'L', 'i', 's', 
-'t', 'e', 'n', 'e', 'r', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', 
-'\022', 'A', '\n', '\007', 'a', 'd', 'd', 'r', 'e', 's', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'd', 'd', 'r', 'e', 's', 's', 'B', '\010', 
-'\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\007', 'a', 'd', 'd', 'r', 'e', 's', 's', '\022', 'J', '\n', '\r', 'f', 'i', 'l', 't', 
-'e', 'r', '_', 'c', 'h', 'a', 'i', 'n', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 
-'h', 'a', 'i', 'n', 'R', '\014', 'f', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 's', '\022', 'o', '\n', '!', 'p', 'e', 'r', 
-'_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'b', 'u', 'f', 'f', 'e', 'r', '_', 'l', 'i', 'm', 'i', 't', '_', 
-'b', 'y', 't', 'e', 's', '\030', '\005', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
-'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\212', '\223', '\267', '*', '\002', '\010', '\001', 
-'R', '\035', 'p', 'e', 'r', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'u', 'f', 'f', 'e', 'r', 'L', 'i', 'm', 'i', 
-'t', 'B', 'y', 't', 'e', 's', '\022', ':', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\006', ' ', '\001', '(', '\013', '2', 
-'\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 
-'t', 'a', 'd', 'a', 't', 'a', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', 'T', '\n', '\r', 'd', 'e', 'p', 'r', 'e', 
-'c', 'a', 't', 'e', 'd', '_', 'v', '1', '\030', '\007', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 
-'.', 'D', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', 'V', '1', 'R', '\014', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', 
-'V', '1', '\022', 'K', '\n', '\n', 'd', 'r', 'a', 'i', 'n', '_', 't', 'y', 'p', 'e', '\030', '\010', ' ', '\001', '(', '\016', '2', ',', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 
-'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'D', 'r', 'a', 'i', 'n', 'T', 'y', 'p', 'e', 'R', '\t', 'd', 'r', 'a', 'i', 'n', 
-'T', 'y', 'p', 'e', '\022', 'S', '\n', '\020', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', 's', '\030', 
-'\t', ' ', '\003', '(', '\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 
-'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\017', 'l', 
-'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 's', '\022', 'S', '\n', '\030', 'l', 'i', 's', 't', 'e', 'n', 'e', 
-'r', '_', 'f', 'i', 'l', 't', 'e', 'r', 's', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\017', ' ', '\001', '(', '\013', '2', '\031', 
-'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 
-'R', '\026', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 's', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 
-'N', '\n', '$', 'c', 'o', 'n', 't', 'i', 'n', 'u', 'e', '_', 'o', 'n', '_', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'f', 
-'i', 'l', 't', 'e', 'r', 's', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\021', ' ', '\001', '(', '\010', 'R', ' ', 'c', 'o', 'n', 
-'t', 'i', 'n', 'u', 'e', 'O', 'n', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 's', 'T', 'i', 'm', 
-'e', 'o', 'u', 't', '\022', '<', '\n', '\013', 't', 'r', 'a', 'n', 's', 'p', 'a', 'r', 'e', 'n', 't', '\030', '\n', ' ', '\001', '(', '\013', 
-'2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 
-'l', 'u', 'e', 'R', '\013', 't', 'r', 'a', 'n', 's', 'p', 'a', 'r', 'e', 'n', 't', '\022', '6', '\n', '\010', 'f', 'r', 'e', 'e', 'b', 
-'i', 'n', 'd', '\030', '\013', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
-'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\010', 'f', 'r', 'e', 'e', 'b', 'i', 'n', 'd', '\022', 'I', '\n', 
-'\016', 's', 'o', 'c', 'k', 'e', 't', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\r', ' ', '\003', '(', '\013', '2', '\"', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'S', 'o', 'c', 'k', 'e', 
-'t', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\r', 's', 'o', 'c', 'k', 'e', 't', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'X', '\n', 
-'\032', 't', 'c', 'p', '_', 'f', 'a', 's', 't', '_', 'o', 'p', 'e', 'n', '_', 'q', 'u', 'e', 'u', 'e', '_', 'l', 'e', 'n', 'g', 
-'t', 'h', '\030', '\014', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
-'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\026', 't', 'c', 'p', 'F', 'a', 's', 't', 'O', 'p', 'e', 
-'n', 'Q', 'u', 'e', 'u', 'e', 'L', 'e', 'n', 'g', 't', 'h', '\022', 'S', '\n', '\021', 't', 'r', 'a', 'f', 'f', 'i', 'c', '_', 'd', 
-'i', 'r', 'e', 'c', 't', 'i', 'o', 'n', '\030', '\020', ' ', '\001', '(', '\016', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'f', 'f', 'i', 'c', 'D', 'i', 'r', 'e', 'c', 
-'t', 'i', 'o', 'n', 'R', '\020', 't', 'r', 'a', 'f', 'f', 'i', 'c', 'D', 'i', 'r', 'e', 'c', 't', 'i', 'o', 'n', '\022', '[', '\n', 
-'\023', 'u', 'd', 'p', '_', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\022', ' ', '\001', '(', 
-'\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 
-'.', 'v', '3', '.', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\021', 'u', 'd', 
-'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'H', '\n', '\014', 'a', 'p', 'i', '_', 'l', 'i', 
-'s', 't', 'e', 'n', 'e', 'r', '\030', '\023', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'A', 'p', 'i', 'L', 'i', 's', 't', 'e', 'n', 'e', 
-'r', 'R', '\013', 'a', 'p', 'i', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '\022', 'v', '\n', '\031', 'c', 'o', 'n', 'n', 'e', 'c', 't', 
-'i', 'o', 'n', '_', 'b', 'a', 'l', 'a', 'n', 'c', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\024', ' ', '\001', '(', '\013', '2', 
-':', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', 
-'3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'a', 'l', 'a', 
-'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\027', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'a', 'l', 'a', 
-'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '\035', '\n', '\n', 'r', 'e', 'u', 's', 'e', '_', 'p', 'o', 'r', 't', '\030', '\025', 
-' ', '\001', '(', '\010', 'R', '\t', 'r', 'e', 'u', 's', 'e', 'P', 'o', 'r', 't', '\022', 'C', '\n', '\n', 'a', 'c', 'c', 'e', 's', 's', 
-'_', 'l', 'o', 'g', '\030', '\026', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'R', '\t', 
-'a', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', '\022', 'V', '\n', '\021', 'u', 'd', 'p', '_', 'w', 'r', 'i', 't', 'e', 'r', '_', 'c', 
-'o', 'n', 'f', 'i', 'g', '\030', '\027', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 
-'o', 'n', 'f', 'i', 'g', 'R', '\017', 'u', 'd', 'p', 'W', 'r', 'i', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'F', '\n', 
-'\020', 't', 'c', 'p', '_', 'b', 'a', 'c', 'k', 'l', 'o', 'g', '_', 's', 'i', 'z', 'e', '\030', '\030', ' ', '\001', '(', '\013', '2', '\034', 
-'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 
-'l', 'u', 'e', 'R', '\016', 't', 'c', 'p', 'B', 'a', 'c', 'k', 'l', 'o', 'g', 'S', 'i', 'z', 'e', '\032', 'w', '\n', '\014', 'D', 'e', 
-'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', 'V', '1', '\022', '<', '\n', '\014', 'b', 'i', 'n', 'd', '_', 't', 'o', '_', 'p', 'o', 'r', 
-'t', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
-'.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\n', 'b', 'i', 'n', 'd', 'T', 'o', 'P', 'o', 'r', 't', ':', ')', '\232', 
-'\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'i', 's', 't', 'e', 'n', 
-'e', 'r', '.', 'D', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', 'V', '1', '\032', '\247', '\002', '\n', '\027', 'C', 'o', 'n', 'n', 'e', 
-'c', 't', 'i', 'o', 'n', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'n', '\n', '\r', 'e', 'x', 'a', 
-'c', 't', '_', 'b', 'a', 'l', 'a', 'n', 'c', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'i', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
+'/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 
+'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\"', 'x', 
+'d', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'c', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', '_', 'e', 'n', 't', 
+'r', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 
+'s', '/', 's', 'e', 'c', 'u', 'r', 'i', 't', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 
+'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 
+'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 
+'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 
+'e', '.', 'p', 'r', 'o', 't', 'o', '\"', 'L', '\n', '\022', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'l', 'l', 'e', 'c', 
+'t', 'i', 'o', 'n', '\022', '6', '\n', '\007', 'e', 'n', 't', 'r', 'i', 'e', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '\034', '.', 'x', 
+'d', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 't', 'r', 
+'y', 'R', '\007', 'e', 'n', 't', 'r', 'i', 'e', 's', '\"', '\335', '\022', '\n', '\010', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '\022', '\022', 
+'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'A', '\n', '\007', 'a', 'd', 'd', 
+'r', 'e', 's', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'd', 'd', 'r', 'e', 's', 's', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', 
+'\001', 'R', '\007', 'a', 'd', 'd', 'r', 'e', 's', 's', '\022', 'J', '\n', '\r', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'h', 'a', 'i', 
+'n', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 
+'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'R', '\014', 'f', 
+'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 's', '\022', 'D', '\n', '\020', 'u', 's', 'e', '_', 'o', 'r', 'i', 'g', 'i', 'n', 
+'a', 'l', '_', 'd', 's', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\016', 'u', 's', 'e', 'O', 'r', 'i', 'g', 'i', 
+'n', 'a', 'l', 'D', 's', 't', '\022', 'W', '\n', '\024', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'f', 'i', 'l', 't', 'e', 'r', '_', 
+'c', 'h', 'a', 'i', 'n', '\030', '\031', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 
+'R', '\022', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', '\022', 'o', '\n', '!', 'p', 
+'e', 'r', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'b', 'u', 'f', 'f', 'e', 'r', '_', 'l', 'i', 'm', 'i', 
+'t', '_', 'b', 'y', 't', 'e', 's', '\030', '\005', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\212', '\223', '\267', '*', '\002', 
+'\010', '\001', 'R', '\035', 'p', 'e', 'r', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'u', 'f', 'f', 'e', 'r', 'L', 'i', 
+'m', 'i', 't', 'B', 'y', 't', 'e', 's', '\022', ':', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\006', ' ', '\001', '(', 
+'\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
+'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', 'X', '\n', '\r', 'd', 'e', 'p', 
+'r', 'e', 'c', 'a', 't', 'e', 'd', '_', 'v', '1', '\030', '\007', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 
 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 
-'e', 'r', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 
-'g', '.', 'E', 'x', 'a', 'c', 't', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'H', '\000', 'R', '\014', 'e', 'x', 'a', 'c', 't', 'B', 'a', 
-'l', 'a', 'n', 'c', 'e', '\032', 'Q', '\n', '\014', 'E', 'x', 'a', 'c', 't', 'B', 'a', 'l', 'a', 'n', 'c', 'e', ':', 'A', '\232', '\305', 
-'\210', '\036', '<', '\n', ':', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 
-'r', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 
-'.', 'E', 'x', 'a', 'c', 't', 'B', 'a', 'l', 'a', 'n', 'c', 'e', ':', '4', '\232', '\305', '\210', '\036', '/', '\n', '-', 'e', 'n', 'v', 
-'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'C', 'o', 'n', 'n', 'e', 'c', 
-'t', 'i', 'o', 'n', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'B', '\023', '\n', '\014', 'b', 'a', 'l', 'a', 
-'n', 'c', 'e', '_', 't', 'y', 'p', 'e', '\022', '\003', '\370', 'B', '\001', '\"', ')', '\n', '\t', 'D', 'r', 'a', 'i', 'n', 'T', 'y', 'p', 
-'e', '\022', '\013', '\n', '\007', 'D', 'E', 'F', 'A', 'U', 'L', 'T', '\020', '\000', '\022', '\017', '\n', '\013', 'M', 'O', 'D', 'I', 'F', 'Y', '_', 
-'O', 'N', 'L', 'Y', '\020', '\001', ':', '\034', '\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 
-'v', '2', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'J', '\004', '\010', '\016', '\020', '\017', 'J', '\004', '\010', '\004', '\020', '\005', 'R', '\020', 
-'u', 's', 'e', '_', 'o', 'r', 'i', 'g', 'i', 'n', 'a', 'l', '_', 'd', 's', 't', 'B', 'A', '\n', '&', 'i', 'o', '.', 'e', 'n', 
-'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 
-'t', 'e', 'n', 'e', 'r', '.', 'v', '3', 'B', '\r', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', 
-'\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'e', 'r', '.', 'D', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', 'V', '1', 'B', '\002', '\030', '\001', 'R', '\014', 'd', 'e', 'p', 'r', 
+'e', 'c', 'a', 't', 'e', 'd', 'V', '1', '\022', 'K', '\n', '\n', 'd', 'r', 'a', 'i', 'n', '_', 't', 'y', 'p', 'e', '\030', '\010', ' ', 
+'\001', '(', '\016', '2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 
+'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'D', 'r', 'a', 'i', 'n', 'T', 'y', 'p', 'e', 'R', 
+'\t', 'd', 'r', 'a', 'i', 'n', 'T', 'y', 'p', 'e', '\022', 'S', '\n', '\020', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'f', 'i', 
+'l', 't', 'e', 'r', 's', '\030', '\t', ' ', '\003', '(', '\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 
+'t', 'e', 'r', 'R', '\017', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 's', '\022', 'S', '\n', '\030', 'l', 
+'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', 's', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\017', 
+' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 
+'r', 'a', 't', 'i', 'o', 'n', 'R', '\026', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 's', 'T', 'i', 
+'m', 'e', 'o', 'u', 't', '\022', 'N', '\n', '$', 'c', 'o', 'n', 't', 'i', 'n', 'u', 'e', '_', 'o', 'n', '_', 'l', 'i', 's', 't', 
+'e', 'n', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', 's', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\021', ' ', '\001', '(', 
+'\010', 'R', ' ', 'c', 'o', 'n', 't', 'i', 'n', 'u', 'e', 'O', 'n', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 
+'e', 'r', 's', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', '<', '\n', '\013', 't', 'r', 'a', 'n', 's', 'p', 'a', 'r', 'e', 'n', 't', 
+'\030', '\n', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
+'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\013', 't', 'r', 'a', 'n', 's', 'p', 'a', 'r', 'e', 'n', 't', '\022', '6', '\n', 
+'\010', 'f', 'r', 'e', 'e', 'b', 'i', 'n', 'd', '\030', '\013', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\010', 'f', 'r', 'e', 'e', 'b', 
+'i', 'n', 'd', '\022', 'I', '\n', '\016', 's', 'o', 'c', 'k', 'e', 't', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\r', ' ', '\003', 
+'(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
+'.', 'S', 'o', 'c', 'k', 'e', 't', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\r', 's', 'o', 'c', 'k', 'e', 't', 'O', 'p', 't', 'i', 
+'o', 'n', 's', '\022', 'X', '\n', '\032', 't', 'c', 'p', '_', 'f', 'a', 's', 't', '_', 'o', 'p', 'e', 'n', '_', 'q', 'u', 'e', 'u', 
+'e', '_', 'l', 'e', 'n', 'g', 't', 'h', '\030', '\014', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
+'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\026', 't', 'c', 'p', 'F', 
+'a', 's', 't', 'O', 'p', 'e', 'n', 'Q', 'u', 'e', 'u', 'e', 'L', 'e', 'n', 'g', 't', 'h', '\022', 'S', '\n', '\021', 't', 'r', 'a', 
+'f', 'f', 'i', 'c', '_', 'd', 'i', 'r', 'e', 'c', 't', 'i', 'o', 'n', '\030', '\020', ' ', '\001', '(', '\016', '2', '&', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'f', 'f', 'i', 
+'c', 'D', 'i', 'r', 'e', 'c', 't', 'i', 'o', 'n', 'R', '\020', 't', 'r', 'a', 'f', 'f', 'i', 'c', 'D', 'i', 'r', 'e', 'c', 't', 
+'i', 'o', 'n', '\022', '[', '\n', '\023', 'u', 'd', 'p', '_', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 
+'g', '\030', '\022', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 
+'s', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 
+'i', 'g', 'R', '\021', 'u', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'H', '\n', '\014', 
+'a', 'p', 'i', '_', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '\030', '\023', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'A', 'p', 'i', 'L', 
+'i', 's', 't', 'e', 'n', 'e', 'r', 'R', '\013', 'a', 'p', 'i', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '\022', 'v', '\n', '\031', 'c', 
+'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'b', 'a', 'l', 'a', 'n', 'c', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', 
+'\024', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 
+'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
+'o', 'n', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\027', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
+'o', 'n', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '\035', '\n', '\n', 'r', 'e', 'u', 's', 'e', '_', 
+'p', 'o', 'r', 't', '\030', '\025', ' ', '\001', '(', '\010', 'R', '\t', 'r', 'e', 'u', 's', 'e', 'P', 'o', 'r', 't', '\022', 'C', '\n', '\n', 
+'a', 'c', 'c', 'e', 's', 's', '_', 'l', 'o', 'g', '\030', '\026', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 's', 
+'s', 'L', 'o', 'g', 'R', '\t', 'a', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', '\022', 'V', '\n', '\021', 'u', 'd', 'p', '_', 'w', 'r', 
+'i', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\027', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 
+'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\017', 'u', 'd', 'p', 'W', 'r', 'i', 't', 'e', 'r', 'C', 'o', 'n', 
+'f', 'i', 'g', '\022', 'F', '\n', '\020', 't', 'c', 'p', '_', 'b', 'a', 'c', 'k', 'l', 'o', 'g', '_', 's', 'i', 'z', 'e', '\030', '\030', 
+' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 
+'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\016', 't', 'c', 'p', 'B', 'a', 'c', 'k', 'l', 'o', 'g', 'S', 'i', 'z', 'e', 
+'\022', '<', '\n', '\014', 'b', 'i', 'n', 'd', '_', 't', 'o', '_', 'p', 'o', 'r', 't', '\030', '\032', ' ', '\001', '(', '\013', '2', '\032', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 
+'R', '\n', 'b', 'i', 'n', 'd', 'T', 'o', 'P', 'o', 'r', 't', '\032', 'w', '\n', '\014', 'D', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 
+'d', 'V', '1', '\022', '<', '\n', '\014', 'b', 'i', 'n', 'd', '_', 't', 'o', '_', 'p', 'o', 'r', 't', '\030', '\001', ' ', '\001', '(', '\013', 
+'2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 
+'l', 'u', 'e', 'R', '\n', 'b', 'i', 'n', 'd', 'T', 'o', 'P', 'o', 'r', 't', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 
+'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'D', 'e', 'p', 'r', 
+'e', 'c', 'a', 't', 'e', 'd', 'V', '1', '\032', '\247', '\002', '\n', '\027', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'a', 
+'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'n', '\n', '\r', 'e', 'x', 'a', 'c', 't', '_', 'b', 'a', 'l', 'a', 
+'n', 'c', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'C', 'o', 'n', 'n', 
+'e', 'c', 't', 'i', 'o', 'n', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'E', 'x', 'a', 'c', 't', 
+'B', 'a', 'l', 'a', 'n', 'c', 'e', 'H', '\000', 'R', '\014', 'e', 'x', 'a', 'c', 't', 'B', 'a', 'l', 'a', 'n', 'c', 'e', '\032', 'Q', 
+'\n', '\014', 'E', 'x', 'a', 'c', 't', 'B', 'a', 'l', 'a', 'n', 'c', 'e', ':', 'A', '\232', '\305', '\210', '\036', '<', '\n', ':', 'e', 'n', 
+'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'C', 'o', 'n', 'n', 'e', 
+'c', 't', 'i', 'o', 'n', 'B', 'a', 'l', 'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'E', 'x', 'a', 'c', 't', 'B', 
+'a', 'l', 'a', 'n', 'c', 'e', ':', '4', '\232', '\305', '\210', '\036', '/', '\n', '-', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 
+'v', '2', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'B', 'a', 'l', 
+'a', 'n', 'c', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'B', '\023', '\n', '\014', 'b', 'a', 'l', 'a', 'n', 'c', 'e', '_', 't', 'y', 'p', 
+'e', '\022', '\003', '\370', 'B', '\001', '\"', ')', '\n', '\t', 'D', 'r', 'a', 'i', 'n', 'T', 'y', 'p', 'e', '\022', '\013', '\n', '\007', 'D', 'E', 
+'F', 'A', 'U', 'L', 'T', '\020', '\000', '\022', '\017', '\n', '\013', 'M', 'O', 'D', 'I', 'F', 'Y', '_', 'O', 'N', 'L', 'Y', '\020', '\001', ':', 
+'\034', '\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'i', 's', 't', 
+'e', 'n', 'e', 'r', 'J', '\004', '\010', '\016', '\020', '\017', 'B', 'A', '\n', '&', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 
+'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 
+'v', '3', 'B', '\r', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', 
+'\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[17] = {
+static upb_def_init *deps[16] = {
   &envoy_config_accesslog_v3_accesslog_proto_upbdefinit,
   &envoy_config_core_v3_address_proto_upbdefinit,
   &envoy_config_core_v3_base_proto_upbdefinit,
@@ -171,10 +177,9 @@
   &envoy_config_listener_v3_api_listener_proto_upbdefinit,
   &envoy_config_listener_v3_listener_components_proto_upbdefinit,
   &envoy_config_listener_v3_udp_listener_config_proto_upbdefinit,
-  &google_api_annotations_proto_upbdefinit,
   &google_protobuf_duration_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
-  &udpa_core_v1_collection_entry_proto_upbdefinit,
+  &xds_core_v3_collection_entry_proto_upbdefinit,
   &udpa_annotations_security_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
@@ -186,5 +191,5 @@
   deps,
   layouts,
   "envoy/config/listener/v3/listener.proto",
-  UPB_STRVIEW_INIT(descriptor, 3016)
+  UPB_STRVIEW_INIT(descriptor, 3185)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c
index 2ec7304..ffe22ce 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.c
@@ -11,10 +11,10 @@
 
 extern upb_def_init envoy_config_core_v3_address_proto_upbdefinit;
 extern upb_def_init envoy_config_core_v3_base_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_extension_proto_upbdefinit;
 extern upb_def_init envoy_type_v3_range_proto_upbdefinit;
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
-extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
@@ -37,139 +37,147 @@
   &envoy_config_listener_v3_ListenerFilter_msginit,
 };
 
-static const char descriptor[3082] = {'\n', '2', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 'v', 
+static const char descriptor[3284] = {'\n', '2', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 'v', 
 '3', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'c', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', '.', 'p', 'r', 'o', 
 't', 'o', '\022', '\030', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 
 '.', 'v', '3', '\032', '\"', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', 
 '/', 'a', 'd', 'd', 'r', 'e', 's', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 
-'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'e', 
-'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'v', '3', '/', 'r', 'a', 'n', 'g', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', 
-'\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 
-'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 
-'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
-'/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 
-'t', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 
-'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 
-'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 
-'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 
-'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\250', '\001', '\n', '\006', 'F', 'i', 'l', 't', 'e', 'r', '\022', '\033', '\n', 
-'\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 
-'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\004', ' ', '\001', '(', '\013', '2', '\024', 
-'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 
-'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '#', '\232', '\305', '\210', '\036', '\036', '\n', '\034', 'e', 'n', 'v', 'o', 'y', '.', 
-'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\r', '\n', 
-'\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\003', '\020', '\004', 'J', '\004', '\010', '\002', '\020', '\003', 'R', 
-'\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\212', '\006', '\n', '\020', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 
-'t', 'c', 'h', '\022', 'T', '\n', '\020', 'd', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', '_', 'p', 'o', 'r', 't', '\030', '\010', 
-' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 
-'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\013', '\372', 'B', '\010', '*', '\006', '\030', '\377', '\377', '\003', '(', '\001', 'R', '\017', 'd', 
-'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'P', 'o', 'r', 't', '\022', 'D', '\n', '\r', 'p', 'r', 'e', 'f', 'i', 'x', '_', 
-'r', 'a', 'n', 'g', 'e', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '\037', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'i', 'd', 'r', 'R', 'a', 'n', 'g', 'e', 'R', '\014', 'p', 'r', 'e', 
-'f', 'i', 'x', 'R', 'a', 'n', 'g', 'e', 's', '\022', '%', '\n', '\016', 'a', 'd', 'd', 'r', 'e', 's', 's', '_', 's', 'u', 'f', 'f', 
-'i', 'x', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\r', 'a', 'd', 'd', 'r', 'e', 's', 's', 'S', 'u', 'f', 'f', 'i', 'x', '\022', ';', 
-'\n', '\n', 's', 'u', 'f', 'f', 'i', 'x', '_', 'l', 'e', 'n', '\030', '\005', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 
-'s', 'u', 'f', 'f', 'i', 'x', 'L', 'e', 'n', '\022', 'j', '\n', '\013', 's', 'o', 'u', 'r', 'c', 'e', '_', 't', 'y', 'p', 'e', '\030', 
-'\014', ' ', '\001', '(', '\016', '2', '?', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 
-'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', '.', 
-'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'S', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', 
-'\202', '\001', '\002', '\020', '\001', 'R', '\n', 's', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', '\022', 'Q', '\n', '\024', 's', 'o', 'u', 'r', 
-'c', 'e', '_', 'p', 'r', 'e', 'f', 'i', 'x', '_', 'r', 'a', 'n', 'g', 'e', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', '\037', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'i', 'd', 'r', 
-'R', 'a', 'n', 'g', 'e', 'R', '\022', 's', 'o', 'u', 'r', 'c', 'e', 'P', 'r', 'e', 'f', 'i', 'x', 'R', 'a', 'n', 'g', 'e', 's', 
-'\022', '3', '\n', '\014', 's', 'o', 'u', 'r', 'c', 'e', '_', 'p', 'o', 'r', 't', 's', '\030', '\007', ' ', '\003', '(', '\r', 'B', '\020', '\372', 
-'B', '\r', '\222', '\001', '\n', '\"', '\010', '*', '\006', '\030', '\377', '\377', '\003', '(', '\001', 'R', '\013', 's', 'o', 'u', 'r', 'c', 'e', 'P', 'o', 
-'r', 't', 's', '\022', '!', '\n', '\014', 's', 'e', 'r', 'v', 'e', 'r', '_', 'n', 'a', 'm', 'e', 's', '\030', '\013', ' ', '\003', '(', '\t', 
-'R', '\013', 's', 'e', 'r', 'v', 'e', 'r', 'N', 'a', 'm', 'e', 's', '\022', '-', '\n', '\022', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 
-'t', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '\030', '\t', ' ', '\001', '(', '\t', 'R', '\021', 't', 'r', 'a', 'n', 's', 'p', 'o', 
-'r', 't', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', '\022', '3', '\n', '\025', 'a', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 'o', 'n', 
-'_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\030', '\n', ' ', '\003', '(', '\t', 'R', '\024', 'a', 'p', 'p', 'l', 'i', 'c', 'a', 
-'t', 'i', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\"', 'F', '\n', '\024', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
-'o', 'n', 'S', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', '\022', '\007', '\n', '\003', 'A', 'N', 'Y', '\020', '\000', '\022', '\027', '\n', '\023', 
-'S', 'A', 'M', 'E', '_', 'I', 'P', '_', 'O', 'R', '_', 'L', 'O', 'O', 'P', 'B', 'A', 'C', 'K', '\020', '\001', '\022', '\014', '\n', '\010', 
-'E', 'X', 'T', 'E', 'R', 'N', 'A', 'L', '\020', '\002', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 'y', '.', 
-'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 
-'i', 'n', 'M', 'a', 't', 'c', 'h', 'J', '\004', '\010', '\001', '\020', '\002', '\"', '\230', '\005', '\n', '\013', 'F', 'i', 'l', 't', 'e', 'r', 'C', 
-'h', 'a', 'i', 'n', '\022', 'X', '\n', '\022', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'h', 'a', 'i', 'n', '_', 'm', 'a', 't', 'c', 
-'h', '\030', '\001', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 
-'s', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 
-'h', 'R', '\020', 'f', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', '\022', ':', '\n', '\007', 'f', 'i', 
-'l', 't', 'e', 'r', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\007', 'f', 'i', 'l', 
-'t', 'e', 'r', 's', '\022', 'B', '\n', '\017', 'u', 's', 'e', '_', 'p', 'r', 'o', 'x', 'y', '_', 'p', 'r', 'o', 't', 'o', '\030', '\004', 
-' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 
-'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\r', 'u', 's', 'e', 'P', 'r', 'o', 'x', 'y', 'P', 'r', 'o', 't', 'o', '\022', ':', '\n', 
-'\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\005', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', '\010', 'm', 
-'e', 't', 'a', 'd', 'a', 't', 'a', '\022', 'P', '\n', '\020', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 
-'e', 't', '\030', '\006', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 
-'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'R', '\017', 't', 
-'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\007', ' ', 
-'\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 's', '\n', '\027', 'o', 'n', '_', 'd', 'e', 'm', 'a', 'n', 'd', '_', 'c', 'o', 
-'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\030', '\010', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 
-'r', 'C', 'h', 'a', 'i', 'n', '.', 'O', 'n', 'D', 'e', 'm', 'a', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 
-'i', 'o', 'n', 'R', '\025', 'o', 'n', 'D', 'e', 'm', 'a', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 
-'n', '\032', '[', '\n', '\025', 'O', 'n', 'D', 'e', 'm', 'a', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 
-'n', '\022', 'B', '\n', '\017', 'r', 'e', 'b', 'u', 'i', 'l', 'd', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\001', ' ', '\001', '(', 
-'\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 
-'i', 'o', 'n', 'R', '\016', 'r', 'e', 'b', 'u', 'i', 'l', 'd', 'T', 'i', 'm', 'e', 'o', 'u', 't', ':', '(', '\232', '\305', '\210', '\036', 
-'#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 
-'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\013', 't', 'l', 's', '_', 'c', 'o', 
-'n', 't', 'e', 'x', 't', '\"', '\302', '\005', '\n', '!', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 
-'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '\022', 'a', '\n', '\010', 'o', 'r', '_', 
-'m', 'a', 't', 'c', 'h', '\030', '\001', ' ', '\001', '(', '\013', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 
-'t', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '.', 'M', 'a', 
-'t', 'c', 'h', 'S', 'e', 't', 'H', '\000', 'R', '\007', 'o', 'r', 'M', 'a', 't', 'c', 'h', '\022', 'c', '\n', '\t', 'a', 'n', 'd', '_', 
-'m', 'a', 't', 'c', 'h', '\030', '\002', ' ', '\001', '(', '\013', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 
-'t', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '.', 'M', 'a', 
-'t', 'c', 'h', 'S', 'e', 't', 'H', '\000', 'R', '\010', 'a', 'n', 'd', 'M', 'a', 't', 'c', 'h', '\022', 'Z', '\n', '\t', 'n', 'o', 't', 
-'_', 'm', 'a', 't', 'c', 'h', '\030', '\003', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 
-'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 'H', '\000', 
-'R', '\010', 'n', 'o', 't', 'M', 'a', 't', 'c', 'h', '\022', '&', '\n', '\t', 'a', 'n', 'y', '_', 'm', 'a', 't', 'c', 'h', '\030', '\004', 
-' ', '\001', '(', '\010', 'B', '\007', '\372', 'B', '\004', 'j', '\002', '\010', '\001', 'H', '\000', 'R', '\010', 'a', 'n', 'y', 'M', 'a', 't', 'c', 'h', 
-'\022', 'Q', '\n', '\026', 'd', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', '_', 'p', 'o', 'r', 't', '_', 'r', 'a', 'n', 'g', 
-'e', '\030', '\005', ' ', '\001', '(', '\013', '2', '\031', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'I', 
-'n', 't', '3', '2', 'R', 'a', 'n', 'g', 'e', 'H', '\000', 'R', '\024', 'd', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'P', 
-'o', 'r', 't', 'R', 'a', 'n', 'g', 'e', '\032', '\260', '\001', '\n', '\010', 'M', 'a', 't', 'c', 'h', 'S', 'e', 't', '\022', '[', '\n', '\005', 
-'r', 'u', 'l', 'e', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 
-'t', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 'B', '\010', '\372', 
-'B', '\005', '\222', '\001', '\002', '\010', '\002', 'R', '\005', 'r', 'u', 'l', 'e', 's', ':', 'G', '\232', '\305', '\210', '\036', 'B', '\n', '@', 'e', 'n', 
+'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '$', 'e', 
+'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'e', 'x', 't', 'e', 'n', 
+'s', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'v', '3', 
+'/', 'r', 'a', 'n', 'g', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 
+'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 
+'t', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 
+'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 
+'d', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\202', '\002', '\n', '\006', 'F', 
+'i', 'l', 't', 'e', 'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', 
+'\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', 
+'\030', '\004', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
+'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'X', '\n', '\020', 'c', 'o', 'n', 
+'f', 'i', 'g', '_', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '\030', '\005', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 
+'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\017', 'c', 'o', 'n', 'f', 'i', 'g', 'D', 
+'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', ':', '#', '\232', '\305', '\210', '\036', '\036', '\n', '\034', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\r', '\n', '\013', 'c', 
+'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\003', '\020', '\004', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 
+'o', 'n', 'f', 'i', 'g', '\"', '\212', '\006', '\n', '\020', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 
+'h', '\022', 'T', '\n', '\020', 'd', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', '_', 'p', 'o', 'r', 't', '\030', '\010', ' ', '\001', 
+'(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', 
+'3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\013', '\372', 'B', '\010', '*', '\006', '\030', '\377', '\377', '\003', '(', '\001', 'R', '\017', 'd', 'e', 's', 
+'t', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'P', 'o', 'r', 't', '\022', 'D', '\n', '\r', 'p', 'r', 'e', 'f', 'i', 'x', '_', 'r', 'a', 
+'n', 'g', 'e', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '\037', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'i', 'd', 'r', 'R', 'a', 'n', 'g', 'e', 'R', '\014', 'p', 'r', 'e', 'f', 'i', 
+'x', 'R', 'a', 'n', 'g', 'e', 's', '\022', '%', '\n', '\016', 'a', 'd', 'd', 'r', 'e', 's', 's', '_', 's', 'u', 'f', 'f', 'i', 'x', 
+'\030', '\004', ' ', '\001', '(', '\t', 'R', '\r', 'a', 'd', 'd', 'r', 'e', 's', 's', 'S', 'u', 'f', 'f', 'i', 'x', '\022', ';', '\n', '\n', 
+'s', 'u', 'f', 'f', 'i', 'x', '_', 'l', 'e', 'n', '\030', '\005', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
+'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 's', 'u', 
+'f', 'f', 'i', 'x', 'L', 'e', 'n', '\022', 'j', '\n', '\013', 's', 'o', 'u', 'r', 'c', 'e', '_', 't', 'y', 'p', 'e', '\030', '\014', ' ', 
+'\001', '(', '\016', '2', '?', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 
+'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', '.', 'C', 'o', 
+'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'S', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', 
+'\002', '\020', '\001', 'R', '\n', 's', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', '\022', 'Q', '\n', '\024', 's', 'o', 'u', 'r', 'c', 'e', 
+'_', 'p', 'r', 'e', 'f', 'i', 'x', '_', 'r', 'a', 'n', 'g', 'e', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', '\037', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'i', 'd', 'r', 'R', 'a', 
+'n', 'g', 'e', 'R', '\022', 's', 'o', 'u', 'r', 'c', 'e', 'P', 'r', 'e', 'f', 'i', 'x', 'R', 'a', 'n', 'g', 'e', 's', '\022', '3', 
+'\n', '\014', 's', 'o', 'u', 'r', 'c', 'e', '_', 'p', 'o', 'r', 't', 's', '\030', '\007', ' ', '\003', '(', '\r', 'B', '\020', '\372', 'B', '\r', 
+'\222', '\001', '\n', '\"', '\010', '*', '\006', '\030', '\377', '\377', '\003', '(', '\001', 'R', '\013', 's', 'o', 'u', 'r', 'c', 'e', 'P', 'o', 'r', 't', 
+'s', '\022', '!', '\n', '\014', 's', 'e', 'r', 'v', 'e', 'r', '_', 'n', 'a', 'm', 'e', 's', '\030', '\013', ' ', '\003', '(', '\t', 'R', '\013', 
+'s', 'e', 'r', 'v', 'e', 'r', 'N', 'a', 'm', 'e', 's', '\022', '-', '\n', '\022', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 
+'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '\030', '\t', ' ', '\001', '(', '\t', 'R', '\021', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 
+'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', '\022', '3', '\n', '\025', 'a', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 'o', 'n', '_', 'p', 
+'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\030', '\n', ' ', '\003', '(', '\t', 'R', '\024', 'a', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 
+'o', 'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\"', 'F', '\n', '\024', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
+'S', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', '\022', '\007', '\n', '\003', 'A', 'N', 'Y', '\020', '\000', '\022', '\027', '\n', '\023', 'S', 'A', 
+'M', 'E', '_', 'I', 'P', '_', 'O', 'R', '_', 'L', 'O', 'O', 'P', 'B', 'A', 'C', 'K', '\020', '\001', '\022', '\014', '\n', '\010', 'E', 'X', 
+'T', 'E', 'R', 'N', 'A', 'L', '\020', '\002', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 
+'M', 'a', 't', 'c', 'h', 'J', '\004', '\010', '\001', '\020', '\002', '\"', '\200', '\006', '\n', '\013', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 
+'i', 'n', '\022', 'X', '\n', '\022', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'h', 'a', 'i', 'n', '_', 'm', 'a', 't', 'c', 'h', '\030', 
+'\001', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 
+'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'R', 
+'\020', 'f', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', '\022', ':', '\n', '\007', 'f', 'i', 'l', 't', 
+'e', 'r', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\007', 'f', 'i', 'l', 't', 'e', 
+'r', 's', '\022', 'F', '\n', '\017', 'u', 's', 'e', '_', 'p', 'r', 'o', 'x', 'y', '_', 'p', 'r', 'o', 't', 'o', '\030', '\004', ' ', '\001', 
+'(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 
+'V', 'a', 'l', 'u', 'e', 'B', '\002', '\030', '\001', 'R', '\r', 'u', 's', 'e', 'P', 'r', 'o', 'x', 'y', 'P', 'r', 'o', 't', 'o', '\022', 
+':', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\005', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', 
+'\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', 'P', '\n', '\020', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 
+'c', 'k', 'e', 't', '\030', '\006', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', 'R', 
+'\017', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 'e', 't', '\022', 'b', '\n', ' ', 't', 'r', 'a', 'n', 's', 
+'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', '_', 't', 'i', 'm', 'e', 'o', 
+'u', 't', '\030', '\t', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\035', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 'S', 'o', 'c', 'k', 
+'e', 't', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', 
+'\007', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 's', '\n', '\027', 'o', 'n', '_', 'd', 'e', 'm', 'a', 'n', 'd', '_', 
+'c', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\030', '\010', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'F', 'i', 'l', 
+'t', 'e', 'r', 'C', 'h', 'a', 'i', 'n', '.', 'O', 'n', 'D', 'e', 'm', 'a', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 
+'a', 't', 'i', 'o', 'n', 'R', '\025', 'o', 'n', 'D', 'e', 'm', 'a', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 
+'i', 'o', 'n', '\032', '[', '\n', '\025', 'O', 'n', 'D', 'e', 'm', 'a', 'n', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 
+'i', 'o', 'n', '\022', 'B', '\n', '\017', 'r', 'e', 'b', 'u', 'i', 'l', 'd', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\001', ' ', 
+'\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 
+'a', 't', 'i', 'o', 'n', 'R', '\016', 'r', 'e', 'b', 'u', 'i', 'l', 'd', 'T', 'i', 'm', 'e', 'o', 'u', 't', ':', '(', '\232', '\305', 
+'\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 
+'r', '.', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\013', 't', 'l', 's', '_', 
+'c', 'o', 'n', 't', 'e', 'x', 't', '\"', '\302', '\005', '\n', '!', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 
+'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '\022', 'a', '\n', '\010', 'o', 
+'r', '_', 'm', 'a', 't', 'c', 'h', '\030', '\001', ' ', '\001', '(', '\013', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 
+'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '.', 
+'M', 'a', 't', 'c', 'h', 'S', 'e', 't', 'H', '\000', 'R', '\007', 'o', 'r', 'M', 'a', 't', 'c', 'h', '\022', 'c', '\n', '\t', 'a', 'n', 
+'d', '_', 'm', 'a', 't', 'c', 'h', '\030', '\002', ' ', '\001', '(', '\013', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 
+'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '.', 
+'M', 'a', 't', 'c', 'h', 'S', 'e', 't', 'H', '\000', 'R', '\010', 'a', 'n', 'd', 'M', 'a', 't', 'c', 'h', '\022', 'Z', '\n', '\t', 'n', 
+'o', 't', '_', 'm', 'a', 't', 'c', 'h', '\030', '\003', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 
+'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 
+'H', '\000', 'R', '\010', 'n', 'o', 't', 'M', 'a', 't', 'c', 'h', '\022', '&', '\n', '\t', 'a', 'n', 'y', '_', 'm', 'a', 't', 'c', 'h', 
+'\030', '\004', ' ', '\001', '(', '\010', 'B', '\007', '\372', 'B', '\004', 'j', '\002', '\010', '\001', 'H', '\000', 'R', '\010', 'a', 'n', 'y', 'M', 'a', 't', 
+'c', 'h', '\022', 'Q', '\n', '\026', 'd', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', '_', 'p', 'o', 'r', 't', '_', 'r', 'a', 
+'n', 'g', 'e', '\030', '\005', ' ', '\001', '(', '\013', '2', '\031', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', 
+'.', 'I', 'n', 't', '3', '2', 'R', 'a', 'n', 'g', 'e', 'H', '\000', 'R', '\024', 'd', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 
+'n', 'P', 'o', 'r', 't', 'R', 'a', 'n', 'g', 'e', '\032', '\260', '\001', '\n', '\010', 'M', 'a', 't', 'c', 'h', 'S', 'e', 't', '\022', '[', 
+'\n', '\005', 'r', 'u', 'l', 'e', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 
+'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 'B', 
+'\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\002', 'R', '\005', 'r', 'u', 'l', 'e', 's', ':', 'G', '\232', '\305', '\210', '\036', 'B', '\n', '@', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'L', 'i', 's', 
+'t', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 
+'i', 'c', 'a', 't', 'e', '.', 'M', 'a', 't', 'c', 'h', 'S', 'e', 't', ':', '>', '\232', '\305', '\210', '\036', '9', '\n', '7', 'e', 'n', 
 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'L', 'i', 's', 't', 'e', 
 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 
-'a', 't', 'e', '.', 'M', 'a', 't', 'c', 'h', 'S', 'e', 't', ':', '>', '\232', '\305', '\210', '\036', '9', '\n', '7', 'e', 'n', 'v', 'o', 
-'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 
-'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 
-'e', 'B', '\013', '\n', '\004', 'r', 'u', 'l', 'e', '\022', '\003', '\370', 'B', '\001', '\"', '\230', '\002', '\n', '\016', 'L', 'i', 's', 't', 'e', 'n', 
-'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 
-'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 
-'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
-'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'd', '\n', '\017', 
-'f', 'i', 'l', 't', 'e', 'r', '_', 'd', 'i', 's', 'a', 'b', 'l', 'e', 'd', '\030', '\004', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 
-'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 'P', 'r', 
-'e', 'd', 'i', 'c', 'a', 't', 'e', 'R', '\016', 'f', 'i', 'l', 't', 'e', 'r', 'D', 'i', 's', 'a', 'b', 'l', 'e', 'd', ':', '+', 
-'\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 
-'n', 'e', 'r', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 
-'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', 'B', 'K', '\n', 
-'&', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', 'B', '\027', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 
-'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', 
-'\006', 'p', 'r', 'o', 't', 'o', '3', 
+'a', 't', 'e', 'B', '\013', '\n', '\004', 'r', 'u', 'l', 'e', '\022', '\003', '\370', 'B', '\001', '\"', '\230', '\002', '\n', '\016', 'L', 'i', 's', 't', 
+'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', 
+'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 
+'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'd', 
+'\n', '\017', 'f', 'i', 'l', 't', 'e', 'r', '_', 'd', 'i', 's', 'a', 'b', 'l', 'e', 'd', '\030', '\004', ' ', '\001', '(', '\013', '2', ';', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', 
+'.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'h', 'a', 'i', 'n', 'M', 'a', 't', 'c', 'h', 
+'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 'R', '\016', 'f', 'i', 'l', 't', 'e', 'r', 'D', 'i', 's', 'a', 'b', 'l', 'e', 'd', 
+':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 
+'t', 'e', 'n', 'e', 'r', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\r', '\n', '\013', 'c', 
+'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', 'B', 
+'K', '\n', '&', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', 'B', '\027', 'L', 'i', 's', 't', 'e', 'n', 'e', 
+'r', 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', 
+'\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
 static upb_def_init *deps[11] = {
   &envoy_config_core_v3_address_proto_upbdefinit,
   &envoy_config_core_v3_base_proto_upbdefinit,
+  &envoy_config_core_v3_extension_proto_upbdefinit,
   &envoy_type_v3_range_proto_upbdefinit,
   &google_protobuf_any_proto_upbdefinit,
   &google_protobuf_duration_proto_upbdefinit,
-  &google_protobuf_struct_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
@@ -181,5 +189,5 @@
   deps,
   layouts,
   "envoy/config/listener/v3/listener_components.proto",
-  UPB_STRVIEW_INIT(descriptor, 3082)
+  UPB_STRVIEW_INIT(descriptor, 3284)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c
index 6d607cd..525a38a 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c
@@ -10,7 +10,6 @@
 #include "envoy/config/listener/v3/udp_listener_config.upbdefs.h"
 
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
-extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
 extern const upb_msglayout envoy_config_listener_v3_UdpListenerConfig_msginit;
@@ -21,34 +20,32 @@
   &envoy_config_listener_v3_ActiveRawUdpListenerConfig_msginit,
 };
 
-static const char descriptor[574] = {'\n', '2', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 'v', 
+static const char descriptor[544] = {'\n', '2', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 'v', 
 '3', '/', 'u', 'd', 'p', '_', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'p', 'r', 'o', 
 't', 'o', '\022', '\030', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 
 '.', 'v', '3', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 
-'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 
-'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 
-'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 
-'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 
-'o', '\"', '\307', '\001', '\n', '\021', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '*', 
-'\n', '\021', 'u', 'd', 'p', '_', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
-'R', '\017', 'u', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'N', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 
-'d', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
-'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 
-'g', ':', '.', '\232', '\305', '\210', '\036', ')', '\n', '\'', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 
-'s', 't', 'e', 'n', 'e', 'r', '.', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'B', 
-'\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 
-'f', 'i', 'g', '\"', 'U', '\n', '\032', 'A', 'c', 't', 'i', 'v', 'e', 'R', 'a', 'w', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 
-'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'A', 'c', 't', 'i', 'v', 'e', 'R', 'a', 'w', 'U', 'd', 
-'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'B', 'J', '\n', '&', 'i', 'o', '.', 'e', 'n', 'v', 
-'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 
-'e', 'n', 'e', 'r', '.', 'v', '3', 'B', '\026', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 
-'g', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 
+'t', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
+'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\"', '\307', '\001', '\n', 
+'\021', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '*', '\n', '\021', 'u', 'd', 'p', 
+'_', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\017', 'u', 'd', 'p', 
+'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'N', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 
+'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '.', '\232', '\305', 
+'\210', '\036', ')', '\n', '\'', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 
+'r', '.', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'B', '\r', '\n', '\013', 'c', 'o', 
+'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', 'U', 
+'\n', '\032', 'A', 'c', 't', 'i', 'v', 'e', 'R', 'a', 'w', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 
+'f', 'i', 'g', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
+'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'A', 'c', 't', 'i', 'v', 'e', 'R', 'a', 'w', 'U', 'd', 'p', 'L', 'i', 's', 't', 
+'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'B', 'J', '\n', '&', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 
+'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 
+'v', '3', 'B', '\026', 'U', 'd', 'p', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'P', 'r', 'o', 't', 
+'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[5] = {
+static upb_def_init *deps[4] = {
   &google_protobuf_any_proto_upbdefinit,
-  &google_protobuf_struct_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
   NULL
@@ -58,5 +55,5 @@
   deps,
   layouts,
   "envoy/config/listener/v3/udp_listener_config.proto",
-  UPB_STRVIEW_INIT(descriptor, 574)
+  UPB_STRVIEW_INIT(descriptor, 544)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c
new file mode 100644
index 0000000..e49149a
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c
@@ -0,0 +1,141 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/metrics/v3/stats.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/config/metrics/v3/stats.upbdefs.h"
+
+extern upb_def_init envoy_config_core_v3_address_proto_upbdefinit;
+extern upb_def_init envoy_type_matcher_v3_string_proto_upbdefinit;
+extern upb_def_init google_protobuf_any_proto_upbdefinit;
+extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsSink_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsConfig_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsMatcher_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_TagSpecifier_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_HistogramBucketSettings_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_StatsdSink_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_DogStatsdSink_msginit;
+extern const upb_msglayout envoy_config_metrics_v3_HystrixSink_msginit;
+
+static const upb_msglayout *layouts[8] = {
+  &envoy_config_metrics_v3_StatsSink_msginit,
+  &envoy_config_metrics_v3_StatsConfig_msginit,
+  &envoy_config_metrics_v3_StatsMatcher_msginit,
+  &envoy_config_metrics_v3_TagSpecifier_msginit,
+  &envoy_config_metrics_v3_HistogramBucketSettings_msginit,
+  &envoy_config_metrics_v3_StatsdSink_msginit,
+  &envoy_config_metrics_v3_DogStatsdSink_msginit,
+  &envoy_config_metrics_v3_HystrixSink_msginit,
+};
+
+static const char descriptor[2091] = {'\n', '#', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'm', 'e', 't', 'r', 'i', 'c', 's', '/', 'v', '3', 
+'/', 's', 't', 'a', 't', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\027', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'm', 'e', 't', 'r', 'i', 'c', 's', '.', 'v', '3', '\032', '\"', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 
+'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'a', 'd', 'd', 'r', 'e', 's', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\"', 
+'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 'e', 'r', '/', 'v', '3', '/', 's', 't', 'r', 
+'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 
+'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 
+'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', 
+'!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 
+'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 
+'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\241', '\001', '\n', '\t', 'S', 't', 'a', 't', 's', 'S', 'i', 'n', 'k', '\022', '\022', 
+'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 
+'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 
+'i', 'g', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 
+'e', 't', 'r', 'i', 'c', 's', '.', 'v', '2', '.', 'S', 't', 'a', 't', 's', 'S', 'i', 'n', 'k', 'B', '\r', '\n', '\013', 'c', 'o', 
+'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\206', 
+'\003', '\n', '\013', 'S', 't', 'a', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'D', '\n', '\n', 's', 't', 'a', 't', 's', '_', 't', 
+'a', 'g', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'m', 'e', 't', 'r', 'i', 'c', 's', '.', 'v', '3', '.', 'T', 'a', 'g', 'S', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'R', '\t', 
+'s', 't', 'a', 't', 's', 'T', 'a', 'g', 's', '\022', 'K', '\n', '\024', 'u', 's', 'e', '_', 'a', 'l', 'l', '_', 'd', 'e', 'f', 'a', 
+'u', 'l', 't', '_', 't', 'a', 'g', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
+'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\021', 'u', 's', 'e', 'A', 'l', 'l', 
+'D', 'e', 'f', 'a', 'u', 'l', 't', 'T', 'a', 'g', 's', '\022', 'J', '\n', '\r', 's', 't', 'a', 't', 's', '_', 'm', 'a', 't', 'c', 
+'h', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'m', 'e', 't', 'r', 'i', 'c', 's', '.', 'v', '3', '.', 'S', 't', 'a', 't', 's', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\014', 
+'s', 't', 'a', 't', 's', 'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', 'l', '\n', '\031', 'h', 'i', 's', 't', 'o', 'g', 'r', 'a', 'm', 
+'_', 'b', 'u', 'c', 'k', 'e', 't', '_', 's', 'e', 't', 't', 'i', 'n', 'g', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', '0', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 'e', 't', 'r', 'i', 'c', 's', '.', 'v', '3', '.', 'H', 
+'i', 's', 't', 'o', 'g', 'r', 'a', 'm', 'B', 'u', 'c', 'k', 'e', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', 'R', '\027', 'h', 
+'i', 's', 't', 'o', 'g', 'r', 'a', 'm', 'B', 'u', 'c', 'k', 'e', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', ':', '*', '\232', 
+'\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 'e', 't', 'r', 'i', 'c', 
+'s', '.', 'v', '2', '.', 'S', 't', 'a', 't', 's', 'C', 'o', 'n', 'f', 'i', 'g', '\"', '\230', '\002', '\n', '\014', 'S', 't', 'a', 't', 
+'s', 'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', '\037', '\n', '\n', 'r', 'e', 'j', 'e', 'c', 't', '_', 'a', 'l', 'l', '\030', '\001', ' ', 
+'\001', '(', '\010', 'H', '\000', 'R', '\t', 'r', 'e', 'j', 'e', 'c', 't', 'A', 'l', 'l', '\022', 'Q', '\n', '\016', 'e', 'x', 'c', 'l', 'u', 
+'s', 'i', 'o', 'n', '_', 'l', 'i', 's', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 
+'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'S', 't', 'r', 'i', 'n', 'g', 
+'M', 'a', 't', 'c', 'h', 'e', 'r', 'H', '\000', 'R', '\r', 'e', 'x', 'c', 'l', 'u', 's', 'i', 'o', 'n', 'L', 'i', 's', 't', '\022', 
+'Q', '\n', '\016', 'i', 'n', 'c', 'l', 'u', 's', 'i', 'o', 'n', '_', 'l', 'i', 's', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', '(', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 
+'s', 't', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'H', '\000', 'R', '\r', 'i', 'n', 'c', 'l', 'u', 's', 
+'i', 'o', 'n', 'L', 'i', 's', 't', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'm', 'e', 't', 'r', 'i', 'c', 's', '.', 'v', '2', '.', 'S', 't', 'a', 't', 's', 'M', 'a', 't', 'c', 'h', 
+'e', 'r', 'B', '\024', '\n', '\r', 's', 't', 'a', 't', 's', '_', 'm', 'a', 't', 'c', 'h', 'e', 'r', '\022', '\003', '\370', 'B', '\001', '\"', 
+'\250', '\001', '\n', '\014', 'T', 'a', 'g', 'S', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\031', '\n', '\010', 't', 'a', 'g', '_', 'n', 
+'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\007', 't', 'a', 'g', 'N', 'a', 'm', 'e', '\022', ' ', '\n', '\005', 'r', 'e', 'g', 
+'e', 'x', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\010', '\372', 'B', '\005', 'r', '\003', '(', '\200', '\010', 'H', '\000', 'R', '\005', 'r', 'e', 'g', 
+'e', 'x', '\022', '!', '\n', '\013', 'f', 'i', 'x', 'e', 'd', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'H', '\000', 
+'R', '\n', 'f', 'i', 'x', 'e', 'd', 'V', 'a', 'l', 'u', 'e', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 'e', 't', 'r', 'i', 'c', 's', '.', 'v', '2', '.', 'T', 'a', 'g', 'S', 'p', 
+'e', 'c', 'i', 'f', 'i', 'e', 'r', 'B', '\013', '\n', '\t', 't', 'a', 'g', '_', 'v', 'a', 'l', 'u', 'e', '\"', '\222', '\001', '\n', '\027', 
+'H', 'i', 's', 't', 'o', 'g', 'r', 'a', 'm', 'B', 'u', 'c', 'k', 'e', 't', 'S', 'e', 't', 't', 'i', 'n', 'g', 's', '\022', 'D', 
+'\n', '\005', 'm', 'a', 't', 'c', 'h', '\030', '\001', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 
+'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 
+'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\005', 'm', 'a', 't', 'c', 'h', '\022', '1', '\n', '\007', 'b', 'u', 'c', 
+'k', 'e', 't', 's', '\030', '\002', ' ', '\003', '(', '\001', 'B', '\027', '\372', 'B', '\024', '\222', '\001', '\021', '\010', '\001', '\030', '\001', '\"', '\013', '\022', 
+'\t', '!', '\000', '\000', '\000', '\000', '\000', '\000', '\000', '\000', 'R', '\007', 'b', 'u', 'c', 'k', 'e', 't', 's', '\"', '\317', '\001', '\n', '\n', 'S', 
+'t', 'a', 't', 's', 'd', 'S', 'i', 'n', 'k', '\022', '9', '\n', '\007', 'a', 'd', 'd', 'r', 'e', 's', 's', '\030', '\001', ' ', '\001', '(', 
+'\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
+'A', 'd', 'd', 'r', 'e', 's', 's', 'H', '\000', 'R', '\007', 'a', 'd', 'd', 'r', 'e', 's', 's', '\022', '*', '\n', '\020', 't', 'c', 'p', 
+'_', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\016', 't', 'c', 
+'p', 'C', 'l', 'u', 's', 't', 'e', 'r', 'N', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\003', ' ', 
+'\001', '(', '\t', 'R', '\006', 'p', 'r', 'e', 'f', 'i', 'x', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 'e', 't', 'r', 'i', 'c', 's', '.', 'v', '2', '.', 'S', 't', 'a', 't', 's', 'd', 
+'S', 'i', 'n', 'k', 'B', '\027', '\n', '\020', 's', 't', 'a', 't', 's', 'd', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', 
+'\003', '\370', 'B', '\001', '\"', '\217', '\002', '\n', '\r', 'D', 'o', 'g', 'S', 't', 'a', 't', 's', 'd', 'S', 'i', 'n', 'k', '\022', '9', '\n', 
+'\007', 'a', 'd', 'd', 'r', 'e', 's', 's', '\030', '\001', ' ', '\001', '(', '\013', '2', '\035', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'A', 'd', 'd', 'r', 'e', 's', 's', 'H', '\000', 'R', '\007', 'a', 
+'d', 'd', 'r', 'e', 's', 's', '\022', '\026', '\n', '\006', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\006', 'p', 
+'r', 'e', 'f', 'i', 'x', '\022', 'Z', '\n', '\026', 'm', 'a', 'x', '_', 'b', 'y', 't', 'e', 's', '_', 'p', 'e', 'r', '_', 'd', 'a', 
+'t', 'a', 'g', 'r', 'a', 'm', '\030', '\004', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '6', '4', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '2', '\002', ' ', 
+'\000', 'R', '\023', 'm', 'a', 'x', 'B', 'y', 't', 'e', 's', 'P', 'e', 'r', 'D', 'a', 't', 'a', 'g', 'r', 'a', 'm', ':', ',', '\232', 
+'\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 'e', 't', 'r', 'i', 'c', 
+'s', '.', 'v', '2', '.', 'D', 'o', 'g', 'S', 't', 'a', 't', 's', 'd', 'S', 'i', 'n', 'k', 'B', '\033', '\n', '\024', 'd', 'o', 'g', 
+'_', 's', 't', 'a', 't', 's', 'd', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', 
+'\002', '\020', '\003', '\"', 'Z', '\n', '\013', 'H', 'y', 's', 't', 'r', 'i', 'x', 'S', 'i', 'n', 'k', '\022', '\037', '\n', '\013', 'n', 'u', 'm', 
+'_', 'b', 'u', 'c', 'k', 'e', 't', 's', '\030', '\001', ' ', '\001', '(', '\003', 'R', '\n', 'n', 'u', 'm', 'B', 'u', 'c', 'k', 'e', 't', 
+'s', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'm', 'e', 
+'t', 'r', 'i', 'c', 's', '.', 'v', '2', '.', 'H', 'y', 's', 't', 'r', 'i', 'x', 'S', 'i', 'n', 'k', 'B', '=', '\n', '%', 'i', 
+'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'm', 'e', 't', 'r', 'i', 'c', 's', '.', 'v', '3', 'B', '\n', 'S', 't', 'a', 't', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', 
+'\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[8] = {
+  &envoy_config_core_v3_address_proto_upbdefinit,
+  &envoy_type_matcher_v3_string_proto_upbdefinit,
+  &google_protobuf_any_proto_upbdefinit,
+  &google_protobuf_wrappers_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_config_metrics_v3_stats_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/config/metrics/v3/stats.proto",
+  UPB_STRVIEW_INIT(descriptor, 2091)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h
new file mode 100644
index 0000000..0432cfd
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h
@@ -0,0 +1,70 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/metrics/v3/stats.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_CONFIG_METRICS_V3_STATS_PROTO_UPBDEFS_H_
+#define ENVOY_CONFIG_METRICS_V3_STATS_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_config_metrics_v3_stats_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_config_metrics_v3_StatsSink_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_metrics_v3_stats_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.metrics.v3.StatsSink");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_metrics_v3_StatsConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_metrics_v3_stats_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.metrics.v3.StatsConfig");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_metrics_v3_StatsMatcher_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_metrics_v3_stats_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.metrics.v3.StatsMatcher");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_metrics_v3_TagSpecifier_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_metrics_v3_stats_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.metrics.v3.TagSpecifier");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_metrics_v3_HistogramBucketSettings_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_metrics_v3_stats_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.metrics.v3.HistogramBucketSettings");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_metrics_v3_StatsdSink_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_metrics_v3_stats_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.metrics.v3.StatsdSink");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_metrics_v3_DogStatsdSink_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_metrics_v3_stats_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.metrics.v3.DogStatsdSink");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_metrics_v3_HystrixSink_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_metrics_v3_stats_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.metrics.v3.HystrixSink");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_CONFIG_METRICS_V3_STATS_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c
new file mode 100644
index 0000000..e189d99
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c
@@ -0,0 +1,141 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/overload/v3/overload.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/config/overload/v3/overload.upbdefs.h"
+
+extern upb_def_init envoy_type_v3_percent_proto_upbdefinit;
+extern upb_def_init google_protobuf_any_proto_upbdefinit;
+extern upb_def_init google_protobuf_duration_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout envoy_config_overload_v3_ResourceMonitor_msginit;
+extern const upb_msglayout envoy_config_overload_v3_ThresholdTrigger_msginit;
+extern const upb_msglayout envoy_config_overload_v3_ScaledTrigger_msginit;
+extern const upb_msglayout envoy_config_overload_v3_Trigger_msginit;
+extern const upb_msglayout envoy_config_overload_v3_ScaleTimersOverloadActionConfig_msginit;
+extern const upb_msglayout envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit;
+extern const upb_msglayout envoy_config_overload_v3_OverloadAction_msginit;
+extern const upb_msglayout envoy_config_overload_v3_OverloadManager_msginit;
+
+static const upb_msglayout *layouts[8] = {
+  &envoy_config_overload_v3_ResourceMonitor_msginit,
+  &envoy_config_overload_v3_ThresholdTrigger_msginit,
+  &envoy_config_overload_v3_ScaledTrigger_msginit,
+  &envoy_config_overload_v3_Trigger_msginit,
+  &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_msginit,
+  &envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_msginit,
+  &envoy_config_overload_v3_OverloadAction_msginit,
+  &envoy_config_overload_v3_OverloadManager_msginit,
+};
+
+static const char descriptor[2145] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '/', 'v', 
+'3', '/', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'p', 'r', 'o', 't', 'o', '\022', '\030', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '3', '\032', '\033', 'e', 'n', 'v', 'o', 'y', '/', 
+'t', 'y', 'p', 'e', '/', 'v', '3', '/', 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 
+'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 
+'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 
+'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 
+'t', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
+'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 
+'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\274', '\001', '\n', 
+'\017', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'M', 'o', 'n', 'i', 't', 'o', 'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', 
+'\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 
+'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 
+'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 
+'n', 'f', 'i', 'g', ':', '4', '\232', '\305', '\210', '\036', '/', '\n', '-', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 
+'e', 'M', 'o', 'n', 'i', 't', 'o', 'r', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', 
+'\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', 'x', '\n', '\020', 'T', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', 
+'T', 'r', 'i', 'g', 'g', 'e', 'r', '\022', '-', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\001', ' ', '\001', '(', '\001', 'B', '\027', '\372', 
+'B', '\024', '\022', '\022', '\031', '\000', '\000', '\000', '\000', '\000', '\000', '\360', '?', ')', '\000', '\000', '\000', '\000', '\000', '\000', '\000', '\000', 'R', '\005', 'v', 
+'a', 'l', 'u', 'e', ':', '5', '\232', '\305', '\210', '\036', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'T', 'h', 'r', 'e', 's', 'h', 'o', 
+'l', 'd', 'T', 'r', 'i', 'g', 'g', 'e', 'r', '\"', '\241', '\001', '\n', '\r', 'S', 'c', 'a', 'l', 'e', 'd', 'T', 'r', 'i', 'g', 'g', 
+'e', 'r', '\022', 'D', '\n', '\021', 's', 'c', 'a', 'l', 'i', 'n', 'g', '_', 't', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\030', '\001', 
+' ', '\001', '(', '\001', 'B', '\027', '\372', 'B', '\024', '\022', '\022', '\031', '\000', '\000', '\000', '\000', '\000', '\000', '\360', '?', ')', '\000', '\000', '\000', '\000', 
+'\000', '\000', '\000', '\000', 'R', '\020', 's', 'c', 'a', 'l', 'i', 'n', 'g', 'T', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\022', 'J', '\n', 
+'\024', 's', 'a', 't', 'u', 'r', 'a', 't', 'i', 'o', 'n', '_', 't', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\030', '\002', ' ', '\001', 
+'(', '\001', 'B', '\027', '\372', 'B', '\024', '\022', '\022', '\031', '\000', '\000', '\000', '\000', '\000', '\000', '\360', '?', ')', '\000', '\000', '\000', '\000', '\000', '\000', 
+'\000', '\000', 'R', '\023', 's', 'a', 't', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'T', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\"', '\371', 
+'\001', '\n', '\007', 'T', 'r', 'i', 'g', 'g', 'e', 'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', 
+'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'J', '\n', '\t', 't', 'h', 'r', 'e', 's', 'h', 'o', 
+'l', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'o', 
+'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '3', '.', 'T', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', 'T', 'r', 'i', 'g', 'g', 
+'e', 'r', 'H', '\000', 'R', '\t', 't', 'h', 'r', 'e', 's', 'h', 'o', 'l', 'd', '\022', 'A', '\n', '\006', 's', 'c', 'a', 'l', 'e', 'd', 
+'\030', '\003', ' ', '\001', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 
+'r', 'l', 'o', 'a', 'd', '.', 'v', '3', '.', 'S', 'c', 'a', 'l', 'e', 'd', 'T', 'r', 'i', 'g', 'g', 'e', 'r', 'H', '\000', 'R', 
+'\006', 's', 'c', 'a', 'l', 'e', 'd', ':', ',', '\232', '\305', '\210', '\036', '\'', '\n', '%', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'T', 'r', 'i', 'g', 
+'g', 'e', 'r', 'B', '\024', '\n', '\r', 't', 'r', 'i', 'g', 'g', 'e', 'r', '_', 'o', 'n', 'e', 'o', 'f', '\022', '\003', '\370', 'B', '\001', 
+'\"', '\247', '\004', '\n', '\037', 'S', 'c', 'a', 'l', 'e', 'T', 'i', 'm', 'e', 'r', 's', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'A', 
+'c', 't', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '~', '\n', '\023', 't', 'i', 'm', 'e', 'r', '_', 's', 'c', 'a', 'l', 
+'e', '_', 'f', 'a', 'c', 't', 'o', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '3', '.', 'S', 'c', 'a', 'l', 'e', 'T', 'i', 
+'m', 'e', 'r', 's', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'A', 'c', 't', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', '.', 
+'S', 'c', 'a', 'l', 'e', 'T', 'i', 'm', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\021', 't', 'i', 'm', 
+'e', 'r', 'S', 'c', 'a', 'l', 'e', 'F', 'a', 'c', 't', 'o', 'r', 's', '\032', '\200', '\002', '\n', '\n', 'S', 'c', 'a', 'l', 'e', 'T', 
+'i', 'm', 'e', 'r', '\022', 'e', '\n', '\005', 't', 'i', 'm', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\016', '2', 'C', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '3', '.', 'S', 'c', 'a', 
+'l', 'e', 'T', 'i', 'm', 'e', 'r', 's', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'A', 'c', 't', 'i', 'o', 'n', 'C', 'o', 'n', 
+'f', 'i', 'g', '.', 'T', 'i', 'm', 'e', 'r', 'T', 'y', 'p', 'e', 'B', '\n', '\372', 'B', '\007', '\202', '\001', '\004', '\020', '\001', ' ', '\000', 
+'R', '\005', 't', 'i', 'm', 'e', 'r', '\022', '<', '\n', '\013', 'm', 'i', 'n', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\002', ' ', 
+'\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 
+'a', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\n', 'm', 'i', 'n', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', '5', '\n', '\t', 'm', 'i', 
+'n', '_', 's', 'c', 'a', 'l', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 
+'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'H', '\000', 'R', '\010', 'm', 'i', 'n', 'S', 'c', 'a', 'l', 'e', 'B', 
+'\026', '\n', '\017', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '_', 'a', 'd', 'j', 'u', 's', 't', '\022', '\003', '\370', 'B', '\001', '\"', '\200', 
+'\001', '\n', '\t', 'T', 'i', 'm', 'e', 'r', 'T', 'y', 'p', 'e', '\022', '\017', '\n', '\013', 'U', 'N', 'S', 'P', 'E', 'C', 'I', 'F', 'I', 
+'E', 'D', '\020', '\000', '\022', '#', '\n', '\037', 'H', 'T', 'T', 'P', '_', 'D', 'O', 'W', 'N', 'S', 'T', 'R', 'E', 'A', 'M', '_', 'C', 
+'O', 'N', 'N', 'E', 'C', 'T', 'I', 'O', 'N', '_', 'I', 'D', 'L', 'E', '\020', '\001', '\022', '\037', '\n', '\033', 'H', 'T', 'T', 'P', '_', 
+'D', 'O', 'W', 'N', 'S', 'T', 'R', 'E', 'A', 'M', '_', 'S', 'T', 'R', 'E', 'A', 'M', '_', 'I', 'D', 'L', 'E', '\020', '\002', '\022', 
+'\034', '\n', '\030', 'T', 'R', 'A', 'N', 'S', 'P', 'O', 'R', 'T', '_', 'S', 'O', 'C', 'K', 'E', 'T', '_', 'C', 'O', 'N', 'N', 'E', 
+'C', 'T', '\020', '\003', '\"', '\344', '\001', '\n', '\016', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'A', 'c', 't', 'i', 'o', 'n', '\022', '\033', 
+'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 
+'m', 'e', '\022', 'G', '\n', '\010', 't', 'r', 'i', 'g', 'g', 'e', 'r', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '!', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '3', '.', 'T', 'r', 
+'i', 'g', 'g', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\010', 't', 'r', 'i', 'g', 'g', 'e', 'r', 's', 
+'\022', '7', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\013', 't', 'y', 'p', 'e', 
+'d', 'C', 'o', 'n', 'f', 'i', 'g', ':', '3', '\232', '\305', '\210', '\036', '.', '\n', ',', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'O', 'v', 'e', 'r', 
+'l', 'o', 'a', 'd', 'A', 'c', 't', 'i', 'o', 'n', '\"', '\263', '\002', '\n', '\017', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'M', 'a', 
+'n', 'a', 'g', 'e', 'r', '\022', 'D', '\n', '\020', 'r', 'e', 'f', 'r', 'e', 's', 'h', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', 
+'\030', '\001', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
+'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\017', 'r', 'e', 'f', 'r', 'e', 's', 'h', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', 
+'\022', '`', '\n', '\021', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'm', 'o', 'n', 'i', 't', 'o', 'r', 's', '\030', '\002', ' ', '\003', 
+'(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 
+'d', '.', 'v', '3', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'M', 'o', 'n', 'i', 't', 'o', 'r', 'B', '\010', '\372', 'B', '\005', 
+'\222', '\001', '\002', '\010', '\001', 'R', '\020', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'M', 'o', 'n', 'i', 't', 'o', 'r', 's', '\022', 'B', 
+'\n', '\007', 'a', 'c', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '(', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '3', '.', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 
+'d', 'A', 'c', 't', 'i', 'o', 'n', 'R', '\007', 'a', 'c', 't', 'i', 'o', 'n', 's', ':', '4', '\232', '\305', '\210', '\036', '/', '\n', '-', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '2', 'a', 
+'l', 'p', 'h', 'a', '.', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'M', 'a', 'n', 'a', 'g', 'e', 'r', 'B', 'A', '\n', '&', 'i', 
+'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'o', 'v', 'e', 'r', 'l', 'o', 'a', 'd', '.', 'v', '3', 'B', '\r', 'O', 'v', 'e', 'r', 'l', 'o', 'a', 'd', 'P', 'r', 'o', 
+'t', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[7] = {
+  &envoy_type_v3_percent_proto_upbdefinit,
+  &google_protobuf_any_proto_upbdefinit,
+  &google_protobuf_duration_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_config_overload_v3_overload_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/config/overload/v3/overload.proto",
+  UPB_STRVIEW_INIT(descriptor, 2145)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h
new file mode 100644
index 0000000..ca1dc51
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h
@@ -0,0 +1,70 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/config/overload/v3/overload.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_CONFIG_OVERLOAD_V3_OVERLOAD_PROTO_UPBDEFS_H_
+#define ENVOY_CONFIG_OVERLOAD_V3_OVERLOAD_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_config_overload_v3_overload_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_config_overload_v3_ResourceMonitor_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_overload_v3_overload_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.overload.v3.ResourceMonitor");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_overload_v3_ThresholdTrigger_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_overload_v3_overload_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.overload.v3.ThresholdTrigger");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_overload_v3_ScaledTrigger_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_overload_v3_overload_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.overload.v3.ScaledTrigger");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_overload_v3_Trigger_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_overload_v3_overload_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.overload.v3.Trigger");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_overload_v3_overload_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.overload.v3.ScaleTimersOverloadActionConfig");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_overload_v3_overload_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.overload.v3.ScaleTimersOverloadActionConfig.ScaleTimer");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_overload_v3_OverloadAction_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_overload_v3_overload_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.overload.v3.OverloadAction");
+}
+
+UPB_INLINE const upb_msgdef *envoy_config_overload_v3_OverloadManager_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_overload_v3_overload_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.overload.v3.OverloadManager");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_CONFIG_OVERLOAD_V3_OVERLOAD_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c
index 446ce00..8e6490a 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c
@@ -24,7 +24,7 @@
   &envoy_config_route_v3_Vhds_msginit,
 };
 
-static const char descriptor[1282] = {'\n', '!', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'r', 'o', 'u', 't', 'e', '/', 'v', '3', '/', 'r', 
+static const char descriptor[1389] = {'\n', '!', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'r', 'o', 'u', 't', 'e', '/', 'v', '3', '/', 'r', 
 'o', 'u', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\022', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '\032', '\037', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 
 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '(', 'e', 'n', 'v', 'o', 'y', '/', 'c', 
@@ -36,7 +36,7 @@
 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 
 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 
 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 
-'t', 'o', '\"', '\227', '\006', '\n', '\022', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 
+'t', 'o', '\"', '\202', '\007', '\n', '\022', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 
 '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'G', '\n', '\r', 'v', 
 'i', 'r', 't', 'u', 'a', 'l', '_', 'h', 'o', 's', 't', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 
 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 
@@ -66,16 +66,20 @@
 'i', 'o', 'n', 's', 'W', 'i', 'n', 's', '\022', 'G', '\n', '\021', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '_', 'c', 'l', 'u', 's', 
 't', 'e', 'r', 's', '\030', '\007', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\020', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 'C', 'l', 
-'u', 's', 't', 'e', 'r', 's', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 
-'v', '2', '.', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\"', 's', '\n', '\004', 
-'V', 'h', 'd', 's', '\022', 'Q', '\n', '\r', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\001', ' ', '\001', 
-'(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
-'.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\014', 
-'c', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', ':', '\030', '\232', '\305', '\210', '\036', '\023', '\n', '\021', 'e', 'n', 'v', 'o', 
-'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'V', 'h', 'd', 's', 'B', ';', '\n', '#', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 
-'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 
-'v', '3', 'B', '\n', 'R', 'o', 'u', 't', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', 
-'\006', 'p', 'r', 'o', 't', 'o', '3', 
+'u', 's', 't', 'e', 'r', 's', '\022', 'i', '\n', '#', 'm', 'a', 'x', '_', 'd', 'i', 'r', 'e', 'c', 't', '_', 'r', 'e', 's', 'p', 
+'o', 'n', 's', 'e', '_', 'b', 'o', 'd', 'y', '_', 's', 'i', 'z', 'e', '_', 'b', 'y', 't', 'e', 's', '\030', '\013', ' ', '\001', '(', 
+'\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', 
+'2', 'V', 'a', 'l', 'u', 'e', 'R', '\036', 'm', 'a', 'x', 'D', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 
+'B', 'o', 'd', 'y', 'S', 'i', 'z', 'e', 'B', 'y', 't', 'e', 's', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 
+'i', 'o', 'n', '\"', 's', '\n', '\004', 'V', 'h', 'd', 's', '\022', 'Q', '\n', '\r', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 
+'r', 'c', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\010', '\372', 'B', '\005', 
+'\212', '\001', '\002', '\020', '\001', 'R', '\014', 'c', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', ':', '\030', '\232', '\305', '\210', '\036', 
+'\023', '\n', '\021', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'V', 'h', 'd', 's', 'B', ';', '\n', '#', 'i', 
+'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 'B', '\n', 'R', 'o', 'u', 't', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', 
+'\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
 static upb_def_init *deps[8] = {
@@ -93,5 +97,5 @@
   deps,
   layouts,
   "envoy/config/route/v3/route.proto",
-  UPB_STRVIEW_INIT(descriptor, 1282)
+  UPB_STRVIEW_INIT(descriptor, 1389)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c
index 72a74f2..b9e2316 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c
@@ -20,7 +20,6 @@
 extern upb_def_init envoy_type_v3_range_proto_upbdefinit;
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
-extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init envoy_annotations_deprecation_proto_upbdefinit;
 extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
@@ -72,13 +71,15 @@
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Action_GenericKey_msginit;
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Action_HeaderValueMatch_msginit;
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Action_DynamicMetaData_msginit;
+extern const upb_msglayout envoy_config_route_v3_RateLimit_Action_MetaData_msginit;
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Override_msginit;
 extern const upb_msglayout envoy_config_route_v3_RateLimit_Override_DynamicMetadata_msginit;
 extern const upb_msglayout envoy_config_route_v3_HeaderMatcher_msginit;
 extern const upb_msglayout envoy_config_route_v3_QueryParameterMatcher_msginit;
 extern const upb_msglayout envoy_config_route_v3_InternalRedirectPolicy_msginit;
+extern const upb_msglayout envoy_config_route_v3_FilterConfig_msginit;
 
-static const upb_msglayout *layouts[50] = {
+static const upb_msglayout *layouts[52] = {
   &envoy_config_route_v3_VirtualHost_msginit,
   &envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry_msginit,
   &envoy_config_route_v3_FilterAction_msginit,
@@ -124,14 +125,16 @@
   &envoy_config_route_v3_RateLimit_Action_GenericKey_msginit,
   &envoy_config_route_v3_RateLimit_Action_HeaderValueMatch_msginit,
   &envoy_config_route_v3_RateLimit_Action_DynamicMetaData_msginit,
+  &envoy_config_route_v3_RateLimit_Action_MetaData_msginit,
   &envoy_config_route_v3_RateLimit_Override_msginit,
   &envoy_config_route_v3_RateLimit_Override_DynamicMetadata_msginit,
   &envoy_config_route_v3_HeaderMatcher_msginit,
   &envoy_config_route_v3_QueryParameterMatcher_msginit,
   &envoy_config_route_v3_InternalRedirectPolicy_msginit,
+  &envoy_config_route_v3_FilterConfig_msginit,
 };
 
-static const char descriptor[18792] = {'\n', ',', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'r', 'o', 'u', 't', 'e', '/', 'v', '3', '/', 'r', 
+static const char descriptor[19463] = {'\n', ',', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'r', 'o', 'u', 't', 'e', '/', 'v', '3', '/', 'r', 
 'o', 'u', 't', 'e', '_', 'c', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\025', 'e', 'n', 
 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '\032', '\037', 'e', 'n', 'v', 'o', 
 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 'o', 
@@ -148,744 +151,771 @@
 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 
 'v', '3', '/', 'r', 'a', 'n', 'g', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 
 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 
-'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 
-'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 
-'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 
-'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
-'i', 'o', 'n', 's', '/', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 
-'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 
-'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 
-'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 
-'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 
-'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\324', '\014', '\n', '\013', 
-'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
-'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ',', '\n', '\007', 'd', 'o', 'm', 'a', 'i', 'n', 
-'s', '\030', '\002', ' ', '\003', '(', '\t', 'B', '\022', '\372', 'B', '\017', '\222', '\001', '\014', '\010', '\001', '\"', '\010', 'r', '\006', '\300', '\001', '\002', '\310', 
-'\001', '\000', 'R', '\007', 'd', 'o', 'm', 'a', 'i', 'n', 's', '\022', '4', '\n', '\006', 'r', 'o', 'u', 't', 'e', 's', '\030', '\003', ' ', '\003', 
-'(', '\013', '2', '\034', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', 
-'3', '.', 'R', 'o', 'u', 't', 'e', 'R', '\006', 'r', 'o', 'u', 't', 'e', 's', '\022', '`', '\n', '\013', 'r', 'e', 'q', 'u', 'i', 'r', 
-'e', '_', 't', 'l', 's', '\030', '\004', ' ', '\001', '(', '\016', '2', '5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', '.', 'T', 'l', 
-'s', 'R', 'e', 'q', 'u', 'i', 'r', 'e', 'm', 'e', 'n', 't', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', 
-'\001', 'R', '\n', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'T', 'l', 's', '\022', 'P', '\n', '\020', 'v', 'i', 'r', 't', 'u', 'a', 'l', '_', 
-'c', 'l', 'u', 's', 't', 'e', 'r', 's', '\030', '\005', ' ', '\003', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'C', 'l', 'u', 's', 
-'t', 'e', 'r', 'R', '\017', 'v', 'i', 'r', 't', 'u', 'a', 'l', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', '\022', 'A', '\n', '\013', 'r', 
-'a', 't', 'e', '_', 'l', 'i', 'm', 'i', 't', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 
-'R', '\n', 'r', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 's', '\022', 'g', '\n', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 
-'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\007', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 
-'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\023', 'r', 'e', 
-'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'M', '\n', '\031', 'r', 'e', 'q', 'u', 
-'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\r', ' ', '\003', 
-'(', '\t', 'B', '\022', '\372', 'B', '\017', '\222', '\001', '\014', '\"', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\026', 'r', 
-'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', 'i', '\n', '\027', 
-'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\n', 
-' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
-'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', 
-'\222', '\001', '\003', '\020', '\350', '\007', 'R', '\024', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 
-'A', 'd', 'd', '\022', 'O', '\n', '\032', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 
-'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\013', ' ', '\003', '(', '\t', 'B', '\022', '\372', 'B', '\017', '\222', '\001', '\014', '\"', '\n', 'r', 
-'\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\027', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 
-'s', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', '5', '\n', '\004', 'c', 'o', 'r', 's', '\030', '\010', ' ', '\001', '(', '\013', '2', '!', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'C', 'o', 
-'r', 's', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\004', 'c', 'o', 'r', 's', '\022', 's', '\n', '\027', 't', 'y', 'p', 'e', 'd', '_', 'p', 
-'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\017', ' ', '\003', '(', '\013', '2', '<', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 
-'t', 'u', 'a', 'l', 'H', 'o', 's', 't', '.', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 
-'n', 'f', 'i', 'g', 'E', 'n', 't', 'r', 'y', 'R', '\024', 't', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 
-'C', 'o', 'n', 'f', 'i', 'g', '\022', 'A', '\n', '\035', 'i', 'n', 'c', 'l', 'u', 'd', 'e', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', 
-'_', 'a', 't', 't', 'e', 'm', 'p', 't', '_', 'c', 'o', 'u', 'n', 't', '\030', '\016', ' ', '\001', '(', '\010', 'R', '\032', 'i', 'n', 'c', 
-'l', 'u', 'd', 'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'A', 't', 't', 'e', 'm', 'p', 't', 'C', 'o', 'u', 'n', 't', '\022', 'H', 
-'\n', '!', 'i', 'n', 'c', 'l', 'u', 'd', 'e', '_', 'a', 't', 't', 'e', 'm', 'p', 't', '_', 'c', 'o', 'u', 'n', 't', '_', 'i', 
-'n', '_', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '\030', '\023', ' ', '\001', '(', '\010', 'R', '\035', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 
-'A', 't', 't', 'e', 'm', 'p', 't', 'C', 'o', 'u', 'n', 't', 'I', 'n', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\022', 'E', '\n', 
-'\014', 'r', 'e', 't', 'r', 'y', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\020', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 
-'o', 'l', 'i', 'c', 'y', 'R', '\013', 'r', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'O', '\n', '\031', 'r', 'e', 't', 
-'r', 'y', '_', 'p', 'o', 'l', 'i', 'c', 'y', '_', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\024', ' ', 
-'\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 
-'R', '\026', 'r', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 'T', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 
-'E', '\n', '\014', 'h', 'e', 'd', 'g', 'e', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\021', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'd', 'g', 
-'e', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\013', 'h', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '`', '\n', '\036', 'p', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 
+'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 
+'p', 'r', 'o', 't', 'o', '\032', '#', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 
+'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 
+'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', 
+'\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 
+'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 
+'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 
+'/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\324', '\014', '\n', '\013', 'V', 'i', 'r', 't', 'u', 
+'a', 'l', 'H', 'o', 's', 't', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 
+'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ',', '\n', '\007', 'd', 'o', 'm', 'a', 'i', 'n', 's', '\030', '\002', ' ', '\003', 
+'(', '\t', 'B', '\022', '\372', 'B', '\017', '\222', '\001', '\014', '\010', '\001', '\"', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\007', 'd', 
+'o', 'm', 'a', 'i', 'n', 's', '\022', '4', '\n', '\006', 'r', 'o', 'u', 't', 'e', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '\034', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 
+'t', 'e', 'R', '\006', 'r', 'o', 'u', 't', 'e', 's', '\022', '`', '\n', '\013', 'r', 'e', 'q', 'u', 'i', 'r', 'e', '_', 't', 'l', 's', 
+'\030', '\004', ' ', '\001', '(', '\016', '2', '5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 
+'t', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', '.', 'T', 'l', 's', 'R', 'e', 'q', 'u', 
+'i', 'r', 'e', 'm', 'e', 'n', 't', 'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\n', 'r', 'e', 
+'q', 'u', 'i', 'r', 'e', 'T', 'l', 's', '\022', 'P', '\n', '\020', 'v', 'i', 'r', 't', 'u', 'a', 'l', '_', 'c', 'l', 'u', 's', 't', 
+'e', 'r', 's', '\030', '\005', ' ', '\003', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'C', 'l', 'u', 's', 't', 'e', 'r', 'R', '\017', 
+'v', 'i', 'r', 't', 'u', 'a', 'l', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', '\022', 'A', '\n', '\013', 'r', 'a', 't', 'e', '_', 'l', 
+'i', 'm', 'i', 't', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'R', '\n', 'r', 'a', 't', 
+'e', 'L', 'i', 'm', 'i', 't', 's', '\022', 'g', '\n', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 
+'s', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\007', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 
+'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\023', 'r', 'e', 'q', 'u', 'e', 's', 't', 
+'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'M', '\n', '\031', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 
+'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\r', ' ', '\003', '(', '\t', 'B', '\022', '\372', 
+'B', '\017', '\222', '\001', '\014', '\"', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\026', 'r', 'e', 'q', 'u', 'e', 's', 
+'t', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', 'i', '\n', '\027', 'r', 'e', 's', 'p', 'o', 
+'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\n', ' ', '\003', '(', '\013', '2', 
+'\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 
+'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', 
+'\007', 'R', '\024', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'O', 
+'\n', '\032', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 
+'o', 'v', 'e', '\030', '\013', ' ', '\003', '(', '\t', 'B', '\022', '\372', 'B', '\017', '\222', '\001', '\014', '\"', '\n', 'r', '\010', '\020', '\001', '\300', '\001', 
+'\001', '\310', '\001', '\000', 'R', '\027', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 
+'m', 'o', 'v', 'e', '\022', '5', '\n', '\004', 'c', 'o', 'r', 's', '\030', '\010', ' ', '\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'C', 'o', 'r', 's', 'P', 'o', 'l', 
+'i', 'c', 'y', 'R', '\004', 'c', 'o', 'r', 's', '\022', 's', '\n', '\027', 't', 'y', 'p', 'e', 'd', '_', 'p', 'e', 'r', '_', 'f', 'i', 
+'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\017', ' ', '\003', '(', '\013', '2', '<', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 
+'o', 's', 't', '.', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'E', 
+'n', 't', 'r', 'y', 'R', '\024', 't', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 
+'g', '\022', 'A', '\n', '\035', 'i', 'n', 'c', 'l', 'u', 'd', 'e', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'a', 't', 't', 'e', 
+'m', 'p', 't', '_', 'c', 'o', 'u', 'n', 't', '\030', '\016', ' ', '\001', '(', '\010', 'R', '\032', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 'R', 
+'e', 'q', 'u', 'e', 's', 't', 'A', 't', 't', 'e', 'm', 'p', 't', 'C', 'o', 'u', 'n', 't', '\022', 'H', '\n', '!', 'i', 'n', 'c', 
+'l', 'u', 'd', 'e', '_', 'a', 't', 't', 'e', 'm', 'p', 't', '_', 'c', 'o', 'u', 'n', 't', '_', 'i', 'n', '_', 'r', 'e', 's', 
+'p', 'o', 'n', 's', 'e', '\030', '\023', ' ', '\001', '(', '\010', 'R', '\035', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 'A', 't', 't', 'e', 'm', 
+'p', 't', 'C', 'o', 'u', 'n', 't', 'I', 'n', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\022', 'E', '\n', '\014', 'r', 'e', 't', 'r', 
+'y', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\020', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 
+'R', '\013', 'r', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'O', '\n', '\031', 'r', 'e', 't', 'r', 'y', '_', 'p', 'o', 
+'l', 'i', 'c', 'y', '_', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\024', ' ', '\001', '(', '\013', '2', '\024', 
+'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\026', 'r', 'e', 't', 
+'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 'T', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'E', '\n', '\014', 'h', 'e', 
+'d', 'g', 'e', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\021', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 
+'c', 'y', 'R', '\013', 'h', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '`', '\n', '\036', 'p', 'e', 'r', '_', 'r', 'e', 
+'q', 'u', 'e', 's', 't', '_', 'b', 'u', 'f', 'f', 'e', 'r', '_', 'l', 'i', 'm', 'i', 't', '_', 'b', 'y', 't', 'e', 's', '\030', 
+'\022', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 
+'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\032', 'p', 'e', 'r', 'R', 'e', 'q', 'u', 'e', 's', 't', 'B', 'u', 'f', 
+'f', 'e', 'r', 'L', 'i', 'm', 'i', 't', 'B', 'y', 't', 'e', 's', '\032', ']', '\n', '\031', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 
+'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', 
+'\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '*', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', 
+'2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\005', 'v', 
+'a', 'l', 'u', 'e', ':', '\002', '8', '\001', '\"', ':', '\n', '\022', 'T', 'l', 's', 'R', 'e', 'q', 'u', 'i', 'r', 'e', 'm', 'e', 'n', 
+'t', 'T', 'y', 'p', 'e', '\022', '\010', '\n', '\004', 'N', 'O', 'N', 'E', '\020', '\000', '\022', '\021', '\n', '\r', 'E', 'X', 'T', 'E', 'R', 'N', 
+'A', 'L', '_', 'O', 'N', 'L', 'Y', '\020', '\001', '\022', '\007', '\n', '\003', 'A', 'L', 'L', '\020', '\002', ':', '%', '\232', '\305', '\210', '\036', ' ', 
+'\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'V', 'i', 'r', 't', 
+'u', 'a', 'l', 'H', 'o', 's', 't', 'J', '\004', '\010', '\t', '\020', '\n', 'J', '\004', '\010', '\014', '\020', '\r', 'R', '\021', 'p', 'e', 'r', '_', 
+'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\"', 'd', '\n', '\014', 'F', 'i', 'l', 't', 'e', 'r', 'A', 'c', 
+'t', 'i', 'o', 'n', '\022', ',', '\n', '\006', 'a', 'c', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\006', 'a', 'c', 't', 'i', 'o', 'n', 
+':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 
+'t', 'e', '.', 'F', 'i', 'l', 't', 'e', 'r', 'A', 'c', 't', 'i', 'o', 'n', '\"', '\254', '\n', '\n', '\005', 'R', 'o', 'u', 't', 'e', 
+'\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\016', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'A', '\n', '\005', 'm', 
+'a', 't', 'c', 'h', '\030', '\001', ' ', '\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'B', '\010', '\372', 'B', '\005', 
+'\212', '\001', '\002', '\020', '\001', 'R', '\005', 'm', 'a', 't', 'c', 'h', '\022', ':', '\n', '\005', 'r', 'o', 'u', 't', 'e', '\030', '\002', ' ', '\001', 
+'(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', 
+'3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\005', 'r', 'o', 'u', 't', 'e', '\022', 'C', '\n', 
+'\010', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 'c', 
+'t', 'i', 'o', 'n', 'H', '\000', 'R', '\010', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', 'V', '\n', '\017', 'd', 'i', 'r', 'e', 'c', 
+'t', '_', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '\030', '\007', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'D', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 
+'p', 'o', 'n', 's', 'e', 'A', 'c', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\016', 'd', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 
+'o', 'n', 's', 'e', '\022', 'J', '\n', '\r', 'f', 'i', 'l', 't', 'e', 'r', '_', 'a', 'c', 't', 'i', 'o', 'n', '\030', '\021', ' ', '\001', 
+'(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', 
+'3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'A', 'c', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\014', 'f', 'i', 'l', 't', 'e', 'r', 'A', 
+'c', 't', 'i', 'o', 'n', '\022', ':', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\004', ' ', '\001', '(', '\013', '2', '\036', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 't', 
+'a', 'd', 'a', 't', 'a', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', '>', '\n', '\t', 'd', 'e', 'c', 'o', 'r', 'a', 
+'t', 'o', 'r', '\030', '\005', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'D', 'e', 'c', 'o', 'r', 'a', 't', 'o', 'r', 'R', '\t', 'd', 'e', 'c', 'o', 'r', 
+'a', 't', 'o', 'r', '\022', 'm', '\n', '\027', 't', 'y', 'p', 'e', 'd', '_', 'p', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '_', 
+'c', 'o', 'n', 'f', 'i', 'g', '\030', '\r', ' ', '\003', '(', '\013', '2', '6', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', '.', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 
+'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'E', 'n', 't', 'r', 'y', 'R', '\024', 't', 'y', 'p', 'e', 'd', 
+'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'g', '\n', '\026', 'r', 'e', 'q', 'u', 'e', 's', 
+'t', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\t', ' ', '\003', '(', '\013', '2', '\'', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 
+'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', 
+'\023', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'M', '\n', '\031', 'r', 
+'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', 
+'\014', ' ', '\003', '(', '\t', 'B', '\022', '\372', 'B', '\017', '\222', '\001', '\014', '\"', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 
+'R', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', 
+'i', '\n', '\027', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 
+'d', '\030', '\n', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
+'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', 
+'\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\024', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 
+'s', 'T', 'o', 'A', 'd', 'd', '\022', 'O', '\n', '\032', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 
+'s', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\013', ' ', '\003', '(', '\t', 'B', '\022', '\372', 'B', '\017', '\222', '\001', '\014', 
+'\"', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\027', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 'e', 'a', 
+'d', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', '8', '\n', '\007', 't', 'r', 'a', 'c', 'i', 'n', 'g', '\030', '\017', 
+' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', 
+'.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', 'R', '\007', 't', 'r', 'a', 'c', 'i', 'n', 'g', '\022', '`', '\n', '\036', 'p', 
 'e', 'r', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'b', 'u', 'f', 'f', 'e', 'r', '_', 'l', 'i', 'm', 'i', 't', '_', 'b', 
-'y', 't', 'e', 's', '\030', '\022', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
+'y', 't', 'e', 's', '\030', '\020', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\032', 'p', 'e', 'r', 'R', 'e', 'q', 'u', 'e', 
 's', 't', 'B', 'u', 'f', 'f', 'e', 'r', 'L', 'i', 'm', 'i', 't', 'B', 'y', 't', 'e', 's', '\032', ']', '\n', '\031', 'T', 'y', 'p', 
 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', 
 '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '*', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', 
 '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 
-'n', 'y', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', '\"', ':', '\n', '\022', 'T', 'l', 's', 'R', 'e', 'q', 'u', 'i', 
-'r', 'e', 'm', 'e', 'n', 't', 'T', 'y', 'p', 'e', '\022', '\010', '\n', '\004', 'N', 'O', 'N', 'E', '\020', '\000', '\022', '\021', '\n', '\r', 'E', 
-'X', 'T', 'E', 'R', 'N', 'A', 'L', '_', 'O', 'N', 'L', 'Y', '\020', '\001', '\022', '\007', '\n', '\003', 'A', 'L', 'L', '\020', '\002', ':', '%', 
-'\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', 
-'.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', 'J', '\004', '\010', '\t', '\020', '\n', 'J', '\004', '\010', '\014', '\020', '\r', 'R', 
-'\021', 'p', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\"', 'd', '\n', '\014', 'F', 'i', 'l', 
-'t', 'e', 'r', 'A', 'c', 't', 'i', 'o', 'n', '\022', ',', '\n', '\006', 'a', 'c', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', 
-'2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\006', 'a', 
-'c', 't', 'i', 'o', 'n', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', 
-'2', '.', 'r', 'o', 'u', 't', 'e', '.', 'F', 'i', 'l', 't', 'e', 'r', 'A', 'c', 't', 'i', 'o', 'n', '\"', '\254', '\n', '\n', '\005', 
-'R', 'o', 'u', 't', 'e', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\016', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', 
-'\022', 'A', '\n', '\005', 'm', 'a', 't', 'c', 'h', '\030', '\001', ' ', '\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 
-'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\005', 'm', 'a', 't', 'c', 'h', '\022', ':', '\n', '\005', 'r', 'o', 'u', 't', 
-'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 
-'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\005', 'r', 'o', 'u', 
-'t', 'e', '\022', 'C', '\n', '\010', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', '%', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 'd', 'i', 'r', 
-'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\010', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', 'V', '\n', '\017', 
-'d', 'i', 'r', 'e', 'c', 't', '_', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '\030', '\007', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'D', 'i', 'r', 'e', 
-'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'A', 'c', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\016', 'd', 'i', 'r', 'e', 'c', 
-'t', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\022', 'J', '\n', '\r', 'f', 'i', 'l', 't', 'e', 'r', '_', 'a', 'c', 't', 'i', 'o', 
-'n', '\030', '\021', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 
-'u', 't', 'e', '.', 'v', '3', '.', 'F', 'i', 'l', 't', 'e', 'r', 'A', 'c', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\014', 'f', 'i', 
-'l', 't', 'e', 'r', 'A', 'c', 't', 'i', 'o', 'n', '\022', ':', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\004', ' ', 
-'\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
-'3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', '>', '\n', '\t', 'd', 
-'e', 'c', 'o', 'r', 'a', 't', 'o', 'r', '\030', '\005', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'D', 'e', 'c', 'o', 'r', 'a', 't', 'o', 'r', 'R', '\t', 
-'d', 'e', 'c', 'o', 'r', 'a', 't', 'o', 'r', '\022', 'm', '\n', '\027', 't', 'y', 'p', 'e', 'd', '_', 'p', 'e', 'r', '_', 'f', 'i', 
-'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\r', ' ', '\003', '(', '\013', '2', '6', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', '.', 'T', 'y', 
-'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'E', 'n', 't', 'r', 'y', 'R', '\024', 
-'t', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'g', '\n', '\026', 'r', 
-'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\t', ' ', '\003', 
-'(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
-'.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', 
-'\003', '\020', '\350', '\007', 'R', '\023', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', 
-'\022', 'M', '\n', '\031', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 
-'m', 'o', 'v', 'e', '\030', '\014', ' ', '\003', '(', '\t', 'B', '\022', '\372', 'B', '\017', '\222', '\001', '\014', '\"', '\n', 'r', '\010', '\020', '\001', '\300', 
-'\001', '\001', '\310', '\001', '\000', 'R', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 
-'m', 'o', 'v', 'e', '\022', 'i', '\n', '\027', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 
-'t', 'o', '_', 'a', 'd', 'd', '\030', '\n', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 
-'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\024', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 
-'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'O', '\n', '\032', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 
-'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\013', ' ', '\003', '(', '\t', 'B', '\022', '\372', 
-'B', '\017', '\222', '\001', '\014', '\"', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\027', 'r', 'e', 's', 'p', 'o', 'n', 
-'s', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', '8', '\n', '\007', 't', 'r', 'a', 'c', 
-'i', 'n', 'g', '\030', '\017', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', 'R', '\007', 't', 'r', 'a', 'c', 'i', 'n', 'g', 
-'\022', '`', '\n', '\036', 'p', 'e', 'r', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'b', 'u', 'f', 'f', 'e', 'r', '_', 'l', 'i', 
-'m', 'i', 't', '_', 'b', 'y', 't', 'e', 's', '\030', '\020', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
-'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\032', 'p', 'e', 'r', 
-'R', 'e', 'q', 'u', 'e', 's', 't', 'B', 'u', 'f', 'f', 'e', 'r', 'L', 'i', 'm', 'i', 't', 'B', 'y', 't', 'e', 's', '\032', ']', 
-'\n', '\031', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'E', 'n', 't', 
-'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '*', '\n', '\005', 'v', 
-'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
-'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', ':', '\037', '\232', '\305', '\210', '\036', '\032', 
-'\n', '\030', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 
-'e', 'B', '\r', '\n', '\006', 'a', 'c', 't', 'i', 'o', 'n', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\006', '\020', '\007', 'J', '\004', '\010', 
-'\010', '\020', '\t', 'R', '\021', 'p', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\353', '\010', 
-'\n', '\017', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', 'Z', '\n', '\010', 'c', 'l', 'u', 's', 
-'t', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', 
-'.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'W', 'e', 'i', 'g', 'h', 't', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', 
-'\010', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', '\022', 'H', '\n', '\014', 't', 'o', 't', 'a', 'l', '_', 'w', 'e', 'i', 'g', 'h', 't', 
-'\030', '\003', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
-'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', '(', '\001', 'R', '\013', 't', 'o', 't', 
-'a', 'l', 'W', 'e', 'i', 'g', 'h', 't', '\022', ',', '\n', '\022', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '_', 'p', 
-'r', 'e', 'f', 'i', 'x', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\020', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', 'P', 'r', 
-'e', 'f', 'i', 'x', '\032', '\330', '\006', '\n', '\r', 'C', 'l', 'u', 's', 't', 'e', 'r', 'W', 'e', 'i', 'g', 'h', 't', '\022', '\033', '\n', 
-'\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 
-'e', '\022', '4', '\n', '\006', 'w', 'e', 'i', 'g', 'h', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\006', 'w', 
-'e', 'i', 'g', 'h', 't', '\022', 'E', '\n', '\016', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', 'm', 'a', 't', 'c', 'h', '\030', '\003', 
-' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
-'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', '\r', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'M', 'a', 't', 'c', 
-'h', '\022', 'g', '\n', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 
-'d', 'd', '\030', '\004', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 
-'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', 
-'\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\023', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 
-'s', 'T', 'o', 'A', 'd', 'd', '\022', 'K', '\n', '\031', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', 
-'_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\t', ' ', '\003', '(', '\t', 'B', '\020', '\372', 'B', '\r', '\222', '\001', '\n', '\"', 
-'\010', 'r', '\006', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 
-'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', 'i', '\n', '\027', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 
-'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\005', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 
-'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\024', 'r', 'e', 's', 'p', 'o', 
-'n', 's', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'M', '\n', '\032', 'r', 'e', 's', 'p', 'o', 'n', 
-'s', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\006', ' ', '\003', '(', 
-'\t', 'B', '\020', '\372', 'B', '\r', '\222', '\001', '\n', '\"', '\010', 'r', '\006', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\027', 'r', 'e', 's', 'p', 
-'o', 'n', 's', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', '\205', '\001', '\n', '\027', 't', 
-'y', 'p', 'e', 'd', '_', 'p', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\n', ' ', 
-'\003', '(', '\013', '2', 'N', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 
-'v', '3', '.', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'l', 'u', 's', 't', 'e', 
-'r', 'W', 'e', 'i', 'g', 'h', 't', '.', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 
-'f', 'i', 'g', 'E', 'n', 't', 'r', 'y', 'R', '\024', 't', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 
-'o', 'n', 'f', 'i', 'g', '\032', ']', '\n', '\031', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 
-'n', 'f', 'i', 'g', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 
-'e', 'y', '\022', '*', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', 
-':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 
-'t', 'e', '.', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'l', 'u', 's', 't', 'e', 
-'r', 'W', 'e', 'i', 'g', 'h', 't', 'J', '\004', '\010', '\007', '\020', '\010', 'J', '\004', '\010', '\010', '\020', '\t', 'R', '\021', 'p', 'e', 'r', '_', 
-'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 
-'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 
-'l', 'u', 's', 't', 'e', 'r', '\"', '\313', '\010', '\n', '\n', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', '\022', '\030', '\n', '\006', 
-'p', 'r', 'e', 'f', 'i', 'x', '\030', '\001', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\006', 'p', 'r', 'e', 'f', 'i', 'x', '\022', '\024', '\n', 
-'\004', 'p', 'a', 't', 'h', '\030', '\002', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\004', 'p', 'a', 't', 'h', '\022', 'N', '\n', '\n', 's', 'a', 
-'f', 'e', '_', 'r', 'e', 'g', 'e', 'x', '\030', '\n', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 
-'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'e', 
-'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'H', '\000', 'R', '\t', 's', 'a', 'f', 'e', 'R', 'e', 'g', 'e', 'x', '\022', 
-'[', '\n', '\017', 'c', 'o', 'n', 'n', 'e', 'c', 't', '_', 'm', 'a', 't', 'c', 'h', 'e', 'r', '\030', '\014', ' ', '\001', '(', '\013', '2', 
-'0', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 
-'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'H', 
-'\000', 'R', '\016', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', 'A', '\n', '\016', 'c', 'a', 's', 'e', 
-'_', 's', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\r', 'c', 'a', 's', 'e', 
-'S', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e', '\022', 'Y', '\n', '\020', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'f', 'r', 'a', 'c', 
-'t', 'i', 'o', 'n', '\030', '\t', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 
-'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\017', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 
-'\022', '>', '\n', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 
-'t', 'c', 'h', 'e', 'r', 'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\022', 'W', '\n', '\020', 'q', 'u', 'e', 'r', 'y', '_', 'p', 
-'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', '\030', '\007', ' ', '\003', '(', '\013', '2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 
-'e', 't', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\017', 'q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 
-'e', 'r', 's', '\022', 'K', '\n', '\004', 'g', 'r', 'p', 'c', '\030', '\010', ' ', '\001', '(', '\013', '2', '7', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 
-'c', 'h', '.', 'G', 'r', 'p', 'c', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', 
-'\004', 'g', 'r', 'p', 'c', '\022', 'Y', '\n', '\013', 't', 'l', 's', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\013', ' ', '\001', '(', 
-'\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 
-'.', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', '.', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'a', 't', 
-'c', 'h', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\n', 't', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\032', 'S', '\n', '\025', 
-'G', 'r', 'p', 'c', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'O', 'p', 't', 'i', 'o', 'n', 's', ':', ':', '\232', '\305', 
-'\210', '\036', '5', '\n', '3', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 
-'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', '.', 'G', 'r', 'p', 'c', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'O', 
-'p', 't', 'i', 'o', 'n', 's', '\032', '\311', '\001', '\n', '\026', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'a', 't', 'c', 
-'h', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '8', '\n', '\t', 'p', 'r', 'e', 's', 'e', 'n', 't', 'e', 'd', '\030', '\001', ' ', '\001', 
-'(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 
-'V', 'a', 'l', 'u', 'e', 'R', '\t', 'p', 'r', 'e', 's', 'e', 'n', 't', 'e', 'd', '\022', '8', '\n', '\t', 'v', 'a', 'l', 'i', 'd', 
-'a', 't', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
-'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 'd', ':', 
-';', '\232', '\305', '\210', '\036', '6', '\n', '4', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 
-'e', '.', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', '.', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'a', 
-'t', 'c', 'h', 'O', 'p', 't', 'i', 'o', 'n', 's', '\032', '\020', '\n', '\016', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'M', 'a', 't', 'c', 
-'h', 'e', 'r', ':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
-'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'B', '\025', '\n', '\016', 'p', 'a', 't', 'h', '_', 
-'s', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\005', '\020', '\006', 'J', '\004', '\010', '\003', '\020', 
-'\004', 'R', '\005', 'r', 'e', 'g', 'e', 'x', '\"', '\350', '\004', '\n', '\n', 'C', 'o', 'r', 's', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '_', 
-'\n', '\031', 'a', 'l', 'l', 'o', 'w', '_', 'o', 'r', 'i', 'g', 'i', 'n', '_', 's', 't', 'r', 'i', 'n', 'g', '_', 'm', 'a', 't', 
-'c', 'h', '\030', '\013', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 
-'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\026', 'a', 'l', 
-'l', 'o', 'w', 'O', 'r', 'i', 'g', 'i', 'n', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', '\022', '#', '\n', '\r', 'a', 
-'l', 'l', 'o', 'w', '_', 'm', 'e', 't', 'h', 'o', 'd', 's', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\014', 'a', 'l', 'l', 'o', 'w', 
-'M', 'e', 't', 'h', 'o', 'd', 's', '\022', '#', '\n', '\r', 'a', 'l', 'l', 'o', 'w', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', 
-'\003', ' ', '\001', '(', '\t', 'R', '\014', 'a', 'l', 'l', 'o', 'w', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', '%', '\n', '\016', 'e', 'x', 
-'p', 'o', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\r', 'e', 'x', 'p', 'o', 's', 
-'e', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', '\027', '\n', '\007', 'm', 'a', 'x', '_', 'a', 'g', 'e', '\030', '\005', ' ', '\001', '(', '\t', 
-'R', '\006', 'm', 'a', 'x', 'A', 'g', 'e', '\022', 'G', '\n', '\021', 'a', 'l', 'l', 'o', 'w', '_', 'c', 'r', 'e', 'd', 'e', 'n', 't', 
-'i', 'a', 'l', 's', '\030', '\006', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
-'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\020', 'a', 'l', 'l', 'o', 'w', 'C', 'r', 'e', 'd', 'e', 
-'n', 't', 'i', 'a', 'l', 's', '\022', 'W', '\n', '\016', 'f', 'i', 'l', 't', 'e', 'r', '_', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\030', 
+'n', 'y', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', ':', '\037', '\232', '\305', '\210', '\036', '\032', '\n', '\030', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'B', '\r', '\n', '\006', 
+'a', 'c', 't', 'i', 'o', 'n', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\006', '\020', '\007', 'J', '\004', '\010', '\010', '\020', '\t', 'R', '\021', 
+'p', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\353', '\010', '\n', '\017', 'W', 'e', 'i', 
+'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', 'Z', '\n', '\010', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', '\030', 
+'\001', ' ', '\003', '(', '\013', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 
+'e', '.', 'v', '3', '.', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'l', 'u', 's', 
+'t', 'e', 'r', 'W', 'e', 'i', 'g', 'h', 't', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\010', 'c', 'l', 'u', 's', 
+'t', 'e', 'r', 's', '\022', 'H', '\n', '\014', 't', 'o', 't', 'a', 'l', '_', 'w', 'e', 'i', 'g', 'h', 't', '\030', '\003', ' ', '\001', '(', 
+'\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', 
+'2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', '(', '\001', 'R', '\013', 't', 'o', 't', 'a', 'l', 'W', 'e', 'i', 
+'g', 'h', 't', '\022', ',', '\n', '\022', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '_', 'p', 'r', 'e', 'f', 'i', 'x', 
+'\030', '\002', ' ', '\001', '(', '\t', 'R', '\020', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'K', 'e', 'y', 'P', 'r', 'e', 'f', 'i', 'x', '\032', 
+'\330', '\006', '\n', '\r', 'C', 'l', 'u', 's', 't', 'e', 'r', 'W', 'e', 'i', 'g', 'h', 't', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', 
+'\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '4', '\n', '\006', 
+'w', 'e', 'i', 'g', 'h', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\006', 'w', 'e', 'i', 'g', 'h', 't', 
+'\022', 'E', '\n', '\016', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', 'm', 'a', 't', 'c', 'h', '\030', '\003', ' ', '\001', '(', '\013', '2', 
+'\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 
+'t', 'a', 'd', 'a', 't', 'a', 'R', '\r', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'M', 'a', 't', 'c', 'h', '\022', 'g', '\n', '\026', 
+'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\004', ' ', 
+'\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
+'3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', 
+'\001', '\003', '\020', '\350', '\007', 'R', '\023', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 
+'d', '\022', 'K', '\n', '\031', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 
+'e', 'm', 'o', 'v', 'e', '\030', '\t', ' ', '\003', '(', '\t', 'B', '\020', '\372', 'B', '\r', '\222', '\001', '\n', '\"', '\010', 'r', '\006', '\300', '\001', 
+'\001', '\310', '\001', '\000', 'R', '\026', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 
+'o', 'v', 'e', '\022', 'i', '\n', '\027', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 
+'o', '_', 'a', 'd', 'd', '\030', '\005', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 
+'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\024', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 'e', 
+'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\022', 'M', '\n', '\032', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'h', 'e', 
+'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'r', 'e', 'm', 'o', 'v', 'e', '\030', '\006', ' ', '\003', '(', '\t', 'B', '\020', '\372', 'B', 
+'\r', '\222', '\001', '\n', '\"', '\010', 'r', '\006', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\027', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'H', 
+'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'R', 'e', 'm', 'o', 'v', 'e', '\022', '\205', '\001', '\n', '\027', 't', 'y', 'p', 'e', 'd', '_', 
+'p', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\n', ' ', '\003', '(', '\013', '2', 'N', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'W', 'e', 
+'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'W', 'e', 'i', 'g', 
+'h', 't', '.', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'E', 'n', 
+'t', 'r', 'y', 'R', '\024', 't', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 
+'\032', ']', '\n', '\031', 'T', 'y', 'p', 'e', 'd', 'P', 'e', 'r', 'F', 'i', 'l', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', 'E', 
+'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '*', '\n', 
+'\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', ':', '7', '\232', '\305', '\210', 
+'\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'W', 'e', 
+'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'W', 'e', 'i', 'g', 
+'h', 't', 'J', '\004', '\010', '\007', '\020', '\010', 'J', '\004', '\010', '\010', '\020', '\t', 'R', '\021', 'p', 'e', 'r', '_', 'f', 'i', 'l', 't', 'e', 
+'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 
+'r', '\"', '\313', '\010', '\n', '\n', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', '\022', '\030', '\n', '\006', 'p', 'r', 'e', 'f', 'i', 
+'x', '\030', '\001', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\006', 'p', 'r', 'e', 'f', 'i', 'x', '\022', '\024', '\n', '\004', 'p', 'a', 't', 'h', 
+'\030', '\002', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\004', 'p', 'a', 't', 'h', '\022', 'N', '\n', '\n', 's', 'a', 'f', 'e', '_', 'r', 'e', 
+'g', 'e', 'x', '\030', '\n', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 
+'t', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\010', '\372', 'B', 
+'\005', '\212', '\001', '\002', '\020', '\001', 'H', '\000', 'R', '\t', 's', 'a', 'f', 'e', 'R', 'e', 'g', 'e', 'x', '\022', '[', '\n', '\017', 'c', 'o', 
+'n', 'n', 'e', 'c', 't', '_', 'm', 'a', 't', 'c', 'h', 'e', 'r', '\030', '\014', ' ', '\001', '(', '\013', '2', '0', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'M', 
+'a', 't', 'c', 'h', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'H', '\000', 'R', '\016', 'c', 'o', 
+'n', 'n', 'e', 'c', 't', 'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', 'A', '\n', '\016', 'c', 'a', 's', 'e', '_', 's', 'e', 'n', 's', 
+'i', 't', 'i', 'v', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\r', 'c', 'a', 's', 'e', 'S', 'e', 'n', 's', 'i', 
+'t', 'i', 'v', 'e', '\022', 'Y', '\n', '\020', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'f', 'r', 'a', 'c', 't', 'i', 'o', 'n', '\030', 
 '\t', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
 '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 
-'e', 'n', 't', 'H', '\000', 'R', '\r', 'f', 'i', 'l', 't', 'e', 'r', 'E', 'n', 'a', 'b', 'l', 'e', 'd', '\022', 'U', '\n', '\016', 's', 
-'h', 'a', 'd', 'o', 'w', '_', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\030', '\n', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 
-'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\r', 's', 'h', 'a', 'd', 'o', 'w', 
-'E', 'n', 'a', 'b', 'l', 'e', 'd', ':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
-'.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'C', 'o', 'r', 's', 'P', 'o', 'l', 'i', 'c', 'y', 'B', '\023', '\n', '\021', 'e', 
-'n', 'a', 'b', 'l', 'e', 'd', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'J', '\004', '\010', '\001', '\020', '\002', 'J', '\004', '\010', 
-'\010', '\020', '\t', 'J', '\004', '\010', '\007', '\020', '\010', 'R', '\014', 'a', 'l', 'l', 'o', 'w', '_', 'o', 'r', 'i', 'g', 'i', 'n', 'R', '\022', 
-'a', 'l', 'l', 'o', 'w', '_', 'o', 'r', 'i', 'g', 'i', 'n', '_', 'r', 'e', 'g', 'e', 'x', 'R', '\007', 'e', 'n', 'a', 'b', 'l', 
-'e', 'd', '\"', '\236', '&', '\n', '\013', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '\022', '#', '\n', '\007', 'c', 'l', 'u', 
-'s', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\007', 'c', 'l', 
-'u', 's', 't', 'e', 'r', '\022', '6', '\n', '\016', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\002', 
-' ', '\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'H', '\000', 'R', '\r', 'c', 'l', 
-'u', 's', 't', 'e', 'r', 'H', 'e', 'a', 'd', 'e', 'r', '\022', 'U', '\n', '\021', 'w', 'e', 'i', 'g', 'h', 't', 'e', 'd', '_', 'c', 
-'l', 'u', 's', 't', 'e', 'r', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 
-'t', 'e', 'r', 'H', '\000', 'R', '\020', 'w', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', '\022', '\216', 
-'\001', '\n', '\037', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'n', 'o', 't', '_', 'f', 'o', 'u', 'n', 'd', '_', 'r', 'e', 's', 'p', 
-'o', 'n', 's', 'e', '_', 'c', 'o', 'd', 'e', '\030', '\024', ' ', '\001', '(', '\016', '2', '>', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 
-'n', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'N', 'o', 't', 'F', 'o', 'u', 'n', 'd', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 
-'C', 'o', 'd', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\033', 'c', 'l', 'u', 's', 't', 'e', 'r', 'N', 'o', 
-'t', 'F', 'o', 'u', 'n', 'd', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', '\022', 'E', '\n', '\016', 'm', 'e', 't', 
-'a', 'd', 'a', 't', 'a', '_', 'm', 'a', 't', 'c', 'h', '\030', '\004', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', 
-'\r', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'M', 'a', 't', 'c', 'h', '\022', '2', '\n', '\016', 'p', 'r', 'e', 'f', 'i', 'x', '_', 
-'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', '\005', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', 
-'\000', 'R', '\r', 'p', 'r', 'e', 'f', 'i', 'x', 'R', 'e', 'w', 'r', 'i', 't', 'e', '\022', 'S', '\n', '\r', 'r', 'e', 'g', 'e', 'x', 
-'_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', ' ', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 
-'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'A', 
-'n', 'd', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 'e', 'R', '\014', 'r', 'e', 'g', 'e', 'x', 'R', 'e', 'w', 'r', 'i', 't', 
-'e', '\022', '?', '\n', '\024', 'h', 'o', 's', 't', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 'l', 'i', 't', 'e', 'r', 'a', 'l', 
-'\030', '\006', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'H', '\001', 'R', '\022', 'h', 'o', 
-'s', 't', 'R', 'e', 'w', 'r', 'i', 't', 'e', 'L', 'i', 't', 'e', 'r', 'a', 'l', '\022', 'H', '\n', '\021', 'a', 'u', 't', 'o', '_', 
-'h', 'o', 's', 't', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', '\007', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'H', '\001', 'R', '\017', 
-'a', 'u', 't', 'o', 'H', 'o', 's', 't', 'R', 'e', 'w', 'r', 'i', 't', 'e', '\022', '=', '\n', '\023', 'h', 'o', 's', 't', '_', 'r', 
-'e', 'w', 'r', 'i', 't', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\035', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', 
-'\006', '\300', '\001', '\001', '\310', '\001', '\000', 'H', '\001', 'R', '\021', 'h', 'o', 's', 't', 'R', 'e', 'w', 'r', 'i', 't', 'e', 'H', 'e', 'a', 
-'d', 'e', 'r', '\022', 'g', '\n', '\027', 'h', 'o', 's', 't', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 'p', 'a', 't', 'h', '_', 
-'r', 'e', 'g', 'e', 'x', '\030', '#', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 
-'m', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'A', 'n', 'd', 'S', 
-'u', 'b', 's', 't', 'i', 't', 'u', 't', 'e', 'H', '\001', 'R', '\024', 'h', 'o', 's', 't', 'R', 'e', 'w', 'r', 'i', 't', 'e', 'P', 
-'a', 't', 'h', 'R', 'e', 'g', 'e', 'x', '\022', '3', '\n', '\007', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\010', ' ', '\001', '(', '\013', 
+'e', 'n', 't', 'R', '\017', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', '\022', '>', '\n', '\007', 'h', 
+'e', 'a', 'd', 'e', 'r', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 
+'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\022', 'W', '\n', '\020', 'q', 'u', 'e', 'r', 'y', '_', 'p', 'a', 'r', 'a', 'm', 'e', 
+'t', 'e', 'r', 's', '\030', '\007', ' ', '\003', '(', '\013', '2', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 'M', 
+'a', 't', 'c', 'h', 'e', 'r', 'R', '\017', 'q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', '\022', 'K', 
+'\n', '\004', 'g', 'r', 'p', 'c', '\030', '\010', ' ', '\001', '(', '\013', '2', '7', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', '.', 'G', 'r', 
+'p', 'c', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\004', 'g', 'r', 'p', 'c', 
+'\022', 'Y', '\n', '\013', 't', 'l', 's', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\013', ' ', '\001', '(', '\013', '2', '8', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 
+'e', 'M', 'a', 't', 'c', 'h', '.', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'a', 't', 'c', 'h', 'O', 'p', 't', 
+'i', 'o', 'n', 's', 'R', '\n', 't', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\032', 'S', '\n', '\025', 'G', 'r', 'p', 'c', 'R', 
+'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'O', 'p', 't', 'i', 'o', 'n', 's', ':', ':', '\232', '\305', '\210', '\036', '5', '\n', '3', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'M', 
+'a', 't', 'c', 'h', '.', 'G', 'r', 'p', 'c', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'O', 'p', 't', 'i', 'o', 'n', 
+'s', '\032', '\311', '\001', '\n', '\026', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'a', 't', 'c', 'h', 'O', 'p', 't', 'i', 
+'o', 'n', 's', '\022', '8', '\n', '\t', 'p', 'r', 'e', 's', 'e', 'n', 't', 'e', 'd', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 
+'R', '\t', 'p', 'r', 'e', 's', 'e', 'n', 't', 'e', 'd', '\022', '8', '\n', '\t', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 'd', '\030', 
+'\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 
+'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 'd', ':', ';', '\232', '\305', '\210', '\036', 
+'6', '\n', '4', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 
+'t', 'e', 'M', 'a', 't', 'c', 'h', '.', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'a', 't', 'c', 'h', 'O', 'p', 
+'t', 'i', 'o', 'n', 's', '\032', '\020', '\n', '\016', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'M', 'a', 't', 'c', 'h', 'e', 'r', ':', '$', 
+'\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', 
+'.', 'R', 'o', 'u', 't', 'e', 'M', 'a', 't', 'c', 'h', 'B', '\025', '\n', '\016', 'p', 'a', 't', 'h', '_', 's', 'p', 'e', 'c', 'i', 
+'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\005', '\020', '\006', 'J', '\004', '\010', '\003', '\020', '\004', 'R', '\005', 'r', 'e', 
+'g', 'e', 'x', '\"', '\350', '\004', '\n', '\n', 'C', 'o', 'r', 's', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '_', '\n', '\031', 'a', 'l', 'l', 
+'o', 'w', '_', 'o', 'r', 'i', 'g', 'i', 'n', '_', 's', 't', 'r', 'i', 'n', 'g', '_', 'm', 'a', 't', 'c', 'h', '\030', '\013', ' ', 
+'\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 
+'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\026', 'a', 'l', 'l', 'o', 'w', 'O', 'r', 
+'i', 'g', 'i', 'n', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', '\022', '#', '\n', '\r', 'a', 'l', 'l', 'o', 'w', '_', 
+'m', 'e', 't', 'h', 'o', 'd', 's', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\014', 'a', 'l', 'l', 'o', 'w', 'M', 'e', 't', 'h', 'o', 
+'d', 's', '\022', '#', '\n', '\r', 'a', 'l', 'l', 'o', 'w', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\003', ' ', '\001', '(', '\t', 
+'R', '\014', 'a', 'l', 'l', 'o', 'w', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', '%', '\n', '\016', 'e', 'x', 'p', 'o', 's', 'e', '_', 
+'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\r', 'e', 'x', 'p', 'o', 's', 'e', 'H', 'e', 'a', 'd', 
+'e', 'r', 's', '\022', '\027', '\n', '\007', 'm', 'a', 'x', '_', 'a', 'g', 'e', '\030', '\005', ' ', '\001', '(', '\t', 'R', '\006', 'm', 'a', 'x', 
+'A', 'g', 'e', '\022', 'G', '\n', '\021', 'a', 'l', 'l', 'o', 'w', '_', 'c', 'r', 'e', 'd', 'e', 'n', 't', 'i', 'a', 'l', 's', '\030', 
+'\006', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 
+'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\020', 'a', 'l', 'l', 'o', 'w', 'C', 'r', 'e', 'd', 'e', 'n', 't', 'i', 'a', 'l', 
+'s', '\022', 'W', '\n', '\016', 'f', 'i', 'l', 't', 'e', 'r', '_', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\030', '\t', ' ', '\001', '(', '\013', 
+'2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 
+'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'H', '\000', 
+'R', '\r', 'f', 'i', 'l', 't', 'e', 'r', 'E', 'n', 'a', 'b', 'l', 'e', 'd', '\022', 'U', '\n', '\016', 's', 'h', 'a', 'd', 'o', 'w', 
+'_', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\030', '\n', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 
+'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\r', 's', 'h', 'a', 'd', 'o', 'w', 'E', 'n', 'a', 'b', 'l', 
+'e', 'd', ':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 
+'o', 'u', 't', 'e', '.', 'C', 'o', 'r', 's', 'P', 'o', 'l', 'i', 'c', 'y', 'B', '\023', '\n', '\021', 'e', 'n', 'a', 'b', 'l', 'e', 
+'d', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'J', '\004', '\010', '\001', '\020', '\002', 'J', '\004', '\010', '\010', '\020', '\t', 'J', '\004', 
+'\010', '\007', '\020', '\010', 'R', '\014', 'a', 'l', 'l', 'o', 'w', '_', 'o', 'r', 'i', 'g', 'i', 'n', 'R', '\022', 'a', 'l', 'l', 'o', 'w', 
+'_', 'o', 'r', 'i', 'g', 'i', 'n', '_', 'r', 'e', 'g', 'e', 'x', 'R', '\007', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\"', '\310', '&', 
+'\n', '\013', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '\022', '#', '\n', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', 
+'\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', 
+'\022', '6', '\n', '\016', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\t', 'B', 
+'\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'H', '\000', 'R', '\r', 'c', 'l', 'u', 's', 't', 'e', 'r', 
+'H', 'e', 'a', 'd', 'e', 'r', '\022', 'U', '\n', '\021', 'w', 'e', 'i', 'g', 'h', 't', 'e', 'd', '_', 'c', 'l', 'u', 's', 't', 'e', 
+'r', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 
+'o', 'u', 't', 'e', '.', 'v', '3', '.', 'W', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', 'H', '\000', 
+'R', '\020', 'w', 'e', 'i', 'g', 'h', 't', 'e', 'd', 'C', 'l', 'u', 's', 't', 'e', 'r', 's', '\022', '\216', '\001', '\n', '\037', 'c', 'l', 
+'u', 's', 't', 'e', 'r', '_', 'n', 'o', 't', '_', 'f', 'o', 'u', 'n', 'd', '_', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 
+'c', 'o', 'd', 'e', '\030', '\024', ' ', '\001', '(', '\016', '2', '>', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'C', 'l', 'u', 
+'s', 't', 'e', 'r', 'N', 'o', 't', 'F', 'o', 'u', 'n', 'd', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', 'B', 
+'\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\033', 'c', 'l', 'u', 's', 't', 'e', 'r', 'N', 'o', 't', 'F', 'o', 'u', 'n', 
+'d', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', '\022', 'E', '\n', '\016', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 
+'_', 'm', 'a', 't', 'c', 'h', '\030', '\004', ' ', '\001', '(', '\013', '2', '\036', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'R', '\r', 'm', 'e', 't', 'a', 
+'d', 'a', 't', 'a', 'M', 'a', 't', 'c', 'h', '\022', '2', '\n', '\016', 'p', 'r', 'e', 'f', 'i', 'x', '_', 'r', 'e', 'w', 'r', 'i', 
+'t', 'e', '\030', '\005', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\r', 'p', 'r', 
+'e', 'f', 'i', 'x', 'R', 'e', 'w', 'r', 'i', 't', 'e', '\022', 'S', '\n', '\r', 'r', 'e', 'g', 'e', 'x', '_', 'r', 'e', 'w', 'r', 
+'i', 't', 'e', '\030', ' ', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 
+'t', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'A', 'n', 'd', 'S', 'u', 'b', 
+'s', 't', 'i', 't', 'u', 't', 'e', 'R', '\014', 'r', 'e', 'g', 'e', 'x', 'R', 'e', 'w', 'r', 'i', 't', 'e', '\022', '?', '\n', '\024', 
+'h', 'o', 's', 't', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 'l', 'i', 't', 'e', 'r', 'a', 'l', '\030', '\006', ' ', '\001', '(', 
+'\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'H', '\001', 'R', '\022', 'h', 'o', 's', 't', 'R', 'e', 'w', 
+'r', 'i', 't', 'e', 'L', 'i', 't', 'e', 'r', 'a', 'l', '\022', 'H', '\n', '\021', 'a', 'u', 't', 'o', '_', 'h', 'o', 's', 't', '_', 
+'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', '\007', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'H', '\001', 'R', '\017', 'a', 'u', 't', 'o', 'H', 
+'o', 's', 't', 'R', 'e', 'w', 'r', 'i', 't', 'e', '\022', '=', '\n', '\023', 'h', 'o', 's', 't', '_', 'r', 'e', 'w', 'r', 'i', 't', 
+'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\035', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\001', '\310', 
+'\001', '\000', 'H', '\001', 'R', '\021', 'h', 'o', 's', 't', 'R', 'e', 'w', 'r', 'i', 't', 'e', 'H', 'e', 'a', 'd', 'e', 'r', '\022', 'g', 
+'\n', '\027', 'h', 'o', 's', 't', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 'p', 'a', 't', 'h', '_', 'r', 'e', 'g', 'e', 'x', 
+'\030', '#', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 
+'e', 'r', '.', 'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'A', 'n', 'd', 'S', 'u', 'b', 's', 't', 'i', 
+'t', 'u', 't', 'e', 'H', '\001', 'R', '\024', 'h', 'o', 's', 't', 'R', 'e', 'w', 'r', 'i', 't', 'e', 'P', 'a', 't', 'h', 'R', 'e', 
+'g', 'e', 'x', '\022', '3', '\n', '\007', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\010', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\007', 't', 
+'i', 'm', 'e', 'o', 'u', 't', '\022', '<', '\n', '\014', 'i', 'd', 'l', 'e', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\030', ' ', 
+'\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 
+'a', 't', 'i', 'o', 'n', 'R', '\013', 'i', 'd', 'l', 'e', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'E', '\n', '\014', 'r', 'e', 't', 
+'r', 'y', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\t', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 
+'y', 'R', '\013', 'r', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'O', '\n', '\031', 'r', 'e', 't', 'r', 'y', '_', 'p', 
+'o', 'l', 'i', 'c', 'y', '_', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '!', ' ', '\001', '(', '\013', '2', 
+'\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\026', 'r', 'e', 
+'t', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 'T', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'n', '\n', '\027', 'r', 
+'e', 'q', 'u', 'e', 's', 't', '_', 'm', 'i', 'r', 'r', 'o', 'r', '_', 'p', 'o', 'l', 'i', 'c', 'i', 'e', 's', '\030', '\036', ' ', 
+'\003', '(', '\013', '2', '6', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 
+'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'M', 'i', 'r', 
+'r', 'o', 'r', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\025', 'r', 'e', 'q', 'u', 'e', 's', 't', 'M', 'i', 'r', 'r', 'o', 'r', 'P', 
+'o', 'l', 'i', 'c', 'i', 'e', 's', '\022', 'K', '\n', '\010', 'p', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\030', '\013', ' ', '\001', '(', '\016', 
+'2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 
+'o', 'u', 't', 'i', 'n', 'g', 'P', 'r', 'i', 'o', 'r', 'i', 't', 'y', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', 
+'\010', 'p', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\022', 'A', '\n', '\013', 'r', 'a', 't', 'e', '_', 'l', 'i', 'm', 'i', 't', 's', '\030', 
+'\r', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 
+'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'R', '\n', 'r', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 
+'s', '\022', 'S', '\n', '\026', 'i', 'n', 'c', 'l', 'u', 'd', 'e', '_', 'v', 'h', '_', 'r', 'a', 't', 'e', '_', 'l', 'i', 'm', 'i', 
+'t', 's', '\030', '\016', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'B', '\002', '\030', '\001', 'R', '\023', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 'V', 
+'h', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 's', '\022', 'N', '\n', '\013', 'h', 'a', 's', 'h', '_', 'p', 'o', 'l', 'i', 'c', 
+'y', '\030', '\017', ' ', '\003', '(', '\013', '2', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 
+'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 
+'l', 'i', 'c', 'y', 'R', '\n', 'h', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '5', '\n', '\004', 'c', 'o', 'r', 's', '\030', 
+'\021', ' ', '\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 
+'e', '.', 'v', '3', '.', 'C', 'o', 'r', 's', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\004', 'c', 'o', 'r', 's', '\022', 'G', '\n', '\020', 
+'m', 'a', 'x', '_', 'g', 'r', 'p', 'c', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\027', ' ', '\001', '(', '\013', '2', '\031', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', 
+'\002', '\030', '\001', 'R', '\016', 'm', 'a', 'x', 'G', 'r', 'p', 'c', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'M', '\n', '\023', 'g', 'r', 
+'p', 'c', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'o', 'f', 'f', 's', 'e', 't', '\030', '\034', ' ', '\001', '(', '\013', '2', '\031', 
+'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 
+'B', '\002', '\030', '\001', 'R', '\021', 'g', 'r', 'p', 'c', 'T', 'i', 'm', 'e', 'o', 'u', 't', 'O', 'f', 'f', 's', 'e', 't', '\022', 'Y', 
+'\n', '\017', 'u', 'p', 'g', 'r', 'a', 'd', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\031', ' ', '\003', '(', '\013', '2', '0', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 
+'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 
+'u', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', 'g', '\n', '\030', 'i', 'n', 't', 'e', 'r', 'n', 'a', 
+'l', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\"', ' ', '\001', '(', '\013', '2', '-', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'I', 'n', 
+'t', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\026', 'i', 'n', 't', 
+'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'w', '\n', '\030', 'i', 'n', 
+'t', 'e', 'r', 'n', 'a', 'l', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '_', 'a', 'c', 't', 'i', 'o', 'n', '\030', '\032', ' ', 
+'\001', '(', '\016', '2', '9', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 
+'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 
+'d', 'i', 'r', 'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', 'B', '\002', '\030', '\001', 'R', '\026', 'i', 'n', 't', 'e', 'r', 'n', 'a', 
+'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', '\022', 'V', '\n', '\026', 'm', 'a', 'x', '_', 'i', 'n', 
+'t', 'e', 'r', 'n', 'a', 'l', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', 's', '\030', '\037', ' ', '\001', '(', '\013', '2', '\034', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 
+'u', 'e', 'B', '\002', '\030', '\001', 'R', '\024', 'm', 'a', 'x', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 
+'c', 't', 's', '\022', 'E', '\n', '\014', 'h', 'e', 'd', 'g', 'e', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\033', ' ', '\001', '(', '\013', 
+'2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 
+'H', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\013', 'h', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 
+'d', '\n', '\023', 'm', 'a', 'x', '_', 's', 't', 'r', 'e', 'a', 'm', '_', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\030', '$', ' ', 
+'\001', '(', '\013', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 
+'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'M', 'a', 'x', 'S', 't', 'r', 'e', 'a', 'm', 'D', 
+'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\021', 'm', 'a', 'x', 'S', 't', 'r', 'e', 'a', 'm', 'D', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', '\032', '\242', '\002', '\n', '\023', 'R', 'e', 'q', 'u', 'e', 's', 't', 'M', 'i', 'r', 'r', 'o', 'r', 'P', 'o', 'l', 'i', 'c', 'y', 
+'\022', '!', '\n', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', 
+'\001', 'R', '\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\022', 'Y', '\n', '\020', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'f', 'r', 'a', 
+'c', 't', 'i', 'o', 'n', '\030', '\003', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 
+'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\017', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 
+'n', '\022', '?', '\n', '\r', 't', 'r', 'a', 'c', 'e', '_', 's', 'a', 'm', 'p', 'l', 'e', 'd', '\030', '\004', ' ', '\001', '(', '\013', '2', 
+'\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 
+'u', 'e', 'R', '\014', 't', 'r', 'a', 'c', 'e', 'S', 'a', 'm', 'p', 'l', 'e', 'd', ':', '9', '\232', '\305', '\210', '\036', '4', '\n', '2', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 
+'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'M', 'i', 'r', 'r', 'o', 'r', 'P', 'o', 'l', 'i', 'c', 'y', 
+'J', '\004', '\010', '\002', '\020', '\003', 'R', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\032', '\226', '\n', '\n', '\n', 'H', 
+'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'N', '\n', '\006', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', 
+'2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 
+'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'H', 'e', 
+'a', 'd', 'e', 'r', 'H', '\000', 'R', '\006', 'h', 'e', 'a', 'd', 'e', 'r', '\022', 'N', '\n', '\006', 'c', 'o', 'o', 'k', 'i', 'e', '\030', 
+'\002', ' ', '\001', '(', '\013', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 
+'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 
+'c', 'y', '.', 'C', 'o', 'o', 'k', 'i', 'e', 'H', '\000', 'R', '\006', 'c', 'o', 'o', 'k', 'i', 'e', '\022', 'y', '\n', '\025', 'c', 'o', 
+'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', '\030', '\003', ' ', '\001', '(', '\013', 
+'2', 'B', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 
+'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'C', 'o', 
+'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 'H', '\000', 'R', '\024', 'c', 'o', 'n', 
+'n', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', '\022', 'g', '\n', '\017', 'q', 'u', 'e', 'r', 
+'y', '_', 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', '\030', '\005', ' ', '\001', '(', '\013', '2', '<', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 
+'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 
+'e', 't', 'e', 'r', 'H', '\000', 'R', '\016', 'q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', '\022', '^', '\n', 
+'\014', 'f', 'i', 'l', 't', 'e', 'r', '_', 's', 't', 'a', 't', 'e', '\030', '\006', ' ', '\001', '(', '\013', '2', '9', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 
+'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'F', 'i', 'l', 't', 'e', 'r', 'S', 't', 
+'a', 't', 'e', 'H', '\000', 'R', '\013', 'f', 'i', 'l', 't', 'e', 'r', 'S', 't', 'a', 't', 'e', '\022', '\032', '\n', '\010', 't', 'e', 'r', 
+'m', 'i', 'n', 'a', 'l', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\010', 't', 'e', 'r', 'm', 'i', 'n', 'a', 'l', '\032', '\306', '\001', '\n', 
+'\006', 'H', 'e', 'a', 'd', 'e', 'r', '\022', '.', '\n', '\013', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', 
+'\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\n', 'h', 'e', 'a', 'd', 'e', 
+'r', 'N', 'a', 'm', 'e', '\022', 'S', '\n', '\r', 'r', 'e', 'g', 'e', 'x', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', '\002', ' ', 
+'\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 
+'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'A', 'n', 'd', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 
+'e', 'R', '\014', 'r', 'e', 'g', 'e', 'x', 'R', 'e', 'w', 'r', 'i', 't', 'e', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 
+'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 
+'t', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'H', 'e', 'a', 'd', 'e', 'r', '\032', '\237', '\001', 
+'\n', '\006', 'C', 'o', 'o', 'k', 'i', 'e', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 
+'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '+', '\n', '\003', 't', 't', 'l', '\030', '\002', ' ', '\001', '(', '\013', 
 '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 
-'o', 'n', 'R', '\007', 't', 'i', 'm', 'e', 'o', 'u', 't', '\022', '<', '\n', '\014', 'i', 'd', 'l', 'e', '_', 't', 'i', 'm', 'e', 'o', 
-'u', 't', '\030', '\030', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
-'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\013', 'i', 'd', 'l', 'e', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'E', 
-'\n', '\014', 'r', 'e', 't', 'r', 'y', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\t', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 
-'P', 'o', 'l', 'i', 'c', 'y', 'R', '\013', 'r', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'O', '\n', '\031', 'r', 'e', 
-'t', 'r', 'y', '_', 'p', 'o', 'l', 'i', 'c', 'y', '_', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '!', 
-' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 
-'y', 'R', '\026', 'r', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 'T', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 
-'\022', 'n', '\n', '\027', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'm', 'i', 'r', 'r', 'o', 'r', '_', 'p', 'o', 'l', 'i', 'c', 'i', 
-'e', 's', '\030', '\036', ' ', '\003', '(', '\013', '2', '6', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 
-'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'q', 'u', 'e', 
-'s', 't', 'M', 'i', 'r', 'r', 'o', 'r', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\025', 'r', 'e', 'q', 'u', 'e', 's', 't', 'M', 'i', 
-'r', 'r', 'o', 'r', 'P', 'o', 'l', 'i', 'c', 'i', 'e', 's', '\022', 'K', '\n', '\010', 'p', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\030', 
-'\013', ' ', '\001', '(', '\016', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
-'.', 'v', '3', '.', 'R', 'o', 'u', 't', 'i', 'n', 'g', 'P', 'r', 'i', 'o', 'r', 'i', 't', 'y', 'B', '\010', '\372', 'B', '\005', '\202', 
-'\001', '\002', '\020', '\001', 'R', '\010', 'p', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\022', 'A', '\n', '\013', 'r', 'a', 't', 'e', '_', 'l', 'i', 
-'m', 'i', 't', 's', '\030', '\r', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'R', '\n', 'r', 'a', 't', 'e', 
-'L', 'i', 'm', 'i', 't', 's', '\022', 'S', '\n', '\026', 'i', 'n', 'c', 'l', 'u', 'd', 'e', '_', 'v', 'h', '_', 'r', 'a', 't', 'e', 
-'_', 'l', 'i', 'm', 'i', 't', 's', '\030', '\016', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
-'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'B', '\002', '\030', '\001', 'R', '\023', 'i', 'n', 'c', 
-'l', 'u', 'd', 'e', 'V', 'h', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 's', '\022', 'N', '\n', '\013', 'h', 'a', 's', 'h', '_', 
-'p', 'o', 'l', 'i', 'c', 'y', '\030', '\017', ' ', '\003', '(', '\013', '2', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 
-'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\n', 'h', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '5', '\n', '\004', 
-'c', 'o', 'r', 's', '\030', '\021', ' ', '\001', '(', '\013', '2', '!', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'C', 'o', 'r', 's', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\004', 'c', 'o', 'r', 
-'s', '\022', 'C', '\n', '\020', 'm', 'a', 'x', '_', 'g', 'r', 'p', 'c', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\027', ' ', '\001', 
-'(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 
-'t', 'i', 'o', 'n', 'R', '\016', 'm', 'a', 'x', 'G', 'r', 'p', 'c', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'I', '\n', '\023', 'g', 
-'r', 'p', 'c', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'o', 'f', 'f', 's', 'e', 't', '\030', '\034', ' ', '\001', '(', '\013', '2', 
-'\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 
-'n', 'R', '\021', 'g', 'r', 'p', 'c', 'T', 'i', 'm', 'e', 'o', 'u', 't', 'O', 'f', 'f', 's', 'e', 't', '\022', 'Y', '\n', '\017', 'u', 
-'p', 'g', 'r', 'a', 'd', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\031', ' ', '\003', '(', '\013', '2', '0', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 
-'A', 'c', 't', 'i', 'o', 'n', '.', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'u', 'p', 'g', 
-'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', 'g', '\n', '\030', 'i', 'n', 't', 'e', 'r', 'n', 'a', 'l', '_', 'r', 
-'e', 'd', 'i', 'r', 'e', 'c', 't', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\"', ' ', '\001', '(', '\013', '2', '-', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'I', 'n', 't', 'e', 'r', 
-'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\026', 'i', 'n', 't', 'e', 'r', 'n', 
-'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'w', '\n', '\030', 'i', 'n', 't', 'e', 'r', 
-'n', 'a', 'l', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '_', 'a', 'c', 't', 'i', 'o', 'n', '\030', '\032', ' ', '\001', '(', '\016', 
-'2', '9', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 
-'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 
-'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', 'B', '\002', '\030', '\001', 'R', '\026', 'i', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 
-'d', 'i', 'r', 'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', '\022', 'V', '\n', '\026', 'm', 'a', 'x', '_', 'i', 'n', 't', 'e', 'r', 
-'n', 'a', 'l', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', 's', '\030', '\037', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 
-'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', 
-'\002', '\030', '\001', 'R', '\024', 'm', 'a', 'x', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 's', 
-'\022', 'E', '\n', '\014', 'h', 'e', 'd', 'g', 'e', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\033', ' ', '\001', '(', '\013', '2', '\"', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'd', 
-'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', 'R', '\013', 'h', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'd', '\n', '\023', 
-'m', 'a', 'x', '_', 's', 't', 'r', 'e', 'a', 'm', '_', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\030', '$', ' ', '\001', '(', '\013', 
-'2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 
-'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'M', 'a', 'x', 'S', 't', 'r', 'e', 'a', 'm', 'D', 'u', 'r', 'a', 
-'t', 'i', 'o', 'n', 'R', '\021', 'm', 'a', 'x', 'S', 't', 'r', 'e', 'a', 'm', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\032', '\242', 
-'\002', '\n', '\023', 'R', 'e', 'q', 'u', 'e', 's', 't', 'M', 'i', 'r', 'r', 'o', 'r', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '!', '\n', 
-'\007', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\007', 
-'c', 'l', 'u', 's', 't', 'e', 'r', '\022', 'Y', '\n', '\020', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'f', 'r', 'a', 'c', 't', 'i', 
-'o', 'n', '\030', '\003', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 
-'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 
-'e', 'r', 'c', 'e', 'n', 't', 'R', '\017', 'r', 'u', 'n', 't', 'i', 'm', 'e', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', '\022', '?', 
-'\n', '\r', 't', 'r', 'a', 'c', 'e', '_', 's', 'a', 'm', 'p', 'l', 'e', 'd', '\030', '\004', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 
-'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', 
-'\014', 't', 'r', 'a', 'c', 'e', 'S', 'a', 'm', 'p', 'l', 'e', 'd', ':', '9', '\232', '\305', '\210', '\036', '4', '\n', '2', 'e', 'n', 'v', 
-'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 
-'o', 'n', '.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'M', 'i', 'r', 'r', 'o', 'r', 'P', 'o', 'l', 'i', 'c', 'y', 'J', '\004', '\010', 
-'\002', '\020', '\003', 'R', '\013', 'r', 'u', 'n', 't', 'i', 'm', 'e', '_', 'k', 'e', 'y', '\032', '\226', '\n', '\n', '\n', 'H', 'a', 's', 'h', 
-'P', 'o', 'l', 'i', 'c', 'y', '\022', 'N', '\n', '\006', 'h', 'e', 'a', 'd', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '4', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 
-'t', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'H', 'e', 'a', 'd', 'e', 
-'r', 'H', '\000', 'R', '\006', 'h', 'e', 'a', 'd', 'e', 'r', '\022', 'N', '\n', '\006', 'c', 'o', 'o', 'k', 'i', 'e', '\030', '\002', ' ', '\001', 
-'(', '\013', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', 
-'3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 
-'C', 'o', 'o', 'k', 'i', 'e', 'H', '\000', 'R', '\006', 'c', 'o', 'o', 'k', 'i', 'e', '\022', 'y', '\n', '\025', 'c', 'o', 'n', 'n', 'e', 
-'c', 't', 'i', 'o', 'n', '_', 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', 'B', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 
-'t', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'C', 'o', 'n', 'n', 'e', 
-'c', 't', 'i', 'o', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 'H', '\000', 'R', '\024', 'c', 'o', 'n', 'n', 'e', 'c', 
-'t', 'i', 'o', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', '\022', 'g', '\n', '\017', 'q', 'u', 'e', 'r', 'y', '_', 'p', 
-'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', '\030', '\005', ' ', '\001', '(', '\013', '2', '<', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', 
-'.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 
-'r', 'H', '\000', 'R', '\016', 'q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', '\022', '^', '\n', '\014', 'f', 'i', 
-'l', 't', 'e', 'r', '_', 's', 't', 'a', 't', 'e', '\030', '\006', ' ', '\001', '(', '\013', '2', '9', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 
-'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'F', 'i', 'l', 't', 'e', 'r', 'S', 't', 'a', 't', 'e', 
-'H', '\000', 'R', '\013', 'f', 'i', 'l', 't', 'e', 'r', 'S', 't', 'a', 't', 'e', '\022', '\032', '\n', '\010', 't', 'e', 'r', 'm', 'i', 'n', 
-'a', 'l', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\010', 't', 'e', 'r', 'm', 'i', 'n', 'a', 'l', '\032', '\306', '\001', '\n', '\006', 'H', 'e', 
-'a', 'd', 'e', 'r', '\022', '.', '\n', '\013', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
-'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\n', 'h', 'e', 'a', 'd', 'e', 'r', 'N', 'a', 
-'m', 'e', '\022', 'S', '\n', '\r', 'r', 'e', 'g', 'e', 'x', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', 
-'2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 
-'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'A', 'n', 'd', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 'e', 'R', '\014', 
-'r', 'e', 'g', 'e', 'x', 'R', 'e', 'w', 'r', 'i', 't', 'e', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 
-'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 
-'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'H', 'e', 'a', 'd', 'e', 'r', '\032', '\237', '\001', '\n', '\006', 'C', 
-'o', 'o', 'k', 'i', 'e', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', 
-'\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '+', '\n', '\003', 't', 't', 'l', '\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 
-'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', 
-'\003', 't', 't', 'l', '\022', '\022', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\004', 'p', 'a', 't', 'h', ':', 
-'7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 
-'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 
-'C', 'o', 'o', 'k', 'i', 'e', '\032', 'z', '\n', '\024', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'r', 'o', 'p', 'e', 
-'r', 't', 'i', 'e', 's', '\022', '\033', '\n', '\t', 's', 'o', 'u', 'r', 'c', 'e', '_', 'i', 'p', '\030', '\001', ' ', '\001', '(', '\010', 'R', 
-'\010', 's', 'o', 'u', 'r', 'c', 'e', 'I', 'p', ':', 'E', '\232', '\305', '\210', '\036', '@', '\n', '>', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
-'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 
-'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'r', 'o', 'p', 'e', 
-'r', 't', 'i', 'e', 's', '\032', 'n', '\n', '\016', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', '\022', '\033', 
-'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 
-'m', 'e', ':', '?', '\232', '\305', '\210', '\036', ':', '\n', '8', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 
+'o', 'n', 'R', '\003', 't', 't', 'l', '\022', '\022', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\004', 'p', 'a', 
+'t', 'h', ':', '7', '\232', '\305', '\210', '\036', '2', '\n', '0', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 
 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 
-'c', 'y', '.', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', '\032', 'f', '\n', '\013', 'F', 'i', 'l', 't', 
-'e', 'r', 'S', 't', 'a', 't', 'e', '\022', '\031', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 
-'r', '\002', '\020', '\001', 'R', '\003', 'k', 'e', 'y', ':', '<', '\232', '\305', '\210', '\036', '7', '\n', '5', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
-'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 
-'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'F', 'i', 'l', 't', 'e', 'r', 'S', 't', 'a', 't', 'e', ':', '0', '\232', '\305', 
-'\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 
-'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', 'B', '\027', '\n', '\020', 
-'p', 'o', 'l', 'i', 'c', 'y', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', '\032', '\201', '\003', '\n', 
-'\r', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '.', '\n', '\014', 'u', 'p', 'g', 'r', 'a', 'd', 'e', 
-'_', 't', 'y', 'p', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', 
-'\013', 'u', 'p', 'g', 'r', 'a', 'd', 'e', 'T', 'y', 'p', 'e', '\022', '4', '\n', '\007', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\030', '\002', 
-' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 
-'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\007', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\022', 'e', '\n', '\016', 'c', 'o', 'n', 'n', 'e', 
-'c', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '>', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 
-'n', '.', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'C', 'o', 
-'n', 'f', 'i', 'g', 'R', '\r', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\032', 'n', '\n', '\r', 'C', 'o', 
-'n', 'n', 'e', 'c', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', ']', '\n', '\025', 'p', 'r', 'o', 'x', 'y', '_', 'p', 'r', 'o', 't', 
-'o', 'c', 'o', 'l', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'P', 'r', 'o', 'x', 'y', 'P', 'r', 'o', 't', 
-'o', 'c', 'o', 'l', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\023', 'p', 'r', 'o', 'x', 'y', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 
-'C', 'o', 'n', 'f', 'i', 'g', ':', '3', '\232', '\305', '\210', '\036', '.', '\n', ',', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 
-'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'U', 'p', 'g', 'r', 
-'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\210', '\002', '\n', '\021', 'M', 'a', 'x', 'S', 't', 'r', 'e', 'a', 'm', 'D', 'u', 
-'r', 'a', 't', 'i', 'o', 'n', '\022', 'I', '\n', '\023', 'm', 'a', 'x', '_', 's', 't', 'r', 'e', 'a', 'm', '_', 'd', 'u', 'r', 'a', 
-'t', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
-'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\021', 'm', 'a', 'x', 'S', 't', 'r', 'e', 'a', 'm', 'D', 'u', 
-'r', 'a', 't', 'i', 'o', 'n', '\022', 'P', '\n', '\027', 'g', 'r', 'p', 'c', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'h', 'e', 
-'a', 'd', 'e', 'r', '_', 'm', 'a', 'x', '\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
-'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\024', 'g', 'r', 'p', 'c', 'T', 'i', 'm', 
-'e', 'o', 'u', 't', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 'x', '\022', 'V', '\n', '\032', 'g', 'r', 'p', 'c', '_', 't', 'i', 'm', 
-'e', 'o', 'u', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'o', 'f', 'f', 's', 'e', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', 
-'\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 
-'n', 'R', '\027', 'g', 'r', 'p', 'c', 'T', 'i', 'm', 'e', 'o', 'u', 't', 'H', 'e', 'a', 'd', 'e', 'r', 'O', 'f', 'f', 's', 'e', 
-'t', '\"', 'E', '\n', '\033', 'C', 'l', 'u', 's', 't', 'e', 'r', 'N', 'o', 't', 'F', 'o', 'u', 'n', 'd', 'R', 'e', 's', 'p', 'o', 
-'n', 's', 'e', 'C', 'o', 'd', 'e', '\022', '\027', '\n', '\023', 'S', 'E', 'R', 'V', 'I', 'C', 'E', '_', 'U', 'N', 'A', 'V', 'A', 'I', 
-'L', 'A', 'B', 'L', 'E', '\020', '\000', '\022', '\r', '\n', '\t', 'N', 'O', 'T', '_', 'F', 'O', 'U', 'N', 'D', '\020', '\001', '\"', '^', '\n', 
-'\026', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', '\022', '\"', 
-'\n', '\036', 'P', 'A', 'S', 'S', '_', 'T', 'H', 'R', 'O', 'U', 'G', 'H', '_', 'I', 'N', 'T', 'E', 'R', 'N', 'A', 'L', '_', 'R', 
-'E', 'D', 'I', 'R', 'E', 'C', 'T', '\020', '\000', '\022', '\034', '\n', '\030', 'H', 'A', 'N', 'D', 'L', 'E', '_', 'I', 'N', 'T', 'E', 'R', 
-'N', 'A', 'L', '_', 'R', 'E', 'D', 'I', 'R', 'E', 'C', 'T', '\020', '\001', '\032', '\002', '\030', '\001', ':', '%', '\232', '\305', '\210', '\036', ' ', 
-'\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 
-'e', 'A', 'c', 't', 'i', 'o', 'n', 'B', '\030', '\n', '\021', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 's', 'p', 'e', 'c', 'i', 'f', 
-'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'B', '\030', '\n', '\026', 'h', 'o', 's', 't', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 
-'s', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'J', '\004', '\010', '\014', '\020', '\r', 'J', '\004', '\010', '\022', '\020', '\023', 'J', '\004', '\010', '\023', 
-'\020', '\024', 'J', '\004', '\010', '\020', '\020', '\021', 'J', '\004', '\010', '\026', '\020', '\027', 'J', '\004', '\010', '\025', '\020', '\026', 'J', '\004', '\010', '\n', '\020', 
-'\013', 'R', '\025', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'm', 'i', 'r', 'r', 'o', 'r', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\"', 
-'\215', '\017', '\n', '\013', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\022', '\031', '\n', '\010', 'r', 'e', 't', 'r', 'y', '_', 
-'o', 'n', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\007', 'r', 'e', 't', 'r', 'y', 'O', 'n', '\022', 'R', '\n', '\013', 'n', 'u', 'm', '_', 
-'r', 'e', 't', 'r', 'i', 'e', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
-'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\023', '\362', '\230', '\376', '\217', '\005', 
-'\r', '\n', '\013', 'm', 'a', 'x', '_', 'r', 'e', 't', 'r', 'i', 'e', 's', 'R', '\n', 'n', 'u', 'm', 'R', 'e', 't', 'r', 'i', 'e', 
-'s', '\022', 'A', '\n', '\017', 'p', 'e', 'r', '_', 't', 'r', 'y', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\003', ' ', '\001', '(', 
+'c', 'y', '.', 'C', 'o', 'o', 'k', 'i', 'e', '\032', 'z', '\n', '\024', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'r', 
+'o', 'p', 'e', 'r', 't', 'i', 'e', 's', '\022', '\033', '\n', '\t', 's', 'o', 'u', 'r', 'c', 'e', '_', 'i', 'p', '\030', '\001', ' ', '\001', 
+'(', '\010', 'R', '\010', 's', 'o', 'u', 'r', 'c', 'e', 'I', 'p', ':', 'E', '\232', '\305', '\210', '\036', '@', '\n', '>', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 
+'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'P', 'r', 
+'o', 'p', 'e', 'r', 't', 'i', 'e', 's', '\032', 'n', '\n', '\016', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 
+'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', 
+'\004', 'n', 'a', 'm', 'e', ':', '?', '\232', '\305', '\210', '\036', ':', '\n', '8', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', 
+'2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 
+'o', 'l', 'i', 'c', 'y', '.', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', '\032', 'f', '\n', '\013', 'F', 
+'i', 'l', 't', 'e', 'r', 'S', 't', 'a', 't', 'e', '\022', '\031', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', 
+'\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\003', 'k', 'e', 'y', ':', '<', '\232', '\305', '\210', '\036', '7', '\n', '5', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 
+'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'F', 'i', 'l', 't', 'e', 'r', 'S', 't', 'a', 't', 'e', ':', 
+'0', '\232', '\305', '\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 
+'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'a', 's', 'h', 'P', 'o', 'l', 'i', 'c', 'y', 'B', 
+'\027', '\n', '\020', 'p', 'o', 'l', 'i', 'c', 'y', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', '\032', 
+'\243', '\003', '\n', '\r', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '0', '\n', '\014', 'u', 'p', 'g', 'r', 
+'a', 'd', 'e', '_', 't', 'y', 'p', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', 
+'\002', '\310', '\001', '\000', 'R', '\013', 'u', 'p', 'g', 'r', 'a', 'd', 'e', 'T', 'y', 'p', 'e', '\022', '4', '\n', '\007', 'e', 'n', 'a', 'b', 
+'l', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\007', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\022', 'e', '\n', '\016', 
+'c', 'o', 'n', 'n', 'e', 'c', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '>', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 
+'A', 'c', 't', 'i', 'o', 'n', '.', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '.', 'C', 'o', 'n', 'n', 
+'e', 'c', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\r', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\032', 
+'\215', '\001', '\n', '\r', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', ']', '\n', '\025', 'p', 'r', 'o', 'x', 
+'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', ')', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'P', 'r', 'o', 
+'x', 'y', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\023', 'p', 'r', 'o', 'x', 'y', 'P', 'r', 
+'o', 't', 'o', 'c', 'o', 'l', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '\035', '\n', '\n', 'a', 'l', 'l', 'o', 'w', '_', 'p', 'o', 's', 
+'t', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\t', 'a', 'l', 'l', 'o', 'w', 'P', 'o', 's', 't', ':', '3', '\232', '\305', '\210', '\036', '.', 
+'\n', ',', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 
+'e', 'A', 'c', 't', 'i', 'o', 'n', '.', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\210', '\002', '\n', 
+'\021', 'M', 'a', 'x', 'S', 't', 'r', 'e', 'a', 'm', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\022', 'I', '\n', '\023', 'm', 'a', 'x', 
+'_', 's', 't', 'r', 'e', 'a', 'm', '_', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', '\031', '.', 
+'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', 
+'\021', 'm', 'a', 'x', 'S', 't', 'r', 'e', 'a', 'm', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', '\022', 'P', '\n', '\027', 'g', 'r', 'p', 
+'c', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'm', 'a', 'x', '\030', '\002', ' ', '\001', '(', 
 '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 
-'i', 'o', 'n', 'R', '\r', 'p', 'e', 'r', 'T', 'r', 'y', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'W', '\n', '\016', 'r', 'e', 't', 
-'r', 'y', '_', 'p', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\030', '\004', ' ', '\001', '(', '\013', '2', '0', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 
-'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 'y', 'P', 'r', 'i', 'o', 'r', 'i', 't', 'y', 'R', '\r', 'r', 'e', 't', 'r', 'y', 'P', 
-'r', 'i', 'o', 'r', 'i', 't', 'y', '\022', 'g', '\n', '\024', 'r', 'e', 't', 'r', 'y', '_', 'h', 'o', 's', 't', '_', 'p', 'r', 'e', 
-'d', 'i', 'c', 'a', 't', 'e', '\030', '\005', ' ', '\003', '(', '\013', '2', '5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 
-'e', 't', 'r', 'y', 'H', 'o', 's', 't', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 'R', '\022', 'r', 'e', 't', 'r', 'y', 'H', 
-'o', 's', 't', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '\022', 'H', '\n', '!', 'h', 'o', 's', 't', '_', 's', 'e', 'l', 'e', 
-'c', 't', 'i', 'o', 'n', '_', 'r', 'e', 't', 'r', 'y', '_', 'm', 'a', 'x', '_', 'a', 't', 't', 'e', 'm', 'p', 't', 's', '\030', 
-'\006', ' ', '\001', '(', '\003', 'R', '\035', 'h', 'o', 's', 't', 'S', 'e', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'R', 'e', 't', 'r', 'y', 
-'M', 'a', 'x', 'A', 't', 't', 'e', 'm', 'p', 't', 's', '\022', '4', '\n', '\026', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', '_', 
-'s', 't', 'a', 't', 'u', 's', '_', 'c', 'o', 'd', 'e', 's', '\030', '\007', ' ', '\003', '(', '\r', 'R', '\024', 'r', 'e', 't', 'r', 'i', 
-'a', 'b', 'l', 'e', 'S', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', 's', '\022', 'U', '\n', '\016', 'r', 'e', 't', 'r', 'y', '_', 
-'b', 'a', 'c', 'k', '_', 'o', 'f', 'f', '\030', '\010', ' ', '\001', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 
-'.', 'R', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', 'R', '\014', 'r', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 
-'f', 'f', '\022', 'x', '\n', '\033', 'r', 'a', 't', 'e', '_', 'l', 'i', 'm', 'i', 't', 'e', 'd', '_', 'r', 'e', 't', 'r', 'y', '_', 
-'b', 'a', 'c', 'k', '_', 'o', 'f', 'f', '\030', '\013', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 
-'.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'e', 'd', 'R', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', 'R', 
-'\027', 'r', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'e', 'd', 'R', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\022', 
-'Q', '\n', '\021', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\t', ' ', '\003', '(', 
-'\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 
-'.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\020', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', 
-'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', '`', '\n', '\031', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', '_', 'r', 'e', 'q', 'u', 
-'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\n', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 
-'t', 'c', 'h', 'e', 'r', 'R', '\027', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 
-'a', 'd', 'e', 'r', 's', '\032', '\271', '\001', '\n', '\r', 'R', 'e', 't', 'r', 'y', 'P', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\022', '\033', 
-'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 
-'m', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', 
-'\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 
-'t', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '3', '\232', '\305', '\210', '\036', '.', '\n', ',', 'e', 'n', 'v', 'o', 'y', 
-'.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', 
-'.', 'R', 'e', 't', 'r', 'y', 'P', 'r', 'i', 'o', 'r', 'i', 't', 'y', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 
-'t', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\032', '\303', '\001', '\n', '\022', 'R', 'e', 
-'t', 'r', 'y', 'H', 'o', 's', 't', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', 
-'\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 
-'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 
-'n', 'f', 'i', 'g', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', 
-'.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 'y', 'H', 
-'o', 's', 't', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 
-'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\032', '\326', '\001', '\n', '\014', 'R', 'e', 't', 'r', 
-'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\022', 'J', '\n', '\r', 'b', 'a', 's', 'e', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', 
-'\030', '\001', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
-'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\n', '\372', 'B', '\007', '\252', '\001', '\004', '\010', '\001', '*', '\000', 'R', '\014', 'b', 'a', 's', 
-'e', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', 'F', '\n', '\014', 'm', 'a', 'x', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', 
-'\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
-'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\013', 'm', 'a', 'x', 'I', 'n', 
-'t', 'e', 'r', 'v', 'a', 'l', ':', '2', '\232', '\305', '\210', '\036', '-', '\n', '+', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 
-'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 
-'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\032', '\210', '\001', '\n', '\013', 'R', 'e', 's', 'e', 't', 'H', 'e', 'a', 'd', 'e', 'r', '\022', 
-'!', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', 
-'\310', '\001', '\000', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'V', '\n', '\006', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\002', ' ', '\001', '(', '\016', 
-'2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 
-'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 's', 'e', 't', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'o', 
-'r', 'm', 'a', 't', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\006', 'f', 'o', 'r', 'm', 'a', 't', '\032', '\300', '\001', 
-'\n', '\027', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'e', 'd', 'R', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', 
-'\022', ']', '\n', '\r', 'r', 'e', 's', 'e', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '.', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 
-'t', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 's', 'e', 't', 'H', 'e', 'a', 'd', 'e', 'r', 'B', '\010', '\372', 'B', 
-'\005', '\222', '\001', '\002', '\010', '\001', 'R', '\014', 'r', 'e', 's', 'e', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', 'F', '\n', '\014', 'm', 
-'a', 'x', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', 
-'\001', '\002', '*', '\000', 'R', '\013', 'm', 'a', 'x', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\"', '4', '\n', '\021', 'R', 'e', 's', 'e', 
-'t', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'o', 'r', 'm', 'a', 't', '\022', '\013', '\n', '\007', 'S', 'E', 'C', 'O', 'N', 'D', 'S', '\020', 
-'\000', '\022', '\022', '\n', '\016', 'U', 'N', 'I', 'X', '_', 'T', 'I', 'M', 'E', 'S', 'T', 'A', 'M', 'P', '\020', '\001', ':', '%', '\232', '\305', 
-'\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 
-'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\"', '\234', '\002', '\n', '\013', 'H', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 
-'y', '\022', 'P', '\n', '\020', 'i', 'n', 'i', 't', 'i', 'a', 'l', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', 's', '\030', '\001', ' ', '\001', 
-'(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', 
-'3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', '(', '\001', 'R', '\017', 'i', 'n', 'i', 't', 'i', 'a', 'l', 
-'R', 'e', 'q', 'u', 'e', 's', 't', 's', '\022', '\\', '\n', '\031', 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', '_', 'r', 'e', 
-'q', 'u', 'e', 's', 't', '_', 'c', 'h', 'a', 'n', 'c', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 
-'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 
-'n', 't', 'R', '\027', 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'R', 'e', 'q', 'u', 'e', 's', 't', 'C', 'h', 'a', 'n', 
-'c', 'e', '\022', '6', '\n', '\030', 'h', 'e', 'd', 'g', 'e', '_', 'o', 'n', '_', 'p', 'e', 'r', '_', 't', 'r', 'y', '_', 't', 'i', 
-'m', 'e', 'o', 'u', 't', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\024', 'h', 'e', 'd', 'g', 'e', 'O', 'n', 'P', 'e', 'r', 'T', 'r', 
-'y', 'T', 'i', 'm', 'e', 'o', 'u', 't', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'H', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', '\"', '\212', '\005', 
-'\n', '\016', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', '\022', '\'', '\n', '\016', 'h', 't', 't', 'p', 's', 
-'_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\004', ' ', '\001', '(', '\010', 'H', '\000', 'R', '\r', 'h', 't', 't', 'p', 's', 'R', 
-'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', ')', '\n', '\017', 's', 'c', 'h', 'e', 'm', 'e', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 
-'t', '\030', '\007', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\016', 's', 'c', 'h', 'e', 'm', 'e', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 
-'\022', '0', '\n', '\r', 'h', 'o', 's', 't', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\013', 
-'\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\014', 'h', 'o', 's', 't', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 
-'\022', '#', '\n', '\r', 'p', 'o', 'r', 't', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\010', ' ', '\001', '(', '\r', 'R', '\014', 
-'p', 'o', 'r', 't', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', '2', '\n', '\r', 'p', 'a', 't', 'h', '_', 'r', 'e', 'd', 'i', 
-'r', 'e', 'c', 't', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'H', '\001', 
-'R', '\014', 'p', 'a', 't', 'h', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', '4', '\n', '\016', 'p', 'r', 'e', 'f', 'i', 'x', '_', 
-'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', '\005', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', 
-'\000', 'H', '\001', 'R', '\r', 'p', 'r', 'e', 'f', 'i', 'x', 'R', 'e', 'w', 'r', 'i', 't', 'e', '\022', 'i', '\n', '\r', 'r', 'e', 's', 
-'p', 'o', 'n', 's', 'e', '_', 'c', 'o', 'd', 'e', '\030', '\003', ' ', '\001', '(', '\016', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 
-'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 
-'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\014', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', 
-'\022', '\037', '\n', '\013', 's', 't', 'r', 'i', 'p', '_', 'q', 'u', 'e', 'r', 'y', '\030', '\006', ' ', '\001', '(', '\010', 'R', '\n', 's', 't', 
-'r', 'i', 'p', 'Q', 'u', 'e', 'r', 'y', '\"', 'w', '\n', '\024', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 
-'n', 's', 'e', 'C', 'o', 'd', 'e', '\022', '\025', '\n', '\021', 'M', 'O', 'V', 'E', 'D', '_', 'P', 'E', 'R', 'M', 'A', 'N', 'E', 'N', 
-'T', 'L', 'Y', '\020', '\000', '\022', '\t', '\n', '\005', 'F', 'O', 'U', 'N', 'D', '\020', '\001', '\022', '\r', '\n', '\t', 'S', 'E', 'E', '_', 'O', 
-'T', 'H', 'E', 'R', '\020', '\002', '\022', '\026', '\n', '\022', 'T', 'E', 'M', 'P', 'O', 'R', 'A', 'R', 'Y', '_', 'R', 'E', 'D', 'I', 'R', 
-'E', 'C', 'T', '\020', '\003', '\022', '\026', '\n', '\022', 'P', 'E', 'R', 'M', 'A', 'N', 'E', 'N', 'T', '_', 'R', 'E', 'D', 'I', 'R', 'E', 
-'C', 'T', '\020', '\004', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', 
-'.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', 'B', '\032', '\n', '\030', 
-'s', 'c', 'h', 'e', 'm', 'e', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'B', 
-'\030', '\n', '\026', 'p', 'a', 't', 'h', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 
-'\"', '\240', '\001', '\n', '\024', 'D', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'A', 'c', 't', 'i', 'o', 'n', 
-'\022', '\"', '\n', '\006', 's', 't', 'a', 't', 'u', 's', '\030', '\001', ' ', '\001', '(', '\r', 'B', '\n', '\372', 'B', '\007', '*', '\005', '\020', '\330', 
-'\004', '(', 'd', 'R', '\006', 's', 't', 'a', 't', 'u', 's', '\022', '4', '\n', '\004', 'b', 'o', 'd', 'y', '\030', '\002', ' ', '\001', '(', '\013', 
-'2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 
-'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\004', 'b', 'o', 'd', 'y', ':', '.', '\232', '\305', '\210', '\036', ')', '\n', '\'', 'e', 
-'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'D', 'i', 'r', 'e', 'c', 't', 'R', 
-'e', 's', 'p', 'o', 'n', 's', 'e', 'A', 'c', 't', 'i', 'o', 'n', '\"', '\221', '\001', '\n', '\t', 'D', 'e', 'c', 'o', 'r', 'a', 't', 
-'o', 'r', '\022', '%', '\n', '\t', 'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', 
-'\004', 'r', '\002', '\020', '\001', 'R', '\t', 'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', '\022', '8', '\n', '\t', 'p', 'r', 'o', 'p', 'a', 
-'g', 'a', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
-'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 'p', 'r', 'o', 'p', 'a', 'g', 'a', 't', 'e', ':', 
-'#', '\232', '\305', '\210', '\036', '\036', '\n', '\034', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 
-'e', '.', 'D', 'e', 'c', 'o', 'r', 'a', 't', 'o', 'r', '\"', '\322', '\002', '\n', '\007', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '\022', 'I', 
-'\n', '\017', 'c', 'l', 'i', 'e', 'n', 't', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 
-'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'c', 'l', 'i', 'e', 'n', 't', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', 'I', 
-'\n', '\017', 'r', 'a', 'n', 'd', 'o', 'm', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', ' ', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 
-'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'r', 'a', 'n', 'd', 'o', 'm', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', 'K', 
-'\n', '\020', 'o', 'v', 'e', 'r', 'a', 'l', 'l', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', 
-' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 
-'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\017', 'o', 'v', 'e', 'r', 'a', 'l', 'l', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', 
-'\022', 'A', '\n', '\013', 'c', 'u', 's', 't', 'o', 'm', '_', 't', 'a', 'g', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 't', 'r', 'a', 'c', 'i', 'n', 'g', '.', 'v', '3', '.', 'C', 'u', 's', 't', 
-'o', 'm', 'T', 'a', 'g', 'R', '\n', 'c', 'u', 's', 't', 'o', 'm', 'T', 'a', 'g', 's', ':', '!', '\232', '\305', '\210', '\036', '\034', '\n', 
-'\032', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'T', 'r', 'a', 'c', 'i', 
-'n', 'g', '\"', '\264', '\001', '\n', '\016', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', '>', '\n', '\007', 
-'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'i', 'o', 'n', 'R', '\024', 'g', 'r', 'p', 'c', 'T', 'i', 'm', 'e', 'o', 'u', 't', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 'x', 
+'\022', 'V', '\n', '\032', 'g', 'r', 'p', 'c', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'o', 
+'f', 'f', 's', 'e', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\027', 'g', 'r', 'p', 'c', 'T', 'i', 'm', 'e', 'o', 'u', 
+'t', 'H', 'e', 'a', 'd', 'e', 'r', 'O', 'f', 'f', 's', 'e', 't', '\"', 'E', '\n', '\033', 'C', 'l', 'u', 's', 't', 'e', 'r', 'N', 
+'o', 't', 'F', 'o', 'u', 'n', 'd', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', '\022', '\027', '\n', '\023', 'S', 'E', 
+'R', 'V', 'I', 'C', 'E', '_', 'U', 'N', 'A', 'V', 'A', 'I', 'L', 'A', 'B', 'L', 'E', '\020', '\000', '\022', '\r', '\n', '\t', 'N', 'O', 
+'T', '_', 'F', 'O', 'U', 'N', 'D', '\020', '\001', '\"', '^', '\n', '\026', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 
+'r', 'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', '\022', '\"', '\n', '\036', 'P', 'A', 'S', 'S', '_', 'T', 'H', 'R', 'O', 'U', 'G', 
+'H', '_', 'I', 'N', 'T', 'E', 'R', 'N', 'A', 'L', '_', 'R', 'E', 'D', 'I', 'R', 'E', 'C', 'T', '\020', '\000', '\022', '\034', '\n', '\030', 
+'H', 'A', 'N', 'D', 'L', 'E', '_', 'I', 'N', 'T', 'E', 'R', 'N', 'A', 'L', '_', 'R', 'E', 'D', 'I', 'R', 'E', 'C', 'T', '\020', 
+'\001', '\032', '\002', '\030', '\001', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', 
+'2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'o', 'u', 't', 'e', 'A', 'c', 't', 'i', 'o', 'n', 'B', '\030', '\n', '\021', 'c', 'l', 
+'u', 's', 't', 'e', 'r', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'B', '\030', '\n', '\026', 'h', 
+'o', 's', 't', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'J', '\004', '\010', '\014', 
+'\020', '\r', 'J', '\004', '\010', '\022', '\020', '\023', 'J', '\004', '\010', '\023', '\020', '\024', 'J', '\004', '\010', '\020', '\020', '\021', 'J', '\004', '\010', '\026', '\020', 
+'\027', 'J', '\004', '\010', '\025', '\020', '\026', 'J', '\004', '\010', '\n', '\020', '\013', 'R', '\025', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'm', 'i', 
+'r', 'r', 'o', 'r', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\"', '\215', '\017', '\n', '\013', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 
+'c', 'y', '\022', '\031', '\n', '\010', 'r', 'e', 't', 'r', 'y', '_', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\007', 'r', 'e', 't', 
+'r', 'y', 'O', 'n', '\022', 'R', '\n', '\013', 'n', 'u', 'm', '_', 'r', 'e', 't', 'r', 'i', 'e', 's', '\030', '\002', ' ', '\001', '(', '\013', 
+'2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 
+'V', 'a', 'l', 'u', 'e', 'B', '\023', '\362', '\230', '\376', '\217', '\005', '\r', '\n', '\013', 'm', 'a', 'x', '_', 'r', 'e', 't', 'r', 'i', 'e', 
+'s', 'R', '\n', 'n', 'u', 'm', 'R', 'e', 't', 'r', 'i', 'e', 's', '\022', 'A', '\n', '\017', 'p', 'e', 'r', '_', 't', 'r', 'y', '_', 
+'t', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\r', 'p', 'e', 'r', 'T', 'r', 'y', 'T', 'i', 
+'m', 'e', 'o', 'u', 't', '\022', 'W', '\n', '\016', 'r', 'e', 't', 'r', 'y', '_', 'p', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\030', '\004', 
+' ', '\001', '(', '\013', '2', '0', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', 
+'.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 'y', 'P', 'r', 'i', 'o', 
+'r', 'i', 't', 'y', 'R', '\r', 'r', 'e', 't', 'r', 'y', 'P', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\022', 'g', '\n', '\024', 'r', 'e', 
+'t', 'r', 'y', '_', 'h', 'o', 's', 't', '_', 'p', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '\030', '\005', ' ', '\003', '(', '\013', '2', 
+'5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 
+'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 'y', 'H', 'o', 's', 't', 'P', 'r', 'e', 'd', 'i', 
+'c', 'a', 't', 'e', 'R', '\022', 'r', 'e', 't', 'r', 'y', 'H', 'o', 's', 't', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', '\022', 
+'H', '\n', '!', 'h', 'o', 's', 't', '_', 's', 'e', 'l', 'e', 'c', 't', 'i', 'o', 'n', '_', 'r', 'e', 't', 'r', 'y', '_', 'm', 
+'a', 'x', '_', 'a', 't', 't', 'e', 'm', 'p', 't', 's', '\030', '\006', ' ', '\001', '(', '\003', 'R', '\035', 'h', 'o', 's', 't', 'S', 'e', 
+'l', 'e', 'c', 't', 'i', 'o', 'n', 'R', 'e', 't', 'r', 'y', 'M', 'a', 'x', 'A', 't', 't', 'e', 'm', 'p', 't', 's', '\022', '4', 
+'\n', '\026', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', '_', 's', 't', 'a', 't', 'u', 's', '_', 'c', 'o', 'd', 'e', 's', '\030', 
+'\007', ' ', '\003', '(', '\r', 'R', '\024', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', 'S', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 
+'e', 's', '\022', 'U', '\n', '\016', 'r', 'e', 't', 'r', 'y', '_', 'b', 'a', 'c', 'k', '_', 'o', 'f', 'f', '\030', '\010', ' ', '\001', '(', 
+'\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 
+'.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', 
+'R', '\014', 'r', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\022', 'x', '\n', '\033', 'r', 'a', 't', 'e', '_', 'l', 'i', 
+'m', 'i', 't', 'e', 'd', '_', 'r', 'e', 't', 'r', 'y', '_', 'b', 'a', 'c', 'k', '_', 'o', 'f', 'f', '\030', '\013', ' ', '\001', '(', 
+'\013', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 
+'.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'e', 'd', 'R', 
+'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', 'R', '\027', 'r', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'e', 'd', 'R', 
+'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\022', 'Q', '\n', '\021', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', '_', 
+'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\t', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 
-'r', 'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'B', 
-'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 
-'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'C', 
-'l', 'u', 's', 't', 'e', 'r', 'J', '\004', '\010', '\001', '\020', '\002', 'J', '\004', '\010', '\003', '\020', '\004', 'R', '\007', 'p', 'a', 't', 't', 'e', 
-'r', 'n', 'R', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\"', '\304', '\022', '\n', '\t', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '\022', 
-';', '\n', '\005', 's', 't', 'a', 'g', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
-'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', 
-'\002', '\030', '\n', 'R', '\005', 's', 't', 'a', 'g', 'e', '\022', '\037', '\n', '\013', 'd', 'i', 's', 'a', 'b', 'l', 'e', '_', 'k', 'e', 'y', 
-'\030', '\002', ' ', '\001', '(', '\t', 'R', '\n', 'd', 'i', 's', 'a', 'b', 'l', 'e', 'K', 'e', 'y', '\022', 'K', '\n', '\007', 'a', 'c', 't', 
-'i', 'o', 'n', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 
-'n', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\007', 'a', 'c', 't', 'i', 'o', 'n', 's', '\022', '?', '\n', '\005', 'l', 
-'i', 'm', 'i', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'O', 'v', 'e', 'r', 'r', 
-'i', 'd', 'e', 'R', '\005', 'l', 'i', 'm', 'i', 't', '\032', '\260', '\016', '\n', '\006', 'A', 'c', 't', 'i', 'o', 'n', '\022', '^', '\n', '\016', 
-'s', 'o', 'u', 'r', 'c', 'e', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '5', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 
-'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'l', 'u', 's', 't', 'e', 'r', 
-'H', '\000', 'R', '\r', 's', 'o', 'u', 'r', 'c', 'e', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', 'm', '\n', '\023', 'd', 'e', 's', 't', 
-'i', 'n', 'a', 't', 'i', 'o', 'n', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 
-'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'D', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'C', 
-'l', 'u', 's', 't', 'e', 'r', 'H', '\000', 'R', '\022', 'd', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'C', 'l', 'u', 's', 
-'t', 'e', 'r', '\022', 'a', '\n', '\017', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\003', ' ', 
-'\001', '(', '\013', '2', '6', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 
-'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'q', 'u', 'e', 
-'s', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'H', '\000', 'R', '\016', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 
-'r', 's', '\022', '^', '\n', '\016', 'r', 'e', 'm', 'o', 't', 'e', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', '\030', '\004', ' ', '\001', '(', 
-'\013', '2', '5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 
-'.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'm', 'o', 't', 'e', 'A', 
-'d', 'd', 'r', 'e', 's', 's', 'H', '\000', 'R', '\r', 'r', 'e', 'm', 'o', 't', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', '\022', 'U', 
-'\n', '\013', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 'k', 'e', 'y', '\030', '\005', ' ', '\001', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 
-'m', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'K', 'e', 'y', 'H', '\000', 'R', '\n', 
-'g', 'e', 'n', 'e', 'r', 'i', 'c', 'K', 'e', 'y', '\022', 'h', '\n', '\022', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'v', 'a', 'l', 'u', 
-'e', '_', 'm', 'a', 't', 'c', 'h', '\030', '\006', ' ', '\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 
-'t', 'i', 'o', 'n', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', 'H', '\000', 'R', '\020', 
-'h', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', '\022', 'd', '\n', '\020', 'd', 'y', 'n', 'a', 'm', 
-'i', 'c', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\007', ' ', '\001', '(', '\013', '2', '7', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 
-'t', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'D', 'a', 't', 'a', 'H', 
-'\000', 'R', '\017', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\032', 'I', '\n', '\r', 'S', 'o', 'u', 
-'r', 'c', 'e', 'C', 'l', 'u', 's', 't', 'e', 'r', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 
-'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 
-'t', 'i', 'o', 'n', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'l', 'u', 's', 't', 'e', 'r', '\032', 'S', '\n', '\022', 'D', 'e', 's', 
-'t', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'C', 'l', 'u', 's', 't', 'e', 'r', ':', '=', '\232', '\305', '\210', '\036', '8', '\n', '6', 'e', 
-'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 
-'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'D', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'C', 'l', 'u', 's', 
-'t', 'e', 'r', '\032', '\321', '\001', '\n', '\016', 'R', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', '.', '\n', 
-'\013', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', 
-'\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\n', 'h', 'e', 'a', 'd', 'e', 'r', 'N', 'a', 'm', 'e', '\022', '.', '\n', '\016', 'd', 
-'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', 
-'\002', '\020', '\001', 'R', '\r', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'K', 'e', 'y', '\022', '$', '\n', '\016', 's', 'k', 'i', 
-'p', '_', 'i', 'f', '_', 'a', 'b', 's', 'e', 'n', 't', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\014', 's', 'k', 'i', 'p', 'I', 'f', 
-'A', 'b', 's', 'e', 'n', 't', ':', '9', '\232', '\305', '\210', '\036', '4', '\n', '2', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 
-'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', 
-'.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\032', 'I', '\n', '\r', 'R', 'e', 'm', 'o', 't', 'e', 
-'A', 'd', 'd', 'r', 'e', 's', 's', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
-'.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 
-'n', '.', 'R', 'e', 'm', 'o', 't', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', '\032', '\236', '\001', '\n', '\n', 'G', 'e', 'n', 'e', 'r', 
-'i', 'c', 'K', 'e', 'y', '\022', '2', '\n', '\020', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'v', 'a', 'l', 'u', 'e', 
-'\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\017', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 
-'o', 'r', 'V', 'a', 'l', 'u', 'e', '\022', '%', '\n', '\016', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'k', 'e', 'y', 
-'\030', '\002', ' ', '\001', '(', '\t', 'R', '\r', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'K', 'e', 'y', ':', '5', '\232', '\305', 
-'\210', '\036', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 
-'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'K', 'e', 
-'y', '\032', '\214', '\002', '\n', '\020', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', '\022', '2', '\n', 
-'\020', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', 
-'\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\017', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'V', 'a', 'l', 'u', 'e', '\022', 
-'=', '\n', '\014', 'e', 'x', 'p', 'e', 'c', 't', '_', 'm', 'a', 't', 'c', 'h', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 
-'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', 
-'\013', 'e', 'x', 'p', 'e', 'c', 't', 'M', 'a', 't', 'c', 'h', '\022', 'H', '\n', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\003', 
+'r', 'R', '\020', 'r', 'e', 't', 'r', 'i', 'a', 'b', 'l', 'e', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', '`', '\n', '\031', 'r', 'e', 
+'t', 'r', 'i', 'a', 'b', 'l', 'e', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\n', 
 ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', 
-'.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', 
-'\010', '\001', 'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', ':', ';', '\232', '\305', '\210', '\036', '6', '\n', '4', 'e', 'n', 'v', 'o', 'y', 
-'.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 
-'c', 't', 'i', 'o', 'n', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', '\032', '\270', '\001', 
-'\n', '\017', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'D', 'a', 't', 'a', '\022', '.', '\n', '\016', 'd', 'e', 's', 'c', 
-'r', 'i', 'p', 't', 'o', 'r', '_', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 
-'R', '\r', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'K', 'e', 'y', '\022', 'P', '\n', '\014', 'm', 'e', 't', 'a', 'd', 'a', 
-'t', 'a', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', 
-'.', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', 'B', 
-'\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\013', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', '\022', '#', '\n', 
-'\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\014', 'd', 'e', 'f', 
-'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 
-'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 
-'i', 'o', 'n', 'B', '\027', '\n', '\020', 'a', 'c', 't', 'i', 'o', 'n', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', 
-'\370', 'B', '\001', '\032', '\362', '\001', '\n', '\010', 'O', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '\022', 'f', '\n', '\020', 'd', 'y', 'n', 'a', 'm', 
-'i', 'c', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\001', ' ', '\001', '(', '\013', '2', '9', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 
-'t', '.', 'O', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'd', 'a', 't', 
-'a', 'H', '\000', 'R', '\017', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\032', 'c', '\n', '\017', 'D', 
-'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', 'P', '\n', '\014', 'm', 'e', 't', 'a', 'd', 'a', 't', 
-'a', '_', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 
-'m', 'e', 't', 'a', 'd', 'a', 't', 'a', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', 'B', '\010', 
-'\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\013', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', 'B', '\031', '\n', '\022', 
-'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', ':', '#', 
+'.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\027', 'r', 'e', 't', 'r', 'i', 'a', 
+'b', 'l', 'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\032', '\271', '\001', '\n', '\r', 'R', 'e', 't', 
+'r', 'y', 'P', 'r', 'i', 'o', 'r', 'i', 't', 'y', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', 
+'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 
+'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '3', 
+'\232', '\305', '\210', '\036', '.', '\n', ',', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', 
+'.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 'y', 'P', 'r', 'i', 'o', 'r', 'i', 't', 
+'y', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 
+'o', 'n', 'f', 'i', 'g', '\032', '\303', '\001', '\n', '\022', 'R', 'e', 't', 'r', 'y', 'H', 'o', 's', 't', 'P', 'r', 'e', 'd', 'i', 'c', 
+'a', 't', 'e', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', 
+'\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', 
+' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 
+'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'e', 't', 'r', 'y', 'P', 
+'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 'y', 'H', 'o', 's', 't', 'P', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 'B', 
+'\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 
+'f', 'i', 'g', '\032', '\326', '\001', '\n', '\014', 'R', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\022', 'J', '\n', '\r', 'b', 
+'a', 's', 'e', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\001', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 
+'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\n', '\372', 'B', '\007', 
+'\252', '\001', '\004', '\010', '\001', '*', '\000', 'R', '\014', 'b', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\022', 'F', '\n', '\014', 
+'m', 'a', 'x', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\002', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 
+'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', 
+'\252', '\001', '\002', '*', '\000', 'R', '\013', 'm', 'a', 'x', 'I', 'n', 't', 'e', 'r', 'v', 'a', 'l', ':', '2', '\232', '\305', '\210', '\036', '-', 
+'\n', '+', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'e', 't', 'r', 
+'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\032', '\210', '\001', '\n', '\013', 
+'R', 'e', 's', 'e', 't', 'H', 'e', 'a', 'd', 'e', 'r', '\022', '!', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
+'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'V', '\n', '\006', 
+'f', 'o', 'r', 'm', 'a', 't', '\030', '\002', ' ', '\001', '(', '\016', '2', '4', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 
+'e', 's', 'e', 't', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'o', 'r', 'm', 'a', 't', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', 
+'\001', 'R', '\006', 'f', 'o', 'r', 'm', 'a', 't', '\032', '\300', '\001', '\n', '\027', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'e', 'd', 
+'R', 'e', 't', 'r', 'y', 'B', 'a', 'c', 'k', 'O', 'f', 'f', '\022', ']', '\n', '\r', 'r', 'e', 's', 'e', 't', '_', 'h', 'e', 'a', 
+'d', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '.', 'R', 'e', 's', 
+'e', 't', 'H', 'e', 'a', 'd', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\014', 'r', 'e', 's', 'e', 't', 
+'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', 'F', '\n', '\014', 'm', 'a', 'x', '_', 'i', 'n', 't', 'e', 'r', 'v', 'a', 'l', '\030', '\002', 
+' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 
+'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'R', '\013', 'm', 'a', 'x', 'I', 'n', 't', 'e', 
+'r', 'v', 'a', 'l', '\"', '4', '\n', '\021', 'R', 'e', 's', 'e', 't', 'H', 'e', 'a', 'd', 'e', 'r', 'F', 'o', 'r', 'm', 'a', 't', 
+'\022', '\013', '\n', '\007', 'S', 'E', 'C', 'O', 'N', 'D', 'S', '\020', '\000', '\022', '\022', '\n', '\016', 'U', 'N', 'I', 'X', '_', 'T', 'I', 'M', 
+'E', 'S', 'T', 'A', 'M', 'P', '\020', '\001', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'e', 't', 'r', 'y', 'P', 'o', 'l', 'i', 'c', 'y', '\"', '\234', '\002', 
+'\n', '\013', 'H', 'e', 'd', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 'P', '\n', '\020', 'i', 'n', 'i', 't', 'i', 'a', 'l', '_', 
+'r', 'e', 'q', 'u', 'e', 's', 't', 's', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
+'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', 
+'\002', '(', '\001', 'R', '\017', 'i', 'n', 'i', 't', 'i', 'a', 'l', 'R', 'e', 'q', 'u', 'e', 's', 't', 's', '\022', '\\', '\n', '\031', 'a', 
+'d', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'c', 'h', 'a', 'n', 'c', 'e', '\030', 
+'\002', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 
+'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\027', 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 
+'l', 'R', 'e', 'q', 'u', 'e', 's', 't', 'C', 'h', 'a', 'n', 'c', 'e', '\022', '6', '\n', '\030', 'h', 'e', 'd', 'g', 'e', '_', 'o', 
+'n', '_', 'p', 'e', 'r', '_', 't', 'r', 'y', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\024', 
+'h', 'e', 'd', 'g', 'e', 'O', 'n', 'P', 'e', 'r', 'T', 'r', 'y', 'T', 'i', 'm', 'e', 'o', 'u', 't', ':', '%', '\232', '\305', '\210', 
+'\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'H', 'e', 
+'d', 'g', 'e', 'P', 'o', 'l', 'i', 'c', 'y', '\"', '\341', '\005', '\n', '\016', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 'c', 't', 
+'i', 'o', 'n', '\022', '\'', '\n', '\016', 'h', 't', 't', 'p', 's', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\004', ' ', '\001', 
+'(', '\010', 'H', '\000', 'R', '\r', 'h', 't', 't', 'p', 's', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', ')', '\n', '\017', 's', 'c', 
+'h', 'e', 'm', 'e', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\007', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\016', 's', 'c', 
+'h', 'e', 'm', 'e', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', '0', '\n', '\r', 'h', 'o', 's', 't', '_', 'r', 'e', 'd', 'i', 
+'r', 'e', 'c', 't', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\014', 
+'h', 'o', 's', 't', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', '#', '\n', '\r', 'p', 'o', 'r', 't', '_', 'r', 'e', 'd', 'i', 
+'r', 'e', 'c', 't', '\030', '\010', ' ', '\001', '(', '\r', 'R', '\014', 'p', 'o', 'r', 't', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\022', 
+'2', '\n', '\r', 'p', 'a', 't', 'h', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\013', '\372', 
+'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'H', '\001', 'R', '\014', 'p', 'a', 't', 'h', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 
+'t', '\022', '4', '\n', '\016', 'p', 'r', 'e', 'f', 'i', 'x', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', '\005', ' ', '\001', '(', '\t', 
+'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'H', '\001', 'R', '\r', 'p', 'r', 'e', 'f', 'i', 'x', 'R', 'e', 
+'w', 'r', 'i', 't', 'e', '\022', 'U', '\n', '\r', 'r', 'e', 'g', 'e', 'x', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '\030', '\t', ' ', 
+'\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 
+'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'A', 'n', 'd', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 
+'e', 'H', '\001', 'R', '\014', 'r', 'e', 'g', 'e', 'x', 'R', 'e', 'w', 'r', 'i', 't', 'e', '\022', 'i', '\n', '\r', 'r', 'e', 's', 'p', 
+'o', 'n', 's', 'e', '_', 'c', 'o', 'd', 'e', '\030', '\003', ' ', '\001', '(', '\016', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 'c', 
+'t', 'i', 'o', 'n', '.', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', 
+'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\014', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', '\022', 
+'\037', '\n', '\013', 's', 't', 'r', 'i', 'p', '_', 'q', 'u', 'e', 'r', 'y', '\030', '\006', ' ', '\001', '(', '\010', 'R', '\n', 's', 't', 'r', 
+'i', 'p', 'Q', 'u', 'e', 'r', 'y', '\"', 'w', '\n', '\024', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 
+'s', 'e', 'C', 'o', 'd', 'e', '\022', '\025', '\n', '\021', 'M', 'O', 'V', 'E', 'D', '_', 'P', 'E', 'R', 'M', 'A', 'N', 'E', 'N', 'T', 
+'L', 'Y', '\020', '\000', '\022', '\t', '\n', '\005', 'F', 'O', 'U', 'N', 'D', '\020', '\001', '\022', '\r', '\n', '\t', 'S', 'E', 'E', '_', 'O', 'T', 
+'H', 'E', 'R', '\020', '\002', '\022', '\026', '\n', '\022', 'T', 'E', 'M', 'P', 'O', 'R', 'A', 'R', 'Y', '_', 'R', 'E', 'D', 'I', 'R', 'E', 
+'C', 'T', '\020', '\003', '\022', '\026', '\n', '\022', 'P', 'E', 'R', 'M', 'A', 'N', 'E', 'N', 'T', '_', 'R', 'E', 'D', 'I', 'R', 'E', 'C', 
+'T', '\020', '\004', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 
+'r', 'o', 'u', 't', 'e', '.', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'A', 'c', 't', 'i', 'o', 'n', 'B', '\032', '\n', '\030', 's', 
+'c', 'h', 'e', 'm', 'e', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'B', '\030', 
+'\n', '\026', 'p', 'a', 't', 'h', '_', 'r', 'e', 'w', 'r', 'i', 't', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\"', 
+'\240', '\001', '\n', '\024', 'D', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'A', 'c', 't', 'i', 'o', 'n', '\022', 
+'\"', '\n', '\006', 's', 't', 'a', 't', 'u', 's', '\030', '\001', ' ', '\001', '(', '\r', 'B', '\n', '\372', 'B', '\007', '*', '\005', '\020', '\330', '\004', 
+'(', 'd', 'R', '\006', 's', 't', 'a', 't', 'u', 's', '\022', '4', '\n', '\004', 'b', 'o', 'd', 'y', '\030', '\002', ' ', '\001', '(', '\013', '2', 
+' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 
+'t', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\004', 'b', 'o', 'd', 'y', ':', '.', '\232', '\305', '\210', '\036', ')', '\n', '\'', 'e', 'n', 
+'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'D', 'i', 'r', 'e', 'c', 't', 'R', 'e', 
+'s', 'p', 'o', 'n', 's', 'e', 'A', 'c', 't', 'i', 'o', 'n', '\"', '\221', '\001', '\n', '\t', 'D', 'e', 'c', 'o', 'r', 'a', 't', 'o', 
+'r', '\022', '%', '\n', '\t', 'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 
+'r', '\002', '\020', '\001', 'R', '\t', 'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', '\022', '8', '\n', '\t', 'p', 'r', 'o', 'p', 'a', 'g', 
+'a', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\t', 'p', 'r', 'o', 'p', 'a', 'g', 'a', 't', 'e', ':', '#', 
 '\232', '\305', '\210', '\036', '\036', '\n', '\034', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', 
-'.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '\"', '\236', '\004', '\n', '\r', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 
-'h', 'e', 'r', '\022', '!', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', 
-'\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '!', '\n', '\013', 'e', 'x', 'a', 'c', 't', '_', 'm', 'a', 
-'t', 'c', 'h', '\030', '\004', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\n', 'e', 'x', 'a', 'c', 't', 'M', 'a', 't', 'c', 'h', '\022', 'O', 
-'\n', '\020', 's', 'a', 'f', 'e', '_', 'r', 'e', 'g', 'e', 'x', '_', 'm', 'a', 't', 'c', 'h', '\030', '\013', ' ', '\001', '(', '\013', '2', 
-'#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'R', 
-'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'H', '\000', 'R', '\016', 's', 'a', 'f', 'e', 'R', 'e', 'g', 'e', 'x', 'M', 
-'a', 't', 'c', 'h', '\022', '<', '\n', '\013', 'r', 'a', 'n', 'g', 'e', '_', 'm', 'a', 't', 'c', 'h', '\030', '\006', ' ', '\001', '(', '\013', 
-'2', '\031', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'I', 'n', 't', '6', '4', 'R', 'a', 'n', 
-'g', 'e', 'H', '\000', 'R', '\n', 'r', 'a', 'n', 'g', 'e', 'M', 'a', 't', 'c', 'h', '\022', '%', '\n', '\r', 'p', 'r', 'e', 's', 'e', 
-'n', 't', '_', 'm', 'a', 't', 'c', 'h', '\030', '\007', ' ', '\001', '(', '\010', 'H', '\000', 'R', '\014', 'p', 'r', 'e', 's', 'e', 'n', 't', 
-'M', 'a', 't', 'c', 'h', '\022', ',', '\n', '\014', 'p', 'r', 'e', 'f', 'i', 'x', '_', 'm', 'a', 't', 'c', 'h', '\030', '\t', ' ', '\001', 
-'(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\013', 'p', 'r', 'e', 'f', 'i', 'x', 'M', 'a', 't', 'c', 
-'h', '\022', ',', '\n', '\014', 's', 'u', 'f', 'f', 'i', 'x', '_', 'm', 'a', 't', 'c', 'h', '\030', '\n', ' ', '\001', '(', '\t', 'B', '\007', 
-'\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\013', 's', 'u', 'f', 'f', 'i', 'x', 'M', 'a', 't', 'c', 'h', '\022', '0', '\n', 
-'\016', 'c', 'o', 'n', 't', 'a', 'i', 'n', 's', '_', 'm', 'a', 't', 'c', 'h', '\030', '\014', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', 
-'\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\r', 'c', 'o', 'n', 't', 'a', 'i', 'n', 's', 'M', 'a', 't', 'c', 'h', '\022', '!', '\n', 
-'\014', 'i', 'n', 'v', 'e', 'r', 't', '_', 'm', 'a', 't', 'c', 'h', '\030', '\010', ' ', '\001', '(', '\010', 'R', '\013', 'i', 'n', 'v', 'e', 
-'r', 't', 'M', 'a', 't', 'c', 'h', ':', '\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
-'.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\030', 
-'\n', '\026', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'm', 'a', 't', 'c', 'h', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'J', 
-'\004', '\010', '\002', '\020', '\003', 'J', '\004', '\010', '\003', '\020', '\004', 'J', '\004', '\010', '\005', '\020', '\006', 'R', '\013', 'r', 'e', 'g', 'e', 'x', '_', 
-'m', 'a', 't', 'c', 'h', '\"', '\241', '\002', '\n', '\025', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 'M', 
-'a', 't', 'c', 'h', 'e', 'r', '\022', '\036', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\n', '\372', 'B', '\007', 
-'r', '\005', '\020', '\001', '(', '\200', '\010', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'S', '\n', '\014', 's', 't', 'r', 'i', 'n', 'g', '_', 'm', 
-'a', 't', 'c', 'h', '\030', '\005', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 
-'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\010', 
-'\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'H', '\000', 'R', '\013', 's', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', '\022', '%', 
-'\n', '\r', 'p', 'r', 'e', 's', 'e', 'n', 't', '_', 'm', 'a', 't', 'c', 'h', '\030', '\006', ' ', '\001', '(', '\010', 'H', '\000', 'R', '\014', 
-'p', 'r', 'e', 's', 'e', 'n', 't', 'M', 'a', 't', 'c', 'h', ':', '/', '\232', '\305', '\210', '\036', '*', '\n', '(', 'e', 'n', 'v', 'o', 
-'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 
-'e', 't', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '!', '\n', '\037', 'q', 'u', 'e', 'r', 'y', '_', 'p', 'a', 'r', 'a', 
-'m', 'e', 't', 'e', 'r', '_', 'm', 'a', 't', 'c', 'h', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'J', '\004', '\010', '\003', 
-'\020', '\004', 'J', '\004', '\010', '\004', '\020', '\005', 'R', '\005', 'v', 'a', 'l', 'u', 'e', 'R', '\005', 'r', 'e', 'g', 'e', 'x', '\"', '\271', '\002', 
-'\n', '\026', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', '\022', 
-'R', '\n', '\026', 'm', 'a', 'x', '_', 'i', 'n', 't', 'e', 'r', 'n', 'a', 'l', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', 's', 
-'\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
-'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\024', 'm', 'a', 'x', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 
-'e', 'd', 'i', 'r', 'e', 'c', 't', 's', '\022', '@', '\n', '\027', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '_', 'r', 'e', 's', 'p', 
-'o', 'n', 's', 'e', '_', 'c', 'o', 'd', 'e', 's', '\030', '\002', ' ', '\003', '(', '\r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\020', 
-'\005', 'R', '\025', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', 's', '\022', 
-'J', '\n', '\n', 'p', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 
-'t', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\n', 'p', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 's', 
-'\022', '=', '\n', '\033', 'a', 'l', 'l', 'o', 'w', '_', 'c', 'r', 'o', 's', 's', '_', 's', 'c', 'h', 'e', 'm', 'e', '_', 'r', 'e', 
-'d', 'i', 'r', 'e', 'c', 't', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\030', 'a', 'l', 'l', 'o', 'w', 'C', 'r', 'o', 's', 's', 'S', 
-'c', 'h', 'e', 'm', 'e', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'B', 'E', '\n', '#', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 
-'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 
-'v', '3', 'B', '\024', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', 'P', 'r', 'o', 't', 'o', 'P', 
-'\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'.', 'D', 'e', 'c', 'o', 'r', 'a', 't', 'o', 'r', '\"', '\322', '\002', '\n', '\007', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '\022', 'I', '\n', 
+'\017', 'c', 'l', 'i', 'e', 'n', 't', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 
+'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'c', 'l', 'i', 'e', 'n', 't', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', 'I', '\n', 
+'\017', 'r', 'a', 'n', 'd', 'o', 'm', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', ' ', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 
+'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'r', 'a', 'n', 'd', 'o', 'm', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', 'K', '\n', 
+'\020', 'o', 'v', 'e', 'r', 'a', 'l', 'l', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', ' ', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 
+'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\017', 'o', 'v', 'e', 'r', 'a', 'l', 'l', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', 
+'A', '\n', '\013', 'c', 'u', 's', 't', 'o', 'm', '_', 't', 'a', 'g', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 't', 'r', 'a', 'c', 'i', 'n', 'g', '.', 'v', '3', '.', 'C', 'u', 's', 't', 'o', 
+'m', 'T', 'a', 'g', 'R', '\n', 'c', 'u', 's', 't', 'o', 'm', 'T', 'a', 'g', 's', ':', '!', '\232', '\305', '\210', '\036', '\034', '\n', '\032', 
+'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'T', 'r', 'a', 'c', 'i', 'n', 
+'g', '\"', '\264', '\001', '\n', '\016', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', '>', '\n', '\007', 'h', 
+'e', 'a', 'd', 'e', 'r', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 
+'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', 
+'\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'C', 'l', 
+'u', 's', 't', 'e', 'r', 'J', '\004', '\010', '\001', '\020', '\002', 'J', '\004', '\010', '\003', '\020', '\004', 'R', '\007', 'p', 'a', 't', 't', 'e', 'r', 
+'n', 'R', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\"', '\241', '\026', '\n', '\t', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '\022', ';', 
+'\n', '\005', 's', 't', 'a', 'g', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\372', 'B', '\004', '*', '\002', 
+'\030', '\n', 'R', '\005', 's', 't', 'a', 'g', 'e', '\022', '\037', '\n', '\013', 'd', 'i', 's', 'a', 'b', 'l', 'e', '_', 'k', 'e', 'y', '\030', 
+'\002', ' ', '\001', '(', '\t', 'R', '\n', 'd', 'i', 's', 'a', 'b', 'l', 'e', 'K', 'e', 'y', '\022', 'K', '\n', '\007', 'a', 'c', 't', 'i', 
+'o', 'n', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', 
+'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\007', 'a', 'c', 't', 'i', 'o', 'n', 's', '\022', '?', '\n', '\005', 'l', 'i', 
+'m', 'i', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'O', 'v', 'e', 'r', 'r', 'i', 
+'d', 'e', 'R', '\005', 'l', 'i', 'm', 'i', 't', '\032', '\215', '\022', '\n', '\006', 'A', 'c', 't', 'i', 'o', 'n', '\022', '^', '\n', '\016', 's', 
+'o', 'u', 'r', 'c', 'e', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '5', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 
+'m', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'l', 'u', 's', 't', 'e', 'r', 'H', 
+'\000', 'R', '\r', 's', 'o', 'u', 'r', 'c', 'e', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', 'm', '\n', '\023', 'd', 'e', 's', 't', 'i', 
+'n', 'a', 't', 'i', 'o', 'n', '_', 'c', 'l', 'u', 's', 't', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 
+'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'D', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'C', 'l', 
+'u', 's', 't', 'e', 'r', 'H', '\000', 'R', '\022', 'd', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'C', 'l', 'u', 's', 't', 
+'e', 'r', '\022', 'a', '\n', '\017', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\003', ' ', '\001', 
+'(', '\013', '2', '6', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', 
+'3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'q', 'u', 'e', 's', 
+'t', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'H', '\000', 'R', '\016', 'r', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 
+'s', '\022', '^', '\n', '\016', 'r', 'e', 'm', 'o', 't', 'e', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', '\030', '\004', ' ', '\001', '(', '\013', 
+'2', '5', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 
+'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'm', 'o', 't', 'e', 'A', 'd', 
+'d', 'r', 'e', 's', 's', 'H', '\000', 'R', '\r', 'r', 'e', 'm', 'o', 't', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', '\022', 'U', '\n', 
+'\013', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 'k', 'e', 'y', '\030', '\005', ' ', '\001', '(', '\013', '2', '2', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 
+'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'K', 'e', 'y', 'H', '\000', 'R', '\n', 'g', 
+'e', 'n', 'e', 'r', 'i', 'c', 'K', 'e', 'y', '\022', 'h', '\n', '\022', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'v', 'a', 'l', 'u', 'e', 
+'_', 'm', 'a', 't', 'c', 'h', '\030', '\006', ' ', '\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 
+'i', 'o', 'n', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', 'H', '\000', 'R', '\020', 'h', 
+'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', '\022', 'n', '\n', '\020', 'd', 'y', 'n', 'a', 'm', 'i', 
+'c', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\007', ' ', '\001', '(', '\013', '2', '7', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 
+'.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'D', 'a', 't', 'a', 'B', '\010', 
+'\030', '\001', '\270', '\356', '\362', '\322', '\005', '\001', 'H', '\000', 'R', '\017', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'd', 'a', 
+'t', 'a', '\022', 'N', '\n', '\010', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\010', ' ', '\001', '(', '\013', '2', '0', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 
+'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'M', 'e', 't', 'a', 'D', 'a', 't', 'a', 'H', '\000', 'R', '\010', 'm', 
+'e', 't', 'a', 'd', 'a', 't', 'a', '\022', 'J', '\n', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\t', ' ', '\001', '(', 
+'\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
+'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\000', 'R', '\t', 'e', 
+'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\032', 'I', '\n', '\r', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'l', 'u', 's', 't', 'e', 'r', 
+':', '8', '\232', '\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 
+'t', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'S', 'o', 'u', 'r', 'c', 
+'e', 'C', 'l', 'u', 's', 't', 'e', 'r', '\032', 'S', '\n', '\022', 'D', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'C', 'l', 
+'u', 's', 't', 'e', 'r', ':', '=', '\232', '\305', '\210', '\036', '8', '\n', '6', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', 
+'2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 
+'D', 'e', 's', 't', 'i', 'n', 'a', 't', 'i', 'o', 'n', 'C', 'l', 'u', 's', 't', 'e', 'r', '\032', '\321', '\001', '\n', '\016', 'R', 'e', 
+'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', '.', '\n', '\013', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'n', 'a', 
+'m', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', '\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\n', 
+'h', 'e', 'a', 'd', 'e', 'r', 'N', 'a', 'm', 'e', '\022', '.', '\n', '\016', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 
+'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\r', 'd', 'e', 's', 'c', 'r', 
+'i', 'p', 't', 'o', 'r', 'K', 'e', 'y', '\022', '$', '\n', '\016', 's', 'k', 'i', 'p', '_', 'i', 'f', '_', 'a', 'b', 's', 'e', 'n', 
+'t', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\014', 's', 'k', 'i', 'p', 'I', 'f', 'A', 'b', 's', 'e', 'n', 't', ':', '9', '\232', '\305', 
+'\210', '\036', '4', '\n', '2', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 
+'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'H', 'e', 
+'a', 'd', 'e', 'r', 's', '\032', 'I', '\n', '\r', 'R', 'e', 'm', 'o', 't', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', ':', '8', '\232', 
+'\305', '\210', '\036', '3', '\n', '1', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 
+'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'R', 'e', 'm', 'o', 't', 'e', 'A', 'd', 
+'d', 'r', 'e', 's', 's', '\032', '\236', '\001', '\n', '\n', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'K', 'e', 'y', '\022', '2', '\n', '\020', 'd', 
+'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', 
+'\004', 'r', '\002', '\020', '\001', 'R', '\017', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'V', 'a', 'l', 'u', 'e', '\022', '%', '\n', 
+'\016', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\r', 'd', 'e', 
+'s', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'K', 'e', 'y', ':', '5', '\232', '\305', '\210', '\036', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 
+'c', 't', 'i', 'o', 'n', '.', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'K', 'e', 'y', '\032', '\214', '\002', '\n', '\020', 'H', 'e', 'a', 'd', 
+'e', 'r', 'V', 'a', 'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', '\022', '2', '\n', '\020', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 
+'r', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\017', 'd', 
+'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'V', 'a', 'l', 'u', 'e', '\022', '=', '\n', '\014', 'e', 'x', 'p', 'e', 'c', 't', '_', 
+'m', 'a', 't', 'c', 'h', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\013', 'e', 'x', 'p', 'e', 'c', 't', 'M', 'a', 't', 
+'c', 'h', '\022', 'H', '\n', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 
+'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 
+'s', ':', ';', '\232', '\305', '\210', '\036', '6', '\n', '4', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 
+'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'H', 'e', 'a', 'd', 
+'e', 'r', 'V', 'a', 'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', '\032', '\270', '\001', '\n', '\017', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 
+'e', 't', 'a', 'D', 'a', 't', 'a', '\022', '.', '\n', '\016', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'k', 'e', 'y', 
+'\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\r', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 
+'o', 'r', 'K', 'e', 'y', '\022', 'P', '\n', '\014', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', 
+'(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '.', 
+'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', 
+'\013', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', '\022', '#', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 
+'a', 'l', 'u', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\032', 
+'\264', '\002', '\n', '\010', 'M', 'e', 't', 'a', 'D', 'a', 't', 'a', '\022', '.', '\n', '\016', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 
+'r', '_', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\r', 'd', 'e', 's', 
+'c', 'r', 'i', 'p', 't', 'o', 'r', 'K', 'e', 'y', '\022', 'P', '\n', '\014', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', 'k', 'e', 
+'y', '\030', '\002', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'e', 't', 'a', 
+'d', 'a', 't', 'a', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', 'B', '\010', '\372', 'B', '\005', '\212', 
+'\001', '\002', '\020', '\001', 'R', '\013', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', '\022', '#', '\n', '\r', 'd', 'e', 'f', 'a', 
+'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 
+'a', 'l', 'u', 'e', '\022', 'Y', '\n', '\006', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\004', ' ', '\001', '(', '\016', '2', '7', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 
+'i', 'm', 'i', 't', '.', 'A', 'c', 't', 'i', 'o', 'n', '.', 'M', 'e', 't', 'a', 'D', 'a', 't', 'a', '.', 'S', 'o', 'u', 'r', 
+'c', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\006', 's', 'o', 'u', 'r', 'c', 'e', '\"', '&', '\n', '\006', 'S', 
+'o', 'u', 'r', 'c', 'e', '\022', '\013', '\n', '\007', 'D', 'Y', 'N', 'A', 'M', 'I', 'C', '\020', '\000', '\022', '\017', '\n', '\013', 'R', 'O', 'U', 
+'T', 'E', '_', 'E', 'N', 'T', 'R', 'Y', '\020', '\001', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 
+'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'A', 'c', 
+'t', 'i', 'o', 'n', 'B', '\027', '\n', '\020', 'a', 'c', 't', 'i', 'o', 'n', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', 
+'\003', '\370', 'B', '\001', '\032', '\362', '\001', '\n', '\010', 'O', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '\022', 'f', '\n', '\020', 'd', 'y', 'n', 'a', 
+'m', 'i', 'c', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '\030', '\001', ' ', '\001', '(', '\013', '2', '9', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 
+'i', 't', '.', 'O', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '.', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'd', 'a', 
+'t', 'a', 'H', '\000', 'R', '\017', 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\032', 'c', '\n', '\017', 
+'D', 'y', 'n', 'a', 'm', 'i', 'c', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', '\022', 'P', '\n', '\014', 'm', 'e', 't', 'a', 'd', 'a', 
+'t', 'a', '_', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', 
+'.', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '.', 'v', '3', '.', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', 'B', 
+'\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\013', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 'K', 'e', 'y', 'B', '\031', '\n', 
+'\022', 'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', ':', 
+'#', '\232', '\305', '\210', '\036', '\036', '\n', '\034', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 
+'e', '.', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '\"', '\236', '\004', '\n', '\r', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 
+'c', 'h', 'e', 'r', '\022', '!', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\r', '\372', 'B', '\n', 'r', '\010', 
+'\020', '\001', '\300', '\001', '\001', '\310', '\001', '\000', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '!', '\n', '\013', 'e', 'x', 'a', 'c', 't', '_', 'm', 
+'a', 't', 'c', 'h', '\030', '\004', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\n', 'e', 'x', 'a', 'c', 't', 'M', 'a', 't', 'c', 'h', '\022', 
+'O', '\n', '\020', 's', 'a', 'f', 'e', '_', 'r', 'e', 'g', 'e', 'x', '_', 'm', 'a', 't', 'c', 'h', '\030', '\013', ' ', '\001', '(', '\013', 
+'2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 
+'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'H', '\000', 'R', '\016', 's', 'a', 'f', 'e', 'R', 'e', 'g', 'e', 'x', 
+'M', 'a', 't', 'c', 'h', '\022', '<', '\n', '\013', 'r', 'a', 'n', 'g', 'e', '_', 'm', 'a', 't', 'c', 'h', '\030', '\006', ' ', '\001', '(', 
+'\013', '2', '\031', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'I', 'n', 't', '6', '4', 'R', 'a', 
+'n', 'g', 'e', 'H', '\000', 'R', '\n', 'r', 'a', 'n', 'g', 'e', 'M', 'a', 't', 'c', 'h', '\022', '%', '\n', '\r', 'p', 'r', 'e', 's', 
+'e', 'n', 't', '_', 'm', 'a', 't', 'c', 'h', '\030', '\007', ' ', '\001', '(', '\010', 'H', '\000', 'R', '\014', 'p', 'r', 'e', 's', 'e', 'n', 
+'t', 'M', 'a', 't', 'c', 'h', '\022', ',', '\n', '\014', 'p', 'r', 'e', 'f', 'i', 'x', '_', 'm', 'a', 't', 'c', 'h', '\030', '\t', ' ', 
+'\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\013', 'p', 'r', 'e', 'f', 'i', 'x', 'M', 'a', 't', 
+'c', 'h', '\022', ',', '\n', '\014', 's', 'u', 'f', 'f', 'i', 'x', '_', 'm', 'a', 't', 'c', 'h', '\030', '\n', ' ', '\001', '(', '\t', 'B', 
+'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\013', 's', 'u', 'f', 'f', 'i', 'x', 'M', 'a', 't', 'c', 'h', '\022', '0', 
+'\n', '\016', 'c', 'o', 'n', 't', 'a', 'i', 'n', 's', '_', 'm', 'a', 't', 'c', 'h', '\030', '\014', ' ', '\001', '(', '\t', 'B', '\007', '\372', 
+'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\r', 'c', 'o', 'n', 't', 'a', 'i', 'n', 's', 'M', 'a', 't', 'c', 'h', '\022', '!', 
+'\n', '\014', 'i', 'n', 'v', 'e', 'r', 't', '_', 'm', 'a', 't', 'c', 'h', '\030', '\010', ' ', '\001', '(', '\010', 'R', '\013', 'i', 'n', 'v', 
+'e', 'r', 't', 'M', 'a', 't', 'c', 'h', ':', '\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', 
+'\030', '\n', '\026', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'm', 'a', 't', 'c', 'h', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 
+'J', '\004', '\010', '\002', '\020', '\003', 'J', '\004', '\010', '\003', '\020', '\004', 'J', '\004', '\010', '\005', '\020', '\006', 'R', '\013', 'r', 'e', 'g', 'e', 'x', 
+'_', 'm', 'a', 't', 'c', 'h', '\"', '\241', '\002', '\n', '\025', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 
+'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', '\036', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\n', '\372', 'B', 
+'\007', 'r', '\005', '\020', '\001', '(', '\200', '\010', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'S', '\n', '\014', 's', 't', 'r', 'i', 'n', 'g', '_', 
+'m', 'a', 't', 'c', 'h', '\030', '\005', ' ', '\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 
+'m', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', 
+'\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'H', '\000', 'R', '\013', 's', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', '\022', 
+'%', '\n', '\r', 'p', 'r', 'e', 's', 'e', 'n', 't', '_', 'm', 'a', 't', 'c', 'h', '\030', '\006', ' ', '\001', '(', '\010', 'H', '\000', 'R', 
+'\014', 'p', 'r', 'e', 's', 'e', 'n', 't', 'M', 'a', 't', 'c', 'h', ':', '/', '\232', '\305', '\210', '\036', '*', '\n', '(', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'r', 'o', 'u', 't', 'e', '.', 'Q', 'u', 'e', 'r', 'y', 'P', 'a', 'r', 'a', 
+'m', 'e', 't', 'e', 'r', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '!', '\n', '\037', 'q', 'u', 'e', 'r', 'y', '_', 'p', 'a', 'r', 
+'a', 'm', 'e', 't', 'e', 'r', '_', 'm', 'a', 't', 'c', 'h', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'J', '\004', '\010', 
+'\003', '\020', '\004', 'J', '\004', '\010', '\004', '\020', '\005', 'R', '\005', 'v', 'a', 'l', 'u', 'e', 'R', '\005', 'r', 'e', 'g', 'e', 'x', '\"', '\271', 
+'\002', '\n', '\026', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'P', 'o', 'l', 'i', 'c', 'y', 
+'\022', 'R', '\n', '\026', 'm', 'a', 'x', '_', 'i', 'n', 't', 'e', 'r', 'n', 'a', 'l', '_', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', 
+'s', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
+'.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\024', 'm', 'a', 'x', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 
+'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', 's', '\022', '@', '\n', '\027', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', '_', 'r', 'e', 's', 
+'p', 'o', 'n', 's', 'e', '_', 'c', 'o', 'd', 'e', 's', '\030', '\002', ' ', '\003', '(', '\r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', 
+'\020', '\005', 'R', '\025', 'r', 'e', 'd', 'i', 'r', 'e', 'c', 't', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'C', 'o', 'd', 'e', 's', 
+'\022', 'J', '\n', '\n', 'p', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '*', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 
+'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\n', 'p', 'r', 'e', 'd', 'i', 'c', 'a', 't', 'e', 
+'s', '\022', '=', '\n', '\033', 'a', 'l', 'l', 'o', 'w', '_', 'c', 'r', 'o', 's', 's', '_', 's', 'c', 'h', 'e', 'm', 'e', '_', 'r', 
+'e', 'd', 'i', 'r', 'e', 'c', 't', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\030', 'a', 'l', 'l', 'o', 'w', 'C', 'r', 'o', 's', 's', 
+'S', 'c', 'h', 'e', 'm', 'e', 'R', 'e', 'd', 'i', 'r', 'e', 'c', 't', '\"', ']', '\n', '\014', 'F', 'i', 'l', 't', 'e', 'r', 'C', 
+'o', 'n', 'f', 'i', 'g', '\022', ',', '\n', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 
+'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 
+'g', '\022', '\037', '\n', '\013', 'i', 's', '_', 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\n', 'i', 
+'s', 'O', 'p', 't', 'i', 'o', 'n', 'a', 'l', 'B', 'E', '\n', '#', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 
+'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 'B', '\024', 
+'R', 'o', 'u', 't', 'e', 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', 
+'\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[19] = {
+static upb_def_init *deps[18] = {
   &envoy_config_core_v3_base_proto_upbdefinit,
   &envoy_config_core_v3_extension_proto_upbdefinit,
   &envoy_config_core_v3_proxy_protocol_proto_upbdefinit,
@@ -897,7 +927,6 @@
   &envoy_type_v3_range_proto_upbdefinit,
   &google_protobuf_any_proto_upbdefinit,
   &google_protobuf_duration_proto_upbdefinit,
-  &google_protobuf_struct_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
   &envoy_annotations_deprecation_proto_upbdefinit,
   &udpa_annotations_migrate_proto_upbdefinit,
@@ -911,5 +940,5 @@
   deps,
   layouts,
   "envoy/config/route/v3/route_components.proto",
-  UPB_STRVIEW_INIT(descriptor, 18792)
+  UPB_STRVIEW_INIT(descriptor, 19463)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h
index e4c85f2..a3cce45 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.h
@@ -246,6 +246,11 @@
   return upb_symtab_lookupmsg(s, "envoy.config.route.v3.RateLimit.Action.DynamicMetaData");
 }
 
+UPB_INLINE const upb_msgdef *envoy_config_route_v3_RateLimit_Action_MetaData_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_route_v3_route_components_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.route.v3.RateLimit.Action.MetaData");
+}
+
 UPB_INLINE const upb_msgdef *envoy_config_route_v3_RateLimit_Override_getmsgdef(upb_symtab *s) {
   _upb_symtab_loaddefinit(s, &envoy_config_route_v3_route_components_proto_upbdefinit);
   return upb_symtab_lookupmsg(s, "envoy.config.route.v3.RateLimit.Override");
@@ -271,6 +276,11 @@
   return upb_symtab_lookupmsg(s, "envoy.config.route.v3.InternalRedirectPolicy");
 }
 
+UPB_INLINE const upb_msgdef *envoy_config_route_v3_FilterConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_config_route_v3_route_components_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.config.route.v3.FilterConfig");
+}
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c
index f1b2bc4..3817a57 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c
@@ -10,7 +10,6 @@
 #include "envoy/config/trace/v3/http_tracer.upbdefs.h"
 
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
-extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
 extern upb_def_init validate_validate_proto_upbdefinit;
@@ -22,34 +21,32 @@
   &envoy_config_trace_v3_Tracing_Http_msginit,
 };
 
-static const char descriptor[562] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 't', 'r', 'a', 'c', 'e', '/', 'v', '3', '/', 'h', 
+static const char descriptor[532] = {'\n', '\'', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 't', 'r', 'a', 'c', 'e', '/', 'v', '3', '/', 'h', 
 't', 't', 'p', '_', 't', 'r', 'a', 'c', 'e', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 'a', 'c', 'e', '.', 'v', '3', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 
-'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 
-'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 
-'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 
-'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 
-'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\221', '\002', '\n', '\007', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '\022', 
-'7', '\n', '\004', 'h', 't', 't', 'p', '\030', '\001', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 't', 'r', 'a', 'c', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '.', 'H', 't', 't', 'p', 
-'R', '\004', 'h', 't', 't', 'p', '\032', '\246', '\001', '\n', '\004', 'H', 't', 't', 'p', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', 
-' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 
-'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 
-'f', 'i', 'g', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'t', 'r', 'a', 'c', 'e', '.', 'v', '2', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '.', 'H', 't', 't', 'p', 'B', '\r', '\n', '\013', 
-'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', 
-':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 'a', 
-'c', 'e', '.', 'v', '2', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', 'B', '@', '\n', '#', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 
-'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 'a', 'c', 'e', '.', 
-'v', '3', 'B', '\017', 'H', 't', 't', 'p', 'T', 'r', 'a', 'c', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', 
-'\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 
+'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 
+'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 
+'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 
+'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\221', '\002', '\n', '\007', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '\022', '7', '\n', '\004', 'h', 't', 
+'t', 'p', '\030', '\001', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 
+'r', 'a', 'c', 'e', '.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '.', 'H', 't', 't', 'p', 'R', '\004', 'h', 't', 't', 
+'p', '\032', '\246', '\001', '\n', '\004', 'H', 't', 't', 'p', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', 
+'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 
+'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', ')', 
+'\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 'a', 'c', 'e', 
+'.', 'v', '2', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '.', 'H', 't', 't', 'p', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 
+'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', ':', '$', '\232', '\305', '\210', 
+'\036', '\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 'a', 'c', 'e', '.', 'v', '2', 
+'.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', 'B', '@', '\n', '#', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 'a', 'c', 'e', '.', 'v', '3', 'B', '\017', 'H', 
+'t', 't', 'p', 'T', 'r', 'a', 'c', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', 
+'\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[6] = {
+static upb_def_init *deps[5] = {
   &google_protobuf_any_proto_upbdefinit,
-  &google_protobuf_struct_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
   &validate_validate_proto_upbdefinit,
@@ -60,5 +57,5 @@
   deps,
   layouts,
   "envoy/config/trace/v3/http_tracer.proto",
-  UPB_STRVIEW_INIT(descriptor, 562)
+  UPB_STRVIEW_INIT(descriptor, 532)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c
new file mode 100644
index 0000000..d159a99
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c
@@ -0,0 +1,51 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/clusters/aggregate/v3/cluster.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h"
+
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout envoy_extensions_clusters_aggregate_v3_ClusterConfig_msginit;
+
+static const upb_msglayout *layouts[1] = {
+  &envoy_extensions_clusters_aggregate_v3_ClusterConfig_msginit,
+};
+
+static const char descriptor[389] = {'\n', '4', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 'c', 'l', 'u', 's', 't', 'e', 
+'r', 's', '/', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', '/', 'v', '3', '/', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'p', 
+'r', 'o', 't', 'o', '\022', '&', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'c', 'l', 
+'u', 's', 't', 'e', 'r', 's', '.', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', '.', 'v', '3', '\032', '\035', 'u', 'd', 'p', 'a', 
+'/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', 
+'\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 
+'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 
+'d', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', 'r', '\n', '\r', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'n', 'f', 
+'i', 'g', '\022', '$', '\n', '\010', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\t', 'B', '\010', '\372', 'B', '\005', 
+'\222', '\001', '\002', '\010', '\001', 'R', '\010', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', ':', ';', '\232', '\305', '\210', '\036', '6', '\n', '4', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', '.', 'a', 'g', 'g', 'r', 'e', 
+'g', 'a', 't', 'e', '.', 'v', '2', 'a', 'l', 'p', 'h', 'a', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 
+'g', 'B', 'N', '\n', '4', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'c', 'l', 'u', 's', 't', 'e', 'r', 's', '.', 'a', 'g', 'g', 'r', 'e', 
+'g', 'a', 't', 'e', '.', 'v', '3', 'B', '\014', 'C', 'l', 'u', 's', 't', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', 
+'\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[4] = {
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_extensions_clusters_aggregate_v3_cluster_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/extensions/clusters/aggregate/v3/cluster.proto",
+  UPB_STRVIEW_INIT(descriptor, 389)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h
new file mode 100644
index 0000000..fd6d1b8
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h
@@ -0,0 +1,35 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/clusters/aggregate/v3/cluster.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_EXTENSIONS_CLUSTERS_AGGREGATE_V3_CLUSTER_PROTO_UPBDEFS_H_
+#define ENVOY_EXTENSIONS_CLUSTERS_AGGREGATE_V3_CLUSTER_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_extensions_clusters_aggregate_v3_cluster_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_extensions_clusters_aggregate_v3_ClusterConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_clusters_aggregate_v3_cluster_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.clusters.aggregate.v3.ClusterConfig");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_EXTENSIONS_CLUSTERS_AGGREGATE_V3_CLUSTER_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c
new file mode 100644
index 0000000..1ee8a91
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c
@@ -0,0 +1,102 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/common/fault/v3/fault.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/extensions/filters/common/fault/v3/fault.upbdefs.h"
+
+extern upb_def_init envoy_type_v3_percent_proto_upbdefinit;
+extern upb_def_init google_protobuf_duration_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultDelay_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit;
+extern const upb_msglayout envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit;
+
+static const upb_msglayout *layouts[5] = {
+  &envoy_extensions_filters_common_fault_v3_FaultDelay_msginit,
+  &envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_msginit,
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit_msginit,
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_msginit,
+  &envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_msginit,
+};
+
+static const char descriptor[1354] = {'\n', '4', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 'f', 'i', 'l', 't', 'e', 'r', 
+'s', '/', 'c', 'o', 'm', 'm', 'o', 'n', '/', 'f', 'a', 'u', 'l', 't', '/', 'v', '3', '/', 'f', 'a', 'u', 'l', 't', '.', 'p', 
+'r', 'o', 't', 'o', '\022', '(', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 
+'l', 't', 'e', 'r', 's', '.', 'c', 'o', 'm', 'm', 'o', 'n', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '3', '\032', '\033', 'e', 'n', 
+'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'v', '3', '/', 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', 
+'\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', 
+'/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 
+'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 
+'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\304', 
+'\003', '\n', '\n', 'F', 'a', 'u', 'l', 't', 'D', 'e', 'l', 'a', 'y', '\022', 'F', '\n', '\013', 'f', 'i', 'x', 'e', 'd', '_', 'd', 'e', 
+'l', 'a', 'y', '\030', '\003', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\252', '\001', '\002', '*', '\000', 'H', '\000', 'R', '\n', 
+'f', 'i', 'x', 'e', 'd', 'D', 'e', 'l', 'a', 'y', '\022', 'e', '\n', '\014', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'd', 'e', 'l', 'a', 
+'y', '\030', '\005', ' ', '\001', '(', '\013', '2', '@', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 
+'s', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'c', 'o', 'm', 'm', 'o', 'n', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '3', 
+'.', 'F', 'a', 'u', 'l', 't', 'D', 'e', 'l', 'a', 'y', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'D', 'e', 'l', 'a', 'y', 'H', '\000', 
+'R', '\013', 'h', 'e', 'a', 'd', 'e', 'r', 'D', 'e', 'l', 'a', 'y', '\022', '@', '\n', '\n', 'p', 'e', 'r', 'c', 'e', 'n', 't', 'a', 
+'g', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 
+'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\n', 'p', 'e', 'r', 'c', 'e', 'n', 
+'t', 'a', 'g', 'e', '\032', 'I', '\n', '\013', 'H', 'e', 'a', 'd', 'e', 'r', 'D', 'e', 'l', 'a', 'y', ':', ':', '\232', '\305', '\210', '\036', 
+'5', '\n', '3', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'f', 'a', 
+'u', 'l', 't', '.', 'v', '2', '.', 'F', 'a', 'u', 'l', 't', 'D', 'e', 'l', 'a', 'y', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'D', 
+'e', 'l', 'a', 'y', '\"', '\033', '\n', '\016', 'F', 'a', 'u', 'l', 't', 'D', 'e', 'l', 'a', 'y', 'T', 'y', 'p', 'e', '\022', '\t', '\n', 
+'\005', 'F', 'I', 'X', 'E', 'D', '\020', '\000', ':', '.', '\232', '\305', '\210', '\036', ')', '\n', '\'', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '2', '.', 'F', 'a', 'u', 'l', 
+'t', 'D', 'e', 'l', 'a', 'y', 'B', '\033', '\n', '\024', 'f', 'a', 'u', 'l', 't', '_', 'd', 'e', 'l', 'a', 'y', '_', 's', 'e', 'c', 
+'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\002', '\020', '\003', 'J', '\004', '\010', '\001', '\020', '\002', 'R', '\004', 't', 
+'y', 'p', 'e', '\"', '\260', '\004', '\n', '\016', 'F', 'a', 'u', 'l', 't', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '\022', 'f', '\n', 
+'\013', 'f', 'i', 'x', 'e', 'd', '_', 'l', 'i', 'm', 'i', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', 'C', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'c', 'o', 'm', 'm', 
+'o', 'n', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '3', '.', 'F', 'a', 'u', 'l', 't', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 
+'t', '.', 'F', 'i', 'x', 'e', 'd', 'L', 'i', 'm', 'i', 't', 'H', '\000', 'R', '\n', 'f', 'i', 'x', 'e', 'd', 'L', 'i', 'm', 'i', 
+'t', '\022', 'i', '\n', '\014', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'l', 'i', 'm', 'i', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', 'D', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', 
+'.', 'c', 'o', 'm', 'm', 'o', 'n', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '3', '.', 'F', 'a', 'u', 'l', 't', 'R', 'a', 't', 
+'e', 'L', 'i', 'm', 'i', 't', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'L', 'i', 'm', 'i', 't', 'H', '\000', 'R', '\013', 'h', 'e', 'a', 
+'d', 'e', 'r', 'L', 'i', 'm', 'i', 't', '\022', '@', '\n', '\n', 'p', 'e', 'r', 'c', 'e', 'n', 't', 'a', 'g', 'e', '\030', '\002', ' ', 
+'\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 
+'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\n', 'p', 'e', 'r', 'c', 'e', 'n', 't', 'a', 'g', 'e', '\032', 
+'s', '\n', '\n', 'F', 'i', 'x', 'e', 'd', 'L', 'i', 'm', 'i', 't', '\022', '&', '\n', '\n', 'l', 'i', 'm', 'i', 't', '_', 'k', 'b', 
+'p', 's', '\030', '\001', ' ', '\001', '(', '\004', 'B', '\007', '\372', 'B', '\004', '2', '\002', '(', '\001', 'R', '\t', 'l', 'i', 'm', 'i', 't', 'K', 
+'b', 'p', 's', ':', '=', '\232', '\305', '\210', '\036', '8', '\n', '6', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'f', 'i', 'l', 't', 'e', 'r', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '2', '.', 'F', 'a', 'u', 'l', 't', 'R', 'a', 't', 'e', 
+'L', 'i', 'm', 'i', 't', '.', 'F', 'i', 'x', 'e', 'd', 'L', 'i', 'm', 'i', 't', '\032', 'M', '\n', '\013', 'H', 'e', 'a', 'd', 'e', 
+'r', 'L', 'i', 'm', 'i', 't', ':', '>', '\232', '\305', '\210', '\036', '9', '\n', '7', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '2', '.', 'F', 'a', 'u', 'l', 't', 'R', 
+'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'L', 'i', 'm', 'i', 't', ':', '2', '\232', '\305', '\210', 
+'\036', '-', '\n', '+', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'f', 
+'a', 'u', 'l', 't', '.', 'v', '2', '.', 'F', 'a', 'u', 'l', 't', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'B', '\021', '\n', 
+'\n', 'l', 'i', 'm', 'i', 't', '_', 't', 'y', 'p', 'e', '\022', '\003', '\370', 'B', '\001', 'B', 'N', '\n', '6', 'i', 'o', '.', 'e', 'n', 
+'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 
+'.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'c', 'o', 'm', 'm', 'o', 'n', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '3', 'B', 
+'\n', 'F', 'a', 'u', 'l', 't', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 
+'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[6] = {
+  &envoy_type_v3_percent_proto_upbdefinit,
+  &google_protobuf_duration_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/extensions/filters/common/fault/v3/fault.proto",
+  UPB_STRVIEW_INIT(descriptor, 1354)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h
new file mode 100644
index 0000000..f3d64b4
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h
@@ -0,0 +1,55 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/common/fault/v3/fault.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_EXTENSIONS_FILTERS_COMMON_FAULT_V3_FAULT_PROTO_UPBDEFS_H_
+#define ENVOY_EXTENSIONS_FILTERS_COMMON_FAULT_V3_FAULT_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_common_fault_v3_FaultDelay_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.common.fault.v3.FaultDelay");
+}
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.common.fault.v3.FaultDelay.HeaderDelay");
+}
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_common_fault_v3_FaultRateLimit_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.common.fault.v3.FaultRateLimit");
+}
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.common.fault.v3.FaultRateLimit.FixedLimit");
+}
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.common.fault.v3.FaultRateLimit.HeaderLimit");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_EXTENSIONS_FILTERS_COMMON_FAULT_V3_FAULT_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c
new file mode 100644
index 0000000..cd46e93
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c
@@ -0,0 +1,120 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/http/fault/v3/fault.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/extensions/filters/http/fault/v3/fault.upbdefs.h"
+
+extern upb_def_init envoy_config_route_v3_route_components_proto_upbdefinit;
+extern upb_def_init envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit;
+extern upb_def_init envoy_type_v3_percent_proto_upbdefinit;
+extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout envoy_extensions_filters_http_fault_v3_FaultAbort_msginit;
+extern const upb_msglayout envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit;
+extern const upb_msglayout envoy_extensions_filters_http_fault_v3_HTTPFault_msginit;
+
+static const upb_msglayout *layouts[3] = {
+  &envoy_extensions_filters_http_fault_v3_FaultAbort_msginit,
+  &envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_msginit,
+  &envoy_extensions_filters_http_fault_v3_HTTPFault_msginit,
+};
+
+static const char descriptor[1812] = {'\n', '2', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 'f', 'i', 'l', 't', 'e', 'r', 
+'s', '/', 'h', 't', 't', 'p', '/', 'f', 'a', 'u', 'l', 't', '/', 'v', '3', '/', 'f', 'a', 'u', 'l', 't', '.', 'p', 'r', 'o', 
+'t', 'o', '\022', '&', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 
+'e', 'r', 's', '.', 'h', 't', 't', 'p', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '3', '\032', ',', 'e', 'n', 'v', 'o', 'y', '/', 
+'c', 'o', 'n', 'f', 'i', 'g', '/', 'r', 'o', 'u', 't', 'e', '/', 'v', '3', '/', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'm', 
+'p', 'o', 'n', 'e', 'n', 't', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '4', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 
+'n', 's', 'i', 'o', 'n', 's', '/', 'f', 'i', 'l', 't', 'e', 'r', 's', '/', 'c', 'o', 'm', 'm', 'o', 'n', '/', 'f', 'a', 'u', 
+'l', 't', '/', 'v', '3', '/', 'f', 'a', 'u', 'l', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\033', 'e', 'n', 'v', 'o', 'y', '/', 
+'t', 'y', 'p', 'e', '/', 'v', '3', '/', 'p', 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 
+'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 
+'t', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 
+'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 
+'d', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\244', '\003', '\n', '\n', 'F', 
+'a', 'u', 'l', 't', 'A', 'b', 'o', 'r', 't', '\022', '.', '\n', '\013', 'h', 't', 't', 'p', '_', 's', 't', 'a', 't', 'u', 's', '\030', 
+'\002', ' ', '\001', '(', '\r', 'B', '\013', '\372', 'B', '\010', '*', '\006', '\020', '\330', '\004', '(', '\310', '\001', 'H', '\000', 'R', '\n', 'h', 't', 't', 
+'p', 'S', 't', 'a', 't', 'u', 's', '\022', '!', '\n', '\013', 'g', 'r', 'p', 'c', '_', 's', 't', 'a', 't', 'u', 's', '\030', '\005', ' ', 
+'\001', '(', '\r', 'H', '\000', 'R', '\n', 'g', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', '\022', 'c', '\n', '\014', 'h', 'e', 'a', 'd', 
+'e', 'r', '_', 'a', 'b', 'o', 'r', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', '>', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 
+'t', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'h', 't', 't', 'p', '.', 'f', 'a', 'u', 
+'l', 't', '.', 'v', '3', '.', 'F', 'a', 'u', 'l', 't', 'A', 'b', 'o', 'r', 't', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'A', 'b', 
+'o', 'r', 't', 'H', '\000', 'R', '\013', 'h', 'e', 'a', 'd', 'e', 'r', 'A', 'b', 'o', 'r', 't', '\022', '@', '\n', '\n', 'p', 'e', 'r', 
+'c', 'e', 'n', 't', 'a', 'g', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 
+'e', '.', 'v', '3', '.', 'F', 'r', 'a', 'c', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\n', 'p', 
+'e', 'r', 'c', 'e', 'n', 't', 'a', 'g', 'e', '\032', 'N', '\n', '\013', 'H', 'e', 'a', 'd', 'e', 'r', 'A', 'b', 'o', 'r', 't', ':', 
+'?', '\232', '\305', '\210', '\036', ':', '\n', '8', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 
+'e', 'r', '.', 'h', 't', 't', 'p', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '2', '.', 'F', 'a', 'u', 'l', 't', 'A', 'b', 'o', 
+'r', 't', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'A', 'b', 'o', 'r', 't', ':', '3', '\232', '\305', '\210', '\036', '.', '\n', ',', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'h', 't', 't', 'p', '.', 'f', 'a', 
+'u', 'l', 't', '.', 'v', '2', '.', 'F', 'a', 'u', 'l', 't', 'A', 'b', 'o', 'r', 't', 'B', '\021', '\n', '\n', 'e', 'r', 'r', 'o', 
+'r', '_', 't', 'y', 'p', 'e', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\001', '\020', '\002', '\"', '\274', '\007', '\n', '\t', 'H', 'T', 'T', 
+'P', 'F', 'a', 'u', 'l', 't', '\022', 'J', '\n', '\005', 'd', 'e', 'l', 'a', 'y', '\030', '\001', ' ', '\001', '(', '\013', '2', '4', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'c', 
+'o', 'm', 'm', 'o', 'n', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '3', '.', 'F', 'a', 'u', 'l', 't', 'D', 'e', 'l', 'a', 'y', 
+'R', '\005', 'd', 'e', 'l', 'a', 'y', '\022', 'H', '\n', '\005', 'a', 'b', 'o', 'r', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '2', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 
+'h', 't', 't', 'p', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '3', '.', 'F', 'a', 'u', 'l', 't', 'A', 'b', 'o', 'r', 't', 'R', 
+'\005', 'a', 'b', 'o', 'r', 't', '\022', ')', '\n', '\020', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'c', 'l', 'u', 's', 't', 'e', 
+'r', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\017', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', 'C', 'l', 'u', 's', 't', 'e', 'r', '\022', 
+'>', '\n', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'M', 'a', 't', 
+'c', 'h', 'e', 'r', 'R', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\022', ')', '\n', '\020', 'd', 'o', 'w', 'n', 's', 't', 'r', 'e', 
+'a', 'm', '_', 'n', 'o', 'd', 'e', 's', '\030', '\005', ' ', '\003', '(', '\t', 'R', '\017', 'd', 'o', 'w', 'n', 's', 't', 'r', 'e', 'a', 
+'m', 'N', 'o', 'd', 'e', 's', '\022', 'H', '\n', '\021', 'm', 'a', 'x', '_', 'a', 'c', 't', 'i', 'v', 'e', '_', 'f', 'a', 'u', 'l', 
+'t', 's', '\030', '\006', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\017', 'm', 'a', 'x', 'A', 'c', 't', 'i', 'v', 'e', 'F', 
+'a', 'u', 'l', 't', 's', '\022', 'h', '\n', '\023', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'r', 'a', 't', 'e', '_', 'l', 'i', 
+'m', 'i', 't', '\030', '\007', ' ', '\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 
+'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'c', 'o', 'm', 'm', 'o', 'n', '.', 'f', 'a', 'u', 'l', 't', '.', 
+'v', '3', '.', 'F', 'a', 'u', 'l', 't', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', 'R', '\021', 'r', 'e', 's', 'p', 'o', 'n', 
+'s', 'e', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 't', '\022', '2', '\n', '\025', 'd', 'e', 'l', 'a', 'y', '_', 'p', 'e', 'r', 'c', 
+'e', 'n', 't', '_', 'r', 'u', 'n', 't', 'i', 'm', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\023', 'd', 'e', 'l', 'a', 'y', 'P', 
+'e', 'r', 'c', 'e', 'n', 't', 'R', 'u', 'n', 't', 'i', 'm', 'e', '\022', '2', '\n', '\025', 'a', 'b', 'o', 'r', 't', '_', 'p', 'e', 
+'r', 'c', 'e', 'n', 't', '_', 'r', 'u', 'n', 't', 'i', 'm', 'e', '\030', '\t', ' ', '\001', '(', '\t', 'R', '\023', 'a', 'b', 'o', 'r', 
+'t', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', 'u', 'n', 't', 'i', 'm', 'e', '\022', '4', '\n', '\026', 'd', 'e', 'l', 'a', 'y', '_', 
+'d', 'u', 'r', 'a', 't', 'i', 'o', 'n', '_', 'r', 'u', 'n', 't', 'i', 'm', 'e', '\030', '\n', ' ', '\001', '(', '\t', 'R', '\024', 'd', 
+'e', 'l', 'a', 'y', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', 'u', 'n', 't', 'i', 'm', 'e', '\022', '9', '\n', '\031', 'a', 'b', 
+'o', 'r', 't', '_', 'h', 't', 't', 'p', '_', 's', 't', 'a', 't', 'u', 's', '_', 'r', 'u', 'n', 't', 'i', 'm', 'e', '\030', '\013', 
+' ', '\001', '(', '\t', 'R', '\026', 'a', 'b', 'o', 'r', 't', 'H', 't', 't', 'p', 'S', 't', 'a', 't', 'u', 's', 'R', 'u', 'n', 't', 
+'i', 'm', 'e', '\022', '9', '\n', '\031', 'm', 'a', 'x', '_', 'a', 'c', 't', 'i', 'v', 'e', '_', 'f', 'a', 'u', 'l', 't', 's', '_', 
+'r', 'u', 'n', 't', 'i', 'm', 'e', '\030', '\014', ' ', '\001', '(', '\t', 'R', '\026', 'm', 'a', 'x', 'A', 'c', 't', 'i', 'v', 'e', 'F', 
+'a', 'u', 'l', 't', 's', 'R', 'u', 'n', 't', 'i', 'm', 'e', '\022', 'L', '\n', '#', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 
+'r', 'a', 't', 'e', '_', 'l', 'i', 'm', 'i', 't', '_', 'p', 'e', 'r', 'c', 'e', 'n', 't', '_', 'r', 'u', 'n', 't', 'i', 'm', 
+'e', '\030', '\r', ' ', '\001', '(', '\t', 'R', '\037', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'R', 'a', 't', 'e', 'L', 'i', 'm', 'i', 
+'t', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', 'u', 'n', 't', 'i', 'm', 'e', '\022', '9', '\n', '\031', 'a', 'b', 'o', 'r', 't', '_', 
+'g', 'r', 'p', 'c', '_', 's', 't', 'a', 't', 'u', 's', '_', 'r', 'u', 'n', 't', 'i', 'm', 'e', '\030', '\016', ' ', '\001', '(', '\t', 
+'R', '\026', 'a', 'b', 'o', 'r', 't', 'G', 'r', 'p', 'c', 'S', 't', 'a', 't', 'u', 's', 'R', 'u', 'n', 't', 'i', 'm', 'e', ':', 
+'2', '\232', '\305', '\210', '\036', '-', '\n', '+', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 
+'e', 'r', '.', 'h', 't', 't', 'p', '.', 'f', 'a', 'u', 'l', 't', '.', 'v', '2', '.', 'H', 'T', 'T', 'P', 'F', 'a', 'u', 'l', 
+'t', 'B', 'L', '\n', '4', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'h', 't', 't', 'p', '.', 'f', 
+'a', 'u', 'l', 't', '.', 'v', '3', 'B', '\n', 'F', 'a', 'u', 'l', 't', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', 
+'\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[8] = {
+  &envoy_config_route_v3_route_components_proto_upbdefinit,
+  &envoy_extensions_filters_common_fault_v3_fault_proto_upbdefinit,
+  &envoy_type_v3_percent_proto_upbdefinit,
+  &google_protobuf_wrappers_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_extensions_filters_http_fault_v3_fault_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/extensions/filters/http/fault/v3/fault.proto",
+  UPB_STRVIEW_INIT(descriptor, 1812)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h
new file mode 100644
index 0000000..0beb986
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h
@@ -0,0 +1,45 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/http/fault/v3/fault.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_EXTENSIONS_FILTERS_HTTP_FAULT_V3_FAULT_PROTO_UPBDEFS_H_
+#define ENVOY_EXTENSIONS_FILTERS_HTTP_FAULT_V3_FAULT_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_extensions_filters_http_fault_v3_fault_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_http_fault_v3_FaultAbort_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_http_fault_v3_fault_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.http.fault.v3.FaultAbort");
+}
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_http_fault_v3_fault_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.http.fault.v3.FaultAbort.HeaderAbort");
+}
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_http_fault_v3_HTTPFault_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_http_fault_v3_fault_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.http.fault.v3.HTTPFault");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_EXTENSIONS_FILTERS_HTTP_FAULT_V3_FAULT_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c
new file mode 100644
index 0000000..f1d9a57
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c
@@ -0,0 +1,76 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/http/router/v3/router.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/extensions/filters/http/router/v3/router.upbdefs.h"
+
+extern upb_def_init envoy_config_accesslog_v3_accesslog_proto_upbdefinit;
+extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout envoy_extensions_filters_http_router_v3_Router_msginit;
+
+static const upb_msglayout *layouts[1] = {
+  &envoy_extensions_filters_http_router_v3_Router_msginit,
+};
+
+static const char descriptor[909] = {'\n', '4', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 'f', 'i', 'l', 't', 'e', 'r', 
+'s', '/', 'h', 't', 't', 'p', '/', 'r', 'o', 'u', 't', 'e', 'r', '/', 'v', '3', '/', 'r', 'o', 'u', 't', 'e', 'r', '.', 'p', 
+'r', 'o', 't', 'o', '\022', '\'', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 
+'l', 't', 'e', 'r', 's', '.', 'h', 't', 't', 'p', '.', 'r', 'o', 'u', 't', 'e', 'r', '.', 'v', '3', '\032', ')', 'e', 'n', 'v', 
+'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '/', 'v', '3', '/', 'a', 'c', 
+'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 
+'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 
+'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 
+'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 
+'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\255', '\004', '\n', '\006', 'R', 'o', 'u', 't', 'e', 'r', '\022', '?', '\n', 
+'\r', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '_', 's', 't', 'a', 't', 's', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\014', 
+'d', 'y', 'n', 'a', 'm', 'i', 'c', 'S', 't', 'a', 't', 's', '\022', '(', '\n', '\020', 's', 't', 'a', 'r', 't', '_', 'c', 'h', 'i', 
+'l', 'd', '_', 's', 'p', 'a', 'n', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\016', 's', 't', 'a', 'r', 't', 'C', 'h', 'i', 'l', 'd', 
+'S', 'p', 'a', 'n', '\022', 'G', '\n', '\014', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '_', 'l', 'o', 'g', '\030', '\003', ' ', '\003', '(', 
+'\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 
+'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'R', '\013', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', 'L', 
+'o', 'g', '\022', '4', '\n', '\026', 's', 'u', 'p', 'p', 'r', 'e', 's', 's', '_', 'e', 'n', 'v', 'o', 'y', '_', 'h', 'e', 'a', 'd', 
+'e', 'r', 's', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\024', 's', 'u', 'p', 'p', 'r', 'e', 's', 's', 'E', 'n', 'v', 'o', 'y', 'H', 
+'e', 'a', 'd', 'e', 'r', 's', '\022', '\307', '\001', '\n', '\024', 's', 't', 'r', 'i', 'c', 't', '_', 'c', 'h', 'e', 'c', 'k', '_', 'h', 
+'e', 'a', 'd', 'e', 'r', 's', '\030', '\005', ' ', '\003', '(', '\t', 'B', '\224', '\001', '\372', 'B', '\220', '\001', '\222', '\001', '\214', '\001', '\"', '\211', 
+'\001', 'r', '\206', '\001', 'R', '\036', 'x', '-', 'e', 'n', 'v', 'o', 'y', '-', 'u', 'p', 's', 't', 'r', 'e', 'a', 'm', '-', 'r', 'q', 
+'-', 't', 'i', 'm', 'e', 'o', 'u', 't', '-', 'm', 's', 'R', '&', 'x', '-', 'e', 'n', 'v', 'o', 'y', '-', 'u', 'p', 's', 't', 
+'r', 'e', 'a', 'm', '-', 'r', 'q', '-', 'p', 'e', 'r', '-', 't', 'r', 'y', '-', 't', 'i', 'm', 'e', 'o', 'u', 't', '-', 'm', 
+'s', 'R', '\023', 'x', '-', 'e', 'n', 'v', 'o', 'y', '-', 'm', 'a', 'x', '-', 'r', 'e', 't', 'r', 'i', 'e', 's', 'R', '\025', 'x', 
+'-', 'e', 'n', 'v', 'o', 'y', '-', 'r', 'e', 't', 'r', 'y', '-', 'g', 'r', 'p', 'c', '-', 'o', 'n', 'R', '\020', 'x', '-', 'e', 
+'n', 'v', 'o', 'y', '-', 'r', 'e', 't', 'r', 'y', '-', 'o', 'n', 'R', '\022', 's', 't', 'r', 'i', 'c', 't', 'C', 'h', 'e', 'c', 
+'k', 'H', 'e', 'a', 'd', 'e', 'r', 's', '\022', '=', '\n', '\033', 'r', 'e', 's', 'p', 'e', 'c', 't', '_', 'e', 'x', 'p', 'e', 'c', 
+'t', 'e', 'd', '_', 'r', 'q', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\006', ' ', '\001', '(', '\010', 'R', '\030', 'r', 'e', 's', 
+'p', 'e', 'c', 't', 'E', 'x', 'p', 'e', 'c', 't', 'e', 'd', 'R', 'q', 'T', 'i', 'm', 'e', 'o', 'u', 't', ':', '0', '\232', '\305', 
+'\210', '\036', '+', '\n', ')', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 
+'h', 't', 't', 'p', '.', 'r', 'o', 'u', 't', 'e', 'r', '.', 'v', '2', '.', 'R', 'o', 'u', 't', 'e', 'r', 'B', 'N', '\n', '5', 
+'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 
+'s', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'h', 't', 't', 'p', '.', 'r', 'o', 'u', 't', 'e', 'r', 
+'.', 'v', '3', 'B', '\013', 'R', 'o', 'u', 't', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', 
+'\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[6] = {
+  &envoy_config_accesslog_v3_accesslog_proto_upbdefinit,
+  &google_protobuf_wrappers_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_extensions_filters_http_router_v3_router_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/extensions/filters/http/router/v3/router.proto",
+  UPB_STRVIEW_INIT(descriptor, 909)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h
new file mode 100644
index 0000000..dc91890
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h
@@ -0,0 +1,35 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/extensions/filters/http/router/v3/router.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_EXTENSIONS_FILTERS_HTTP_ROUTER_V3_ROUTER_PROTO_UPBDEFS_H_
+#define ENVOY_EXTENSIONS_FILTERS_HTTP_ROUTER_V3_ROUTER_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_extensions_filters_http_router_v3_router_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_extensions_filters_http_router_v3_Router_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_extensions_filters_http_router_v3_router_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.extensions.filters.http.router.v3.Router");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_EXTENSIONS_FILTERS_HTTP_ROUTER_V3_ROUTER_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c
index 7eeda1f..916044e 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c
@@ -22,10 +22,7 @@
 extern upb_def_init envoy_type_v3_percent_proto_upbdefinit;
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
-extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_resource_locator_proto_upbdefinit;
-extern upb_def_init envoy_annotations_deprecation_proto_upbdefinit;
 extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
 extern upb_def_init udpa_annotations_security_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
@@ -69,7 +66,7 @@
   &envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension_msginit,
 };
 
-static const char descriptor[10148] = {'\n', 'Y', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 'f', 'i', 'l', 't', 'e', 'r', 
+static const char descriptor[10141] = {'\n', 'Y', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 'f', 'i', 'l', 't', 'e', 'r', 
 's', '/', 'n', 'e', 't', 'w', 'o', 'r', 'k', '/', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
 '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '/', 'v', '3', '/', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', ';', 'e', 'n', 'v', 'o', 'y', '.', 'e', 
@@ -94,390 +91,390 @@
 'a', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\033', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'v', '3', '/', 'p', 
 'e', 'r', 'c', 'e', 'n', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 
 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 
-'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 
-'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 
-'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 
-'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 
-'s', 'o', 'u', 'r', 'c', 'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'e', 'n', 'v', 
-'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'i', 'o', 
-'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', 
-'/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 
-'t', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 'e', 'c', 'u', 'r', 'i', 't', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 
-'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 
-'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 
-'s', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 
-'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\321', ')', '\n', '\025', 'H', 't', 't', 'p', 'C', 'o', 'n', 
-'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '\022', '\205', '\001', '\n', '\n', 'c', 'o', 'd', 'e', 'c', '_', 
-'t', 'y', 'p', 'e', '\030', '\001', ' ', '\001', '(', '\016', '2', '\\', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 
-'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', 
-'_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 
-'t', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'C', 'o', 'd', 'e', 'c', 
-'T', 'y', 'p', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\t', 'c', 'o', 'd', 'e', 'c', 'T', 'y', 'p', 'e', 
-'\022', '(', '\n', '\013', 's', 't', 'a', 't', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', 
-'\004', 'r', '\002', '\020', '\001', 'R', '\n', 's', 't', 'a', 't', 'P', 'r', 'e', 'f', 'i', 'x', '\022', 'T', '\n', '\003', 'r', 'd', 's', '\030', 
-'\003', ' ', '\001', '(', '\013', '2', '@', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
-'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 
-'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'R', 'd', 's', 'H', '\000', 'R', '\003', 
-'r', 'd', 's', '\022', 'N', '\n', '\014', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\004', ' ', '\001', '(', '\013', 
-'2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 
-'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\013', 'r', 'o', 'u', 
-'t', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'p', '\n', '\r', 's', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'o', 'u', 't', 'e', 's', 
-'\030', '\037', ' ', '\001', '(', '\013', '2', 'I', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 
+'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 
+'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 
+'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 
+'o', 'n', 's', '/', 's', 'e', 'c', 'u', 'r', 'i', 't', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 
+'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', 
+'!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 
+'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 
+'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\222', '+', '\n', '\025', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 
+'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '\022', '\205', '\001', '\n', '\n', 'c', 'o', 'd', 'e', 'c', '_', 't', 'y', 'p', 'e', 
+'\030', '\001', ' ', '\001', '(', '\016', '2', '\\', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 
 '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 
-'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 
-'R', 'o', 'u', 't', 'e', 's', 'H', '\000', 'R', '\014', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '\022', 'j', '\n', 
-'\014', 'h', 't', 't', 'p', '_', 'f', 'i', 'l', 't', 'e', 'r', 's', '\030', '\005', ' ', '\003', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 
-'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 
-'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\013', 'h', 't', 't', 'p', 'F', 'i', 
-'l', 't', 'e', 'r', 's', '\022', '@', '\n', '\016', 'a', 'd', 'd', '_', 'u', 's', 'e', 'r', '_', 'a', 'g', 'e', 'n', 't', '\030', '\006', 
-' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 
-'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\014', 'a', 'd', 'd', 'U', 's', 'e', 'r', 'A', 'g', 'e', 'n', 't', '\022', 't', '\n', '\007', 
-'t', 'r', 'a', 'c', 'i', 'n', 'g', '\030', '\007', ' ', '\001', '(', '\013', '2', 'Z', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 
-'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 
-'t', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', 
-'.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'T', 'r', 
-'a', 'c', 'i', 'n', 'g', 'R', '\007', 't', 'r', 'a', 'c', 'i', 'n', 'g', '\022', 's', '\n', '\034', 'c', 'o', 'm', 'm', 'o', 'n', '_', 
-'h', 't', 't', 'p', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '#', ' ', '\001', 
-'(', '\013', '2', ')', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
-'.', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'B', '\007', '\212', '\223', '\267', 
-'*', '\002', '\010', '\001', 'R', '\031', 'c', 'o', 'm', 'm', 'o', 'n', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 
-'p', 't', 'i', 'o', 'n', 's', '\022', '^', '\n', '\025', 'h', 't', 't', 'p', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 
-'p', 't', 'i', 'o', 'n', 's', '\030', '\010', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 'p', '1', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 
-'p', 't', 'i', 'o', 'n', 's', 'R', '\023', 'h', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 
-'n', 's', '\022', 'i', '\n', '\026', 'h', 't', 't', 'p', '2', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 'p', 't', 'i', 
-'o', 'n', 's', '\030', '\t', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 'p', '2', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 
-'o', 'n', 's', 'B', '\007', '\212', '\223', '\267', '*', '\002', '\010', '\001', 'R', '\024', 'h', 't', 't', 'p', '2', 'P', 'r', 'o', 't', 'o', 'c', 
-'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', ',', '\n', '\013', 's', 'e', 'r', 'v', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', 
-'\n', ' ', '\001', '(', '\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\n', 's', 'e', 'r', 'v', 'e', 
-'r', 'N', 'a', 'm', 'e', '\022', '\271', '\001', '\n', '\034', 's', 'e', 'r', 'v', 'e', 'r', '_', 'h', 'e', 'a', 'd', 'e', 'r', '_', 't', 
-'r', 'a', 'n', 's', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', '\030', '\"', ' ', '\001', '(', '\016', '2', 'm', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 
-'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 
-'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 
-'g', 'e', 'r', '.', 'S', 'e', 'r', 'v', 'e', 'r', 'H', 'e', 'a', 'd', 'e', 'r', 'T', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm', 
-'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\032', 's', 'e', 'r', 'v', 'e', 'r', 'H', 'e', 
-'a', 'd', 'e', 'r', 'T', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', '\022', '\\', '\n', '\026', 'm', 'a', 'x', 
-'_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 'k', 'b', '\030', '\035', ' ', '\001', '(', '\013', 
-'2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 
-'V', 'a', 'l', 'u', 'e', 'B', '\t', '\372', 'B', '\006', '*', '\004', '\030', '`', ' ', '\000', 'R', '\023', 'm', 'a', 'x', 'R', 'e', 'q', 'u', 
-'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'K', 'b', '\022', 'R', '\n', '\023', 's', 't', 'r', 'e', 'a', 'm', '_', 'i', 'd', 
-'l', 'e', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\030', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
-'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\007', '\212', '\223', '\267', '*', '\002', 
-'\010', '\001', 'R', '\021', 's', 't', 'r', 'e', 'a', 'm', 'I', 'd', 'l', 'e', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'K', '\n', '\017', 
-'r', 'e', 'q', 'u', 'e', 's', 't', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\034', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 
-'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\007', 
-'\212', '\223', '\267', '*', '\002', '\010', '\001', 'R', '\016', 'r', 'e', 'q', 'u', 'e', 's', 't', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', '>', 
-'\n', '\r', 'd', 'r', 'a', 'i', 'n', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\014', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 
-'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\014', 
-'d', 'r', 'a', 'i', 'n', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'M', '\n', '\025', 'd', 'e', 'l', 'a', 'y', 'e', 'd', '_', 'c', 
-'l', 'o', 's', 'e', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\032', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\023', 'd', 'e', 'l', 
-'a', 'y', 'e', 'd', 'C', 'l', 'o', 's', 'e', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'C', '\n', '\n', 'a', 'c', 'c', 'e', 's', 
-'s', '_', 'l', 'o', 'g', '\030', '\r', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'R', 
-'\t', 'a', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', '\022', 'Q', '\n', '\022', 'u', 's', 'e', '_', 'r', 'e', 'm', 'o', 't', 'e', '_', 
-'a', 'd', 'd', 'r', 'e', 's', 's', '\030', '\016', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
-'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\212', '\223', '\267', '*', '\002', '\010', '\001', 
-'R', '\020', 'u', 's', 'e', 'R', 'e', 'm', 'o', 't', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', '\022', '/', '\n', '\024', 'x', 'f', 'f', 
-'_', 'n', 'u', 'm', '_', 't', 'r', 'u', 's', 't', 'e', 'd', '_', 'h', 'o', 'p', 's', '\030', '\023', ' ', '\001', '(', '\r', 'R', '\021', 
-'x', 'f', 'f', 'N', 'u', 'm', 'T', 'r', 'u', 's', 't', 'e', 'd', 'H', 'o', 'p', 's', '\022', '\240', '\001', '\n', '\027', 'i', 'n', 't', 
-'e', 'r', 'n', 'a', 'l', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\031', ' ', '\001', '(', 
-'\013', '2', 'h', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 
+'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'C', 'o', 
+'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'C', 'o', 'd', 'e', 'c', 'T', 'y', 'p', 'e', 
+'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\t', 'c', 'o', 'd', 'e', 'c', 'T', 'y', 'p', 'e', '\022', '(', '\n', '\013', 
+'s', 't', 'a', 't', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', 
+'\001', 'R', '\n', 's', 't', 'a', 't', 'P', 'r', 'e', 'f', 'i', 'x', '\022', 'T', '\n', '\003', 'r', 'd', 's', '\030', '\003', ' ', '\001', '(', 
+'\013', '2', '@', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 
 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
-'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 
-'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'A', 'd', 'd', 'r', 'e', 's', 
-'s', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\025', 'i', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'A', 'd', 'd', 'r', 'e', 's', 's', 'C', 
-'o', 'n', 'f', 'i', 'g', '\022', '&', '\n', '\017', 's', 'k', 'i', 'p', '_', 'x', 'f', 'f', '_', 'a', 'p', 'p', 'e', 'n', 'd', '\030', 
-'\025', ' ', '\001', '(', '\010', 'R', '\r', 's', 'k', 'i', 'p', 'X', 'f', 'f', 'A', 'p', 'p', 'e', 'n', 'd', '\022', '\020', '\n', '\003', 'v', 
-'i', 'a', '\030', '\026', ' ', '\001', '(', '\t', 'R', '\003', 'v', 'i', 'a', '\022', 'J', '\n', '\023', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e', 
-'_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'i', 'd', '\030', '\017', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\021', 'g', 'e', 'n', 
-'e', 'r', 'a', 't', 'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'd', '\022', '?', '\n', '\034', 'p', 'r', 'e', 's', 'e', 'r', 'v', 
-'e', '_', 'e', 'x', 't', 'e', 'r', 'n', 'a', 'l', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'i', 'd', '\030', ' ', ' ', '\001', 
-'(', '\010', 'R', '\031', 'p', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'E', 'x', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'q', 'u', 'e', 
-'s', 't', 'I', 'd', '\022', 'G', '\n', '!', 'a', 'l', 'w', 'a', 'y', 's', '_', 's', 'e', 't', '_', 'r', 'e', 'q', 'u', 'e', 's', 
-'t', '_', 'i', 'd', '_', 'i', 'n', '_', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '\030', '%', ' ', '\001', '(', '\010', 'R', '\034', 'a', 
-'l', 'w', 'a', 'y', 's', 'S', 'e', 't', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'd', 'I', 'n', 'R', 'e', 's', 'p', 'o', 'n', 
-'s', 'e', '\022', '\264', '\001', '\n', '\033', 'f', 'o', 'r', 'w', 'a', 'r', 'd', '_', 'c', 'l', 'i', 'e', 'n', 't', '_', 'c', 'e', 'r', 
-'t', '_', 'd', 'e', 't', 'a', 'i', 'l', 's', '\030', '\020', ' ', '\001', '(', '\016', '2', 'k', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 
+'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'R', 'd', 's', 'H', '\000', 'R', '\003', 'r', 'd', 's', '\022', 
+'N', '\n', '\014', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\004', ' ', '\001', '(', '\013', '2', ')', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 
+'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'H', '\000', 'R', '\013', 'r', 'o', 'u', 't', 'e', 'C', 'o', 
+'n', 'f', 'i', 'g', '\022', 'p', '\n', '\r', 's', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'o', 'u', 't', 'e', 's', '\030', '\037', ' ', '\001', 
+'(', '\013', '2', 'I', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 
+'t', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 
+'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 
+'e', 's', 'H', '\000', 'R', '\014', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '\022', 'j', '\n', '\014', 'h', 't', 't', 
+'p', '_', 'f', 'i', 'l', 't', 'e', 'r', 's', '\030', '\005', ' ', '\003', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 
+'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', 
+'.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 
+'v', '3', '.', 'H', 't', 't', 'p', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\013', 'h', 't', 't', 'p', 'F', 'i', 'l', 't', 'e', 'r', 
+'s', '\022', '@', '\n', '\016', 'a', 'd', 'd', '_', 'u', 's', 'e', 'r', '_', 'a', 'g', 'e', 'n', 't', '\030', '\006', ' ', '\001', '(', '\013', 
+'2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 
+'l', 'u', 'e', 'R', '\014', 'a', 'd', 'd', 'U', 's', 'e', 'r', 'A', 'g', 'e', 'n', 't', '\022', 't', '\n', '\007', 't', 'r', 'a', 'c', 
+'i', 'n', 'g', '\030', '\007', ' ', '\001', '(', '\013', '2', 'Z', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 
+'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 
+'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 
+'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'T', 'r', 'a', 'c', 'i', 'n', 
+'g', 'R', '\007', 't', 'r', 'a', 'c', 'i', 'n', 'g', '\022', 's', '\n', '\034', 'c', 'o', 'm', 'm', 'o', 'n', '_', 'h', 't', 't', 'p', 
+'_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '#', ' ', '\001', '(', '\013', '2', ')', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 
+'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'B', '\007', '\212', '\223', '\267', '*', '\002', '\010', '\001', 
+'R', '\031', 'c', 'o', 'm', 'm', 'o', 'n', 'H', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 
+'n', 's', '\022', '^', '\n', '\025', 'h', 't', 't', 'p', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 
+'n', 's', '\030', '\010', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 
+'o', 'r', 'e', '.', 'v', '3', '.', 'H', 't', 't', 'p', '1', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 
+'n', 's', 'R', '\023', 'h', 't', 't', 'p', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'i', 
+'\n', '\026', 'h', 't', 't', 'p', '2', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', 
+'\t', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', 
+'.', 'v', '3', '.', 'H', 't', 't', 'p', '2', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 't', 'i', 'o', 'n', 's', 'B', 
+'\007', '\212', '\223', '\267', '*', '\002', '\010', '\001', 'R', '\024', 'h', 't', 't', 'p', '2', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'O', 'p', 
+'t', 'i', 'o', 'n', 's', '\022', ',', '\n', '\013', 's', 'e', 'r', 'v', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\n', ' ', '\001', '(', 
+'\t', 'B', '\013', '\372', 'B', '\010', 'r', '\006', '\300', '\001', '\002', '\310', '\001', '\000', 'R', '\n', 's', 'e', 'r', 'v', 'e', 'r', 'N', 'a', 'm', 
+'e', '\022', '\271', '\001', '\n', '\034', 's', 'e', 'r', 'v', 'e', 'r', '_', 'h', 'e', 'a', 'd', 'e', 'r', '_', 't', 'r', 'a', 'n', 's', 
+'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', '\030', '\"', ' ', '\001', '(', '\016', '2', 'm', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 
 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', 
 '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 
 'v', '3', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 
-'F', 'o', 'r', 'w', 'a', 'r', 'd', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', 'B', 
-'\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\030', 'f', 'o', 'r', 'w', 'a', 'r', 'd', 'C', 'l', 'i', 'e', 'n', 't', 'C', 
-'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', '\022', '\264', '\001', '\n', '\037', 's', 'e', 't', '_', 'c', 'u', 'r', 'r', 'e', 'n', 
-'t', '_', 'c', 'l', 'i', 'e', 'n', 't', '_', 'c', 'e', 'r', 't', '_', 'd', 'e', 't', 'a', 'i', 'l', 's', '\030', '\021', ' ', '\001', 
-'(', '\013', '2', 'n', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 
-'t', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 
-'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 
-'t', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'S', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'C', 'l', 'i', 
-'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', 'R', '\033', 's', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 
-'t', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', '\022', ',', '\n', '\022', 'p', 'r', 'o', 
-'x', 'y', '_', '1', '0', '0', '_', 'c', 'o', 'n', 't', 'i', 'n', 'u', 'e', '\030', '\022', ' ', '\001', '(', '\010', 'R', '\020', 'p', 'r', 
-'o', 'x', 'y', '1', '0', '0', 'C', 'o', 'n', 't', 'i', 'n', 'u', 'e', '\022', 'e', '\n', '1', 'r', 'e', 'p', 'r', 'e', 's', 'e', 
-'n', 't', '_', 'i', 'p', 'v', '4', '_', 'r', 'e', 'm', 'o', 't', 'e', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', '_', 'a', 's', 
-'_', 'i', 'p', 'v', '4', '_', 'm', 'a', 'p', 'p', 'e', 'd', '_', 'i', 'p', 'v', '6', '\030', '\024', ' ', '\001', '(', '\010', 'R', '*', 
-'r', 'e', 'p', 'r', 'e', 's', 'e', 'n', 't', 'I', 'p', 'v', '4', 'R', 'e', 'm', 'o', 't', 'e', 'A', 'd', 'd', 'r', 'e', 's', 
-'s', 'A', 's', 'I', 'p', 'v', '4', 'M', 'a', 'p', 'p', 'e', 'd', 'I', 'p', 'v', '6', '\022', '\211', '\001', '\n', '\017', 'u', 'p', 'g', 
-'r', 'a', 'd', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\027', ' ', '\003', '(', '\013', '2', '`', '.', 'e', 'n', 'v', 'o', 
-'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 
-'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 
-'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 
-'e', 'r', '.', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'u', 'p', 'g', 'r', 'a', 'd', 'e', 
-'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', 'A', '\n', '\016', 'n', 'o', 'r', 'm', 'a', 'l', 'i', 'z', 'e', '_', 'p', 'a', 't', 'h', 
-'\030', '\036', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
-'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\r', 'n', 'o', 'r', 'm', 'a', 'l', 'i', 'z', 'e', 'P', 'a', 't', 'h', '\022', 
-'#', '\n', '\r', 'm', 'e', 'r', 'g', 'e', '_', 's', 'l', 'a', 's', 'h', 'e', 's', '\030', '!', ' ', '\001', '(', '\010', 'R', '\014', 'm', 
-'e', 'r', 'g', 'e', 'S', 'l', 'a', 's', 'h', 'e', 's', '\022', '\201', '\001', '\n', '\024', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'i', 
-'d', '_', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '$', ' ', '\001', '(', '\013', '2', 'O', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 
-'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 
-'r', '.', 'v', '3', '.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'D', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', '\022', 
-'r', 'e', 'q', 'u', 'e', 's', 't', 'I', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', '{', '\n', '\022', 'l', 'o', 'c', 
-'a', 'l', '_', 'r', 'e', 'p', 'l', 'y', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '&', ' ', '\001', '(', '\013', '2', 'M', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 
-'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 
-'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'L', 'o', 'c', 'a', 'l', 'R', 'e', 'p', 'l', 'y', 'C', 'o', 'n', 'f', 'i', 'g', 
-'R', '\020', 'l', 'o', 'c', 'a', 'l', 'R', 'e', 'p', 'l', 'y', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '7', '\n', '\030', 's', 't', 'r', 
-'i', 'p', '_', 'm', 'a', 't', 'c', 'h', 'i', 'n', 'g', '_', 'h', 'o', 's', 't', '_', 'p', 'o', 'r', 't', '\030', '\'', ' ', '\001', 
-'(', '\010', 'R', '\025', 's', 't', 'r', 'i', 'p', 'M', 'a', 't', 'c', 'h', 'i', 'n', 'g', 'H', 'o', 's', 't', 'P', 'o', 'r', 't', 
-'\022', 'i', '\n', '$', 's', 't', 'r', 'e', 'a', 'm', '_', 'e', 'r', 'r', 'o', 'r', '_', 'o', 'n', '_', 'i', 'n', 'v', 'a', 'l', 
-'i', 'd', '_', 'h', 't', 't', 'p', '_', 'm', 'e', 's', 's', 'a', 'g', 'e', '\030', '(', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 
-'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', 
-'\037', 's', 't', 'r', 'e', 'a', 'm', 'E', 'r', 'r', 'o', 'r', 'O', 'n', 'I', 'n', 'v', 'a', 'l', 'i', 'd', 'H', 't', 't', 'p', 
-'M', 'e', 's', 's', 'a', 'g', 'e', '\032', '\366', '\004', '\n', '\007', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '\022', '?', '\n', '\017', 'c', 'l', 
-'i', 'e', 'n', 't', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'c', 'l', 'i', 'e', 'n', 
-'t', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', '?', '\n', '\017', 'r', 'a', 'n', 'd', 'o', 'm', '_', 's', 'a', 'm', 'p', 'l', 
-'i', 'n', 'g', '\030', '\004', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', 
-'.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'r', 'a', 'n', 'd', 'o', 'm', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', 
-'A', '\n', '\020', 'o', 'v', 'e', 'r', 'a', 'l', 'l', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\005', ' ', '\001', '(', '\013', 
-'2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', 
-'\017', 'o', 'v', 'e', 'r', 'a', 'l', 'l', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', '\030', '\n', '\007', 'v', 'e', 'r', 'b', 'o', 
-'s', 'e', '\030', '\006', ' ', '\001', '(', '\010', 'R', '\007', 'v', 'e', 'r', 'b', 'o', 's', 'e', '\022', 'K', '\n', '\023', 'm', 'a', 'x', '_', 
-'p', 'a', 't', 'h', '_', 't', 'a', 'g', '_', 'l', 'e', 'n', 'g', 't', 'h', '\030', '\007', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 
+'S', 'e', 'r', 'v', 'e', 'r', 'H', 'e', 'a', 'd', 'e', 'r', 'T', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 
+'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\032', 's', 'e', 'r', 'v', 'e', 'r', 'H', 'e', 'a', 'd', 'e', 'r', 
+'T', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', '\022', '\\', '\n', '\026', 'm', 'a', 'x', '_', 'r', 'e', 'q', 
+'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 'k', 'b', '\030', '\035', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 
 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 
-'e', 'R', '\020', 'm', 'a', 'x', 'P', 'a', 't', 'h', 'T', 'a', 'g', 'L', 'e', 'n', 'g', 't', 'h', '\022', 'A', '\n', '\013', 'c', 'u', 
-'s', 't', 'o', 'm', '_', 't', 'a', 'g', 's', '\030', '\010', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 
-'y', 'p', 'e', '.', 't', 'r', 'a', 'c', 'i', 'n', 'g', '.', 'v', '3', '.', 'C', 'u', 's', 't', 'o', 'm', 'T', 'a', 'g', 'R', 
-'\n', 'c', 'u', 's', 't', 'o', 'm', 'T', 'a', 'g', 's', '\022', '?', '\n', '\010', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\t', 
-' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 'a', 'c', 'e', 
-'.', 'v', '3', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '.', 'H', 't', 't', 'p', 'R', '\010', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 
-'r', '\"', '(', '\n', '\r', 'O', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', 'N', 'a', 'm', 'e', '\022', '\013', '\n', '\007', 'I', 'N', 'G', 
-'R', 'E', 'S', 'S', '\020', '\000', '\022', '\n', '\n', '\006', 'E', 'G', 'R', 'E', 'S', 'S', '\020', '\001', ':', '[', '\232', '\305', '\210', '\036', 'V', 
-'\n', 'T', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 
-'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 
-'g', 'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 
-'g', 'e', 'r', '.', 'T', 'r', 'a', 'c', 'i', 'n', 'g', 'J', '\004', '\010', '\001', '\020', '\002', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\016', 
-'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', '_', 'n', 'a', 'm', 'e', 'R', '\030', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 
-'e', 'a', 'd', 'e', 'r', 's', '_', 'f', 'o', 'r', '_', 't', 'a', 'g', 's', '\032', '\245', '\001', '\n', '\025', 'I', 'n', 't', 'e', 'r', 
-'n', 'a', 'l', 'A', 'd', 'd', 'r', 'e', 's', 's', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '!', '\n', '\014', 'u', 'n', 'i', 'x', '_', 
-'s', 'o', 'c', 'k', 'e', 't', 's', '\030', '\001', ' ', '\001', '(', '\010', 'R', '\013', 'u', 'n', 'i', 'x', 'S', 'o', 'c', 'k', 'e', 't', 
-'s', ':', 'i', '\232', '\305', '\210', '\036', 'd', '\n', 'b', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 
-'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 
-'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 
-'t', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'A', 'd', 'd', 'r', 'e', 
-'s', 's', 'C', 'o', 'n', 'f', 'i', 'g', '\032', '\230', '\002', '\n', '\033', 'S', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'C', 'l', 
-'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', '\022', '4', '\n', '\007', 's', 'u', 'b', 'j', 'e', 'c', 
-'t', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
-'.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\007', 's', 'u', 'b', 'j', 'e', 'c', 't', '\022', '\022', '\n', '\004', 'c', 'e', 
-'r', 't', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\004', 'c', 'e', 'r', 't', '\022', '\024', '\n', '\005', 'c', 'h', 'a', 'i', 'n', '\030', '\006', 
-' ', '\001', '(', '\010', 'R', '\005', 'c', 'h', 'a', 'i', 'n', '\022', '\020', '\n', '\003', 'd', 'n', 's', '\030', '\004', ' ', '\001', '(', '\010', 'R', 
-'\003', 'd', 'n', 's', '\022', '\020', '\n', '\003', 'u', 'r', 'i', '\030', '\005', ' ', '\001', '(', '\010', 'R', '\003', 'u', 'r', 'i', ':', 'o', '\232', 
-'\305', '\210', '\036', 'j', '\n', 'h', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', 
-'.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 
-'m', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
-'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'S', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'C', 'l', 'i', 'e', 'n', 't', 'C', 
-'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', 'J', '\004', '\010', '\002', '\020', '\003', '\032', '\256', '\002', '\n', '\r', 'U', 'p', 'g', 'r', 
-'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '!', '\n', '\014', 'u', 'p', 'g', 'r', 'a', 'd', 'e', '_', 't', 'y', 'p', 'e', 
-'\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 'u', 'p', 'g', 'r', 'a', 'd', 'e', 'T', 'y', 'p', 'e', '\022', 'a', '\n', '\007', 'f', 'i', 
-'l', 't', 'e', 'r', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 
-'s', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 
-'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 
-'t', 't', 'p', 'F', 'i', 'l', 't', 'e', 'r', 'R', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', '\022', '4', '\n', '\007', 'e', 'n', 'a', 
-'b', 'l', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
-'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\007', 'e', 'n', 'a', 'b', 'l', 'e', 'd', ':', 'a', '\232', 
-'\305', '\210', '\036', '\\', '\n', 'Z', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', 
-'.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 
-'m', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
-'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\"', '6', '\n', '\t', 
-'C', 'o', 'd', 'e', 'c', 'T', 'y', 'p', 'e', '\022', '\010', '\n', '\004', 'A', 'U', 'T', 'O', '\020', '\000', '\022', '\t', '\n', '\005', 'H', 'T', 
-'T', 'P', '1', '\020', '\001', '\022', '\t', '\n', '\005', 'H', 'T', 'T', 'P', '2', '\020', '\002', '\022', '\t', '\n', '\005', 'H', 'T', 'T', 'P', '3', 
-'\020', '\003', '\"', 'S', '\n', '\032', 'S', 'e', 'r', 'v', 'e', 'r', 'H', 'e', 'a', 'd', 'e', 'r', 'T', 'r', 'a', 'n', 's', 'f', 'o', 
-'r', 'm', 'a', 't', 'i', 'o', 'n', '\022', '\r', '\n', '\t', 'O', 'V', 'E', 'R', 'W', 'R', 'I', 'T', 'E', '\020', '\000', '\022', '\024', '\n', 
-'\020', 'A', 'P', 'P', 'E', 'N', 'D', '_', 'I', 'F', '_', 'A', 'B', 'S', 'E', 'N', 'T', '\020', '\001', '\022', '\020', '\n', '\014', 'P', 'A', 
-'S', 'S', '_', 'T', 'H', 'R', 'O', 'U', 'G', 'H', '\020', '\002', '\"', 'y', '\n', '\030', 'F', 'o', 'r', 'w', 'a', 'r', 'd', 'C', 'l', 
-'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', '\022', '\014', '\n', '\010', 'S', 'A', 'N', 'I', 'T', 'I', 
-'Z', 'E', '\020', '\000', '\022', '\020', '\n', '\014', 'F', 'O', 'R', 'W', 'A', 'R', 'D', '_', 'O', 'N', 'L', 'Y', '\020', '\001', '\022', '\022', '\n', 
-'\016', 'A', 'P', 'P', 'E', 'N', 'D', '_', 'F', 'O', 'R', 'W', 'A', 'R', 'D', '\020', '\002', '\022', '\020', '\n', '\014', 'S', 'A', 'N', 'I', 
-'T', 'I', 'Z', 'E', '_', 'S', 'E', 'T', '\020', '\003', '\022', '\027', '\n', '\023', 'A', 'L', 'W', 'A', 'Y', 'S', '_', 'F', 'O', 'R', 'W', 
-'A', 'R', 'D', '_', 'O', 'N', 'L', 'Y', '\020', '\004', ':', 'S', '\232', '\305', '\210', '\036', 'N', '\n', 'L', 'e', 'n', 'v', 'o', 'y', '.', 
-'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 
-'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'H', 
-'t', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', 'B', '\026', '\n', '\017', 'r', 
-'o', 'u', 't', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\033', '\020', '\034', 
-'J', '\004', '\010', '\013', '\020', '\014', 'R', '\014', 'i', 'd', 'l', 'e', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\"', '\312', '\001', '\n', '\020', 
-'L', 'o', 'c', 'a', 'l', 'R', 'e', 'p', 'l', 'y', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'e', '\n', '\007', 'm', 'a', 'p', 'p', 'e', 
-'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', 'K', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 
-'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 
-'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'R', 'e', 's', 'p', 
-'o', 'n', 's', 'e', 'M', 'a', 'p', 'p', 'e', 'r', 'R', '\007', 'm', 'a', 'p', 'p', 'e', 'r', 's', '\022', 'O', '\n', '\013', 'b', 'o', 
-'d', 'y', '_', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\002', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 'i', 'o', 
-'n', 'F', 'o', 'r', 'm', 'a', 't', 'S', 't', 'r', 'i', 'n', 'g', 'R', '\n', 'b', 'o', 'd', 'y', 'F', 'o', 'r', 'm', 'a', 't', 
-'\"', '\234', '\003', '\n', '\016', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'M', 'a', 'p', 'p', 'e', 'r', '\022', 'L', '\n', '\006', 'f', 'i', 
-'l', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'F', 'i', 
-'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\006', 'f', 'i', 'l', 't', 'e', 'r', '\022', 'J', '\n', 
-'\013', 's', 't', 'a', 't', 'u', 's', '_', 'c', 'o', 'd', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\013', 
-'\372', 'B', '\010', '*', '\006', '\020', '\330', '\004', '(', '\310', '\001', 'R', '\n', 's', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', '\022', '4', 
-'\n', '\004', 'b', 'o', 'd', 'y', '\030', '\003', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\004', 'b', 'o', 
-'d', 'y', '\022', '`', '\n', '\024', 'b', 'o', 'd', 'y', '_', 'f', 'o', 'r', 'm', 'a', 't', '_', 'o', 'v', 'e', 'r', 'r', 'i', 'd', 
-'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
-'r', 'e', '.', 'v', '3', '.', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 'i', 'o', 'n', 'F', 'o', 'r', 'm', 'a', 't', 'S', 
-'t', 'r', 'i', 'n', 'g', 'R', '\022', 'b', 'o', 'd', 'y', 'F', 'o', 'r', 'm', 'a', 't', 'O', 'v', 'e', 'r', 'r', 'i', 'd', 'e', 
-'\022', 'X', '\n', '\016', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\005', ' ', '\003', '(', '\013', '2', 
-'\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 
-'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', 
-'\007', 'R', '\014', 'h', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'o', 'A', 'd', 'd', '\"', '\310', '\002', '\n', '\003', 'R', 'd', 's', '\022', 'Q', 
-'\n', '\r', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 
-'g', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\014', 'c', 'o', 'n', 'f', 'i', 'g', 
-'S', 'o', 'u', 'r', 'c', 'e', '\022', 'B', '\n', '\021', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', '_', 'n', 'a', 
-'m', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\026', '\362', '\230', '\376', '\217', '\005', '\020', '\022', '\016', 'n', 'a', 'm', 'e', '_', 's', 'p', 
-'e', 'c', 'i', 'f', 'i', 'e', 'r', 'R', '\017', 'r', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'N', 'a', 'm', 'e', '\022', 
-'g', '\n', '\024', 'r', 'd', 's', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '\030', '\003', 
-' ', '\001', '(', '\013', '2', '\035', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 
-'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'B', '\026', '\362', '\230', '\376', '\217', '\005', '\020', '\022', '\016', 'n', 'a', 'm', 'e', '_', 
-'s', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'R', '\022', 'r', 'd', 's', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 
-'a', 't', 'o', 'r', ':', 'A', '\232', '\305', '\210', '\036', '<', '\n', ':', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 
-'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'R', 'd', 's', '\"', '\367', '\001', '\n', 
-'\035', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 
-'s', 'L', 'i', 's', 't', '\022', 'y', '\n', '\033', 's', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 
-'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 
-'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', 
-'\001', 'R', '\031', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 
-'o', 'n', 's', ':', '[', '\232', '\305', '\210', '\036', 'V', '\n', 'T', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 
-'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 
-'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', 'L', 'i', 's', 't', '\"', '\351', '\016', '\n', 
-'\014', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', 
-'(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\217', '\001', '\n', '\021', 's', 'c', 'o', 
-'p', 'e', '_', 'k', 'e', 'y', '_', 'b', 'u', 'i', 'l', 'd', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\013', '2', 'Y', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 
-'t', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 
-'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 
-'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\017', 's', 'c', 
-'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '\022', 'X', '\n', '\021', 'r', 'd', 's', '_', 'c', 'o', 'n', 'f', 
-'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 
-'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\017', 'r', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 
-'r', 'c', 'e', '\022', '\245', '\001', '\n', ' ', 's', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 
-'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', '_', 'l', 'i', 's', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', 'Z', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 
-'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 
-'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 
-'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', 'L', 'i', 's', 't', 'H', '\000', 'R', '\035', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 
-'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', 'L', 'i', 's', 't', '\022', 'g', '\n', '\n', 
-'s', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'd', 's', '\030', '\005', ' ', '\001', '(', '\013', '2', 'F', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 
-'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', 
-'.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 's', 'H', '\000', 'R', '\t', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 
-'s', '\032', '\331', '\t', '\n', '\017', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '\022', '\221', '\001', '\n', 
-'\t', 'f', 'r', 'a', 'g', 'm', 'e', 'n', 't', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', 'i', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 
-'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', 
-'.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 
-'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', 'B', '\010', 
-'\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\t', 'f', 'r', 'a', 'g', 'm', 'e', 'n', 't', 's', '\032', '\325', '\007', '\n', '\017', 'F', 
-'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '\022', '\266', '\001', '\n', '\026', 'h', 'e', 'a', 'd', 'e', 'r', 
-'_', 'v', 'a', 'l', 'u', 'e', '_', 'e', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '~', '.', 
+'e', 'B', '\t', '\372', 'B', '\006', '*', '\004', '\030', '`', ' ', '\000', 'R', '\023', 'm', 'a', 'x', 'R', 'e', 'q', 'u', 'e', 's', 't', 'H', 
+'e', 'a', 'd', 'e', 'r', 's', 'K', 'b', '\022', 'R', '\n', '\023', 's', 't', 'r', 'e', 'a', 'm', '_', 'i', 'd', 'l', 'e', '_', 't', 
+'i', 'm', 'e', 'o', 'u', 't', '\030', '\030', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\007', '\212', '\223', '\267', '*', '\002', '\010', '\001', 'R', '\021', 
+'s', 't', 'r', 'e', 'a', 'm', 'I', 'd', 'l', 'e', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'K', '\n', '\017', 'r', 'e', 'q', 'u', 
+'e', 's', 't', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\034', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 
+'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\007', '\212', '\223', '\267', '*', 
+'\002', '\010', '\001', 'R', '\016', 'r', 'e', 'q', 'u', 'e', 's', 't', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'b', '\n', '\027', 'r', 'e', 
+'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 's', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', ')', ' ', '\001', 
+'(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 
+'t', 'i', 'o', 'n', 'B', '\017', '\372', 'B', '\005', '\252', '\001', '\002', '2', '\000', '\212', '\223', '\267', '*', '\002', '\010', '\001', 'R', '\025', 'r', 'e', 
+'q', 'u', 'e', 's', 't', 'H', 'e', 'a', 'd', 'e', 'r', 's', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', '>', '\n', '\r', 'd', 'r', 
+'a', 'i', 'n', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\014', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 
+'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\014', 'd', 'r', 'a', 'i', 
+'n', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'M', '\n', '\025', 'd', 'e', 'l', 'a', 'y', 'e', 'd', '_', 'c', 'l', 'o', 's', 'e', 
+'_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\030', '\032', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
+'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'R', '\023', 'd', 'e', 'l', 'a', 'y', 'e', 'd', 
+'C', 'l', 'o', 's', 'e', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', 'C', '\n', '\n', 'a', 'c', 'c', 'e', 's', 's', '_', 'l', 'o', 
+'g', '\030', '\r', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 
+'c', 'e', 's', 's', 'l', 'o', 'g', '.', 'v', '3', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'R', '\t', 'a', 'c', 'c', 
+'e', 's', 's', 'L', 'o', 'g', '\022', 'Q', '\n', '\022', 'u', 's', 'e', '_', 'r', 'e', 'm', 'o', 't', 'e', '_', 'a', 'd', 'd', 'r', 
+'e', 's', 's', '\030', '\016', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'B', '\007', '\212', '\223', '\267', '*', '\002', '\010', '\001', 'R', '\020', 'u', 's', 
+'e', 'R', 'e', 'm', 'o', 't', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', '\022', '/', '\n', '\024', 'x', 'f', 'f', '_', 'n', 'u', 'm', 
+'_', 't', 'r', 'u', 's', 't', 'e', 'd', '_', 'h', 'o', 'p', 's', '\030', '\023', ' ', '\001', '(', '\r', 'R', '\021', 'x', 'f', 'f', 'N', 
+'u', 'm', 'T', 'r', 'u', 's', 't', 'e', 'd', 'H', 'o', 'p', 's', '\022', '\240', '\001', '\n', '\027', 'i', 'n', 't', 'e', 'r', 'n', 'a', 
+'l', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\031', ' ', '\001', '(', '\013', '2', 'h', '.', 
 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 
 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 
-'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 
-'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 
-'l', 'd', 'e', 'r', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', 
-'H', '\000', 'R', '\024', 'h', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', '\032', 
-'\217', '\005', '\n', '\024', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', '\022', 
-'\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 
-'a', 'm', 'e', '\022', '+', '\n', '\021', 'e', 'l', 'e', 'm', 'e', 'n', 't', '_', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', '\030', 
-'\002', ' ', '\001', '(', '\t', 'R', '\020', 'e', 'l', 'e', 'm', 'e', 'n', 't', 'S', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', '\022', '\026', 
-'\n', '\005', 'i', 'n', 'd', 'e', 'x', '\030', '\003', ' ', '\001', '(', '\r', 'H', '\000', 'R', '\005', 'i', 'n', 'd', 'e', 'x', '\022', '\245', '\001', 
-'\n', '\007', 'e', 'l', 'e', 'm', 'e', 'n', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', '\210', '\001', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 
-'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', 
-'.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 
-'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'H', 
-'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', '.', 'K', 'v', 'E', 'l', 'e', 
-'m', 'e', 'n', 't', 'H', '\000', 'R', '\007', 'e', 'l', 'e', 'm', 'e', 'n', 't', '\032', '\333', '\001', '\n', '\t', 'K', 'v', 'E', 'l', 'e', 
-'m', 'e', 'n', 't', '\022', '%', '\n', '\t', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', 
-'\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\t', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', '\022', '\031', '\n', '\003', 'k', 'e', 'y', 
-'\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\003', 'k', 'e', 'y', ':', '\213', '\001', '\232', '\305', 
-'\210', '\036', '\205', '\001', '\n', '\202', '\001', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 
-'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
-'_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 
-'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 
-'u', 'i', 'l', 'd', 'e', 'r', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 
-'o', 'r', '.', 'K', 'v', 'E', 'l', 'e', 'm', 'e', 'n', 't', ':', '\177', '\232', '\305', '\210', '\036', 'z', '\n', 'x', 'e', 'n', 'v', 'o', 
-'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 
-'t', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', 
-'.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 
-'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'H', 'e', 'a', 'd', 
-'e', 'r', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', 'B', '\016', '\n', '\014', 'e', 'x', 't', 'r', 'a', 
-'c', 't', '_', 't', 'y', 'p', 'e', ':', 'j', '\232', '\305', '\210', '\036', 'e', '\n', 'c', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
-'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 
-'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 
-'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 
-'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', 'B', '\013', '\n', '\004', 't', 'y', 'p', 'e', '\022', '\003', 
-'\370', 'B', '\001', ':', 'Z', '\232', '\305', '\210', '\036', 'U', '\n', 'S', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
-'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 
-'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 
-'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', ':', 'J', '\232', '\305', '\210', 
-'\036', 'E', '\n', 'C', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 
-'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 
-'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', 'B', '\027', '\n', '\020', 
-'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', '\"', '\273', '\001', '\n', 
-'\t', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 's', '\022', 'e', '\n', '\030', 's', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'd', 's', '_', 
-'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 
-'o', 'u', 'r', 'c', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\025', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 
-'s', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', ':', 'G', '\232', '\305', '\210', '\036', 'B', '\n', '@', 'e', 'n', 'v', 
+'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 
+'a', 'n', 'a', 'g', 'e', 'r', '.', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'A', 'd', 'd', 'r', 'e', 's', 's', 'C', 'o', 'n', 
+'f', 'i', 'g', 'R', '\025', 'i', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'A', 'd', 'd', 'r', 'e', 's', 's', 'C', 'o', 'n', 'f', 'i', 
+'g', '\022', '&', '\n', '\017', 's', 'k', 'i', 'p', '_', 'x', 'f', 'f', '_', 'a', 'p', 'p', 'e', 'n', 'd', '\030', '\025', ' ', '\001', '(', 
+'\010', 'R', '\r', 's', 'k', 'i', 'p', 'X', 'f', 'f', 'A', 'p', 'p', 'e', 'n', 'd', '\022', '\020', '\n', '\003', 'v', 'i', 'a', '\030', '\026', 
+' ', '\001', '(', '\t', 'R', '\003', 'v', 'i', 'a', '\022', 'J', '\n', '\023', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e', '_', 'r', 'e', 'q', 
+'u', 'e', 's', 't', '_', 'i', 'd', '\030', '\017', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 
+'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\021', 'g', 'e', 'n', 'e', 'r', 'a', 't', 
+'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'd', '\022', '?', '\n', '\034', 'p', 'r', 'e', 's', 'e', 'r', 'v', 'e', '_', 'e', 'x', 
+'t', 'e', 'r', 'n', 'a', 'l', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'i', 'd', '\030', ' ', ' ', '\001', '(', '\010', 'R', '\031', 
+'p', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'E', 'x', 't', 'e', 'r', 'n', 'a', 'l', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'd', 
+'\022', 'G', '\n', '!', 'a', 'l', 'w', 'a', 'y', 's', '_', 's', 'e', 't', '_', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'i', 'd', 
+'_', 'i', 'n', '_', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '\030', '%', ' ', '\001', '(', '\010', 'R', '\034', 'a', 'l', 'w', 'a', 'y', 
+'s', 'S', 'e', 't', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'd', 'I', 'n', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\022', '\264', 
+'\001', '\n', '\033', 'f', 'o', 'r', 'w', 'a', 'r', 'd', '_', 'c', 'l', 'i', 'e', 'n', 't', '_', 'c', 'e', 'r', 't', '_', 'd', 'e', 
+'t', 'a', 'i', 'l', 's', '\030', '\020', ' ', '\001', '(', '\016', '2', 'k', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 
+'s', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 
+'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 
+'t', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'F', 'o', 'r', 'w', 
+'a', 'r', 'd', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', 'B', '\010', '\372', 'B', '\005', 
+'\202', '\001', '\002', '\020', '\001', 'R', '\030', 'f', 'o', 'r', 'w', 'a', 'r', 'd', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 
+'e', 't', 'a', 'i', 'l', 's', '\022', '\264', '\001', '\n', '\037', 's', 'e', 't', '_', 'c', 'u', 'r', 'r', 'e', 'n', 't', '_', 'c', 'l', 
+'i', 'e', 'n', 't', '_', 'c', 'e', 'r', 't', '_', 'd', 'e', 't', 'a', 'i', 'l', 's', '\030', '\021', ' ', '\001', '(', '\013', '2', 'n', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', 
+'.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 
+'m', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
+'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'S', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'C', 'l', 'i', 'e', 'n', 't', 'C', 
+'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', 'R', '\033', 's', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'C', 'l', 'i', 
+'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', '\022', ',', '\n', '\022', 'p', 'r', 'o', 'x', 'y', '_', '1', 
+'0', '0', '_', 'c', 'o', 'n', 't', 'i', 'n', 'u', 'e', '\030', '\022', ' ', '\001', '(', '\010', 'R', '\020', 'p', 'r', 'o', 'x', 'y', '1', 
+'0', '0', 'C', 'o', 'n', 't', 'i', 'n', 'u', 'e', '\022', 'e', '\n', '1', 'r', 'e', 'p', 'r', 'e', 's', 'e', 'n', 't', '_', 'i', 
+'p', 'v', '4', '_', 'r', 'e', 'm', 'o', 't', 'e', '_', 'a', 'd', 'd', 'r', 'e', 's', 's', '_', 'a', 's', '_', 'i', 'p', 'v', 
+'4', '_', 'm', 'a', 'p', 'p', 'e', 'd', '_', 'i', 'p', 'v', '6', '\030', '\024', ' ', '\001', '(', '\010', 'R', '*', 'r', 'e', 'p', 'r', 
+'e', 's', 'e', 'n', 't', 'I', 'p', 'v', '4', 'R', 'e', 'm', 'o', 't', 'e', 'A', 'd', 'd', 'r', 'e', 's', 's', 'A', 's', 'I', 
+'p', 'v', '4', 'M', 'a', 'p', 'p', 'e', 'd', 'I', 'p', 'v', '6', '\022', '\211', '\001', '\n', '\017', 'u', 'p', 'g', 'r', 'a', 'd', 'e', 
+'_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\027', ' ', '\003', '(', '\013', '2', '`', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 
+'t', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 
+'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', 
+'3', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'U', 
+'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\016', 'u', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 
+'i', 'g', 's', '\022', 'A', '\n', '\016', 'n', 'o', 'r', 'm', 'a', 'l', 'i', 'z', 'e', '_', 'p', 'a', 't', 'h', '\030', '\036', ' ', '\001', 
+'(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 
+'V', 'a', 'l', 'u', 'e', 'R', '\r', 'n', 'o', 'r', 'm', 'a', 'l', 'i', 'z', 'e', 'P', 'a', 't', 'h', '\022', '#', '\n', '\r', 'm', 
+'e', 'r', 'g', 'e', '_', 's', 'l', 'a', 's', 'h', 'e', 's', '\030', '!', ' ', '\001', '(', '\010', 'R', '\014', 'm', 'e', 'r', 'g', 'e', 
+'S', 'l', 'a', 's', 'h', 'e', 's', '\022', '\201', '\001', '\n', '\024', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'i', 'd', '_', 'e', 'x', 
+'t', 'e', 'n', 's', 'i', 'o', 'n', '\030', '$', ' ', '\001', '(', '\013', '2', 'O', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 
+'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 
+'t', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', 
+'.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'D', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', '\022', 'r', 'e', 'q', 'u', 
+'e', 's', 't', 'I', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', '{', '\n', '\022', 'l', 'o', 'c', 'a', 'l', '_', 'r', 
+'e', 'p', 'l', 'y', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '&', ' ', '\001', '(', '\013', '2', 'M', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 
+'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 
+'r', '.', 'v', '3', '.', 'L', 'o', 'c', 'a', 'l', 'R', 'e', 'p', 'l', 'y', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\020', 'l', 'o', 
+'c', 'a', 'l', 'R', 'e', 'p', 'l', 'y', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'P', '\n', '\030', 's', 't', 'r', 'i', 'p', '_', 'm', 
+'a', 't', 'c', 'h', 'i', 'n', 'g', '_', 'h', 'o', 's', 't', '_', 'p', 'o', 'r', 't', '\030', '\'', ' ', '\001', '(', '\010', 'B', '\027', 
+'\362', '\230', '\376', '\217', '\005', '\021', '\022', '\017', 's', 't', 'r', 'i', 'p', '_', 'p', 'o', 'r', 't', '_', 'm', 'o', 'd', 'e', 'R', '\025', 
+'s', 't', 'r', 'i', 'p', 'M', 'a', 't', 'c', 'h', 'i', 'n', 'g', 'H', 'o', 's', 't', 'P', 'o', 'r', 't', '\022', '/', '\n', '\023', 
+'s', 't', 'r', 'i', 'p', '_', 'a', 'n', 'y', '_', 'h', 'o', 's', 't', '_', 'p', 'o', 'r', 't', '\030', '*', ' ', '\001', '(', '\010', 
+'H', '\001', 'R', '\020', 's', 't', 'r', 'i', 'p', 'A', 'n', 'y', 'H', 'o', 's', 't', 'P', 'o', 'r', 't', '\022', 'i', '\n', '$', 's', 
+'t', 'r', 'e', 'a', 'm', '_', 'e', 'r', 'r', 'o', 'r', '_', 'o', 'n', '_', 'i', 'n', 'v', 'a', 'l', 'i', 'd', '_', 'h', 't', 
+'t', 'p', '_', 'm', 'e', 's', 's', 'a', 'g', 'e', '\030', '(', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
+'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\037', 's', 't', 'r', 'e', 
+'a', 'm', 'E', 'r', 'r', 'o', 'r', 'O', 'n', 'I', 'n', 'v', 'a', 'l', 'i', 'd', 'H', 't', 't', 'p', 'M', 'e', 's', 's', 'a', 
+'g', 'e', '\032', '\366', '\004', '\n', '\007', 'T', 'r', 'a', 'c', 'i', 'n', 'g', '\022', '?', '\n', '\017', 'c', 'l', 'i', 'e', 'n', 't', '_', 
+'s', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 
+'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\016', 'c', 'l', 'i', 'e', 'n', 't', 'S', 'a', 'm', 'p', 
+'l', 'i', 'n', 'g', '\022', '?', '\n', '\017', 'r', 'a', 'n', 'd', 'o', 'm', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\004', 
+' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 
+'e', 'n', 't', 'R', '\016', 'r', 'a', 'n', 'd', 'o', 'm', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', 'A', '\n', '\020', 'o', 'v', 
+'e', 'r', 'a', 'l', 'l', '_', 's', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\030', '\005', ' ', '\001', '(', '\013', '2', '\026', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'v', '3', '.', 'P', 'e', 'r', 'c', 'e', 'n', 't', 'R', '\017', 'o', 'v', 'e', 'r', 
+'a', 'l', 'l', 'S', 'a', 'm', 'p', 'l', 'i', 'n', 'g', '\022', '\030', '\n', '\007', 'v', 'e', 'r', 'b', 'o', 's', 'e', '\030', '\006', ' ', 
+'\001', '(', '\010', 'R', '\007', 'v', 'e', 'r', 'b', 'o', 's', 'e', '\022', 'K', '\n', '\023', 'm', 'a', 'x', '_', 'p', 'a', 't', 'h', '_', 
+'t', 'a', 'g', '_', 'l', 'e', 'n', 'g', 't', 'h', '\030', '\007', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
+'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\020', 'm', 'a', 
+'x', 'P', 'a', 't', 'h', 'T', 'a', 'g', 'L', 'e', 'n', 'g', 't', 'h', '\022', 'A', '\n', '\013', 'c', 'u', 's', 't', 'o', 'm', '_', 
+'t', 'a', 'g', 's', '\030', '\010', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 't', 
+'r', 'a', 'c', 'i', 'n', 'g', '.', 'v', '3', '.', 'C', 'u', 's', 't', 'o', 'm', 'T', 'a', 'g', 'R', '\n', 'c', 'u', 's', 't', 
+'o', 'm', 'T', 'a', 'g', 's', '\022', '?', '\n', '\010', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\t', ' ', '\001', '(', '\013', '2', 
+'#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 't', 'r', 'a', 'c', 'e', '.', 'v', '3', '.', 'T', 
+'r', 'a', 'c', 'i', 'n', 'g', '.', 'H', 't', 't', 'p', 'R', '\010', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\"', '(', '\n', '\r', 
+'O', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', 'N', 'a', 'm', 'e', '\022', '\013', '\n', '\007', 'I', 'N', 'G', 'R', 'E', 'S', 'S', '\020', 
+'\000', '\022', '\n', '\n', '\006', 'E', 'G', 'R', 'E', 'S', 'S', '\020', '\001', ':', '[', '\232', '\305', '\210', '\036', 'V', '\n', 'T', 'e', 'n', 'v', 
 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 
 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', 
-'2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 's', '\"', '\253', '\002', '\n', '\n', 'H', 't', 't', 'p', 'F', 'i', 'l', 't', 'e', 
-'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', 
-'\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\004', ' ', '\001', 
-'(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', 
-'\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'X', '\n', '\020', 'c', 'o', 'n', 'f', 'i', 'g', '_', 
-'d', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '\030', '\005', ' ', '\001', '(', '\013', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
-'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 
-'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\017', 'c', 'o', 'n', 'f', 'i', 'g', 'D', 'i', 's', 'c', 'o', 
-'v', 'e', 'r', 'y', ':', 'H', '\232', '\305', '\210', '\036', 'C', '\n', 'A', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
-'.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 
-'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'F', 'i', 'l', 
-'t', 'e', 'r', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\003', '\020', '\004', 'J', 
-'\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\237', '\001', '\n', '\022', 'R', 'e', 'q', 'u', 'e', 's', 't', 
-'I', 'D', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', '7', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 
-'i', 'g', '\030', '\001', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
-'f', '.', 'A', 'n', 'y', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', 'P', '\232', '\305', '\210', '\036', 'K', 
-'\n', 'I', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 
-'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 
-'g', 'e', 'r', '.', 'v', '2', '.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'D', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 
-'B', 'q', '\n', 'I', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 
-'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', 
+'2', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'T', 
+'r', 'a', 'c', 'i', 'n', 'g', 'J', '\004', '\010', '\001', '\020', '\002', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\016', 'o', 'p', 'e', 'r', 'a', 
+'t', 'i', 'o', 'n', '_', 'n', 'a', 'm', 'e', 'R', '\030', 'r', 'e', 'q', 'u', 'e', 's', 't', '_', 'h', 'e', 'a', 'd', 'e', 'r', 
+'s', '_', 'f', 'o', 'r', '_', 't', 'a', 'g', 's', '\032', '\245', '\001', '\n', '\025', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'A', 'd', 
+'d', 'r', 'e', 's', 's', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '!', '\n', '\014', 'u', 'n', 'i', 'x', '_', 's', 'o', 'c', 'k', 'e', 
+'t', 's', '\030', '\001', ' ', '\001', '(', '\010', 'R', '\013', 'u', 'n', 'i', 'x', 'S', 'o', 'c', 'k', 'e', 't', 's', ':', 'i', '\232', '\305', 
+'\210', '\036', 'd', '\n', 'b', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 
+'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 
+'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 
+'a', 'n', 'a', 'g', 'e', 'r', '.', 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'A', 'd', 'd', 'r', 'e', 's', 's', 'C', 'o', 'n', 
+'f', 'i', 'g', '\032', '\230', '\002', '\n', '\033', 'S', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'C', 'l', 'i', 'e', 'n', 't', 'C', 
+'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', '\022', '4', '\n', '\007', 's', 'u', 'b', 'j', 'e', 'c', 't', '\030', '\001', ' ', '\001', 
+'(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 
+'V', 'a', 'l', 'u', 'e', 'R', '\007', 's', 'u', 'b', 'j', 'e', 'c', 't', '\022', '\022', '\n', '\004', 'c', 'e', 'r', 't', '\030', '\003', ' ', 
+'\001', '(', '\010', 'R', '\004', 'c', 'e', 'r', 't', '\022', '\024', '\n', '\005', 'c', 'h', 'a', 'i', 'n', '\030', '\006', ' ', '\001', '(', '\010', 'R', 
+'\005', 'c', 'h', 'a', 'i', 'n', '\022', '\020', '\n', '\003', 'd', 'n', 's', '\030', '\004', ' ', '\001', '(', '\010', 'R', '\003', 'd', 'n', 's', '\022', 
+'\020', '\n', '\003', 'u', 'r', 'i', '\030', '\005', ' ', '\001', '(', '\010', 'R', '\003', 'u', 'r', 'i', ':', 'o', '\232', '\305', '\210', '\036', 'j', '\n', 
+'h', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 
+'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 
+'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 
+'e', 'r', '.', 'S', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'D', 'e', 
+'t', 'a', 'i', 'l', 's', 'J', '\004', '\010', '\002', '\020', '\003', '\032', '\256', '\002', '\n', '\r', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 
+'n', 'f', 'i', 'g', '\022', '!', '\n', '\014', 'u', 'p', 'g', 'r', 'a', 'd', 'e', '_', 't', 'y', 'p', 'e', '\030', '\001', ' ', '\001', '(', 
+'\t', 'R', '\013', 'u', 'p', 'g', 'r', 'a', 'd', 'e', 'T', 'y', 'p', 'e', '\022', 'a', '\n', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', 
+'\030', '\002', ' ', '\003', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 
+'.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 
+'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'H', 't', 't', 'p', 'F', 'i', 
+'l', 't', 'e', 'r', 'R', '\007', 'f', 'i', 'l', 't', 'e', 'r', 's', '\022', '4', '\n', '\007', 'e', 'n', 'a', 'b', 'l', 'e', 'd', '\030', 
+'\003', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 
+'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '\007', 'e', 'n', 'a', 'b', 'l', 'e', 'd', ':', 'a', '\232', '\305', '\210', '\036', '\\', '\n', 
+'Z', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 
+'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 
+'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 
+'e', 'r', '.', 'U', 'p', 'g', 'r', 'a', 'd', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\"', '6', '\n', '\t', 'C', 'o', 'd', 'e', 'c', 
+'T', 'y', 'p', 'e', '\022', '\010', '\n', '\004', 'A', 'U', 'T', 'O', '\020', '\000', '\022', '\t', '\n', '\005', 'H', 'T', 'T', 'P', '1', '\020', '\001', 
+'\022', '\t', '\n', '\005', 'H', 'T', 'T', 'P', '2', '\020', '\002', '\022', '\t', '\n', '\005', 'H', 'T', 'T', 'P', '3', '\020', '\003', '\"', 'S', '\n', 
+'\032', 'S', 'e', 'r', 'v', 'e', 'r', 'H', 'e', 'a', 'd', 'e', 'r', 'T', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm', 'a', 't', 'i', 
+'o', 'n', '\022', '\r', '\n', '\t', 'O', 'V', 'E', 'R', 'W', 'R', 'I', 'T', 'E', '\020', '\000', '\022', '\024', '\n', '\020', 'A', 'P', 'P', 'E', 
+'N', 'D', '_', 'I', 'F', '_', 'A', 'B', 'S', 'E', 'N', 'T', '\020', '\001', '\022', '\020', '\n', '\014', 'P', 'A', 'S', 'S', '_', 'T', 'H', 
+'R', 'O', 'U', 'G', 'H', '\020', '\002', '\"', 'y', '\n', '\030', 'F', 'o', 'r', 'w', 'a', 'r', 'd', 'C', 'l', 'i', 'e', 'n', 't', 'C', 
+'e', 'r', 't', 'D', 'e', 't', 'a', 'i', 'l', 's', '\022', '\014', '\n', '\010', 'S', 'A', 'N', 'I', 'T', 'I', 'Z', 'E', '\020', '\000', '\022', 
+'\020', '\n', '\014', 'F', 'O', 'R', 'W', 'A', 'R', 'D', '_', 'O', 'N', 'L', 'Y', '\020', '\001', '\022', '\022', '\n', '\016', 'A', 'P', 'P', 'E', 
+'N', 'D', '_', 'F', 'O', 'R', 'W', 'A', 'R', 'D', '\020', '\002', '\022', '\020', '\n', '\014', 'S', 'A', 'N', 'I', 'T', 'I', 'Z', 'E', '_', 
+'S', 'E', 'T', '\020', '\003', '\022', '\027', '\n', '\023', 'A', 'L', 'W', 'A', 'Y', 'S', '_', 'F', 'O', 'R', 'W', 'A', 'R', 'D', '_', 'O', 
+'N', 'L', 'Y', '\020', '\004', ':', 'S', '\232', '\305', '\210', '\036', 'N', '\n', 'L', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 
+'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'C', 'o', 
+'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', 'B', '\026', '\n', '\017', 'r', 'o', 'u', 't', 'e', '_', 
+'s', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'B', '\021', '\n', '\017', 's', 't', 'r', 'i', 'p', '_', 'p', 
+'o', 'r', 't', '_', 'm', 'o', 'd', 'e', 'J', '\004', '\010', '\033', '\020', '\034', 'J', '\004', '\010', '\013', '\020', '\014', 'R', '\014', 'i', 'd', 'l', 
+'e', '_', 't', 'i', 'm', 'e', 'o', 'u', 't', '\"', '\312', '\001', '\n', '\020', 'L', 'o', 'c', 'a', 'l', 'R', 'e', 'p', 'l', 'y', 'C', 
+'o', 'n', 'f', 'i', 'g', '\022', 'e', '\n', '\007', 'm', 'a', 'p', 'p', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', 'K', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 
+'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 
+'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 'M', 'a', 'p', 'p', 'e', 'r', 'R', 
+'\007', 'm', 'a', 'p', 'p', 'e', 'r', 's', '\022', 'O', '\n', '\013', 'b', 'o', 'd', 'y', '_', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\002', 
+' ', '\001', '(', '\013', '2', '.', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
+'v', '3', '.', 'S', 'u', 'b', 's', 't', 'i', 't', 'u', 't', 'i', 'o', 'n', 'F', 'o', 'r', 'm', 'a', 't', 'S', 't', 'r', 'i', 
+'n', 'g', 'R', '\n', 'b', 'o', 'd', 'y', 'F', 'o', 'r', 'm', 'a', 't', '\"', '\234', '\003', '\n', '\016', 'R', 'e', 's', 'p', 'o', 'n', 
+'s', 'e', 'M', 'a', 'p', 'p', 'e', 'r', '\022', 'L', '\n', '\006', 'f', 'i', 'l', 't', 'e', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', 
+'*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'a', 'c', 'c', 'e', 's', 's', 'l', 'o', 'g', '.', 
+'v', '3', '.', 'A', 'c', 'c', 'e', 's', 's', 'L', 'o', 'g', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', 
+'\002', '\020', '\001', 'R', '\006', 'f', 'i', 'l', 't', 'e', 'r', '\022', 'J', '\n', '\013', 's', 't', 'a', 't', 'u', 's', '_', 'c', 'o', 'd', 
+'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
+'.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'B', '\013', '\372', 'B', '\010', '*', '\006', '\020', '\330', '\004', '(', '\310', '\001', 
+'R', '\n', 's', 't', 'a', 't', 'u', 's', 'C', 'o', 'd', 'e', '\022', '4', '\n', '\004', 'b', 'o', 'd', 'y', '\030', '\003', ' ', '\001', '(', 
+'\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
+'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\004', 'b', 'o', 'd', 'y', '\022', '`', '\n', '\024', 'b', 'o', 'd', 'y', '_', 
+'f', 'o', 'r', 'm', 'a', 't', '_', 'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', '.', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'S', 'u', 'b', 's', 't', 
+'i', 't', 'u', 't', 'i', 'o', 'n', 'F', 'o', 'r', 'm', 'a', 't', 'S', 't', 'r', 'i', 'n', 'g', 'R', '\022', 'b', 'o', 'd', 'y', 
+'F', 'o', 'r', 'm', 'a', 't', 'O', 'v', 'e', 'r', 'r', 'i', 'd', 'e', '\022', 'X', '\n', '\016', 'h', 'e', 'a', 'd', 'e', 'r', 's', 
+'_', 't', 'o', '_', 'a', 'd', 'd', '\030', '\005', ' ', '\003', '(', '\013', '2', '\'', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 
+'t', 'i', 'o', 'n', 'B', '\t', '\372', 'B', '\006', '\222', '\001', '\003', '\020', '\350', '\007', 'R', '\014', 'h', 'e', 'a', 'd', 'e', 'r', 's', 'T', 
+'o', 'A', 'd', 'd', '\"', '\307', '\001', '\n', '\003', 'R', 'd', 's', '\022', 'Q', '\n', '\r', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 
+'u', 'r', 'c', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\010', '\372', 'B', 
+'\005', '\212', '\001', '\002', '\020', '\001', 'R', '\014', 'c', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '*', '\n', '\021', 'r', 
+'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', '_', 'n', 'a', 'm', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\017', 'r', 
+'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'N', 'a', 'm', 'e', ':', 'A', '\232', '\305', '\210', '\036', '<', '\n', ':', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', 
 '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 
-'v', '3', 'B', '\032', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', 
-'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'v', '2', '.', 'R', 'd', 's', '\"', '\367', '\001', '\n', '\035', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 
+'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', 'L', 'i', 's', 't', '\022', 'y', '\n', '\033', 's', 'c', 'o', 'p', 'e', 'd', 
+'_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', '\030', '\001', ' ', '\003', 
+'(', '\013', '2', '/', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', 
+'3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\031', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 
+'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', ':', '[', '\232', '\305', '\210', '\036', 'V', '\n', 'T', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 
+'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', 
+'2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', 's', 'L', 'i', 's', 't', '\"', '\351', '\016', '\n', '\014', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '\022', '\033', 
+'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 
+'m', 'e', '\022', '\217', '\001', '\n', '\021', 's', 'c', 'o', 'p', 'e', '_', 'k', 'e', 'y', '_', 'b', 'u', 'i', 'l', 'd', 'e', 'r', '\030', 
+'\002', ' ', '\001', '(', '\013', '2', 'Y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
+'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 
+'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 
+'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', 'B', '\010', '\372', 'B', 
+'\005', '\212', '\001', '\002', '\020', '\001', 'R', '\017', 's', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '\022', 'X', 
+'\n', '\021', 'r', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\003', ' ', '\001', '(', '\013', 
+'2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 
+'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\017', 'r', 'd', 
+'s', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', '\022', '\245', '\001', '\n', ' ', 's', 'c', 'o', 'p', 'e', 'd', '_', 
+'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', '_', 'l', 'i', 's', 't', 
+'\030', '\004', ' ', '\001', '(', '\013', '2', 'Z', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 
+'.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 
+'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 
+'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', 's', 'L', 'i', 's', 't', 'H', '\000', 
+'R', '\035', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 
+'n', 's', 'L', 'i', 's', 't', '\022', 'g', '\n', '\n', 's', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'd', 's', '\030', '\005', ' ', '\001', '(', 
+'\013', '2', 'F', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 
+'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
+'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 's', 'H', '\000', 
+'R', '\t', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 's', '\032', '\331', '\t', '\n', '\017', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 
+'u', 'i', 'l', 'd', 'e', 'r', '\022', '\221', '\001', '\n', '\t', 'f', 'r', 'a', 'g', 'm', 'e', 'n', 't', 's', '\030', '\001', ' ', '\003', '(', 
+'\013', '2', 'i', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 
+'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
+'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 
+'s', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 
+'t', 'B', 'u', 'i', 'l', 'd', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\t', 'f', 'r', 'a', 'g', 'm', 
+'e', 'n', 't', 's', '\032', '\325', '\007', '\n', '\017', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '\022', 
+'\266', '\001', '\n', '\026', 'h', 'e', 'a', 'd', 'e', 'r', '_', 'v', 'a', 'l', 'u', 'e', '_', 'e', 'x', 't', 'r', 'a', 'c', 't', 'o', 
+'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '~', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 
+'s', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 
+'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 
+'d', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 
+'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 
+'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', 'H', '\000', 'R', '\024', 'h', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 
+'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', '\032', '\217', '\005', '\n', '\024', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 
+'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', 
+'\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '+', '\n', '\021', 'e', 'l', 'e', 'm', 'e', 'n', 't', '_', 
+'s', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\020', 'e', 'l', 'e', 'm', 'e', 'n', 't', 'S', 
+'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', '\022', '\026', '\n', '\005', 'i', 'n', 'd', 'e', 'x', '\030', '\003', ' ', '\001', '(', '\r', 'H', '\000', 
+'R', '\005', 'i', 'n', 'd', 'e', 'x', '\022', '\245', '\001', '\n', '\007', 'e', 'l', 'e', 'm', 'e', 'n', 't', '\030', '\004', ' ', '\001', '(', '\013', 
+'2', '\210', '\001', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 'f', 'i', 'l', 't', 
+'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 
+'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 
+'s', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 
+'t', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 
+'c', 't', 'o', 'r', '.', 'K', 'v', 'E', 'l', 'e', 'm', 'e', 'n', 't', 'H', '\000', 'R', '\007', 'e', 'l', 'e', 'm', 'e', 'n', 't', 
+'\032', '\333', '\001', '\n', '\t', 'K', 'v', 'E', 'l', 'e', 'm', 'e', 'n', 't', '\022', '%', '\n', '\t', 's', 'e', 'p', 'a', 'r', 'a', 't', 
+'o', 'r', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\t', 's', 'e', 'p', 'a', 'r', 'a', 
+'t', 'o', 'r', '\022', '\031', '\n', '\003', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 
+'R', '\003', 'k', 'e', 'y', ':', '\213', '\001', '\232', '\305', '\210', '\036', '\205', '\001', '\n', '\202', '\001', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
+'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 
+'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 
+'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', 
+'.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 
+'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 'r', '.', 'K', 'v', 'E', 'l', 'e', 'm', 'e', 'n', 't', ':', '\177', '\232', 
+'\305', '\210', '\036', 'z', '\n', 'x', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', 
+'.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 
+'m', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 
+'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 
+'i', 'l', 'd', 'e', 'r', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 't', 'r', 'a', 'c', 't', 'o', 
+'r', 'B', '\016', '\n', '\014', 'e', 'x', 't', 'r', 'a', 'c', 't', '_', 't', 'y', 'p', 'e', ':', 'j', '\232', '\305', '\210', '\036', 'e', '\n', 
+'c', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 
+'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 
+'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 
+'e', 'y', 'B', 'u', 'i', 'l', 'd', 'e', 'r', '.', 'F', 'r', 'a', 'g', 'm', 'e', 'n', 't', 'B', 'u', 'i', 'l', 'd', 'e', 'r', 
+'B', '\013', '\n', '\004', 't', 'y', 'p', 'e', '\022', '\003', '\370', 'B', '\001', ':', 'Z', '\232', '\305', '\210', '\036', 'U', '\n', 'S', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 
+'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', 
+'2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', '.', 'S', 'c', 'o', 'p', 'e', 'K', 'e', 'y', 'B', 'u', 
+'i', 'l', 'd', 'e', 'r', ':', 'J', '\232', '\305', '\210', '\036', 'E', '\n', 'C', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 
+'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 
+'R', 'o', 'u', 't', 'e', 's', 'B', '\027', '\n', '\020', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 
+'r', '\022', '\003', '\370', 'B', '\001', '\"', '\273', '\001', '\n', '\t', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 's', '\022', 'e', '\n', '\030', 's', 
+'c', 'o', 'p', 'e', 'd', '_', 'r', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\001', 
+' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
+'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 
+'R', '\025', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', ':', 'G', 
+'\232', '\305', '\210', '\036', 'B', '\n', '@', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 
+'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 
+'_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'd', 's', '\"', '\314', '\002', '\n', 
+'\n', 'H', 't', 't', 'p', 'F', 'i', 'l', 't', 'e', 'r', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
+'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '9', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 
+'c', 'o', 'n', 'f', 'i', 'g', '\030', '\004', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 
+'X', '\n', '\020', 'c', 'o', 'n', 'f', 'i', 'g', '_', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '\030', '\005', ' ', '\001', '(', '\013', 
+'2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'E', 
+'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'H', '\000', 'R', '\017', 'c', 
+'o', 'n', 'f', 'i', 'g', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '\022', '\037', '\n', '\013', 'i', 's', '_', 'o', 'p', 't', 'i', 
+'o', 'n', 'a', 'l', '\030', '\006', ' ', '\001', '(', '\010', 'R', '\n', 'i', 's', 'O', 'p', 't', 'i', 'o', 'n', 'a', 'l', ':', 'H', '\232', 
+'\305', '\210', '\036', 'C', '\n', 'A', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', 
+'.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 
+'m', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 'H', 't', 't', 'p', 'F', 'i', 'l', 't', 'e', 'r', 'B', '\r', '\n', '\013', 
+'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\003', '\020', '\004', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 
+'c', 'o', 'n', 'f', 'i', 'g', '\"', '\237', '\001', '\n', '\022', 'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'D', 'E', 'x', 't', 'e', 'n', 
+'s', 'i', 'o', 'n', '\022', '7', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\001', ' ', '\001', '(', 
+'\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\013', 
+'t', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', 'P', '\232', '\305', '\210', '\036', 'K', '\n', 'I', 'e', 'n', 'v', 'o', 'y', 
+'.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'f', 'i', 'l', 't', 'e', 'r', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 
+'t', 'p', '_', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '2', '.', 
+'R', 'e', 'q', 'u', 'e', 's', 't', 'I', 'D', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'B', 'q', '\n', 'I', 'i', 'o', '.', 
+'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 
+'n', 's', '.', 'f', 'i', 'l', 't', 'e', 'r', 's', '.', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'h', 't', 't', 'p', '_', 'c', 
+'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', '_', 'm', 'a', 'n', 'a', 'g', 'e', 'r', '.', 'v', '3', 'B', '\032', 'H', 't', 't', 
+'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', 'M', 'a', 'n', 'a', 'g', 'e', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', 
+'\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[23] = {
+static upb_def_init *deps[20] = {
   &envoy_config_accesslog_v3_accesslog_proto_upbdefinit,
   &envoy_config_core_v3_base_proto_upbdefinit,
   &envoy_config_core_v3_config_source_proto_upbdefinit,
@@ -491,10 +488,7 @@
   &envoy_type_v3_percent_proto_upbdefinit,
   &google_protobuf_any_proto_upbdefinit,
   &google_protobuf_duration_proto_upbdefinit,
-  &google_protobuf_struct_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
-  &udpa_core_v1_resource_locator_proto_upbdefinit,
-  &envoy_annotations_deprecation_proto_upbdefinit,
   &udpa_annotations_migrate_proto_upbdefinit,
   &udpa_annotations_security_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
@@ -507,5 +501,5 @@
   deps,
   layouts,
   "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto",
-  UPB_STRVIEW_INIT(descriptor, 10148)
+  UPB_STRVIEW_INIT(descriptor, 10141)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c
index 93d4362..c5af261 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c
@@ -9,31 +9,27 @@
 #include "upb/def.h"
 #include "envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.h"
 
-extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init envoy_extensions_transport_sockets_tls_v3_common_proto_upbdefinit;
 extern upb_def_init envoy_extensions_transport_sockets_tls_v3_secret_proto_upbdefinit;
 extern upb_def_init envoy_extensions_transport_sockets_tls_v3_tls_proto_upbdefinit;
 
-static const char descriptor[379] = {'\n', '4', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 
+static const char descriptor[348] = {'\n', '4', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 
 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 'v', '3', '/', 'c', 'e', 'r', 't', '.', 'p', 
 'r', 'o', 't', 'o', '\022', ')', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 
-'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '\032', '\035', 'u', 
-'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 
+'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '\032', '6', 'e', 
+'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 
+'_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 'v', '3', '/', 'c', 'o', 'm', 'm', 'o', 'n', '.', 'p', 'r', 
 'o', 't', 'o', '\032', '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 
-'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 'v', '3', '/', 'c', 'o', 'm', 
-'m', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 
+'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 'v', '3', '/', 's', 'e', 'c', 
+'r', 'e', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '3', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 
 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 
-'v', '3', '/', 's', 'e', 'c', 'r', 'e', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '3', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 
-'t', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 
-'s', '/', 't', 'l', 's', '/', 'v', '3', '/', 't', 'l', 's', '.', 'p', 'r', 'o', 't', 'o', 'B', 'F', '\n', '7', 'i', 'o', '.', 
-'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 
-'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 
-'v', '3', 'B', '\t', 'C', 'e', 'r', 't', 'P', 'r', 'o', 't', 'o', 'P', '\001', 'P', '\001', 'P', '\002', 'P', '\003', 'b', '\006', 'p', 'r', 
-'o', 't', 'o', '3', 
+'v', '3', '/', 't', 'l', 's', '.', 'p', 'r', 'o', 't', 'o', 'B', 'F', '\n', '7', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 
+'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 
+'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', 'B', '\t', 'C', 'e', 
+'r', 't', 'P', 'r', 'o', 't', 'o', 'P', '\001', 'P', '\000', 'P', '\001', 'P', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[5] = {
-  &udpa_annotations_status_proto_upbdefinit,
+static upb_def_init *deps[4] = {
   &envoy_extensions_transport_sockets_tls_v3_common_proto_upbdefinit,
   &envoy_extensions_transport_sockets_tls_v3_secret_proto_upbdefinit,
   &envoy_extensions_transport_sockets_tls_v3_tls_proto_upbdefinit,
@@ -44,5 +40,5 @@
   deps,
   NULL,
   "envoy/extensions/transport_sockets/tls/v3/cert.proto",
-  UPB_STRVIEW_INIT(descriptor, 379)
+  UPB_STRVIEW_INIT(descriptor, 348)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c
index 76b1348..dbf238c 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c
@@ -12,7 +12,6 @@
 extern upb_def_init envoy_config_core_v3_base_proto_upbdefinit;
 extern upb_def_init envoy_type_matcher_v3_string_proto_upbdefinit;
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
-extern upb_def_init google_protobuf_struct_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init udpa_annotations_sensitive_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
@@ -32,124 +31,129 @@
   &envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_msginit,
 };
 
-static const char descriptor[2774] = {'\n', '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 
+static const char descriptor[2914] = {'\n', '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 
 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 'v', '3', '/', 'c', 'o', 'm', 'm', 'o', 'n', 
 '.', 'p', 'r', 'o', 't', 'o', '\022', ')', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '\032', 
 '\037', 'e', 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 
 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\"', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 
 'e', 'r', '/', 'v', '3', '/', 's', 't', 'r', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 
-'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 
-'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', 
-'\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 
-'s', '.', 'p', 'r', 'o', 't', 'o', '\032', ' ', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', 
-'/', 's', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 
-'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 
-'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 
-'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 
-'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\362', '\003', '\n', '\r', 'T', 'l', 's', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', 
-'\022', '\217', '\001', '\n', '\034', 't', 'l', 's', '_', 'm', 'i', 'n', 'i', 'm', 'u', 'm', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', 
-'_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\016', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 
-'t', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 
-'s', '.', 't', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 's', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', '.', 'T', 'l', 
-'s', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\031', 't', 'l', 's', 'M', 
-'i', 'n', 'i', 'm', 'u', 'm', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', '\217', '\001', '\n', 
-'\034', 't', 'l', 's', '_', 'm', 'a', 'x', 'i', 'm', 'u', 'm', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'v', 'e', 'r', 
-'s', 'i', 'o', 'n', '\030', '\002', ' ', '\001', '(', '\016', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 
-'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 
-'s', '.', 'v', '3', '.', 'T', 'l', 's', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', '.', 'T', 'l', 's', 'P', 'r', 'o', 
-'t', 'o', 'c', 'o', 'l', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\031', 't', 'l', 's', 'M', 'a', 'x', 'i', 'm', 
-'u', 'm', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', '#', '\n', '\r', 'c', 'i', 'p', 'h', 
-'e', 'r', '_', 's', 'u', 'i', 't', 'e', 's', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\014', 'c', 'i', 'p', 'h', 'e', 'r', 'S', 'u', 
-'i', 't', 'e', 's', '\022', '\037', '\n', '\013', 'e', 'c', 'd', 'h', '_', 'c', 'u', 'r', 'v', 'e', 's', '\030', '\004', ' ', '\003', '(', '\t', 
-'R', '\n', 'e', 'c', 'd', 'h', 'C', 'u', 'r', 'v', 'e', 's', '\"', 'O', '\n', '\013', 'T', 'l', 's', 'P', 'r', 'o', 't', 'o', 'c', 
-'o', 'l', '\022', '\014', '\n', '\010', 'T', 'L', 'S', '_', 'A', 'U', 'T', 'O', '\020', '\000', '\022', '\013', '\n', '\007', 'T', 'L', 'S', 'v', '1', 
-'_', '0', '\020', '\001', '\022', '\013', '\n', '\007', 'T', 'L', 'S', 'v', '1', '_', '1', '\020', '\002', '\022', '\013', '\n', '\007', 'T', 'L', 'S', 'v', 
-'1', '_', '2', '\020', '\003', '\022', '\013', '\n', '\007', 'T', 'L', 'S', 'v', '1', '_', '3', '\020', '\004', ':', '&', '\232', '\305', '\210', '\036', '!', 
-'\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'T', 'l', 's', 'P', 'a', 
-'r', 'a', 'm', 'e', 't', 'e', 'r', 's', '\"', '\317', '\001', '\n', '\022', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'K', 'e', 'y', 'P', 'r', 
-'o', 'v', 'i', 'd', 'e', 'r', '\022', ',', '\n', '\r', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', 
-' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\014', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'N', 'a', 
-'m', 'e', '\022', 'A', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', 
-'\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'B', '\006', '\270', '\267', 
-'\213', '\244', '\002', '\001', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '+', '\232', '\305', '\210', '\036', 
-'&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'P', 'r', 'i', 'v', 
-'a', 't', 'e', 'K', 'e', 'y', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 
-'t', 'y', 'p', 'e', 'J', '\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\261', '\004', '\n', '\016', 'T', 'l', 
-'s', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\022', 'M', '\n', '\021', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 
-'t', 'e', '_', 'c', 'h', 'a', 'i', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\020', 
-'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'C', 'h', 'a', 'i', 'n', '\022', 'I', '\n', '\013', 'p', 'r', 'i', 'v', 'a', 
-'t', 'e', '_', 'k', 'e', 'y', '\030', '\002', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\006', '\270', '\267', 
-'\213', '\244', '\002', '\001', 'R', '\n', 'p', 'r', 'i', 'v', 'a', 't', 'e', 'K', 'e', 'y', '\022', 'o', '\n', '\024', 'p', 'r', 'i', 'v', 'a', 
-'t', 'e', '_', 'k', 'e', 'y', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\006', ' ', '\001', '(', '\013', '2', '=', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 
-'_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'K', 'e', 
-'y', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'R', '\022', 'p', 'r', 'i', 'v', 'a', 't', 'e', 'K', 'e', 'y', 'P', 'r', 'o', 'v', 
-'i', 'd', 'e', 'r', '\022', 'D', '\n', '\010', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', '\030', '\003', ' ', '\001', '(', '\013', '2', ' ', '.', 
-'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 
-'S', 'o', 'u', 'r', 'c', 'e', 'B', '\006', '\270', '\267', '\213', '\244', '\002', '\001', 'R', '\010', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', '\022', 
-'A', '\n', '\013', 'o', 'c', 's', 'p', '_', 's', 't', 'a', 'p', 'l', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 
-'u', 'r', 'c', 'e', 'R', '\n', 'o', 'c', 's', 'p', 'S', 't', 'a', 'p', 'l', 'e', '\022', 'b', '\n', '\034', 's', 'i', 'g', 'n', 'e', 
-'d', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', '\030', '\005', 
-' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
-'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\032', 's', 'i', 'g', 'n', 'e', 'd', 'C', 'e', 'r', 't', 
-'i', 'f', 'i', 'c', 'a', 't', 'e', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', ':', '\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 
-'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'T', 'l', 's', 'C', 'e', 'r', 't', 
-'i', 'f', 'i', 'c', 'a', 't', 'e', '\"', '\213', '\001', '\n', '\024', 'T', 'l', 's', 'S', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'c', 
-'k', 'e', 't', 'K', 'e', 'y', 's', '\022', 'D', '\n', '\004', 'k', 'e', 'y', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 
-'o', 'u', 'r', 'c', 'e', 'B', '\016', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', '\270', '\267', '\213', '\244', '\002', '\001', 'R', '\004', 'k', 'e', 
-'y', 's', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 
-'u', 't', 'h', '.', 'T', 'l', 's', 'S', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', '\"', 
-'\362', '\006', '\n', '\034', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 
-'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '?', '\n', '\n', 't', 'r', 'u', 's', 't', 'e', 'd', '_', 'c', 'a', '\030', '\001', ' ', '\001', 
+'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 
+'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 
+'t', 'o', '\032', ' ', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 'e', 'n', 's', 
+'i', 't', 'i', 'v', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
+'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 
+'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 
+'t', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 
+'t', 'o', '\"', '\362', '\003', '\n', '\r', 'T', 'l', 's', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', '\022', '\217', '\001', '\n', '\034', 
+'t', 'l', 's', '_', 'm', 'i', 'n', 'i', 'm', 'u', 'm', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'v', 'e', 'r', 's', 
+'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\016', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 
+'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', 
+'.', 'v', '3', '.', 'T', 'l', 's', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', '.', 'T', 'l', 's', 'P', 'r', 'o', 't', 
+'o', 'c', 'o', 'l', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\031', 't', 'l', 's', 'M', 'i', 'n', 'i', 'm', 'u', 
+'m', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', '\217', '\001', '\n', '\034', 't', 'l', 's', '_', 
+'m', 'a', 'x', 'i', 'm', 'u', 'm', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', 
+'\002', ' ', '\001', '(', '\016', '2', 'D', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
+'t', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 
+'T', 'l', 's', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', '.', 'T', 'l', 's', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 
+'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\031', 't', 'l', 's', 'M', 'a', 'x', 'i', 'm', 'u', 'm', 'P', 'r', 'o', 
+'t', 'o', 'c', 'o', 'l', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', '#', '\n', '\r', 'c', 'i', 'p', 'h', 'e', 'r', '_', 's', 'u', 
+'i', 't', 'e', 's', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\014', 'c', 'i', 'p', 'h', 'e', 'r', 'S', 'u', 'i', 't', 'e', 's', '\022', 
+'\037', '\n', '\013', 'e', 'c', 'd', 'h', '_', 'c', 'u', 'r', 'v', 'e', 's', '\030', '\004', ' ', '\003', '(', '\t', 'R', '\n', 'e', 'c', 'd', 
+'h', 'C', 'u', 'r', 'v', 'e', 's', '\"', 'O', '\n', '\013', 'T', 'l', 's', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', '\022', '\014', '\n', 
+'\010', 'T', 'L', 'S', '_', 'A', 'U', 'T', 'O', '\020', '\000', '\022', '\013', '\n', '\007', 'T', 'L', 'S', 'v', '1', '_', '0', '\020', '\001', '\022', 
+'\013', '\n', '\007', 'T', 'L', 'S', 'v', '1', '_', '1', '\020', '\002', '\022', '\013', '\n', '\007', 'T', 'L', 'S', 'v', '1', '_', '2', '\020', '\003', 
+'\022', '\013', '\n', '\007', 'T', 'L', 'S', 'v', '1', '_', '3', '\020', '\004', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'T', 'l', 's', 'P', 'a', 'r', 'a', 'm', 'e', 't', 
+'e', 'r', 's', '\"', '\317', '\001', '\n', '\022', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'K', 'e', 'y', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 
+'r', '\022', ',', '\n', '\r', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', 
+'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\014', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'N', 'a', 'm', 'e', '\022', 'A', '\n', 
+'\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 
+'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'B', '\006', '\270', '\267', '\213', '\244', '\002', '\001', 'H', 
+'\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 
+'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'K', 'e', 
+'y', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'B', '\r', '\n', '\013', 'c', 'o', 'n', 'f', 'i', 'g', '_', 't', 'y', 'p', 'e', 'J', 
+'\004', '\010', '\002', '\020', '\003', 'R', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\206', '\005', '\n', '\016', 'T', 'l', 's', 'C', 'e', 'r', 't', 
+'i', 'f', 'i', 'c', 'a', 't', 'e', '\022', 'M', '\n', '\021', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'c', 'h', 
+'a', 'i', 'n', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\020', 'c', 'e', 'r', 't', 'i', 
+'f', 'i', 'c', 'a', 't', 'e', 'C', 'h', 'a', 'i', 'n', '\022', 'I', '\n', '\013', 'p', 'r', 'i', 'v', 'a', 't', 'e', '_', 'k', 'e', 
+'y', '\030', '\002', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
+'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\006', '\270', '\267', '\213', '\244', '\002', '\001', 'R', 
+'\n', 'p', 'r', 'i', 'v', 'a', 't', 'e', 'K', 'e', 'y', '\022', 'S', '\n', '\021', 'w', 'a', 't', 'c', 'h', 'e', 'd', '_', 'd', 'i', 
+'r', 'e', 'c', 't', 'o', 'r', 'y', '\030', '\007', ' ', '\001', '(', '\013', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'W', 'a', 't', 'c', 'h', 'e', 'd', 'D', 'i', 'r', 'e', 'c', 't', 
+'o', 'r', 'y', 'R', '\020', 'w', 'a', 't', 'c', 'h', 'e', 'd', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', '\022', 'o', '\n', '\024', 
+'p', 'r', 'i', 'v', 'a', 't', 'e', '_', 'k', 'e', 'y', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\006', ' ', '\001', '(', 
+'\013', '2', '=', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 
+'s', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'P', 'r', 'i', 'v', 
+'a', 't', 'e', 'K', 'e', 'y', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'R', '\022', 'p', 'r', 'i', 'v', 'a', 't', 'e', 'K', 'e', 
+'y', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\022', 'D', '\n', '\010', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', '\030', '\003', ' ', '\001', 
 '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
-'.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 't', 'r', 'u', 's', 't', 'e', 'd', 'C', 'a', '\022', 'F', '\n', 
-'\027', 'v', 'e', 'r', 'i', 'f', 'y', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 's', 'p', 'k', 'i', '\030', 
-'\003', ' ', '\003', '(', '\t', 'B', '\016', '\372', 'B', '\013', '\222', '\001', '\010', '\"', '\006', 'r', '\004', '\020', ',', '(', ',', 'R', '\025', 'v', 'e', 
-'r', 'i', 'f', 'y', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'S', 'p', 'k', 'i', '\022', 'F', '\n', '\027', 'v', 'e', 
-'r', 'i', 'f', 'y', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'h', 'a', 's', 'h', '\030', '\002', ' ', '\003', 
-'(', '\t', 'B', '\016', '\372', 'B', '\013', '\222', '\001', '\010', '\"', '\006', 'r', '\004', '\020', '@', '(', '_', 'R', '\025', 'v', 'e', 'r', 'i', 'f', 
-'y', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'H', 'a', 's', 'h', '\022', '[', '\n', '\027', 'm', 'a', 't', 'c', 'h', 
-'_', 's', 'u', 'b', 'j', 'e', 'c', 't', '_', 'a', 'l', 't', '_', 'n', 'a', 'm', 'e', 's', '\030', '\t', ' ', '\003', '(', '\013', '2', 
-'$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 
-'t', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\024', 'm', 'a', 't', 'c', 'h', 'S', 'u', 'b', 'j', 'e', 'c', 
-'t', 'A', 'l', 't', 'N', 'a', 'm', 'e', 's', '\022', 'k', '\n', '$', 'r', 'e', 'q', 'u', 'i', 'r', 'e', '_', 's', 'i', 'g', 'n', 
-'e', 'd', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', '\030', 
-'\006', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 
-'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '!', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'S', 'i', 'g', 'n', 'e', 'd', 'C', 'e', 
-'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', '\022', '2', '\n', '\003', 'c', 'r', 'l', 
-'\030', '\007', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 
-'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\003', 'c', 'r', 'l', '\022', ':', '\n', '\031', 'a', 
-'l', 'l', 'o', 'w', '_', 'e', 'x', 'p', 'i', 'r', 'e', 'd', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\030', 
-'\010', ' ', '\001', '(', '\010', 'R', '\027', 'a', 'l', 'l', 'o', 'w', 'E', 'x', 'p', 'i', 'r', 'e', 'd', 'C', 'e', 'r', 't', 'i', 'f', 
-'i', 'c', 'a', 't', 'e', '\022', '\242', '\001', '\n', '\030', 't', 'r', 'u', 's', 't', '_', 'c', 'h', 'a', 'i', 'n', '_', 'v', 'e', 'r', 
-'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 'n', '\030', '\n', ' ', '\001', '(', '\016', '2', '^', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 
-'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 
-'t', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 
-'d', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'T', 'r', 'u', 's', 't', 'C', 'h', 'a', 'i', 'n', 'V', 
-'e', 'r', 'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\026', 't', 'r', 
-'u', 's', 't', 'C', 'h', 'a', 'i', 'n', 'V', 'e', 'r', 'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 'n', '\"', 'F', '\n', '\026', 'T', 
-'r', 'u', 's', 't', 'C', 'h', 'a', 'i', 'n', 'V', 'e', 'r', 'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\022', 
-'V', 'E', 'R', 'I', 'F', 'Y', '_', 'T', 'R', 'U', 'S', 'T', '_', 'C', 'H', 'A', 'I', 'N', '\020', '\000', '\022', '\024', '\n', '\020', 'A', 
-'C', 'C', 'E', 'P', 'T', '_', 'U', 'N', 'T', 'R', 'U', 'S', 'T', 'E', 'D', '\020', '\001', ':', '5', '\232', '\305', '\210', '\036', '0', '\n', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'C', 'e', 'r', 't', 'i', 'f', 
-'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'J', '\004', '\010', 
-'\004', '\020', '\005', 'J', '\004', '\010', '\005', '\020', '\006', 'R', '\027', 'v', 'e', 'r', 'i', 'f', 'y', '_', 's', 'u', 'b', 'j', 'e', 'c', 't', 
-'_', 'a', 'l', 't', '_', 'n', 'a', 'm', 'e', 'B', 'P', '\n', '7', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 
-'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 
-'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', 'B', '\013', 'C', 'o', 'm', 'm', 'o', 
-'n', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\006', '\270', '\267', '\213', '\244', '\002', '\001', 'R', '\010', 'p', 'a', 's', 's', 
+'w', 'o', 'r', 'd', '\022', 'A', '\n', '\013', 'o', 'c', 's', 'p', '_', 's', 't', 'a', 'p', 'l', 'e', '\030', '\004', ' ', '\001', '(', '\013', 
+'2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 
+'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\n', 'o', 'c', 's', 'p', 'S', 't', 'a', 'p', 'l', 'e', '\022', 'b', '\n', '\034', 
+'s', 'i', 'g', 'n', 'e', 'd', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 't', 'i', 'm', 'e', 's', 't', 
+'a', 'm', 'p', '\030', '\005', ' ', '\003', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 
+'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\032', 's', 'i', 'g', 'n', 'e', 
+'d', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', ':', '\'', '\232', '\305', 
+'\210', '\036', '\"', '\n', ' ', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'T', 'l', 
+'s', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\"', '\213', '\001', '\n', '\024', 'T', 'l', 's', 'S', 'e', 's', 's', 'i', 
+'o', 'n', 'T', 'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', '\022', 'D', '\n', '\004', 'k', 'e', 'y', 's', '\030', '\001', ' ', '\003', '(', 
+'\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
+'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\016', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', '\270', '\267', '\213', '\244', '\002', 
+'\001', 'R', '\004', 'k', 'e', 'y', 's', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
+'.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'T', 'l', 's', 'S', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'c', 'k', 'e', 't', 
+'K', 'e', 'y', 's', '\"', '\307', '\007', '\n', '\034', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 
+'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '?', '\n', '\n', 't', 'r', 'u', 's', 't', 'e', 'd', '_', 'c', 
+'a', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
+'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 't', 'r', 'u', 's', 't', 'e', 'd', 
+'C', 'a', '\022', 'S', '\n', '\021', 'w', 'a', 't', 'c', 'h', 'e', 'd', '_', 'd', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', '\030', '\013', 
+' ', '\001', '(', '\013', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 
+'v', '3', '.', 'W', 'a', 't', 'c', 'h', 'e', 'd', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'R', '\020', 'w', 'a', 't', 'c', 
+'h', 'e', 'd', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', '\022', 'F', '\n', '\027', 'v', 'e', 'r', 'i', 'f', 'y', '_', 'c', 'e', 
+'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 's', 'p', 'k', 'i', '\030', '\003', ' ', '\003', '(', '\t', 'B', '\016', '\372', 'B', '\013', 
+'\222', '\001', '\010', '\"', '\006', 'r', '\004', '\020', ',', '(', ',', 'R', '\025', 'v', 'e', 'r', 'i', 'f', 'y', 'C', 'e', 'r', 't', 'i', 'f', 
+'i', 'c', 'a', 't', 'e', 'S', 'p', 'k', 'i', '\022', 'F', '\n', '\027', 'v', 'e', 'r', 'i', 'f', 'y', '_', 'c', 'e', 'r', 't', 'i', 
+'f', 'i', 'c', 'a', 't', 'e', '_', 'h', 'a', 's', 'h', '\030', '\002', ' ', '\003', '(', '\t', 'B', '\016', '\372', 'B', '\013', '\222', '\001', '\010', 
+'\"', '\006', 'r', '\004', '\020', '@', '(', '_', 'R', '\025', 'v', 'e', 'r', 'i', 'f', 'y', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 
+'t', 'e', 'H', 'a', 's', 'h', '\022', '[', '\n', '\027', 'm', 'a', 't', 'c', 'h', '_', 's', 'u', 'b', 'j', 'e', 'c', 't', '_', 'a', 
+'l', 't', '_', 'n', 'a', 'm', 'e', 's', '\030', '\t', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 
+'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 
+'e', 'r', 'R', '\024', 'm', 'a', 't', 'c', 'h', 'S', 'u', 'b', 'j', 'e', 'c', 't', 'A', 'l', 't', 'N', 'a', 'm', 'e', 's', '\022', 
+'k', '\n', '$', 'r', 'e', 'q', 'u', 'i', 'r', 'e', '_', 's', 'i', 'g', 'n', 'e', 'd', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 
+'c', 'a', 't', 'e', '_', 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', '\030', '\006', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 
+'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 'l', 'u', 'e', 'R', '!', 
+'r', 'e', 'q', 'u', 'i', 'r', 'e', 'S', 'i', 'g', 'n', 'e', 'd', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'T', 
+'i', 'm', 'e', 's', 't', 'a', 'm', 'p', '\022', '2', '\n', '\003', 'c', 'r', 'l', '\030', '\007', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 
+'o', 'u', 'r', 'c', 'e', 'R', '\003', 'c', 'r', 'l', '\022', ':', '\n', '\031', 'a', 'l', 'l', 'o', 'w', '_', 'e', 'x', 'p', 'i', 'r', 
+'e', 'd', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\030', '\010', ' ', '\001', '(', '\010', 'R', '\027', 'a', 'l', 'l', 
+'o', 'w', 'E', 'x', 'p', 'i', 'r', 'e', 'd', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\022', '\242', '\001', '\n', '\030', 
+'t', 'r', 'u', 's', 't', '_', 'c', 'h', 'a', 'i', 'n', '_', 'v', 'e', 'r', 'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 'n', '\030', 
+'\n', ' ', '\001', '(', '\016', '2', '^', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
+'t', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 
+'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 
+'e', 'x', 't', '.', 'T', 'r', 'u', 's', 't', 'C', 'h', 'a', 'i', 'n', 'V', 'e', 'r', 'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 
+'n', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\026', 't', 'r', 'u', 's', 't', 'C', 'h', 'a', 'i', 'n', 'V', 'e', 
+'r', 'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 'n', '\"', 'F', '\n', '\026', 'T', 'r', 'u', 's', 't', 'C', 'h', 'a', 'i', 'n', 'V', 
+'e', 'r', 'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\022', 'V', 'E', 'R', 'I', 'F', 'Y', '_', 'T', 'R', 'U', 
+'S', 'T', '_', 'C', 'H', 'A', 'I', 'N', '\020', '\000', '\022', '\024', '\n', '\020', 'A', 'C', 'C', 'E', 'P', 'T', '_', 'U', 'N', 'T', 'R', 
+'U', 'S', 'T', 'E', 'D', '\020', '\001', ':', '5', '\232', '\305', '\210', '\036', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
+'.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 
+'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'J', '\004', '\010', '\004', '\020', '\005', 'J', '\004', '\010', '\005', '\020', '\006', 'R', 
+'\027', 'v', 'e', 'r', 'i', 'f', 'y', '_', 's', 'u', 'b', 'j', 'e', 'c', 't', '_', 'a', 'l', 't', '_', 'n', 'a', 'm', 'e', 'B', 
+'P', '\n', '7', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 
+'t', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 
+'s', '.', 't', 'l', 's', '.', 'v', '3', 'B', '\013', 'C', 'o', 'm', 'm', 'o', 'n', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', 
+'\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[10] = {
+static upb_def_init *deps[9] = {
   &envoy_config_core_v3_base_proto_upbdefinit,
   &envoy_type_matcher_v3_string_proto_upbdefinit,
   &google_protobuf_any_proto_upbdefinit,
-  &google_protobuf_struct_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
   &udpa_annotations_sensitive_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
@@ -162,5 +166,5 @@
   deps,
   layouts,
   "envoy/extensions/transport_sockets/tls/v3/common.proto",
-  UPB_STRVIEW_INIT(descriptor, 2774)
+  UPB_STRVIEW_INIT(descriptor, 2914)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/secret.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/secret.upbdefs.c
index 7d6cfc4..5623e1b 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/secret.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/secret.upbdefs.c
@@ -12,11 +12,10 @@
 extern upb_def_init envoy_config_core_v3_base_proto_upbdefinit;
 extern upb_def_init envoy_config_core_v3_config_source_proto_upbdefinit;
 extern upb_def_init envoy_extensions_transport_sockets_tls_v3_common_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_resource_locator_proto_upbdefinit;
-extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
 extern upb_def_init udpa_annotations_sensitive_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
 extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_GenericSecret_msginit;
 extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_SdsSecretConfig_msginit;
 extern const upb_msglayout envoy_extensions_transport_sockets_tls_v3_Secret_msginit;
@@ -27,7 +26,7 @@
   &envoy_extensions_transport_sockets_tls_v3_Secret_msginit,
 };
 
-static const char descriptor[1400] = {'\n', '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 
+static const char descriptor[1236] = {'\n', '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 
 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 'v', '3', '/', 's', 'e', 'c', 'r', 'e', 't', 
 '.', 'p', 'r', 'o', 't', 'o', '\022', ')', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '\032', 
@@ -36,64 +35,57 @@
 'e', '/', 'v', '3', '/', 'c', 'o', 'n', 'f', 'i', 'g', '_', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', 
 '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 'o', 
 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 'v', '3', '/', 'c', 'o', 'm', 'm', 'o', 'n', '.', 
-'p', 'r', 'o', 't', 'o', '\032', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 's', 'o', 'u', 
-'r', 'c', 'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 
-'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', 
-' ', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 'e', 'n', 's', 'i', 't', 'i', 
-'v', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 
-'s', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 
-'t', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\"', 
-'y', '\n', '\r', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', '\022', '@', '\n', '\006', 's', 'e', 'c', 'r', 'e', 
-'t', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 
-'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\006', '\270', '\267', '\213', '\244', '\002', '\001', 'R', 
-'\006', 's', 'e', 'c', 'r', 'e', 't', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', 
-'.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', '\"', '\223', '\002', 
-'\n', '\017', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '*', '\n', '\004', 'n', 'a', 'm', 'e', 
-'\030', '\001', ' ', '\001', '(', '\t', 'B', '\026', '\362', '\230', '\376', '\217', '\005', '\020', '\022', '\016', 'n', 'a', 'm', 'e', '_', 's', 'p', 'e', 'c', 
-'i', 'f', 'i', 'e', 'r', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'g', '\n', '\024', 's', 'd', 's', '_', 'r', 'e', 's', 'o', 'u', 'r', 
-'c', 'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '\030', '\003', ' ', '\001', '(', '\013', '2', '\035', '.', 'u', 'd', 'p', 'a', '.', 'c', 
-'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'B', '\026', '\362', 
-'\230', '\376', '\217', '\005', '\020', '\022', '\016', 'n', 'a', 'm', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'R', '\022', 's', 'd', 
-'s', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', '\022', 'A', '\n', '\n', 's', 'd', 's', '_', 'c', 
-'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
-'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 's', 
-'d', 's', 'C', 'o', 'n', 'f', 'i', 'g', ':', '(', '\232', '\305', '\210', '\036', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', 
-'\"', '\373', '\003', '\n', '\006', 'S', 'e', 'c', 'r', 'e', 't', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
-'R', '\004', 'n', 'a', 'm', 'e', '\022', 'd', '\n', '\017', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 
-'\030', '\002', ' ', '\001', '(', '\013', '2', '9', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 
-'.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', 
-'.', 'T', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'H', '\000', 'R', '\016', 't', 'l', 's', 'C', 'e', 'r', 
-'t', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\022', 'q', '\n', '\023', 's', 'e', 's', 's', 'i', 'o', 'n', '_', 't', 'i', 'c', 'k', 'e', 
-'t', '_', 'k', 'e', 'y', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '?', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 
+'p', 'r', 'o', 't', 'o', '\032', ' ', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 
+'e', 'n', 's', 'i', 't', 'i', 'v', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 
+'t', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 
+'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 
+'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 
+'p', 'r', 'o', 't', 'o', '\"', 'y', '\n', '\r', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', '\022', '@', '\n', 
+'\006', 's', 'e', 'c', 'r', 'e', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 
+'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'D', 'a', 't', 'a', 'S', 'o', 'u', 'r', 'c', 'e', 'B', '\006', '\270', 
+'\267', '\213', '\244', '\002', '\001', 'R', '\006', 's', 'e', 'c', 'r', 'e', 't', ':', '&', '\232', '\305', '\210', '\036', '!', '\n', '\037', 'e', 'n', 'v', 
+'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'c', 
+'r', 'e', 't', '\"', '\233', '\001', '\n', '\017', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '\033', 
+'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 
+'m', 'e', '\022', 'A', '\n', '\n', 's', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '\"', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 'f', 
+'i', 'g', 'S', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 's', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', ':', '(', '\232', '\305', '\210', '\036', 
+'#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'S', 'd', 's', 'S', 
+'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\"', '\373', '\003', '\n', '\006', 'S', 'e', 'c', 'r', 'e', 't', '\022', '\022', '\n', 
+'\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 'd', '\n', '\017', 't', 'l', 's', '_', 
+'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '9', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 
+'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 
+'e', 'H', '\000', 'R', '\016', 't', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\022', 'q', '\n', '\023', 's', 'e', 
+'s', 's', 'i', 'o', 'n', '_', 't', 'i', 'c', 'k', 'e', 't', '_', 'k', 'e', 'y', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '?', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 
+'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 's', 'S', 'e', 's', 's', 
+'i', 'o', 'n', 'T', 'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', 'H', '\000', 'R', '\021', 's', 'e', 's', 's', 'i', 'o', 'n', 'T', 
+'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', '\022', 'x', '\n', '\022', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 
+'o', 'n', 't', 'e', 'x', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 
 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 
-'t', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 's', 'S', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'c', 'k', 'e', 't', 'K', 'e', 
-'y', 's', 'H', '\000', 'R', '\021', 's', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', '\022', 'x', 
-'\n', '\022', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\004', ' ', '\001', '(', 
-'\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 
-'s', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'e', 'r', 't', 
-'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'H', 
-'\000', 'R', '\021', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'a', '\n', '\016', 'g', 
-'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'c', 'r', 'e', 't', '\030', '\005', ' ', '\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 
-'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'c', 'r', 
-'e', 't', 'H', '\000', 'R', '\r', 'g', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', ':', '\037', '\232', '\305', '\210', '\036', 
-'\032', '\n', '\030', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'S', 'e', 'c', 'r', 
-'e', 't', 'B', '\006', '\n', '\004', 't', 'y', 'p', 'e', 'B', 'P', '\n', '7', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 
-'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 
-'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', 'B', '\013', 'S', 'e', 'c', 'r', 
-'e', 't', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'t', 'l', 's', '.', 'v', '3', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 
+'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'H', '\000', 'R', '\021', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 
+'o', 'n', 't', 'e', 'x', 't', '\022', 'a', '\n', '\016', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'c', 'r', 'e', 't', '\030', 
+'\005', ' ', '\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
+'t', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 
+'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'c', 'r', 'e', 't', 'H', '\000', 'R', '\r', 'g', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 
+'e', 'c', 'r', 'e', 't', ':', '\037', '\232', '\305', '\210', '\036', '\032', '\n', '\030', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', 
+'2', '.', 'a', 'u', 't', 'h', '.', 'S', 'e', 'c', 'r', 'e', 't', 'B', '\006', '\n', '\004', 't', 'y', 'p', 'e', 'B', 'P', '\n', '7', 
+'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 
+'s', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 
+'l', 's', '.', 'v', '3', 'B', '\013', 'S', 'e', 'c', 'r', 'e', 't', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', 
+'\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[9] = {
+static upb_def_init *deps[8] = {
   &envoy_config_core_v3_base_proto_upbdefinit,
   &envoy_config_core_v3_config_source_proto_upbdefinit,
   &envoy_extensions_transport_sockets_tls_v3_common_proto_upbdefinit,
-  &udpa_core_v1_resource_locator_proto_upbdefinit,
-  &udpa_annotations_migrate_proto_upbdefinit,
   &udpa_annotations_sensitive_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
   NULL
 };
 
@@ -101,5 +93,5 @@
   deps,
   layouts,
   "envoy/extensions/transport_sockets/tls/v3/secret.proto",
-  UPB_STRVIEW_INIT(descriptor, 1400)
+  UPB_STRVIEW_INIT(descriptor, 1236)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/tls.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/tls.upbdefs.c
index 97532f2..a4651fc 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/tls.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/tls.upbdefs.c
@@ -12,7 +12,6 @@
 extern upb_def_init envoy_config_core_v3_extension_proto_upbdefinit;
 extern upb_def_init envoy_extensions_transport_sockets_tls_v3_common_proto_upbdefinit;
 extern upb_def_init envoy_extensions_transport_sockets_tls_v3_secret_proto_upbdefinit;
-extern upb_def_init google_protobuf_any_proto_upbdefinit;
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
@@ -35,7 +34,7 @@
   &envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CombinedCertificateValidationContext_msginit,
 };
 
-static const char descriptor[4734] = {'\n', '3', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 
+static const char descriptor[4707] = {'\n', '3', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 
 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 'v', '3', '/', 't', 'l', 's', '.', 'p', 'r', 
 'o', 't', 'o', '\022', ')', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 
 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '\032', '$', 'e', 'n', 
@@ -44,194 +43,192 @@
 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '/', 't', 'l', 's', '/', 
 'v', '3', '/', 'c', 'o', 'm', 'm', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '6', 'e', 'n', 'v', 'o', 'y', '/', 'e', 'x', 
 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '/', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 
-'s', '/', 't', 'l', 's', '/', 'v', '3', '/', 's', 'e', 'c', 'r', 'e', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 
-'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 
-'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 
-'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 
-'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 
-'t', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', 
-'/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', 
-'\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 
-'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 
-'d', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\301', '\002', '\n', '\022', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'T', 'l', 
-'s', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'i', '\n', '\022', 'c', 'o', 'm', 'm', 'o', 'n', '_', 't', 'l', 's', '_', 'c', 'o', 
-'n', 't', 'e', 'x', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 
-'s', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 
-'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'R', '\020', 'c', 
-'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '\032', '\n', '\003', 's', 'n', 'i', '\030', '\002', ' ', 
-'\001', '(', '\t', 'B', '\010', '\372', 'B', '\005', 'r', '\003', '(', '\377', '\001', 'R', '\003', 's', 'n', 'i', '\022', '/', '\n', '\023', 'a', 'l', 'l', 
-'o', 'w', '_', 'r', 'e', 'n', 'e', 'g', 'o', 't', 'i', 'a', 't', 'i', 'o', 'n', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\022', 'a', 
-'l', 'l', 'o', 'w', 'R', 'e', 'n', 'e', 'g', 'o', 't', 'i', 'a', 't', 'i', 'o', 'n', '\022', 'F', '\n', '\020', 'm', 'a', 'x', '_', 
-'s', 'e', 's', 's', 'i', 'o', 'n', '_', 'k', 'e', 'y', 's', '\030', '\004', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\016', 
-'m', 'a', 'x', 'S', 'e', 's', 's', 'i', 'o', 'n', 'K', 'e', 'y', 's', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 
-'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'T', 
-'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\"', '\352', '\007', '\n', '\024', 'D', 'o', 'w', 'n', 's', 't', 'r', 'e', 'a', 'm', 'T', 
-'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'i', '\n', '\022', 'c', 'o', 'm', 'm', 'o', 'n', '_', 't', 'l', 's', '_', 'c', 
-'o', 'n', 't', 'e', 'x', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 
-'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 
-'t', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'R', '\020', 
-'c', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'X', '\n', '\032', 'r', 'e', 'q', 'u', 'i', 
-'r', 'e', '_', 'c', 'l', 'i', 'e', 'n', 't', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\030', '\002', ' ', '\001', 
-'(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 
-'V', 'a', 'l', 'u', 'e', 'R', '\030', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'i', 
-'f', 'i', 'c', 'a', 't', 'e', '\022', ';', '\n', '\013', 'r', 'e', 'q', 'u', 'i', 'r', 'e', '_', 's', 'n', 'i', '\030', '\003', ' ', '\001', 
-'(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 
-'V', 'a', 'l', 'u', 'e', 'R', '\n', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'S', 'n', 'i', '\022', 'q', '\n', '\023', 's', 'e', 's', 's', 
-'i', 'o', 'n', '_', 't', 'i', 'c', 'k', 'e', 't', '_', 'k', 'e', 'y', 's', '\030', '\004', ' ', '\001', '(', '\013', '2', '?', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 
-'_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 's', 'S', 'e', 's', 's', 'i', 'o', 
-'n', 'T', 'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', 'H', '\000', 'R', '\021', 's', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'c', 
-'k', 'e', 't', 'K', 'e', 'y', 's', '\022', '\215', '\001', '\n', '%', 's', 'e', 's', 's', 'i', 'o', 'n', '_', 't', 'i', 'c', 'k', 'e', 
-'t', '_', 'k', 'e', 'y', 's', '_', 's', 'd', 's', '_', 's', 'e', 'c', 'r', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', 
-'\005', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
-'t', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 
-'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\000', 'R', ' ', 's', 'e', 's', 's', 'i', 'o', 
-'n', 'T', 'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 
-'g', '\022', 'Q', '\n', '$', 'd', 'i', 's', 'a', 'b', 'l', 'e', '_', 's', 't', 'a', 't', 'e', 'l', 'e', 's', 's', '_', 's', 'e', 
-'s', 's', 'i', 'o', 'n', '_', 'r', 'e', 's', 'u', 'm', 'p', 't', 'i', 'o', 'n', '\030', '\007', ' ', '\001', '(', '\010', 'H', '\000', 'R', 
-'!', 'd', 'i', 's', 'a', 'b', 'l', 'e', 'S', 't', 'a', 't', 'e', 'l', 'e', 's', 's', 'S', 'e', 's', 's', 'i', 'o', 'n', 'R', 
-'e', 's', 'u', 'm', 'p', 't', 'i', 'o', 'n', '\022', 'T', '\n', '\017', 's', 'e', 's', 's', 'i', 'o', 'n', '_', 't', 'i', 'm', 'e', 
-'o', 'u', 't', '\030', '\006', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
-'u', 'f', '.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\020', '\372', 'B', '\r', '\252', '\001', '\n', '\032', '\006', '\010', '\200', '\200', '\200', 
-'\200', '\020', '2', '\000', 'R', '\016', 's', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', '\210', '\001', '\n', '\022', 
-'o', 'c', 's', 'p', '_', 's', 't', 'a', 'p', 'l', 'e', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\010', ' ', '\001', '(', '\016', '2', 
-'P', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 
-'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'D', 'o', 'w', 'n', 's', 't', 
-'r', 'e', 'a', 'm', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'O', 'c', 's', 'p', 'S', 't', 'a', 'p', 'l', 'e', 
-'P', 'o', 'l', 'i', 'c', 'y', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\020', 'o', 'c', 's', 'p', 'S', 't', 'a', 
-'p', 'l', 'e', 'P', 'o', 'l', 'i', 'c', 'y', '\"', 'N', '\n', '\020', 'O', 'c', 's', 'p', 'S', 't', 'a', 'p', 'l', 'e', 'P', 'o', 
-'l', 'i', 'c', 'y', '\022', '\024', '\n', '\020', 'L', 'E', 'N', 'I', 'E', 'N', 'T', '_', 'S', 'T', 'A', 'P', 'L', 'I', 'N', 'G', '\020', 
-'\000', '\022', '\023', '\n', '\017', 'S', 'T', 'R', 'I', 'C', 'T', '_', 'S', 'T', 'A', 'P', 'L', 'I', 'N', 'G', '\020', '\001', '\022', '\017', '\n', 
-'\013', 'M', 'U', 'S', 'T', '_', 'S', 'T', 'A', 'P', 'L', 'E', '\020', '\002', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 
-'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'D', 'o', 'w', 'n', 's', 't', 'r', 'e', 'a', 
-'m', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'B', '\032', '\n', '\030', 's', 'e', 's', 's', 'i', 'o', 'n', '_', 't', 'i', 
-'c', 'k', 'e', 't', '_', 'k', 'e', 'y', 's', '_', 't', 'y', 'p', 'e', '\"', '\247', '\026', '\n', '\020', 'C', 'o', 'm', 'm', 'o', 'n', 
-'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'W', '\n', '\n', 't', 'l', 's', '_', 'p', 'a', 'r', 'a', 'm', 's', '\030', 
-'\001', ' ', '\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 
-'t', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 
-'T', 'l', 's', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', 'R', '\t', 't', 'l', 's', 'P', 'a', 'r', 'a', 'm', 's', '\022', 
-'d', '\n', '\020', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 's', '\030', '\002', ' ', '\003', '(', '\013', 
-'2', '9', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 
-'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 's', 'C', 'e', 
-'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'R', '\017', 't', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 
-'s', '\022', '\220', '\001', '\n', '\"', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 's', 'd', 's', 
-'_', 's', 'e', 'c', 'r', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', ':', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', 
-'_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 
-'C', 'o', 'n', 'f', 'i', 'g', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\020', '\001', 'R', '\036', 't', 'l', 's', 'C', 'e', 'r', 't', 
-'i', 'f', 'i', 'c', 'a', 't', 'e', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', '\240', 
-'\001', '\n', '$', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'c', 'e', 'r', 't', 'i', 'f', 
-'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\t', ' ', '\001', '(', '\013', '2', 'O', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 
-'s', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 
-'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 
-'r', 'R', '!', 't', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 
-'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\022', '\271', '\001', '\n', '-', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 
-'f', 'i', 'c', 'a', 't', 'e', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 
-'e', 'r', '_', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', '\030', '\013', ' ', '\001', '(', '\013', '2', 'W', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 
-'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 
-'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 
-'s', 't', 'a', 'n', 'c', 'e', 'R', ')', 't', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'C', 'e', 'r', 
-'t', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', '\022', 
-'x', '\n', '\022', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\003', ' ', '\001', 
-'(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 
-'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'e', 'r', 
-'t', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 
-'H', '\000', 'R', '\021', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '\214', '\001', '\n', 
-'$', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 's', 'd', 's', '_', 's', 
-'e', 'c', 'r', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\007', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 
+'s', '/', 't', 'l', 's', '/', 'v', '3', '/', 's', 'e', 'c', 'r', 'e', 't', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 
+'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 
+'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 
+'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 
+'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 
+'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 
+'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 
+'t', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\301', '\002', '\n', '\022', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'T', 'l', 's', 'C', 
+'o', 'n', 't', 'e', 'x', 't', '\022', 'i', '\n', '\022', 'c', 'o', 'm', 'm', 'o', 'n', '_', 't', 'l', 's', '_', 'c', 'o', 'n', 't', 
+'e', 'x', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 
+'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', 
+'.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'R', '\020', 'c', 'o', 'm', 
+'m', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '\032', '\n', '\003', 's', 'n', 'i', '\030', '\002', ' ', '\001', '(', 
+'\t', 'B', '\010', '\372', 'B', '\005', 'r', '\003', '(', '\377', '\001', 'R', '\003', 's', 'n', 'i', '\022', '/', '\n', '\023', 'a', 'l', 'l', 'o', 'w', 
+'_', 'r', 'e', 'n', 'e', 'g', 'o', 't', 'i', 'a', 't', 'i', 'o', 'n', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\022', 'a', 'l', 'l', 
+'o', 'w', 'R', 'e', 'n', 'e', 'g', 'o', 't', 'i', 'a', 't', 'i', 'o', 'n', '\022', 'F', '\n', '\020', 'm', 'a', 'x', '_', 's', 'e', 
+'s', 's', 'i', 'o', 'n', '_', 'k', 'e', 'y', 's', '\030', '\004', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', 
+'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'I', 'n', 't', '3', '2', 'V', 'a', 'l', 'u', 'e', 'R', '\016', 'm', 'a', 
+'x', 'S', 'e', 's', 's', 'i', 'o', 'n', 'K', 'e', 'y', 's', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'U', 'p', 's', 't', 'r', 'e', 'a', 'm', 'T', 'l', 's', 
+'C', 'o', 'n', 't', 'e', 'x', 't', '\"', '\352', '\007', '\n', '\024', 'D', 'o', 'w', 'n', 's', 't', 'r', 'e', 'a', 'm', 'T', 'l', 's', 
+'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'i', '\n', '\022', 'c', 'o', 'm', 'm', 'o', 'n', '_', 't', 'l', 's', '_', 'c', 'o', 'n', 
+'t', 'e', 'x', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', ';', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 
+'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 
+'s', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'R', '\020', 'c', 'o', 
+'m', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'X', '\n', '\032', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 
+'_', 'c', 'l', 'i', 'e', 'n', 't', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '\030', '\002', ' ', '\001', '(', '\013', 
+'2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 
+'l', 'u', 'e', 'R', '\030', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'e', 'r', 't', 'i', 'f', 'i', 
+'c', 'a', 't', 'e', '\022', ';', '\n', '\013', 'r', 'e', 'q', 'u', 'i', 'r', 'e', '_', 's', 'n', 'i', '\030', '\003', ' ', '\001', '(', '\013', 
+'2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'B', 'o', 'o', 'l', 'V', 'a', 
+'l', 'u', 'e', 'R', '\n', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'S', 'n', 'i', '\022', 'q', '\n', '\023', 's', 'e', 's', 's', 'i', 'o', 
+'n', '_', 't', 'i', 'c', 'k', 'e', 't', '_', 'k', 'e', 'y', 's', '\030', '\004', ' ', '\001', '(', '\013', '2', '?', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 
+'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 's', 'S', 'e', 's', 's', 'i', 'o', 'n', 'T', 
+'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', 'H', '\000', 'R', '\021', 's', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'c', 'k', 'e', 
+'t', 'K', 'e', 'y', 's', '\022', '\215', '\001', '\n', '%', 's', 'e', 's', 's', 'i', 'o', 'n', '_', 't', 'i', 'c', 'k', 'e', 't', '_', 
+'k', 'e', 'y', 's', '_', 's', 'd', 's', '_', 's', 'e', 'c', 'r', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\005', ' ', 
+'\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 
+'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'S', 'd', 
+'s', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\000', 'R', ' ', 's', 'e', 's', 's', 'i', 'o', 'n', 'T', 
+'i', 'c', 'k', 'e', 't', 'K', 'e', 'y', 's', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 
+'Q', '\n', '$', 'd', 'i', 's', 'a', 'b', 'l', 'e', '_', 's', 't', 'a', 't', 'e', 'l', 'e', 's', 's', '_', 's', 'e', 's', 's', 
+'i', 'o', 'n', '_', 'r', 'e', 's', 'u', 'm', 'p', 't', 'i', 'o', 'n', '\030', '\007', ' ', '\001', '(', '\010', 'H', '\000', 'R', '!', 'd', 
+'i', 's', 'a', 'b', 'l', 'e', 'S', 't', 'a', 't', 'e', 'l', 'e', 's', 's', 'S', 'e', 's', 's', 'i', 'o', 'n', 'R', 'e', 's', 
+'u', 'm', 'p', 't', 'i', 'o', 'n', '\022', 'T', '\n', '\017', 's', 'e', 's', 's', 'i', 'o', 'n', '_', 't', 'i', 'm', 'e', 'o', 'u', 
+'t', '\030', '\006', ' ', '\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 
+'.', 'D', 'u', 'r', 'a', 't', 'i', 'o', 'n', 'B', '\020', '\372', 'B', '\r', '\252', '\001', '\n', '\032', '\006', '\010', '\200', '\200', '\200', '\200', '\020', 
+'2', '\000', 'R', '\016', 's', 'e', 's', 's', 'i', 'o', 'n', 'T', 'i', 'm', 'e', 'o', 'u', 't', '\022', '\210', '\001', '\n', '\022', 'o', 'c', 
+'s', 'p', '_', 's', 't', 'a', 'p', 'l', 'e', '_', 'p', 'o', 'l', 'i', 'c', 'y', '\030', '\010', ' ', '\001', '(', '\016', '2', 'P', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 
+'t', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'D', 'o', 'w', 'n', 's', 't', 'r', 'e', 
+'a', 'm', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'O', 'c', 's', 'p', 'S', 't', 'a', 'p', 'l', 'e', 'P', 'o', 
+'l', 'i', 'c', 'y', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\020', 'o', 'c', 's', 'p', 'S', 't', 'a', 'p', 'l', 
+'e', 'P', 'o', 'l', 'i', 'c', 'y', '\"', 'N', '\n', '\020', 'O', 'c', 's', 'p', 'S', 't', 'a', 'p', 'l', 'e', 'P', 'o', 'l', 'i', 
+'c', 'y', '\022', '\024', '\n', '\020', 'L', 'E', 'N', 'I', 'E', 'N', 'T', '_', 'S', 'T', 'A', 'P', 'L', 'I', 'N', 'G', '\020', '\000', '\022', 
+'\023', '\n', '\017', 'S', 'T', 'R', 'I', 'C', 'T', '_', 'S', 'T', 'A', 'P', 'L', 'I', 'N', 'G', '\020', '\001', '\022', '\017', '\n', '\013', 'M', 
+'U', 'S', 'T', '_', 'S', 'T', 'A', 'P', 'L', 'E', '\020', '\002', ':', '-', '\232', '\305', '\210', '\036', '(', '\n', '&', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'D', 'o', 'w', 'n', 's', 't', 'r', 'e', 'a', 'm', 'T', 
+'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'B', '\032', '\n', '\030', 's', 'e', 's', 's', 'i', 'o', 'n', '_', 't', 'i', 'c', 'k', 
+'e', 't', '_', 'k', 'e', 'y', 's', '_', 't', 'y', 'p', 'e', '\"', '\247', '\026', '\n', '\020', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 
+'s', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'W', '\n', '\n', 't', 'l', 's', '_', 'p', 'a', 'r', 'a', 'm', 's', '\030', '\001', ' ', 
+'\001', '(', '\013', '2', '8', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 
+'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 
+'s', 'P', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', 's', 'R', '\t', 't', 'l', 's', 'P', 'a', 'r', 'a', 'm', 's', '\022', 'd', '\n', 
+'\020', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '9', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 
+'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'T', 'l', 's', 'C', 'e', 'r', 't', 
+'i', 'f', 'i', 'c', 'a', 't', 'e', 'R', '\017', 't', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 's', '\022', 
+'\220', '\001', '\n', '\"', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 's', 'd', 's', '_', 's', 
+'e', 'c', 'r', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 
+'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 
+'n', 'f', 'i', 'g', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\020', '\001', 'R', '\036', 't', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 
+'i', 'c', 'a', 't', 'e', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', 's', '\022', '\240', '\001', '\n', 
+'$', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 
+'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\t', ' ', '\001', '(', '\013', '2', 'O', '.', 'e', 'n', 'v', 'o', 
 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 
-'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 
-'f', 'i', 'g', 'H', '\000', 'R', ' ', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'S', 
-'d', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '\242', '\001', '\n', '\033', 'c', 'o', 'm', 'b', 'i', 'n', 
-'e', 'd', '_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\010', ' ', '\001', 
-'(', '\013', '2', '`', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 
+'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 
+'t', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'R', 
+'!', 't', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 
+'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\022', '\271', '\001', '\n', '-', 't', 'l', 's', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 
+'c', 'a', 't', 'e', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 
+'_', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', '\030', '\013', ' ', '\001', '(', '\013', '2', 'W', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 
+'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 
+'t', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 
+'t', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 
+'a', 'n', 'c', 'e', 'R', ')', 't', 'l', 's', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'C', 'e', 'r', 't', 'i', 
+'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', '\022', 'x', '\n', 
+'\022', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\003', ' ', '\001', '(', '\013', 
+'2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 
+'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'e', 'r', 't', 'i', 
+'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'H', '\000', 
+'R', '\021', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '\214', '\001', '\n', '$', 'v', 
+'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 's', 'd', 's', '_', 's', 'e', 'c', 
+'r', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\007', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 
+'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 
+'g', 'H', '\000', 'R', ' ', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'S', 'd', 's', 
+'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\022', '\242', '\001', '\n', '\033', 'c', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 
+'_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\010', ' ', '\001', '(', '\013', 
+'2', '`', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 
+'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 
+'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 'C', 'e', 'r', 't', 'i', 
+'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'H', '\000', 
+'R', '\031', 'c', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 
+'x', 't', '\022', '\250', '\001', '\n', '\'', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', 
+'_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\n', ' ', '\001', 
+'(', '\013', '2', 'O', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 
 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 
-'m', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 'C', 'e', 'r', 
-'t', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 
-'H', '\000', 'R', '\031', 'c', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 
-'t', 'e', 'x', 't', '\022', '\250', '\001', '\n', '\'', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 
-'x', 't', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\n', 
+'m', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 
+'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'H', '\000', 'R', '$', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 
+'t', 'e', 'x', 't', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\022', '\301', 
+'\001', '\n', '0', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'c', 'e', 'r', 
+'t', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '_', 'i', 'n', 's', 't', 'a', 'n', 'c', 
+'e', '\030', '\014', ' ', '\001', '(', '\013', '2', 'W', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 
+'s', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', 
+'3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 
+'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', 'H', '\000', 'R', ',', 
+'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 
+'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', '\022', '%', '\n', '\016', 'a', 'l', 
+'p', 'n', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\030', '\004', ' ', '\003', '(', '\t', 'R', '\r', 'a', 'l', 'p', 'n', 'P', 
+'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\022', 'W', '\n', '\021', 'c', 'u', 's', 't', 'o', 'm', '_', 'h', 'a', 'n', 'd', 's', 'h', 
+'a', 'k', 'e', 'r', '\030', '\r', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', 
+'.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 
+'n', 'f', 'i', 'g', 'R', '\020', 'c', 'u', 's', 't', 'o', 'm', 'H', 'a', 'n', 'd', 's', 'h', 'a', 'k', 'e', 'r', '\032', '\222', '\001', 
+'\n', '\023', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\022', '\033', '\n', '\004', 
+'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', 
+'\022', 'O', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', '*', '.', 
+'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 
+'d', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\000', 'R', '\013', 't', 'y', 'p', 'e', 'd', 
+'C', 'o', 'n', 'f', 'i', 'g', 'B', '\r', '\n', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\022', '\003', '\370', 'B', '\001', '\032', 'm', '\n', '\033', 
+'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 
+'c', 'e', '\022', '#', '\n', '\r', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
+'R', '\014', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'N', 'a', 'm', 'e', '\022', ')', '\n', '\020', 'c', 'e', 'r', 't', 'i', 'f', 'i', 
+'c', 'a', 't', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\017', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 
+'a', 't', 'e', 'N', 'a', 'm', 'e', '\032', '\364', '\006', '\n', '$', 'C', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 'C', 'e', 'r', 't', 'i', 
+'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '\217', 
+'\001', '\n', '\032', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 
+'t', 'e', 'x', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 
+'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 
+'s', '.', 'v', '3', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 
+'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\030', 'd', 'e', 'f', 'a', 'u', 
+'l', 't', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '\266', '\001', '\n', '$', 'v', 
+'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 's', 'd', 's', '_', 's', 'e', 'c', 
+'r', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 
+'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 'f', 'i', 
+'g', 'B', '*', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', '\362', '\230', '\376', '\217', '\005', '\034', '\022', '\032', 'd', 'y', 'n', 'a', 'm', 'i', 
+'c', '_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', 'R', ' ', 'v', 'a', 'l', 
+'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 
+'n', 'f', 'i', 'g', '\022', '\312', '\001', '\n', '\'', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 
+'x', 't', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\030', '\003', 
 ' ', '\001', '(', '\013', '2', 'O', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 
 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 
 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 
-'t', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'H', '\000', 'R', '$', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 
-'o', 'n', 't', 'e', 'x', 't', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 
-'\022', '\301', '\001', '\n', '0', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'c', 
-'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '_', 'i', 'n', 's', 't', 'a', 
-'n', 'c', 'e', '\030', '\014', ' ', '\001', '(', '\013', '2', 'W', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 
-'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', 
-'.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 
-'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', 'H', '\000', 
-'R', ',', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'C', 'e', 'r', 't', 'i', 'f', 
-'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', '\022', '%', '\n', '\016', 
-'a', 'l', 'p', 'n', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\030', '\004', ' ', '\003', '(', '\t', 'R', '\r', 'a', 'l', 'p', 
-'n', 'P', 'r', 'o', 't', 'o', 'c', 'o', 'l', 's', '\022', 'W', '\n', '\021', 'c', 'u', 's', 't', 'o', 'm', '_', 'h', 'a', 'n', 'd', 
-'s', 'h', 'a', 'k', 'e', 'r', '\030', '\r', ' ', '\001', '(', '\013', '2', '*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 
-'C', 'o', 'n', 'f', 'i', 'g', 'R', '\020', 'c', 'u', 's', 't', 'o', 'm', 'H', 'a', 'n', 'd', 's', 'h', 'a', 'k', 'e', 'r', '\032', 
-'\222', '\001', '\n', '\023', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\022', '\033', 
-'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 
-'m', 'e', '\022', 'O', '\n', '\014', 't', 'y', 'p', 'e', 'd', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', 
-'*', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'T', 'y', 
-'p', 'e', 'd', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'C', 'o', 'n', 'f', 'i', 'g', 'H', '\000', 'R', '\013', 't', 'y', 'p', 
-'e', 'd', 'C', 'o', 'n', 'f', 'i', 'g', 'B', '\r', '\n', '\006', 'c', 'o', 'n', 'f', 'i', 'g', '\022', '\003', '\370', 'B', '\001', '\032', 'm', 
-'\n', '\033', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 
-'a', 'n', 'c', 'e', '\022', '#', '\n', '\r', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', 
-'(', '\t', 'R', '\014', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'N', 'a', 'm', 'e', '\022', ')', '\n', '\020', 'c', 'e', 'r', 't', 'i', 
-'f', 'i', 'c', 'a', 't', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\017', 'c', 'e', 'r', 't', 'i', 'f', 
-'i', 'c', 'a', 't', 'e', 'N', 'a', 'm', 'e', '\032', '\364', '\006', '\n', '$', 'C', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 'C', 'e', 'r', 
-'t', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 
-'\022', '\217', '\001', '\n', '\032', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 
-'o', 'n', 't', 'e', 'x', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', 'G', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 
-'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 
-'t', 'l', 's', '.', 'v', '3', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 
-'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\030', 'd', 'e', 'f', 
-'a', 'u', 'l', 't', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', '\266', '\001', '\n', 
-'$', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 's', 'd', 's', '_', 's', 
-'e', 'c', 'r', 'e', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\001', '(', '\013', '2', ':', '.', 'e', 'n', 'v', 'o', 
+'t', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'B', '\"', '\362', '\230', '\376', '\217', '\005', '\034', '\022', '\032', 'd', 'y', 'n', 'a', 'm', 
+'i', 'c', '_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', 'R', '$', 'v', 'a', 
+'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 
+'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\022', '\343', '\001', '\n', '0', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 
+'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 
+'d', 'e', 'r', '_', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', 'W', '.', 'e', 'n', 'v', 'o', 
 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 
-'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 'C', 'o', 'n', 
-'f', 'i', 'g', 'B', '*', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', '\362', '\230', '\376', '\217', '\005', '\034', '\022', '\032', 'd', 'y', 'n', 'a', 
-'m', 'i', 'c', '_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', 'R', ' ', 'v', 
-'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'S', 'd', 's', 'S', 'e', 'c', 'r', 'e', 't', 
-'C', 'o', 'n', 'f', 'i', 'g', '\022', '\312', '\001', '\n', '\'', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 
-'t', 'e', 'x', 't', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 
-'\030', '\003', ' ', '\001', '(', '\013', '2', 'O', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 
-'.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', 
-'.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 
-'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'B', '\"', '\362', '\230', '\376', '\217', '\005', '\034', '\022', '\032', 'd', 'y', 'n', 
-'a', 'm', 'i', 'c', '_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', 'R', '$', 
-'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 
-'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', '\022', '\343', '\001', '\n', '0', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 
-'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '_', 'p', 'r', 'o', 
-'v', 'i', 'd', 'e', 'r', '_', 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', '\030', '\004', ' ', '\001', '(', '\013', '2', 'W', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 
-'s', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 
-'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 
-'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', 'B', '\"', '\362', '\230', '\376', '\217', '\005', '\034', '\022', '\032', 'd', 'y', 'n', 'a', 'm', 'i', 
-'c', '_', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', 'R', ',', 'v', 'a', 'l', 
-'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 
-'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', ':', 'N', '\232', '\305', '\210', '\036', 'I', '\n', 'G', 
-'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 
-'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 'C', 'e', 'r', 't', 'i', 'f', 'i', 
-'c', 'a', 't', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', ':', ')', '\232', '\305', 
-'\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'C', 'o', 
-'m', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'B', '\031', '\n', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 
-'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\005', '\020', '\006', 'B', 'M', '\n', 
-'7', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 
-'n', 's', 'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 
-'t', 'l', 's', '.', 'v', '3', 'B', '\010', 'T', 'l', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', 
-'\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'c', 'k', 'e', 't', 's', '.', 't', 'l', 's', '.', 'v', '3', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 
+'t', 'e', 'x', 't', '.', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 'I', 
+'n', 's', 't', 'a', 'n', 'c', 'e', 'B', '\"', '\362', '\230', '\376', '\217', '\005', '\034', '\022', '\032', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '_', 
+'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', 'R', ',', 'v', 'a', 'l', 'i', 'd', 
+'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', 'P', 'r', 
+'o', 'v', 'i', 'd', 'e', 'r', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', ':', 'N', '\232', '\305', '\210', '\036', 'I', '\n', 'G', 'e', 'n', 
+'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'C', 'o', 'm', 'm', 'o', 'n', 'T', 'l', 's', 
+'C', 'o', 'n', 't', 'e', 'x', 't', '.', 'C', 'o', 'm', 'b', 'i', 'n', 'e', 'd', 'C', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 
+'t', 'e', 'V', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 'n', 'C', 'o', 'n', 't', 'e', 'x', 't', ':', ')', '\232', '\305', '\210', '\036', 
+'$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'a', 'u', 't', 'h', '.', 'C', 'o', 'm', 'm', 
+'o', 'n', 'T', 'l', 's', 'C', 'o', 'n', 't', 'e', 'x', 't', 'B', '\031', '\n', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'i', 'o', 
+'n', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 't', 'y', 'p', 'e', 'J', '\004', '\010', '\005', '\020', '\006', 'B', 'M', '\n', '7', 'i', 
+'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 'e', 'x', 't', 'e', 'n', 's', 
+'i', 'o', 'n', 's', '.', 't', 'r', 'a', 'n', 's', 'p', 'o', 'r', 't', '_', 's', 'o', 'c', 'k', 'e', 't', 's', '.', 't', 'l', 
+'s', '.', 'v', '3', 'B', '\010', 'T', 'l', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', 
+'\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[11] = {
+static upb_def_init *deps[10] = {
   &envoy_config_core_v3_extension_proto_upbdefinit,
   &envoy_extensions_transport_sockets_tls_v3_common_proto_upbdefinit,
   &envoy_extensions_transport_sockets_tls_v3_secret_proto_upbdefinit,
-  &google_protobuf_any_proto_upbdefinit,
   &google_protobuf_duration_proto_upbdefinit,
   &google_protobuf_wrappers_proto_upbdefinit,
   &udpa_annotations_migrate_proto_upbdefinit,
@@ -245,5 +242,5 @@
   deps,
   layouts,
   "envoy/extensions/transport_sockets/tls/v3/tls.proto",
-  UPB_STRVIEW_INIT(descriptor, 4734)
+  UPB_STRVIEW_INIT(descriptor, 4707)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/service/discovery/v3/discovery.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/service/discovery/v3/discovery.upbdefs.c
index 5e8a1bf..0df3b7b 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/service/discovery/v3/discovery.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/service/discovery/v3/discovery.upbdefs.c
@@ -11,10 +11,8 @@
 
 extern upb_def_init envoy_config_core_v3_base_proto_upbdefinit;
 extern upb_def_init google_protobuf_any_proto_upbdefinit;
+extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init google_rpc_status_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_resource_locator_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_resource_name_proto_upbdefinit;
-extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
 extern const upb_msglayout envoy_service_discovery_v3_DiscoveryRequest_msginit;
@@ -23,122 +21,114 @@
 extern const upb_msglayout envoy_service_discovery_v3_DeltaDiscoveryRequest_InitialResourceVersionsEntry_msginit;
 extern const upb_msglayout envoy_service_discovery_v3_DeltaDiscoveryResponse_msginit;
 extern const upb_msglayout envoy_service_discovery_v3_Resource_msginit;
+extern const upb_msglayout envoy_service_discovery_v3_Resource_CacheControl_msginit;
 
-static const upb_msglayout *layouts[6] = {
+static const upb_msglayout *layouts[7] = {
   &envoy_service_discovery_v3_DiscoveryRequest_msginit,
   &envoy_service_discovery_v3_DiscoveryResponse_msginit,
   &envoy_service_discovery_v3_DeltaDiscoveryRequest_msginit,
   &envoy_service_discovery_v3_DeltaDiscoveryRequest_InitialResourceVersionsEntry_msginit,
   &envoy_service_discovery_v3_DeltaDiscoveryResponse_msginit,
   &envoy_service_discovery_v3_Resource_msginit,
+  &envoy_service_discovery_v3_Resource_CacheControl_msginit,
 };
 
-static const char descriptor[2407] = {'\n', '*', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 
+static const char descriptor[2206] = {'\n', '*', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 
 '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'p', 'r', 'o', 't', 'o', '\022', '\032', 'e', 'n', 'v', 'o', 
 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '\032', '\037', 'e', 
 'n', 'v', 'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 
 'p', 'r', 'o', 't', 'o', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 
-'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'r', 'p', 'c', '/', 's', 't', 'a', 't', 'u', 
-'s', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 's', 
-'o', 'u', 'r', 'c', 'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', ' ', 'u', 'd', 'p', 'a', 
-'/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 'm', 'e', '.', 'p', 'r', 
-'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 
-'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 
-'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 
-'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 
-'o', '\"', '\253', '\002', '\n', '\020', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\022', '!', '\n', 
-'\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 'v', 'e', 'r', 's', 
-'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '.', '\n', '\004', 'n', 'o', 'd', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\032', '.', 'e', 
-'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'N', 'o', 'd', 'e', 'R', 
-'\004', 'n', 'o', 'd', 'e', '\022', '%', '\n', '\016', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 'm', 'e', 's', '\030', '\003', 
-' ', '\003', '(', '\t', 'R', '\r', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 's', '\022', '\031', '\n', '\010', 't', 'y', 
-'p', 'e', '_', 'u', 'r', 'l', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 'r', 'l', '\022', '%', '\n', '\016', 
-'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'n', 'o', 'n', 'c', 'e', '\030', '\005', ' ', '\001', '(', '\t', 'R', '\r', 'r', 'e', 's', 
-'p', 'o', 'n', 's', 'e', 'N', 'o', 'n', 'c', 'e', '\022', '5', '\n', '\014', 'e', 'r', 'r', 'o', 'r', '_', 'd', 'e', 't', 'a', 'i', 
-'l', '\030', '\006', ' ', '\001', '(', '\013', '2', '\022', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'r', 'p', 'c', '.', 'S', 't', 'a', 't', 
-'u', 's', 'R', '\013', 'e', 'r', 'r', 'o', 'r', 'D', 'e', 't', 'a', 'i', 'l', ':', '$', '\232', '\305', '\210', '\036', '\037', '\n', '\035', 'e', 
-'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 
-'e', 's', 't', '\"', '\243', '\002', '\n', '\021', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 
-'\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 'v', 
-'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '2', '\n', '\t', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\030', '\002', 
-' ', '\003', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 
-'y', 'R', '\t', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\022', '\026', '\n', '\006', 'c', 'a', 'n', 'a', 'r', 'y', '\030', '\003', ' ', 
-'\001', '(', '\010', 'R', '\006', 'c', 'a', 'n', 'a', 'r', 'y', '\022', '\031', '\n', '\010', 't', 'y', 'p', 'e', '_', 'u', 'r', 'l', '\030', '\004', 
-' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 'r', 'l', '\022', '\024', '\n', '\005', 'n', 'o', 'n', 'c', 'e', '\030', '\005', ' ', 
-'\001', '(', '\t', 'R', '\005', 'n', 'o', 'n', 'c', 'e', '\022', 'G', '\n', '\r', 'c', 'o', 'n', 't', 'r', 'o', 'l', '_', 'p', 'l', 'a', 
-'n', 'e', '\030', '\006', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 
-'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', 'R', '\014', 'c', 'o', 'n', 't', 
-'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
-'i', '.', 'v', '2', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\362', '\005', 
-'\n', '\025', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\022', '.', 
-'\n', '\004', 'n', 'o', 'd', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
-'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'N', 'o', 'd', 'e', 'R', '\004', 'n', 'o', 'd', 'e', '\022', '\031', '\n', '\010', 
-'t', 'y', 'p', 'e', '_', 'u', 'r', 'l', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 'r', 'l', '\022', '8', 
-'\n', '\030', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 'm', 'e', 's', '_', 's', 'u', 'b', 's', 'c', 'r', 'i', 'b', 
-'e', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\026', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 's', 'S', 'u', 'b', 
-'s', 'c', 'r', 'i', 'b', 'e', '\022', 'W', '\n', '\030', 'u', 'd', 'p', 'a', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '_', 
-'s', 'u', 'b', 's', 'c', 'r', 'i', 'b', 'e', '\030', '\010', ' ', '\003', '(', '\013', '2', '\035', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 
-'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'R', '\026', 'u', 'd', 
-'p', 'a', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', 'S', 'u', 'b', 's', 'c', 'r', 'i', 'b', 'e', '\022', '<', '\n', '\032', 'r', 
-'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 'm', 'e', 's', '_', 'u', 'n', 's', 'u', 'b', 's', 'c', 'r', 'i', 'b', 'e', 
-'\030', '\004', ' ', '\003', '(', '\t', 'R', '\030', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 's', 'U', 'n', 's', 'u', 
-'b', 's', 'c', 'r', 'i', 'b', 'e', '\022', '[', '\n', '\032', 'u', 'd', 'p', 'a', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', 
-'_', 'u', 'n', 's', 'u', 'b', 's', 'c', 'r', 'i', 'b', 'e', '\030', '\t', ' ', '\003', '(', '\013', '2', '\035', '.', 'u', 'd', 'p', 'a', 
-'.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'R', 
-'\030', 'u', 'd', 'p', 'a', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', 'U', 'n', 's', 'u', 'b', 's', 'c', 'r', 'i', 'b', 'e', 
-'\022', '\212', '\001', '\n', '\031', 'i', 'n', 'i', 't', 'i', 'a', 'l', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'v', 'e', 'r', 
-'s', 'i', 'o', 'n', 's', '\030', '\005', ' ', '\003', '(', '\013', '2', 'N', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 
-'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 
-'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '.', 'I', 'n', 'i', 't', 'i', 'a', 'l', 'R', 'e', 's', 'o', 'u', 
-'r', 'c', 'e', 'V', 'e', 'r', 's', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', 'R', '\027', 'i', 'n', 'i', 't', 'i', 'a', 'l', 
-'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'V', 'e', 'r', 's', 'i', 'o', 'n', 's', '\022', '%', '\n', '\016', 'r', 'e', 's', 'p', 'o', 
-'n', 's', 'e', '_', 'n', 'o', 'n', 'c', 'e', '\030', '\006', ' ', '\001', '(', '\t', 'R', '\r', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 
-'N', 'o', 'n', 'c', 'e', '\022', '5', '\n', '\014', 'e', 'r', 'r', 'o', 'r', '_', 'd', 'e', 't', 'a', 'i', 'l', '\030', '\007', ' ', '\001', 
-'(', '\013', '2', '\022', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'r', 'p', 'c', '.', 'S', 't', 'a', 't', 'u', 's', 'R', '\013', 'e', 
-'r', 'r', 'o', 'r', 'D', 'e', 't', 'a', 'i', 'l', '\032', 'J', '\n', '\034', 'I', 'n', 'i', 't', 'i', 'a', 'l', 'R', 'e', 's', 'o', 
-'u', 'r', 'c', 'e', 'V', 'e', 'r', 's', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', 
-'\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '\024', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\t', 
-'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', 
-'.', 'a', 'p', 'i', '.', 'v', '2', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 
-'u', 'e', 's', 't', '\"', '\350', '\002', '\n', '\026', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 
-'s', 'p', 'o', 'n', 's', 'e', '\022', '.', '\n', '\023', 's', 'y', 's', 't', 'e', 'm', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 
-'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\021', 's', 'y', 's', 't', 'e', 'm', 'V', 'e', 'r', 's', 'i', 'o', 'n', 
-'I', 'n', 'f', 'o', '\022', 'B', '\n', '\t', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '$', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 
-'v', '3', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\022', '\031', '\n', 
-'\010', 't', 'y', 'p', 'e', '_', 'u', 'r', 'l', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 'r', 'l', '\022', 
-'+', '\n', '\021', 'r', 'e', 'm', 'o', 'v', 'e', 'd', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\030', '\006', ' ', '\003', '(', 
-'\t', 'R', '\020', 'r', 'e', 'm', 'o', 'v', 'e', 'd', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\022', 'P', '\n', '\026', 'u', 'd', 
-'p', 'a', '_', 'r', 'e', 'm', 'o', 'v', 'e', 'd', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\030', '\007', ' ', '\003', '(', 
-'\013', '2', '\032', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 
-'N', 'a', 'm', 'e', 'R', '\024', 'u', 'd', 'p', 'a', 'R', 'e', 'm', 'o', 'v', 'e', 'd', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 
-'s', '\022', '\024', '\n', '\005', 'n', 'o', 'n', 'c', 'e', '\030', '\005', ' ', '\001', '(', '\t', 'R', '\005', 'n', 'o', 'n', 'c', 'e', ':', '*', 
-'\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'D', 'e', 'l', 't', 'a', 
-'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\234', '\002', '\n', '\010', 'R', 'e', 's', 
-'o', 'u', 'r', 'c', 'e', '\022', '*', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'B', '\026', '\362', '\230', '\376', '\217', 
-'\005', '\020', '\022', '\016', 'n', 'a', 'm', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'R', '\004', 'n', 'a', 'm', 'e', '\022', 
-'`', '\n', '\022', 'u', 'd', 'p', 'a', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\005', ' ', '\001', 
-'(', '\013', '2', '\032', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 
-'e', 'N', 'a', 'm', 'e', 'B', '\026', '\362', '\230', '\376', '\217', '\005', '\020', '\022', '\016', 'n', 'a', 'm', 'e', '_', 's', 'p', 'e', 'c', 'i', 
-'f', 'i', 'e', 'r', 'R', '\020', 'u', 'd', 'p', 'a', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', '\022', '\030', '\n', 
-'\007', 'a', 'l', 'i', 'a', 's', 'e', 's', '\030', '\004', ' ', '\003', '(', '\t', 'R', '\007', 'a', 'l', 'i', 'a', 's', 'e', 's', '\022', '\030', 
-'\n', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', 
-'0', '\n', '\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 
-'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', ':', 
-'\034', '\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'R', 'e', 's', 'o', 
-'u', 'r', 'c', 'e', 'B', 'D', '\n', '(', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', 'B', '\016', 
-'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', 
-'\006', 'p', 'r', 'o', 't', 'o', '3', 
+'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 
+'d', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'r', 'p', 
+'c', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 
+'t', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 
+'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 
+'p', 'r', 'o', 't', 'o', '\"', '\253', '\002', '\n', '\020', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 
+'t', '\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\013', 
+'v', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '.', '\n', '\004', 'n', 'o', 'd', 'e', '\030', '\002', ' ', '\001', '(', '\013', 
+'2', '\032', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'N', 
+'o', 'd', 'e', 'R', '\004', 'n', 'o', 'd', 'e', '\022', '%', '\n', '\016', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 'm', 
+'e', 's', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\r', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 's', '\022', '\031', 
+'\n', '\010', 't', 'y', 'p', 'e', '_', 'u', 'r', 'l', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 'r', 'l', 
+'\022', '%', '\n', '\016', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', '_', 'n', 'o', 'n', 'c', 'e', '\030', '\005', ' ', '\001', '(', '\t', 'R', 
+'\r', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'N', 'o', 'n', 'c', 'e', '\022', '5', '\n', '\014', 'e', 'r', 'r', 'o', 'r', '_', 'd', 
+'e', 't', 'a', 'i', 'l', '\030', '\006', ' ', '\001', '(', '\013', '2', '\022', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'r', 'p', 'c', '.', 
+'S', 't', 'a', 't', 'u', 's', 'R', '\013', 'e', 'r', 'r', 'o', 'r', 'D', 'e', 't', 'a', 'i', 'l', ':', '$', '\232', '\305', '\210', '\036', 
+'\037', '\n', '\035', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 
+'R', 'e', 'q', 'u', 'e', 's', 't', '\"', '\243', '\002', '\n', '\021', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 
+'o', 'n', 's', 'e', '\022', '!', '\n', '\014', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 'o', '\030', '\001', ' ', '\001', '(', 
+'\t', 'R', '\013', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 'o', '\022', '2', '\n', '\t', 'r', 'e', 's', 'o', 'u', 'r', 'c', 
+'e', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'A', 'n', 'y', 'R', '\t', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\022', '\026', '\n', '\006', 'c', 'a', 'n', 'a', 'r', 
+'y', '\030', '\003', ' ', '\001', '(', '\010', 'R', '\006', 'c', 'a', 'n', 'a', 'r', 'y', '\022', '\031', '\n', '\010', 't', 'y', 'p', 'e', '_', 'u', 
+'r', 'l', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 'r', 'l', '\022', '\024', '\n', '\005', 'n', 'o', 'n', 'c', 
+'e', '\030', '\005', ' ', '\001', '(', '\t', 'R', '\005', 'n', 'o', 'n', 'c', 'e', '\022', 'G', '\n', '\r', 'c', 'o', 'n', 't', 'r', 'o', 'l', 
+'_', 'p', 'l', 'a', 'n', 'e', '\030', '\006', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 
+'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', 'R', '\014', 
+'c', 'o', 'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 
+'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 
+'e', '\"', '\274', '\004', '\n', '\025', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 
+'s', 't', '\022', '.', '\n', '\004', 'n', 'o', 'd', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'N', 'o', 'd', 'e', 'R', '\004', 'n', 'o', 'd', 'e', 
+'\022', '\031', '\n', '\010', 't', 'y', 'p', 'e', '_', 'u', 'r', 'l', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 
+'r', 'l', '\022', '8', '\n', '\030', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 'm', 'e', 's', '_', 's', 'u', 'b', 's', 
+'c', 'r', 'i', 'b', 'e', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\026', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 
+'s', 'S', 'u', 'b', 's', 'c', 'r', 'i', 'b', 'e', '\022', '<', '\n', '\032', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 
+'m', 'e', 's', '_', 'u', 'n', 's', 'u', 'b', 's', 'c', 'r', 'i', 'b', 'e', '\030', '\004', ' ', '\003', '(', '\t', 'R', '\030', 'r', 'e', 
+'s', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 's', 'U', 'n', 's', 'u', 'b', 's', 'c', 'r', 'i', 'b', 'e', '\022', '\212', '\001', 
+'\n', '\031', 'i', 'n', 'i', 't', 'i', 'a', 'l', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'v', 'e', 'r', 's', 'i', 'o', 
+'n', 's', '\030', '\005', ' ', '\003', '(', '\013', '2', 'N', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 
+'d', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 
+'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '.', 'I', 'n', 'i', 't', 'i', 'a', 'l', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 
+'V', 'e', 'r', 's', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', 'R', '\027', 'i', 'n', 'i', 't', 'i', 'a', 'l', 'R', 'e', 's', 
+'o', 'u', 'r', 'c', 'e', 'V', 'e', 'r', 's', 'i', 'o', 'n', 's', '\022', '%', '\n', '\016', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 
+'_', 'n', 'o', 'n', 'c', 'e', '\030', '\006', ' ', '\001', '(', '\t', 'R', '\r', 'r', 'e', 's', 'p', 'o', 'n', 's', 'e', 'N', 'o', 'n', 
+'c', 'e', '\022', '5', '\n', '\014', 'e', 'r', 'r', 'o', 'r', '_', 'd', 'e', 't', 'a', 'i', 'l', '\030', '\007', ' ', '\001', '(', '\013', '2', 
+'\022', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'r', 'p', 'c', '.', 'S', 't', 'a', 't', 'u', 's', 'R', '\013', 'e', 'r', 'r', 'o', 
+'r', 'D', 'e', 't', 'a', 'i', 'l', '\032', 'J', '\n', '\034', 'I', 'n', 'i', 't', 'i', 'a', 'l', 'R', 'e', 's', 'o', 'u', 'r', 'c', 
+'e', 'V', 'e', 'r', 's', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', 
+'(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '\024', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\005', 'v', 
+'a', 'l', 'u', 'e', ':', '\002', '8', '\001', ':', ')', '\232', '\305', '\210', '\036', '$', '\n', '\"', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 
+'i', '.', 'v', '2', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 
+'t', '\"', '\337', '\002', '\n', '\026', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 
+'n', 's', 'e', '\022', '.', '\n', '\023', 's', 'y', 's', 't', 'e', 'm', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '_', 'i', 'n', 'f', 
+'o', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\021', 's', 'y', 's', 't', 'e', 'm', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'f', 
+'o', '\022', 'B', '\n', '\t', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 
+'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'R', '\t', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\022', '\031', '\n', '\010', 't', 'y', 
+'p', 'e', '_', 'u', 'r', 'l', '\030', '\004', ' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 'r', 'l', '\022', '+', '\n', '\021', 
+'r', 'e', 'm', 'o', 'v', 'e', 'd', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\030', '\006', ' ', '\003', '(', '\t', 'R', '\020', 
+'r', 'e', 'm', 'o', 'v', 'e', 'd', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 's', '\022', '\024', '\n', '\005', 'n', 'o', 'n', 'c', 'e', 
+'\030', '\005', ' ', '\001', '(', '\t', 'R', '\005', 'n', 'o', 'n', 'c', 'e', '\022', 'G', '\n', '\r', 'c', 'o', 'n', 't', 'r', 'o', 'l', '_', 
+'p', 'l', 'a', 'n', 'e', '\030', '\007', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 
+'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', 'R', '\014', 'c', 
+'o', 'n', 't', 'r', 'o', 'l', 'P', 'l', 'a', 'n', 'e', ':', '*', '\232', '\305', '\210', '\036', '%', '\n', '#', 'e', 'n', 'v', 'o', 'y', 
+'.', 'a', 'p', 'i', '.', 'v', '2', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 
+'p', 'o', 'n', 's', 'e', '\"', '\331', '\002', '\n', '\010', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 
+'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\030', '\n', '\007', 'a', 'l', 'i', 'a', 's', 'e', 's', '\030', 
+'\004', ' ', '\003', '(', '\t', 'R', '\007', 'a', 'l', 'i', 'a', 's', 'e', 's', '\022', '\030', '\n', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', 
+'\030', '\001', ' ', '\001', '(', '\t', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', '0', '\n', '\010', 'r', 'e', 's', 'o', 'u', 'r', 
+'c', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 
+'f', '.', 'A', 'n', 'y', 'R', '\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '\022', '+', '\n', '\003', 't', 't', 'l', '\030', '\006', ' ', 
+'\001', '(', '\013', '2', '\031', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'u', 'r', 
+'a', 't', 'i', 'o', 'n', 'R', '\003', 't', 't', 'l', '\022', 'V', '\n', '\r', 'c', 'a', 'c', 'h', 'e', '_', 'c', 'o', 'n', 't', 'r', 
+'o', 'l', '\030', '\007', ' ', '\001', '(', '\013', '2', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 
+'d', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', '.', 'C', 'a', 'c', 
+'h', 'e', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'R', '\014', 'c', 'a', 'c', 'h', 'e', 'C', 'o', 'n', 't', 'r', 'o', 'l', '\032', '0', 
+'\n', '\014', 'C', 'a', 'c', 'h', 'e', 'C', 'o', 'n', 't', 'r', 'o', 'l', '\022', ' ', '\n', '\014', 'd', 'o', '_', 'n', 'o', 't', '_', 
+'c', 'a', 'c', 'h', 'e', '\030', '\001', ' ', '\001', '(', '\010', 'R', '\n', 'd', 'o', 'N', 'o', 't', 'C', 'a', 'c', 'h', 'e', ':', '\034', 
+'\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'R', 'e', 's', 'o', 'u', 
+'r', 'c', 'e', 'B', 'D', '\n', '(', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', 'B', '\016', 'D', 
+'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 
+'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[9] = {
+static upb_def_init *deps[7] = {
   &envoy_config_core_v3_base_proto_upbdefinit,
   &google_protobuf_any_proto_upbdefinit,
+  &google_protobuf_duration_proto_upbdefinit,
   &google_rpc_status_proto_upbdefinit,
-  &udpa_core_v1_resource_locator_proto_upbdefinit,
-  &udpa_core_v1_resource_name_proto_upbdefinit,
-  &udpa_annotations_migrate_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
   NULL
@@ -148,5 +138,5 @@
   deps,
   layouts,
   "envoy/service/discovery/v3/discovery.proto",
-  UPB_STRVIEW_INIT(descriptor, 2407)
+  UPB_STRVIEW_INIT(descriptor, 2206)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/service/discovery/v3/discovery.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/service/discovery/v3/discovery.upbdefs.h
index a53e4c2..770d46d 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/service/discovery/v3/discovery.upbdefs.h
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/service/discovery/v3/discovery.upbdefs.h
@@ -51,6 +51,11 @@
   return upb_symtab_lookupmsg(s, "envoy.service.discovery.v3.Resource");
 }
 
+UPB_INLINE const upb_msgdef *envoy_service_discovery_v3_Resource_CacheControl_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_service_discovery_v3_discovery_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.service.discovery.v3.Resource.CacheControl");
+}
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/service/endpoint/v3/eds.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/service/endpoint/v3/eds.upbdefs.c
index 49fac22..c766787 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/service/endpoint/v3/eds.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/service/endpoint/v3/eds.upbdefs.c
@@ -11,67 +11,57 @@
 
 extern upb_def_init envoy_service_discovery_v3_discovery_proto_upbdefinit;
 extern upb_def_init google_api_annotations_proto_upbdefinit;
-extern upb_def_init google_protobuf_duration_proto_upbdefinit;
-extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init envoy_annotations_resource_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
 extern const upb_msglayout envoy_service_endpoint_v3_EdsDummy_msginit;
 
 static const upb_msglayout *layouts[1] = {
   &envoy_service_endpoint_v3_EdsDummy_msginit,
 };
 
-static const char descriptor[927] = {'\n', '#', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '/', 
+static const char descriptor[838] = {'\n', '#', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '/', 
 'v', '3', '/', 'e', 'd', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\031', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 
 'c', 'e', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', '\032', '*', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 
 'v', 'i', 'c', 'e', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 
 'r', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'a', 'p', 'i', '/', 'a', 'n', 'n', 'o', 
-'t', 'a', 't', 'i', 'o', 'n', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 
-'t', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 
-'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', ' ', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'r', 'e', 's', 
-'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
-'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 
-'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 
-'t', 'o', '\"', '(', '\n', '\010', 'E', 'd', 's', 'D', 'u', 'm', 'm', 'y', ':', '\034', '\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 
-'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'E', 'd', 's', 'D', 'u', 'm', 'm', 'y', '2', '\341', '\003', '\n', '\030', 'E', 
-'n', 'd', 'p', 'o', 'i', 'n', 't', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 't', 
-'\n', '\017', 'S', 't', 'r', 'e', 'a', 'm', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 
-'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 
-'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 
-'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', '}', '\n', '\016', 'D', 'e', 'l', 't', 'a', 
-'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\022', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', 
-'.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 
-'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 
-'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 
-'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', '\227', '\001', '\n', '\016', 'F', 'e', 
-'t', 'c', 'h', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 
-'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 
-'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 
-'d', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 
-'p', 'o', 'n', 's', 'e', '\"', '(', '\202', '\323', '\344', '\223', '\002', '\031', '\"', '\027', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 
-'e', 'r', 'y', ':', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\202', '\323', '\344', '\223', '\002', '\003', ':', '\001', '*', '\032', '6', '\212', 
-'\244', '\226', '\363', '\007', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 
-'i', 'n', 't', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 
-'e', 'n', 't', 'B', '@', '\n', '\'', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 
-'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', 'B', '\010', 'E', 'd', 
-'s', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\210', '\001', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 
-'o', '3', 
+'t', 'a', 't', 'i', 'o', 'n', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', ' ', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 
+'t', 'a', 't', 'i', 'o', 'n', 's', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 
+'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 
+'s', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\"', '(', '\n', '\010', 'E', 'd', 's', 'D', 'u', 'm', 'm', 'y', 
+':', '\034', '\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'E', 'd', 's', 
+'D', 'u', 'm', 'm', 'y', '2', '\341', '\003', '\n', '\030', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'D', 'i', 's', 'c', 'o', 'v', 'e', 
+'r', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 't', '\n', '\017', 'S', 't', 'r', 'e', 'a', 'm', 'E', 'n', 'd', 'p', 'o', 'i', 
+'n', 't', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 
+'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', 
+'-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 
+'.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', 
+'0', '\001', '\022', '}', '\n', '\016', 'D', 'e', 'l', 't', 'a', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\022', '1', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 
+'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '2', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', 
+'.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', 
+'(', '\001', '0', '\001', '\022', '\227', '\001', '\n', '\016', 'F', 'e', 't', 'c', 'h', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\022', ',', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 
+'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 
+'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 
+'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '(', '\202', '\323', '\344', '\223', '\002', '\031', '\"', 
+'\027', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', ':', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', '\202', 
+'\323', '\344', '\223', '\002', '\003', ':', '\001', '*', '\032', '6', '\212', '\244', '\226', '\363', '\007', '0', '\n', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '.', 'v', '3', '.', 'C', 'l', 'u', 's', 't', 'e', 'r', 
+'L', 'o', 'a', 'd', 'A', 's', 's', 'i', 'g', 'n', 'm', 'e', 'n', 't', 'B', '@', '\n', '\'', 'i', 'o', '.', 'e', 'n', 'v', 'o', 
+'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'e', 'n', 'd', 'p', 
+'o', 'i', 'n', 't', '.', 'v', '3', 'B', '\010', 'E', 'd', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\210', '\001', '\001', '\272', '\200', '\310', 
+'\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[9] = {
+static upb_def_init *deps[6] = {
   &envoy_service_discovery_v3_discovery_proto_upbdefinit,
   &google_api_annotations_proto_upbdefinit,
-  &google_protobuf_duration_proto_upbdefinit,
-  &google_protobuf_wrappers_proto_upbdefinit,
   &envoy_annotations_resource_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
   NULL
 };
 
@@ -79,5 +69,5 @@
   deps,
   layouts,
   "envoy/service/endpoint/v3/eds.proto",
-  UPB_STRVIEW_INIT(descriptor, 927)
+  UPB_STRVIEW_INIT(descriptor, 838)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/service/listener/v3/lds.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/service/listener/v3/lds.upbdefs.c
index a436513..c0a9934 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/service/listener/v3/lds.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/service/listener/v3/lds.upbdefs.c
@@ -11,66 +11,56 @@
 
 extern upb_def_init envoy_service_discovery_v3_discovery_proto_upbdefinit;
 extern upb_def_init google_api_annotations_proto_upbdefinit;
-extern upb_def_init google_protobuf_duration_proto_upbdefinit;
-extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init envoy_annotations_resource_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
 extern const upb_msglayout envoy_service_listener_v3_LdsDummy_msginit;
 
 static const upb_msglayout *layouts[1] = {
   &envoy_service_listener_v3_LdsDummy_msginit,
 };
 
-static const char descriptor[914] = {'\n', '#', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 
+static const char descriptor[825] = {'\n', '#', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', 
 'v', '3', '/', 'l', 'd', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\031', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 
 'c', 'e', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '\032', '*', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 
 'v', 'i', 'c', 'e', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 
 'r', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'a', 'p', 'i', '/', 'a', 'n', 'n', 'o', 
-'t', 'a', 't', 'i', 'o', 'n', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 
-'t', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 
-'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', ' ', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'r', 'e', 's', 
-'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 
-'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 
-'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 
-'t', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 
-'t', 'o', '\"', '(', '\n', '\010', 'L', 'd', 's', 'D', 'u', 'm', 'm', 'y', ':', '\034', '\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 
-'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'd', 's', 'D', 'u', 'm', 'm', 'y', '2', '\324', '\003', '\n', '\030', 'L', 
-'i', 's', 't', 'e', 'n', 'e', 'r', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', '}', 
-'\n', '\016', 'D', 'e', 'l', 't', 'a', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', '\022', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 
-'s', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 
-'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '2', '.', 'e', 'n', 'v', 'o', 'y', 
-'.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 
-'t', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', 
-'\022', 't', '\n', '\017', 'S', 't', 'r', 'e', 'a', 'm', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', '\022', ',', '.', 'e', 'n', 'v', 
+'t', 'a', 't', 'i', 'o', 'n', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', ' ', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 
+'t', 'a', 't', 'i', 'o', 'n', 's', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 
+'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 
+'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 
+'s', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\"', '(', '\n', '\010', 'L', 'd', 's', 'D', 'u', 'm', 'm', 'y', 
+':', '\034', '\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'L', 'd', 's', 
+'D', 'u', 'm', 'm', 'y', '2', '\324', '\003', '\n', '\030', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'D', 'i', 's', 'c', 'o', 'v', 'e', 
+'r', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', '}', '\n', '\016', 'D', 'e', 'l', 't', 'a', 'L', 'i', 's', 't', 'e', 'n', 'e', 
+'r', 's', '\022', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 
+'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 
+'e', 's', 't', '\032', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 
+'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 
+'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', 't', '\n', '\017', 'S', 't', 'r', 'e', 'a', 'm', 'L', 'i', 's', 't', 
+'e', 'n', 'e', 'r', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 
+'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 
+'t', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 
+'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', 
+'(', '\001', '0', '\001', '\022', '\227', '\001', '\n', '\016', 'F', 'e', 't', 'c', 'h', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', '\022', ',', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 
+'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 
 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 
-'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 
-'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 
-'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', '\227', '\001', '\n', '\016', 'F', 'e', 
-'t', 'c', 'h', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 
-'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 
-'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 
-'d', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 
-'p', 'o', 'n', 's', 'e', '\"', '(', '\202', '\323', '\344', '\223', '\002', '\031', '\"', '\027', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 
-'e', 'r', 'y', ':', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', '\202', '\323', '\344', '\223', '\002', '\003', ':', '\001', '*', '\032', ')', '\212', 
-'\244', '\226', '\363', '\007', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 
-'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 'B', '@', '\n', '\'', 'i', 'o', '.', 'e', 'n', 'v', 
-'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'l', 'i', 's', 
-'t', 'e', 'n', 'e', 'r', '.', 'v', '3', 'B', '\010', 'L', 'd', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\210', '\001', '\001', '\272', '\200', 
-'\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '(', '\202', '\323', '\344', '\223', '\002', '\031', '\"', 
+'\027', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', ':', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', 's', '\202', 
+'\323', '\344', '\223', '\002', '\003', ':', '\001', '*', '\032', ')', '\212', '\244', '\226', '\363', '\007', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'c', 
+'o', 'n', 'f', 'i', 'g', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', '.', 'L', 'i', 's', 't', 'e', 'n', 'e', 
+'r', 'B', '@', '\n', '\'', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'s', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '.', 'v', '3', 'B', '\010', 'L', 'd', 's', 'P', 
+'r', 'o', 't', 'o', 'P', '\001', '\210', '\001', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[9] = {
+static upb_def_init *deps[6] = {
   &envoy_service_discovery_v3_discovery_proto_upbdefinit,
   &google_api_annotations_proto_upbdefinit,
-  &google_protobuf_duration_proto_upbdefinit,
-  &google_protobuf_wrappers_proto_upbdefinit,
   &envoy_annotations_resource_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
   NULL
 };
 
@@ -78,5 +68,5 @@
   deps,
   layouts,
   "envoy/service/listener/v3/lds.proto",
-  UPB_STRVIEW_INIT(descriptor, 914)
+  UPB_STRVIEW_INIT(descriptor, 825)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c
index 24c1c59..830b398 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/service/load_stats/v3/lrs.upbdefs.c
@@ -14,7 +14,6 @@
 extern upb_def_init google_protobuf_duration_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
 extern const upb_msglayout envoy_service_load_stats_v3_LoadStatsRequest_msginit;
 extern const upb_msglayout envoy_service_load_stats_v3_LoadStatsResponse_msginit;
 
@@ -23,7 +22,7 @@
   &envoy_service_load_stats_v3_LoadStatsResponse_msginit,
 };
 
-static const char descriptor[983] = {'\n', '%', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'l', 'o', 'a', 'd', '_', 's', 't', 'a', 't', 
+static const char descriptor[958] = {'\n', '%', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'l', 'o', 'a', 'd', '_', 's', 't', 'a', 't', 
 's', '/', 'v', '3', '/', 'l', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\033', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 
 'v', 'i', 'c', 'e', '.', 'l', 'o', 'a', 'd', '_', 's', 't', 'a', 't', 's', '.', 'v', '3', '\032', '\037', 'e', 'n', 'v', 'o', 'y', 
 '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 'o', 't', 
@@ -32,8 +31,7 @@
 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 
 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 
 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 
-'s', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 
-'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\304', '\001', '\n', '\020', 'L', 'o', 
+'s', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\"', '\304', '\001', '\n', '\020', 'L', 'o', 
 'a', 'd', 'S', 't', 'a', 't', 's', 'R', 'e', 'q', 'u', 'e', 's', 't', '\022', '.', '\n', '\004', 'n', 'o', 'd', 'e', '\030', '\001', ' ', 
 '\001', '(', '\013', '2', '\032', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', 
 '3', '.', 'N', 'o', 'd', 'e', 'R', '\004', 'n', 'o', 'd', 'e', '\022', 'K', '\n', '\r', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 's', 
@@ -65,13 +63,12 @@
 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[7] = {
+static upb_def_init *deps[6] = {
   &envoy_config_core_v3_base_proto_upbdefinit,
   &envoy_config_endpoint_v3_load_report_proto_upbdefinit,
   &google_protobuf_duration_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
   NULL
 };
 
@@ -79,5 +76,5 @@
   deps,
   layouts,
   "envoy/service/load_stats/v3/lrs.proto",
-  UPB_STRVIEW_INIT(descriptor, 983)
+  UPB_STRVIEW_INIT(descriptor, 958)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c
index 5264e74..d6f9465 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.c
@@ -11,70 +11,64 @@
 
 extern upb_def_init envoy_service_discovery_v3_discovery_proto_upbdefinit;
 extern upb_def_init google_api_annotations_proto_upbdefinit;
-extern upb_def_init google_protobuf_wrappers_proto_upbdefinit;
 extern upb_def_init envoy_annotations_resource_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
 extern const upb_msglayout envoy_service_route_v3_RdsDummy_msginit;
 
 static const upb_msglayout *layouts[1] = {
   &envoy_service_route_v3_RdsDummy_msginit,
 };
 
-static const char descriptor[1071] = {'\n', ' ', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'r', 'o', 'u', 't', 'e', '/', 'v', '3', '/', 
+static const char descriptor[1014] = {'\n', ' ', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'r', 'o', 'u', 't', 'e', '/', 'v', '3', '/', 
 'r', 'd', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\026', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 
 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '\032', '*', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'd', 
 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'p', 'r', 'o', 
 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'a', 'p', 'i', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 
-'s', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 
-'w', 'r', 'a', 'p', 'p', 'e', 'r', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', ' ', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 
-'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 
-'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 
-'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 
-'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 
-'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '(', '\n', '\010', 'R', 'd', 's', 'D', 'u', 'm', 'm', 
-'y', ':', '\034', '\232', '\305', '\210', '\036', '\027', '\n', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'R', 'd', 
-'s', 'D', 'u', 'm', 'm', 'y', '2', '\314', '\003', '\n', '\025', 'R', 'o', 'u', 't', 'e', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 
-'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 'q', '\n', '\014', 'S', 't', 'r', 'e', 'a', 'm', 'R', 'o', 'u', 't', 'e', 's', '\022', ',', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 
-'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 
-'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 
-'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', 'z', '\n', 
-'\013', 'D', 'e', 'l', 't', 'a', 'R', 'o', 'u', 't', 'e', 's', '\022', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 
-'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 
-'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 
-'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 
-'s', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', '\221', '\001', '\n', 
-'\013', 'F', 'e', 't', 'c', 'h', 'R', 'o', 'u', 't', 'e', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 
+'s', '.', 'p', 'r', 'o', 't', 'o', '\032', ' ', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 
+'s', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 
+'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 
+'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 
+'g', '.', 'p', 'r', 'o', 't', 'o', '\"', '(', '\n', '\010', 'R', 'd', 's', 'D', 'u', 'm', 'm', 'y', ':', '\034', '\232', '\305', '\210', '\036', 
+'\027', '\n', '\025', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'p', 'i', '.', 'v', '2', '.', 'R', 'd', 's', 'D', 'u', 'm', 'm', 'y', '2', 
+'\314', '\003', '\n', '\025', 'R', 'o', 'u', 't', 'e', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 
+'\022', 'q', '\n', '\014', 'S', 't', 'r', 'e', 'a', 'm', 'R', 'o', 'u', 't', 'e', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'s', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 
+'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 
 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 
-'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 
-'d', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 
-'p', 'o', 'n', 's', 'e', '\"', '%', '\202', '\323', '\344', '\223', '\002', '\026', '\"', '\024', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 
-'e', 'r', 'y', ':', 'r', 'o', 'u', 't', 'e', 's', '\202', '\323', '\344', '\223', '\002', '\003', ':', '\001', '*', '\032', '0', '\212', '\244', '\226', '\363', 
-'\007', '*', '\n', '(', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 
-'.', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', '2', '\313', '\001', '\n', '\033', 'V', 
-'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 
-'e', '\022', '\200', '\001', '\n', '\021', 'D', 'e', 'l', 't', 'a', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', 's', '\022', '1', 
-'.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 
-'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', 
-'2', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 
-'.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 
-'e', '\"', '\000', '(', '\001', '0', '\001', '\032', ')', '\212', '\244', '\226', '\363', '\007', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 
-'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', 
-'B', '=', '\n', '$', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 
-'e', 'r', 'v', 'i', 'c', 'e', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', 'B', '\010', 'R', 'd', 's', 'P', 'r', 'o', 't', 'o', 
-'P', '\001', '\210', '\001', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', 'z', '\n', '\013', 'D', 'e', 'l', 't', 'a', 'R', 
+'o', 'u', 't', 'e', 's', '\022', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 
+'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 
+'e', 'q', 'u', 'e', 's', 't', '\032', '2', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 
+'s', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 
+'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', '\221', '\001', '\n', '\013', 'F', 'e', 't', 'c', 'h', 'R', 
+'o', 'u', 't', 'e', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 
+'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 
+'t', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 
+'r', 'y', '.', 'v', '3', '.', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '%', 
+'\202', '\323', '\344', '\223', '\002', '\026', '\"', '\024', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', ':', 'r', 'o', 'u', 
+'t', 'e', 's', '\202', '\323', '\344', '\223', '\002', '\003', ':', '\001', '*', '\032', '0', '\212', '\244', '\226', '\363', '\007', '*', '\n', '(', 'e', 'n', 'v', 
+'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 'u', 't', 'e', '.', 'v', '3', '.', 'R', 'o', 'u', 't', 'e', 'C', 
+'o', 'n', 'f', 'i', 'g', 'u', 'r', 'a', 't', 'i', 'o', 'n', '2', '\313', '\001', '\n', '\033', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 
+'o', 's', 't', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', '\200', '\001', '\n', '\021', 'D', 
+'e', 'l', 't', 'a', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', 's', '\022', '1', '.', 'e', 'n', 'v', 'o', 'y', '.', 
+'s', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 't', 
+'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '2', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'v', '3', '.', 'D', 'e', 'l', 
+'t', 'a', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', 
+'\032', ')', '\212', '\244', '\226', '\363', '\007', '#', '\n', '!', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'r', 'o', 
+'u', 't', 'e', '.', 'v', '3', '.', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'H', 'o', 's', 't', 'B', '=', '\n', '$', 'i', 'o', '.', 
+'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 
+'r', 'o', 'u', 't', 'e', '.', 'v', '3', 'B', '\010', 'R', 'd', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\210', '\001', '\001', '\272', '\200', 
+'\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[8] = {
+static upb_def_init *deps[6] = {
   &envoy_service_discovery_v3_discovery_proto_upbdefinit,
   &google_api_annotations_proto_upbdefinit,
-  &google_protobuf_wrappers_proto_upbdefinit,
   &envoy_annotations_resource_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
   NULL
 };
 
@@ -82,5 +76,5 @@
   deps,
   layouts,
   "envoy/service/route/v3/rds.proto",
-  UPB_STRVIEW_INIT(descriptor, 1071)
+  UPB_STRVIEW_INIT(descriptor, 1014)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c
new file mode 100644
index 0000000..2673ebb
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c
@@ -0,0 +1,130 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/service/status/v3/csds.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/service/status/v3/csds.upbdefs.h"
+
+extern upb_def_init envoy_admin_v3_config_dump_proto_upbdefinit;
+extern upb_def_init envoy_config_core_v3_base_proto_upbdefinit;
+extern upb_def_init envoy_type_matcher_v3_node_proto_upbdefinit;
+extern upb_def_init google_api_annotations_proto_upbdefinit;
+extern upb_def_init udpa_annotations_migrate_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern const upb_msglayout envoy_service_status_v3_ClientStatusRequest_msginit;
+extern const upb_msglayout envoy_service_status_v3_PerXdsConfig_msginit;
+extern const upb_msglayout envoy_service_status_v3_ClientConfig_msginit;
+extern const upb_msglayout envoy_service_status_v3_ClientStatusResponse_msginit;
+
+static const upb_msglayout *layouts[4] = {
+  &envoy_service_status_v3_ClientStatusRequest_msginit,
+  &envoy_service_status_v3_PerXdsConfig_msginit,
+  &envoy_service_status_v3_ClientConfig_msginit,
+  &envoy_service_status_v3_ClientStatusResponse_msginit,
+};
+
+static const char descriptor[2001] = {'\n', '\"', 'e', 'n', 'v', 'o', 'y', '/', 's', 'e', 'r', 'v', 'i', 'c', 'e', '/', 's', 't', 'a', 't', 'u', 's', '/', 'v', '3', 
+'/', 'c', 's', 'd', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\027', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 
+'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', '\032', ' ', 'e', 'n', 'v', 'o', 'y', '/', 'a', 'd', 'm', 'i', 'n', '/', 
+'v', '3', '/', 'c', 'o', 'n', 'f', 'i', 'g', '_', 'd', 'u', 'm', 'p', '.', 'p', 'r', 'o', 't', 'o', '\032', '\037', 'e', 'n', 'v', 
+'o', 'y', '/', 'c', 'o', 'n', 'f', 'i', 'g', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'b', 'a', 's', 'e', '.', 'p', 'r', 
+'o', 't', 'o', '\032', ' ', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 'e', 'r', '/', 'v', 
+'3', '/', 'n', 'o', 'd', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'a', 'p', 'i', '/', 
+'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'u', 'd', 'p', 'a', '/', 'a', 
+'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'm', 'i', 'g', 'r', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', 
+'\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 
+'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 
+'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\"', '\302', '\001', '\n', '\023', 'C', 'l', 'i', 'e', 'n', 
+'t', 'S', 't', 'a', 't', 'u', 's', 'R', 'e', 'q', 'u', 'e', 's', 't', '\022', 'G', '\n', '\r', 'n', 'o', 'd', 'e', '_', 'm', 'a', 
+'t', 'c', 'h', 'e', 'r', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', 
+'.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'N', 'o', 'd', 'e', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\014', 
+'n', 'o', 'd', 'e', 'M', 'a', 't', 'c', 'h', 'e', 'r', 's', '\022', '.', '\n', '\004', 'n', 'o', 'd', 'e', '\030', '\002', ' ', '\001', '(', 
+'\013', '2', '\032', '.', 'e', 'n', 'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 
+'N', 'o', 'd', 'e', 'R', '\004', 'n', 'o', 'd', 'e', ':', '2', '\232', '\305', '\210', '\036', '-', '\n', '+', 'e', 'n', 'v', 'o', 'y', '.', 
+'s', 'e', 'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '2', '.', 'C', 'l', 'i', 'e', 'n', 't', 'S', 
+'t', 'a', 't', 'u', 's', 'R', 'e', 'q', 'u', 'e', 's', 't', '\"', '\360', '\004', '\n', '\014', 'P', 'e', 'r', 'X', 'd', 's', 'C', 'o', 
+'n', 'f', 'i', 'g', '\022', '=', '\n', '\006', 's', 't', 'a', 't', 'u', 's', '\030', '\001', ' ', '\001', '(', '\016', '2', '%', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', '.', 'C', 'o', 'n', 
+'f', 'i', 'g', 'S', 't', 'a', 't', 'u', 's', 'R', '\006', 's', 't', 'a', 't', 'u', 's', '\022', 'T', '\n', '\r', 'c', 'l', 'i', 'e', 
+'n', 't', '_', 's', 't', 'a', 't', 'u', 's', '\030', '\007', ' ', '\001', '(', '\016', '2', '+', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 
+'e', 'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'o', 
+'n', 'f', 'i', 'g', 'S', 't', 'a', 't', 'u', 's', 'B', '\002', '\030', '\001', 'R', '\014', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 
+'t', 'u', 's', '\022', 'N', '\n', '\017', 'l', 'i', 's', 't', 'e', 'n', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', 
+'\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'L', 'i', 's', 't', 
+'e', 'n', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', 'H', '\000', 'R', '\016', 'l', 'i', 's', 't', 'e', 'n', 
+'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'K', '\n', '\016', 'c', 'l', 'u', 's', 't', 'e', 'r', '_', 'c', 'o', 'n', 'f', 'i', 
+'g', '\030', '\003', ' ', '\001', '(', '\013', '2', '\"', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 
+'C', 'l', 'u', 's', 't', 'e', 'r', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', 'H', '\000', 'R', '\r', 'c', 'l', 'u', 
+'s', 't', 'e', 'r', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'E', '\n', '\014', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 'n', 'f', 'i', 
+'g', '\030', '\004', ' ', '\001', '(', '\013', '2', ' ', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 
+'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', 'H', '\000', 'R', '\013', 'r', 'o', 'u', 't', 'e', 
+'C', 'o', 'n', 'f', 'i', 'g', '\022', 'X', '\n', '\023', 's', 'c', 'o', 'p', 'e', 'd', '_', 'r', 'o', 'u', 't', 'e', '_', 'c', 'o', 
+'n', 'f', 'i', 'g', '\030', '\005', ' ', '\001', '(', '\013', '2', '&', '.', 'e', 'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 
+'v', '3', '.', 'S', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', 
+'H', '\000', 'R', '\021', 's', 'c', 'o', 'p', 'e', 'd', 'R', 'o', 'u', 't', 'e', 'C', 'o', 'n', 'f', 'i', 'g', '\022', 'N', '\n', '\017', 
+'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\006', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 'a', 'd', 'm', 'i', 'n', '.', 'v', '3', '.', 'E', 'n', 'd', 'p', 'o', 'i', 'n', 't', 's', 'C', 'o', 
+'n', 'f', 'i', 'g', 'D', 'u', 'm', 'p', 'H', '\000', 'R', '\016', 'e', 'n', 'd', 'p', 'o', 'i', 'n', 't', 'C', 'o', 'n', 'f', 'i', 
+'g', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 's', 
+'t', 'a', 't', 'u', 's', '.', 'v', '2', '.', 'P', 'e', 'r', 'X', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'B', '\020', '\n', '\016', 
+'p', 'e', 'r', '_', 'x', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\"', '\261', '\001', '\n', '\014', 'C', 'l', 'i', 'e', 'n', 't', 
+'C', 'o', 'n', 'f', 'i', 'g', '\022', '.', '\n', '\004', 'n', 'o', 'd', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 'e', 'n', 
+'v', 'o', 'y', '.', 'c', 'o', 'n', 'f', 'i', 'g', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'N', 'o', 'd', 'e', 'R', '\004', 
+'n', 'o', 'd', 'e', '\022', 'D', '\n', '\n', 'x', 'd', 's', '_', 'c', 'o', 'n', 'f', 'i', 'g', '\030', '\002', ' ', '\003', '(', '\013', '2', 
+'%', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', 
+'.', 'P', 'e', 'r', 'X', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', 'R', '\t', 'x', 'd', 's', 'C', 'o', 'n', 'f', 'i', 'g', ':', 
+'+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 
+'t', 'u', 's', '.', 'v', '2', '.', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', '\"', '\212', '\001', '\n', '\024', 'C', 
+'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\022', '=', '\n', '\006', 'c', 'o', 
+'n', 'f', 'i', 'g', '\030', '\001', ' ', '\003', '(', '\013', '2', '%', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 
+'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'o', 'n', 'f', 'i', 'g', 'R', 
+'\006', 'c', 'o', 'n', 'f', 'i', 'g', ':', '3', '\232', '\305', '\210', '\036', '.', '\n', ',', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 
+'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '2', '.', 'C', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 
+'u', 's', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '*', 'K', '\n', '\014', 'C', 'o', 'n', 'f', 'i', 'g', 'S', 't', 'a', 't', 'u', 
+'s', '\022', '\013', '\n', '\007', 'U', 'N', 'K', 'N', 'O', 'W', 'N', '\020', '\000', '\022', '\n', '\n', '\006', 'S', 'Y', 'N', 'C', 'E', 'D', '\020', 
+'\001', '\022', '\014', '\n', '\010', 'N', 'O', 'T', '_', 'S', 'E', 'N', 'T', '\020', '\002', '\022', '\t', '\n', '\005', 'S', 'T', 'A', 'L', 'E', '\020', 
+'\003', '\022', '\t', '\n', '\005', 'E', 'R', 'R', 'O', 'R', '\020', '\004', '*', 'c', '\n', '\022', 'C', 'l', 'i', 'e', 'n', 't', 'C', 'o', 'n', 
+'f', 'i', 'g', 'S', 't', 'a', 't', 'u', 's', '\022', '\022', '\n', '\016', 'C', 'L', 'I', 'E', 'N', 'T', '_', 'U', 'N', 'K', 'N', 'O', 
+'W', 'N', '\020', '\000', '\022', '\024', '\n', '\020', 'C', 'L', 'I', 'E', 'N', 'T', '_', 'R', 'E', 'Q', 'U', 'E', 'S', 'T', 'E', 'D', '\020', 
+'\001', '\022', '\020', '\n', '\014', 'C', 'L', 'I', 'E', 'N', 'T', '_', 'A', 'C', 'K', 'E', 'D', '\020', '\002', '\022', '\021', '\n', '\r', 'C', 'L', 
+'I', 'E', 'N', 'T', '_', 'N', 'A', 'C', 'K', 'E', 'D', '\020', '\003', '2', '\270', '\002', '\n', '\034', 'C', 'l', 'i', 'e', 'n', 't', 'S', 
+'t', 'a', 't', 'u', 's', 'D', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 'w', '\n', '\022', 
+'S', 't', 'r', 'e', 'a', 'm', 'C', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 
+'t', 'S', 't', 'a', 't', 'u', 's', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 
+'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 
+'t', 'u', 's', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', '\"', '\000', '(', '\001', '0', '\001', '\022', '\236', '\001', '\n', '\021', 'F', 'e', 't', 
+'c', 'h', 'C', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', '\022', ',', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 
+'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 
+'t', 'u', 's', 'R', 'e', 'q', 'u', 'e', 's', 't', '\032', '-', '.', 'e', 'n', 'v', 'o', 'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 
+'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', '.', 'C', 'l', 'i', 'e', 'n', 't', 'S', 't', 'a', 't', 'u', 's', 'R', 
+'e', 's', 'p', 'o', 'n', 's', 'e', '\"', ',', '\202', '\323', '\344', '\223', '\002', '\035', '\"', '\033', '/', 'v', '3', '/', 'd', 'i', 's', 'c', 
+'o', 'v', 'e', 'r', 'y', ':', 'c', 'l', 'i', 'e', 'n', 't', '_', 's', 't', 'a', 't', 'u', 's', '\202', '\323', '\344', '\223', '\002', '\003', 
+':', '\001', '*', 'B', '?', '\n', '%', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 
+'y', '.', 's', 'e', 'r', 'v', 'i', 'c', 'e', '.', 's', 't', 'a', 't', 'u', 's', '.', 'v', '3', 'B', '\t', 'C', 's', 'd', 's', 
+'P', 'r', 'o', 't', 'o', 'P', '\001', '\210', '\001', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', 
+'3', 
+};
+
+static upb_def_init *deps[8] = {
+  &envoy_admin_v3_config_dump_proto_upbdefinit,
+  &envoy_config_core_v3_base_proto_upbdefinit,
+  &envoy_type_matcher_v3_node_proto_upbdefinit,
+  &google_api_annotations_proto_upbdefinit,
+  &udpa_annotations_migrate_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_service_status_v3_csds_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/service/status/v3/csds.proto",
+  UPB_STRVIEW_INIT(descriptor, 2001)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h
new file mode 100644
index 0000000..91723cc
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h
@@ -0,0 +1,50 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/service/status/v3/csds.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_SERVICE_STATUS_V3_CSDS_PROTO_UPBDEFS_H_
+#define ENVOY_SERVICE_STATUS_V3_CSDS_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_service_status_v3_csds_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_service_status_v3_ClientStatusRequest_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_service_status_v3_csds_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.service.status.v3.ClientStatusRequest");
+}
+
+UPB_INLINE const upb_msgdef *envoy_service_status_v3_PerXdsConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_service_status_v3_csds_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.service.status.v3.PerXdsConfig");
+}
+
+UPB_INLINE const upb_msgdef *envoy_service_status_v3_ClientConfig_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_service_status_v3_csds_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.service.status.v3.ClientConfig");
+}
+
+UPB_INLINE const upb_msgdef *envoy_service_status_v3_ClientStatusResponse_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_service_status_v3_csds_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.service.status.v3.ClientStatusResponse");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_SERVICE_STATUS_V3_CSDS_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c
new file mode 100644
index 0000000..8b0ecb5
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c
@@ -0,0 +1,56 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/type/matcher/v3/node.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/type/matcher/v3/node.upbdefs.h"
+
+extern upb_def_init envoy_type_matcher_v3_string_proto_upbdefinit;
+extern upb_def_init envoy_type_matcher_v3_struct_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern const upb_msglayout envoy_type_matcher_v3_NodeMatcher_msginit;
+
+static const upb_msglayout *layouts[1] = {
+  &envoy_type_matcher_v3_NodeMatcher_msginit,
+};
+
+static const char descriptor[458] = {'\n', ' ', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 'e', 'r', '/', 'v', '3', '/', 'n', 
+'o', 'd', 'e', '.', 'p', 'r', 'o', 't', 'o', '\022', '\025', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 
+'c', 'h', 'e', 'r', '.', 'v', '3', '\032', '\"', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 
+'e', 'r', '/', 'v', '3', '/', 's', 't', 'r', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\"', 'e', 'n', 'v', 'o', 'y', 
+'/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 'e', 'r', '/', 'v', '3', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 
+'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 
+'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 
+'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\"', '\300', '\001', '\n', '\013', 
+'N', 'o', 'd', 'e', 'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', '=', '\n', '\007', 'n', 'o', 'd', 'e', '_', 'i', 'd', '\030', '\001', ' ', 
+'\001', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 
+'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\006', 'n', 'o', 'd', 'e', 'I', 'd', '\022', 
+'K', '\n', '\016', 'n', 'o', 'd', 'e', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '$', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 
+'r', 'u', 'c', 't', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'R', '\r', 'n', 'o', 'd', 'e', 'M', 'e', 't', 'a', 'd', 'a', 't', 'a', 
+'s', ':', '%', '\232', '\305', '\210', '\036', ' ', '\n', '\036', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 
+'h', 'e', 'r', '.', 'N', 'o', 'd', 'e', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', ':', '\n', '#', 'i', 'o', '.', 'e', 'n', 'v', 
+'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 
+'r', '.', 'v', '3', 'B', '\t', 'N', 'o', 'd', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 
+'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[5] = {
+  &envoy_type_matcher_v3_string_proto_upbdefinit,
+  &envoy_type_matcher_v3_struct_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_type_matcher_v3_node_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/type/matcher/v3/node.proto",
+  UPB_STRVIEW_INIT(descriptor, 458)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h
new file mode 100644
index 0000000..9ec4a6d
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h
@@ -0,0 +1,35 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/type/matcher/v3/node.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_TYPE_MATCHER_V3_NODE_PROTO_UPBDEFS_H_
+#define ENVOY_TYPE_MATCHER_V3_NODE_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_type_matcher_v3_node_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_type_matcher_v3_NodeMatcher_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_type_matcher_v3_node_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.type.matcher.v3.NodeMatcher");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_TYPE_MATCHER_V3_NODE_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c
index 6090152..4844b10 100644
--- a/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c
@@ -10,7 +10,6 @@
 #include "envoy/type/matcher/v3/string.upbdefs.h"
 
 extern upb_def_init envoy_type_matcher_v3_regex_proto_upbdefinit;
-extern upb_def_init envoy_annotations_deprecation_proto_upbdefinit;
 extern upb_def_init udpa_annotations_status_proto_upbdefinit;
 extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
 extern upb_def_init validate_validate_proto_upbdefinit;
@@ -22,42 +21,40 @@
   &envoy_type_matcher_v3_ListStringMatcher_msginit,
 };
 
-static const char descriptor[775] = {'\n', '\"', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 'e', 'r', '/', 'v', '3', '/', 's', 
+static const char descriptor[738] = {'\n', '\"', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 'e', 'r', '/', 'v', '3', '/', 's', 
 't', 'r', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\022', '\025', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 
 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '\032', '!', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 
-'c', 'h', 'e', 'r', '/', 'v', '3', '/', 'r', 'e', 'g', 'e', 'x', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'e', 'n', 'v', 'o', 
-'y', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'i', 'o', 'n', 
-'.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 
-'s', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 
-'t', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 
-'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\321', '\002', 
-'\n', '\r', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', '\026', '\n', '\005', 'e', 'x', 'a', 'c', 't', '\030', 
-'\001', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\005', 'e', 'x', 'a', 'c', 't', '\022', '!', '\n', '\006', 'p', 'r', 'e', 'f', 'i', 'x', '\030', 
-'\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\006', 'p', 'r', 'e', 'f', 'i', 'x', '\022', 
-'!', '\n', '\006', 's', 'u', 'f', 'f', 'i', 'x', '\030', '\003', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', 
-'\000', 'R', '\006', 's', 'u', 'f', 'f', 'i', 'x', '\022', 'N', '\n', '\n', 's', 'a', 'f', 'e', '_', 'r', 'e', 'g', 'e', 'x', '\030', '\005', 
-' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', 
-'.', 'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', 
-'\001', 'H', '\000', 'R', '\t', 's', 'a', 'f', 'e', 'R', 'e', 'g', 'e', 'x', '\022', '%', '\n', '\010', 'c', 'o', 'n', 't', 'a', 'i', 'n', 
-'s', '\030', '\007', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\010', 'c', 'o', 'n', 't', 'a', 
-'i', 'n', 's', '\022', '\037', '\n', '\013', 'i', 'g', 'n', 'o', 'r', 'e', '_', 'c', 'a', 's', 'e', '\030', '\006', ' ', '\001', '(', '\010', 'R', 
-'\n', 'i', 'g', 'n', 'o', 'r', 'e', 'C', 'a', 's', 'e', ':', '\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 'e', 'n', 'v', 'o', 'y', 
-'.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 
-'e', 'r', 'B', '\024', '\n', '\r', 'm', 'a', 't', 'c', 'h', '_', 'p', 'a', 't', 't', 'e', 'r', 'n', '\022', '\003', '\370', 'B', '\001', 'J', 
-'\004', '\010', '\004', '\020', '\005', 'R', '\005', 'r', 'e', 'g', 'e', 'x', '\"', '\214', '\001', '\n', '\021', 'L', 'i', 's', 't', 'S', 't', 'r', 'i', 
-'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', 'J', '\n', '\010', 'p', 'a', 't', 't', 'e', 'r', 'n', 's', '\030', '\001', ' ', '\003', 
-'(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', 
-'3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 
-'R', '\010', 'p', 'a', 't', 't', 'e', 'r', 'n', 's', ':', '+', '\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 
-'t', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'L', 'i', 's', 't', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 
-'t', 'c', 'h', 'e', 'r', 'B', '<', '\n', '#', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 
-'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', 'B', '\013', 'S', 't', 'r', 'i', 
-'n', 'g', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+'c', 'h', 'e', 'r', '/', 'v', '3', '/', 'r', 'e', 'g', 'e', 'x', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', 
+'/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', 
+'\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 
+'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 
+'d', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\321', '\002', '\n', '\r', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 
+'h', 'e', 'r', '\022', '\026', '\n', '\005', 'e', 'x', 'a', 'c', 't', '\030', '\001', ' ', '\001', '(', '\t', 'H', '\000', 'R', '\005', 'e', 'x', 'a', 
+'c', 't', '\022', '!', '\n', '\006', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', 
+'\020', '\001', 'H', '\000', 'R', '\006', 'p', 'r', 'e', 'f', 'i', 'x', '\022', '!', '\n', '\006', 's', 'u', 'f', 'f', 'i', 'x', '\030', '\003', ' ', 
+'\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\006', 's', 'u', 'f', 'f', 'i', 'x', '\022', 'N', '\n', 
+'\n', 's', 'a', 'f', 'e', '_', 'r', 'e', 'g', 'e', 'x', '\030', '\005', ' ', '\001', '(', '\013', '2', '#', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'R', 'e', 'g', 'e', 'x', 'M', 'a', 't', 
+'c', 'h', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'H', '\000', 'R', '\t', 's', 'a', 'f', 'e', 'R', 'e', 'g', 
+'e', 'x', '\022', '%', '\n', '\010', 'c', 'o', 'n', 't', 'a', 'i', 'n', 's', '\030', '\007', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 
+'r', '\002', '\020', '\001', 'H', '\000', 'R', '\010', 'c', 'o', 'n', 't', 'a', 'i', 'n', 's', '\022', '\037', '\n', '\013', 'i', 'g', 'n', 'o', 'r', 
+'e', '_', 'c', 'a', 's', 'e', '\030', '\006', ' ', '\001', '(', '\010', 'R', '\n', 'i', 'g', 'n', 'o', 'r', 'e', 'C', 'a', 's', 'e', ':', 
+'\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 
+'r', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\024', '\n', '\r', 'm', 'a', 't', 'c', 'h', '_', 
+'p', 'a', 't', 't', 'e', 'r', 'n', '\022', '\003', '\370', 'B', '\001', 'J', '\004', '\010', '\004', '\020', '\005', 'R', '\005', 'r', 'e', 'g', 'e', 'x', 
+'\"', '\214', '\001', '\n', '\021', 'L', 'i', 's', 't', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', '\022', 'J', '\n', 
+'\010', 'p', 'a', 't', 't', 'e', 'r', 'n', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '$', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 
+'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 
+'h', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', '\010', '\001', 'R', '\010', 'p', 'a', 't', 't', 'e', 'r', 'n', 's', ':', '+', 
+'\232', '\305', '\210', '\036', '&', '\n', '$', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', 
+'.', 'L', 'i', 's', 't', 'S', 't', 'r', 'i', 'n', 'g', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '<', '\n', '#', 'i', 'o', '.', 
+'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 
+'c', 'h', 'e', 'r', '.', 'v', '3', 'B', '\013', 'S', 't', 'r', 'i', 'n', 'g', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', 
+'\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
-static upb_def_init *deps[6] = {
+static upb_def_init *deps[5] = {
   &envoy_type_matcher_v3_regex_proto_upbdefinit,
-  &envoy_annotations_deprecation_proto_upbdefinit,
   &udpa_annotations_status_proto_upbdefinit,
   &udpa_annotations_versioning_proto_upbdefinit,
   &validate_validate_proto_upbdefinit,
@@ -68,5 +65,5 @@
   deps,
   layouts,
   "envoy/type/matcher/v3/string.proto",
-  UPB_STRVIEW_INIT(descriptor, 775)
+  UPB_STRVIEW_INIT(descriptor, 738)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c
new file mode 100644
index 0000000..6660ffa
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c
@@ -0,0 +1,63 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/type/matcher/v3/struct.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "envoy/type/matcher/v3/struct.upbdefs.h"
+
+extern upb_def_init envoy_type_matcher_v3_value_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init udpa_annotations_versioning_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout envoy_type_matcher_v3_StructMatcher_msginit;
+extern const upb_msglayout envoy_type_matcher_v3_StructMatcher_PathSegment_msginit;
+
+static const upb_msglayout *layouts[2] = {
+  &envoy_type_matcher_v3_StructMatcher_msginit,
+  &envoy_type_matcher_v3_StructMatcher_PathSegment_msginit,
+};
+
+static const char descriptor[576] = {'\n', '\"', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 'c', 'h', 'e', 'r', '/', 'v', '3', '/', 's', 
+'t', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\022', '\025', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 
+'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '\032', '!', 'e', 'n', 'v', 'o', 'y', '/', 't', 'y', 'p', 'e', '/', 'm', 'a', 't', 
+'c', 'h', 'e', 'r', '/', 'v', '3', '/', 'v', 'a', 'l', 'u', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', 
+'/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', 
+'\032', '!', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 'v', 'e', 'r', 's', 'i', 'o', 
+'n', 'i', 'n', 'g', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 
+'d', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\276', '\002', '\n', '\r', 'S', 't', 'r', 'u', 'c', 't', 'M', 'a', 't', 'c', 
+'h', 'e', 'r', '\022', 'N', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\002', ' ', '\003', '(', '\013', '2', '0', '.', 'e', 'n', 'v', 'o', 'y', 
+'.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'S', 't', 'r', 'u', 'c', 't', 'M', 'a', 
+'t', 'c', 'h', 'e', 'r', '.', 'P', 'a', 't', 'h', 'S', 'e', 'g', 'm', 'e', 'n', 't', 'B', '\010', '\372', 'B', '\005', '\222', '\001', '\002', 
+'\010', '\001', 'R', '\004', 'p', 'a', 't', 'h', '\022', 'C', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', '#', 
+'.', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', '.', 'V', 'a', 
+'l', 'u', 'e', 'M', 'a', 't', 'c', 'h', 'e', 'r', 'B', '\010', '\372', 'B', '\005', '\212', '\001', '\002', '\020', '\001', 'R', '\005', 'v', 'a', 'l', 
+'u', 'e', '\032', 'o', '\n', '\013', 'P', 'a', 't', 'h', 'S', 'e', 'g', 'm', 'e', 'n', 't', '\022', '\033', '\n', '\003', 'k', 'e', 'y', '\030', 
+'\001', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'H', '\000', 'R', '\003', 'k', 'e', 'y', ':', '3', '\232', '\305', 
+'\210', '\036', '.', '\n', ',', 'e', 'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'S', 
+'t', 'r', 'u', 'c', 't', 'M', 'a', 't', 'c', 'h', 'e', 'r', '.', 'P', 'a', 't', 'h', 'S', 'e', 'g', 'm', 'e', 'n', 't', 'B', 
+'\016', '\n', '\007', 's', 'e', 'g', 'm', 'e', 'n', 't', '\022', '\003', '\370', 'B', '\001', ':', '\'', '\232', '\305', '\210', '\036', '\"', '\n', ' ', 'e', 
+'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'S', 't', 'r', 'u', 'c', 't', 'M', 
+'a', 't', 'c', 'h', 'e', 'r', 'B', '<', '\n', '#', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'e', 
+'n', 'v', 'o', 'y', '.', 't', 'y', 'p', 'e', '.', 'm', 'a', 't', 'c', 'h', 'e', 'r', '.', 'v', '3', 'B', '\013', 'S', 't', 'r', 
+'u', 'c', 't', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\020', '\002', 'b', '\006', 'p', 'r', 'o', 't', 'o', 
+'3', 
+};
+
+static upb_def_init *deps[5] = {
+  &envoy_type_matcher_v3_value_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &udpa_annotations_versioning_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init envoy_type_matcher_v3_struct_proto_upbdefinit = {
+  deps,
+  layouts,
+  "envoy/type/matcher/v3/struct.proto",
+  UPB_STRVIEW_INIT(descriptor, 576)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h
new file mode 100644
index 0000000..472d486
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h
@@ -0,0 +1,40 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     envoy/type/matcher/v3/struct.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef ENVOY_TYPE_MATCHER_V3_STRUCT_PROTO_UPBDEFS_H_
+#define ENVOY_TYPE_MATCHER_V3_STRUCT_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init envoy_type_matcher_v3_struct_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *envoy_type_matcher_v3_StructMatcher_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_type_matcher_v3_struct_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.type.matcher.v3.StructMatcher");
+}
+
+UPB_INLINE const upb_msgdef *envoy_type_matcher_v3_StructMatcher_PathSegment_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &envoy_type_matcher_v3_struct_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "envoy.type.matcher.v3.StructMatcher.PathSegment");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* ENVOY_TYPE_MATCHER_V3_STRUCT_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/google/api/expr/v1alpha1/syntax.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/google/api/expr/v1alpha1/syntax.upbdefs.c
index d44ccca..3ad38ed 100644
--- a/grpc/src/core/ext/upbdefs-generated/google/api/expr/v1alpha1/syntax.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/google/api/expr/v1alpha1/syntax.upbdefs.c
@@ -24,9 +24,10 @@
 extern const upb_msglayout google_api_expr_v1alpha1_Constant_msginit;
 extern const upb_msglayout google_api_expr_v1alpha1_SourceInfo_msginit;
 extern const upb_msglayout google_api_expr_v1alpha1_SourceInfo_PositionsEntry_msginit;
+extern const upb_msglayout google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_msginit;
 extern const upb_msglayout google_api_expr_v1alpha1_SourcePosition_msginit;
 
-static const upb_msglayout *layouts[13] = {
+static const upb_msglayout *layouts[14] = {
   &google_api_expr_v1alpha1_ParsedExpr_msginit,
   &google_api_expr_v1alpha1_Expr_msginit,
   &google_api_expr_v1alpha1_Expr_Ident_msginit,
@@ -39,10 +40,11 @@
   &google_api_expr_v1alpha1_Constant_msginit,
   &google_api_expr_v1alpha1_SourceInfo_msginit,
   &google_api_expr_v1alpha1_SourceInfo_PositionsEntry_msginit,
+  &google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_msginit,
   &google_api_expr_v1alpha1_SourcePosition_msginit,
 };
 
-static const char descriptor[2877] = {'\n', '%', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'a', 'p', 'i', '/', 'e', 'x', 'p', 'r', '/', 'v', '1', 'a', 'l', 'p', 'h', 'a', 
+static const char descriptor[3059] = {'\n', '%', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'a', 'p', 'i', '/', 'e', 'x', 'p', 'r', '/', 'v', '1', 'a', 'l', 'p', 'h', 'a', 
 '1', '/', 's', 'y', 'n', 't', 'a', 'x', '.', 'p', 'r', 'o', 't', 'o', '\022', '\030', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'a', 'p', 
 'i', '.', 'e', 'x', 'p', 'r', '.', 'v', '1', 'a', 'l', 'p', 'h', 'a', '1', '\032', '\036', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 
 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 
@@ -137,7 +139,7 @@
 'm', 'p', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\t', ' ', '\001', '(', '\013', '2', '\032', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 
 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'T', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'B', '\002', '\030', '\001', 'H', '\000', 'R', '\016', 
 't', 'i', 'm', 'e', 's', 't', 'a', 'm', 'p', 'V', 'a', 'l', 'u', 'e', 'B', '\017', '\n', '\r', 'c', 'o', 'n', 's', 't', 'a', 'n', 
-'t', '_', 'k', 'i', 'n', 'd', '\"', '\203', '\002', '\n', '\n', 'S', 'o', 'u', 'r', 'c', 'e', 'I', 'n', 'f', 'o', '\022', '%', '\n', '\016', 
+'t', '_', 'k', 'i', 'n', 'd', '\"', '\271', '\003', '\n', '\n', 'S', 'o', 'u', 'r', 'c', 'e', 'I', 'n', 'f', 'o', '\022', '%', '\n', '\016', 
 's', 'y', 'n', 't', 'a', 'x', '_', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\r', 's', 'y', 'n', 
 't', 'a', 'x', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\022', '\032', '\n', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\030', '\002', ' ', 
 '\001', '(', '\t', 'R', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\022', '!', '\n', '\014', 'l', 'i', 'n', 'e', '_', 'o', 'f', 'f', 
@@ -145,19 +147,26 @@
 '\n', '\t', 'p', 'o', 's', 'i', 't', 'i', 'o', 'n', 's', '\030', '\004', ' ', '\003', '(', '\013', '2', '3', '.', 'g', 'o', 'o', 'g', 'l', 
 'e', '.', 'a', 'p', 'i', '.', 'e', 'x', 'p', 'r', '.', 'v', '1', 'a', 'l', 'p', 'h', 'a', '1', '.', 'S', 'o', 'u', 'r', 'c', 
 'e', 'I', 'n', 'f', 'o', '.', 'P', 'o', 's', 'i', 't', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', 'R', '\t', 'p', 'o', 's', 
-'i', 't', 'i', 'o', 'n', 's', '\032', '<', '\n', '\016', 'P', 'o', 's', 'i', 't', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', '\022', 
-'\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\003', 'R', '\003', 'k', 'e', 'y', '\022', '\024', '\n', '\005', 'v', 'a', 'l', 'u', 
-'e', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', '\"', 'p', '\n', '\016', 'S', 'o', 'u', 
-'r', 'c', 'e', 'P', 'o', 's', 'i', 't', 'i', 'o', 'n', '\022', '\032', '\n', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\030', '\001', 
-' ', '\001', '(', '\t', 'R', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\006', 'o', 'f', 'f', 's', 'e', 't', '\030', 
-'\002', ' ', '\001', '(', '\005', 'R', '\006', 'o', 'f', 'f', 's', 'e', 't', '\022', '\022', '\n', '\004', 'l', 'i', 'n', 'e', '\030', '\003', ' ', '\001', 
-'(', '\005', 'R', '\004', 'l', 'i', 'n', 'e', '\022', '\026', '\n', '\006', 'c', 'o', 'l', 'u', 'm', 'n', '\030', '\004', ' ', '\001', '(', '\005', 'R', 
-'\006', 'c', 'o', 'l', 'u', 'm', 'n', 'B', 'n', '\n', '\034', 'c', 'o', 'm', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'a', 'p', 'i', 
-'.', 'e', 'x', 'p', 'r', '.', 'v', '1', 'a', 'l', 'p', 'h', 'a', '1', 'B', '\013', 'S', 'y', 'n', 't', 'a', 'x', 'P', 'r', 'o', 
-'t', 'o', 'P', '\001', 'Z', '<', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'g', 'o', 'l', 'a', 'n', 'g', '.', 'o', 'r', 'g', '/', 'g', 
-'e', 'n', 'p', 'r', 'o', 't', 'o', '/', 'g', 'o', 'o', 'g', 'l', 'e', 'a', 'p', 'i', 's', '/', 'a', 'p', 'i', '/', 'e', 'x', 
-'p', 'r', '/', 'v', '1', 'a', 'l', 'p', 'h', 'a', '1', ';', 'e', 'x', 'p', 'r', '\370', '\001', '\001', 'b', '\006', 'p', 'r', 'o', 't', 
-'o', '3', 
+'i', 't', 'i', 'o', 'n', 's', '\022', 'U', '\n', '\013', 'm', 'a', 'c', 'r', 'o', '_', 'c', 'a', 'l', 'l', 's', '\030', '\005', ' ', '\003', 
+'(', '\013', '2', '4', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'a', 'p', 'i', '.', 'e', 'x', 'p', 'r', '.', 'v', '1', 'a', 'l', 
+'p', 'h', 'a', '1', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'I', 'n', 'f', 'o', '.', 'M', 'a', 'c', 'r', 'o', 'C', 'a', 'l', 'l', 
+'s', 'E', 'n', 't', 'r', 'y', 'R', '\n', 'm', 'a', 'c', 'r', 'o', 'C', 'a', 'l', 'l', 's', '\032', '<', '\n', '\016', 'P', 'o', 's', 
+'i', 't', 'i', 'o', 'n', 's', 'E', 'n', 't', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\003', 'R', 
+'\003', 'k', 'e', 'y', '\022', '\024', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\005', 'v', 'a', 'l', 'u', 
+'e', ':', '\002', '8', '\001', '\032', ']', '\n', '\017', 'M', 'a', 'c', 'r', 'o', 'C', 'a', 'l', 'l', 's', 'E', 'n', 't', 'r', 'y', '\022', 
+'\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\003', 'R', '\003', 'k', 'e', 'y', '\022', '4', '\n', '\005', 'v', 'a', 'l', 'u', 
+'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\036', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'a', 'p', 'i', '.', 'e', 'x', 'p', 'r', 
+'.', 'v', '1', 'a', 'l', 'p', 'h', 'a', '1', '.', 'E', 'x', 'p', 'r', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', 
+'\"', 'p', '\n', '\016', 'S', 'o', 'u', 'r', 'c', 'e', 'P', 'o', 's', 'i', 't', 'i', 'o', 'n', '\022', '\032', '\n', '\010', 'l', 'o', 'c', 
+'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\006', 
+'o', 'f', 'f', 's', 'e', 't', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\006', 'o', 'f', 'f', 's', 'e', 't', '\022', '\022', '\n', '\004', 'l', 
+'i', 'n', 'e', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\004', 'l', 'i', 'n', 'e', '\022', '\026', '\n', '\006', 'c', 'o', 'l', 'u', 'm', 'n', 
+'\030', '\004', ' ', '\001', '(', '\005', 'R', '\006', 'c', 'o', 'l', 'u', 'm', 'n', 'B', 'n', '\n', '\034', 'c', 'o', 'm', '.', 'g', 'o', 'o', 
+'g', 'l', 'e', '.', 'a', 'p', 'i', '.', 'e', 'x', 'p', 'r', '.', 'v', '1', 'a', 'l', 'p', 'h', 'a', '1', 'B', '\013', 'S', 'y', 
+'n', 't', 'a', 'x', 'P', 'r', 'o', 't', 'o', 'P', '\001', 'Z', '<', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'g', 'o', 'l', 'a', 'n', 
+'g', '.', 'o', 'r', 'g', '/', 'g', 'e', 'n', 'p', 'r', 'o', 't', 'o', '/', 'g', 'o', 'o', 'g', 'l', 'e', 'a', 'p', 'i', 's', 
+'/', 'a', 'p', 'i', '/', 'e', 'x', 'p', 'r', '/', 'v', '1', 'a', 'l', 'p', 'h', 'a', '1', ';', 'e', 'x', 'p', 'r', '\370', '\001', 
+'\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
 };
 
 static upb_def_init *deps[4] = {
@@ -171,5 +180,5 @@
   deps,
   layouts,
   "google/api/expr/v1alpha1/syntax.proto",
-  UPB_STRVIEW_INIT(descriptor, 2877)
+  UPB_STRVIEW_INIT(descriptor, 3059)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/google/api/expr/v1alpha1/syntax.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/google/api/expr/v1alpha1/syntax.upbdefs.h
index f1dedba..750f563 100644
--- a/grpc/src/core/ext/upbdefs-generated/google/api/expr/v1alpha1/syntax.upbdefs.h
+++ b/grpc/src/core/ext/upbdefs-generated/google/api/expr/v1alpha1/syntax.upbdefs.h
@@ -81,6 +81,11 @@
   return upb_symtab_lookupmsg(s, "google.api.expr.v1alpha1.SourceInfo.PositionsEntry");
 }
 
+UPB_INLINE const upb_msgdef *google_api_expr_v1alpha1_SourceInfo_MacroCallsEntry_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &google_api_expr_v1alpha1_syntax_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "google.api.expr.v1alpha1.SourceInfo.MacroCallsEntry");
+}
+
 UPB_INLINE const upb_msgdef *google_api_expr_v1alpha1_SourcePosition_getmsgdef(upb_symtab *s) {
   _upb_symtab_loaddefinit(s, &google_api_expr_v1alpha1_syntax_proto_upbdefinit);
   return upb_symtab_lookupmsg(s, "google.api.expr.v1alpha1.SourcePosition");
diff --git a/grpc/src/core/ext/upbdefs-generated/src/proto/grpc/auth/v1/authz_policy.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/src/proto/grpc/auth/v1/authz_policy.upbdefs.c
new file mode 100644
index 0000000..7f317ae
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/src/proto/grpc/auth/v1/authz_policy.upbdefs.c
@@ -0,0 +1,58 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     src/proto/grpc/auth/v1/authz_policy.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "src/proto/grpc/auth/v1/authz_policy.upbdefs.h"
+
+extern const upb_msglayout grpc_auth_v1_Peer_msginit;
+extern const upb_msglayout grpc_auth_v1_Header_msginit;
+extern const upb_msglayout grpc_auth_v1_Request_msginit;
+extern const upb_msglayout grpc_auth_v1_Rule_msginit;
+extern const upb_msglayout grpc_auth_v1_AuthorizationPolicy_msginit;
+
+static const upb_msglayout *layouts[5] = {
+  &grpc_auth_v1_Peer_msginit,
+  &grpc_auth_v1_Header_msginit,
+  &grpc_auth_v1_Request_msginit,
+  &grpc_auth_v1_Rule_msginit,
+  &grpc_auth_v1_AuthorizationPolicy_msginit,
+};
+
+static const char descriptor[507] = {'\n', ')', 's', 'r', 'c', '/', 'p', 'r', 'o', 't', 'o', '/', 'g', 'r', 'p', 'c', '/', 'a', 'u', 't', 'h', '/', 'v', '1', '/', 
+'a', 'u', 't', 'h', 'z', '_', 'p', 'o', 'l', 'i', 'c', 'y', '.', 'p', 'r', 'o', 't', 'o', '\022', '\014', 'g', 'r', 'p', 'c', '.', 
+'a', 'u', 't', 'h', '.', 'v', '1', '\"', '&', '\n', '\004', 'P', 'e', 'e', 'r', '\022', '\036', '\n', '\n', 'p', 'r', 'i', 'n', 'c', 'i', 
+'p', 'a', 'l', 's', '\030', '\001', ' ', '\003', '(', '\t', 'R', '\n', 'p', 'r', 'i', 'n', 'c', 'i', 'p', 'a', 'l', 's', '\"', '2', '\n', 
+'\006', 'H', 'e', 'a', 'd', 'e', 'r', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', 
+'\022', '\026', '\n', '\006', 'v', 'a', 'l', 'u', 'e', 's', '\030', '\002', ' ', '\003', '(', '\t', 'R', '\006', 'v', 'a', 'l', 'u', 'e', 's', '\"', 
+'O', '\n', '\007', 'R', 'e', 'q', 'u', 'e', 's', 't', '\022', '\024', '\n', '\005', 'p', 'a', 't', 'h', 's', '\030', '\001', ' ', '\003', '(', '\t', 
+'R', '\005', 'p', 'a', 't', 'h', 's', '\022', '.', '\n', '\007', 'h', 'e', 'a', 'd', 'e', 'r', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', 
+'\024', '.', 'g', 'r', 'p', 'c', '.', 'a', 'u', 't', 'h', '.', 'v', '1', '.', 'H', 'e', 'a', 'd', 'e', 'r', 'R', '\007', 'h', 'e', 
+'a', 'd', 'e', 'r', 's', '\"', 'w', '\n', '\004', 'R', 'u', 'l', 'e', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', 
+'(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '*', '\n', '\006', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', 
+'\022', '.', 'g', 'r', 'p', 'c', '.', 'a', 'u', 't', 'h', '.', 'v', '1', '.', 'P', 'e', 'e', 'r', 'R', '\006', 's', 'o', 'u', 'r', 
+'c', 'e', '\022', '/', '\n', '\007', 'r', 'e', 'q', 'u', 'e', 's', 't', '\030', '\003', ' ', '\001', '(', '\013', '2', '\025', '.', 'g', 'r', 'p', 
+'c', '.', 'a', 'u', 't', 'h', '.', 'v', '1', '.', 'R', 'e', 'q', 'u', 'e', 's', 't', 'R', '\007', 'r', 'e', 'q', 'u', 'e', 's', 
+'t', '\"', '\221', '\001', '\n', '\023', 'A', 'u', 't', 'h', 'o', 'r', 'i', 'z', 'a', 't', 'i', 'o', 'n', 'P', 'o', 'l', 'i', 'c', 'y', 
+'\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '1', '\n', '\n', 'd', 
+'e', 'n', 'y', '_', 'r', 'u', 'l', 'e', 's', '\030', '\002', ' ', '\003', '(', '\013', '2', '\022', '.', 'g', 'r', 'p', 'c', '.', 'a', 'u', 
+'t', 'h', '.', 'v', '1', '.', 'R', 'u', 'l', 'e', 'R', '\t', 'd', 'e', 'n', 'y', 'R', 'u', 'l', 'e', 's', '\022', '3', '\n', '\013', 
+'a', 'l', 'l', 'o', 'w', '_', 'r', 'u', 'l', 'e', 's', '\030', '\003', ' ', '\003', '(', '\013', '2', '\022', '.', 'g', 'r', 'p', 'c', '.', 
+'a', 'u', 't', 'h', '.', 'v', '1', '.', 'R', 'u', 'l', 'e', 'R', '\n', 'a', 'l', 'l', 'o', 'w', 'R', 'u', 'l', 'e', 's', 'b', 
+'\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[1] = {
+  NULL
+};
+
+upb_def_init src_proto_grpc_auth_v1_authz_policy_proto_upbdefinit = {
+  deps,
+  layouts,
+  "src/proto/grpc/auth/v1/authz_policy.proto",
+  UPB_STRVIEW_INIT(descriptor, 507)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/src/proto/grpc/auth/v1/authz_policy.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/src/proto/grpc/auth/v1/authz_policy.upbdefs.h
new file mode 100644
index 0000000..c06fb25
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/src/proto/grpc/auth/v1/authz_policy.upbdefs.h
@@ -0,0 +1,55 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     src/proto/grpc/auth/v1/authz_policy.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef SRC_PROTO_GRPC_AUTH_V1_AUTHZ_POLICY_PROTO_UPBDEFS_H_
+#define SRC_PROTO_GRPC_AUTH_V1_AUTHZ_POLICY_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init src_proto_grpc_auth_v1_authz_policy_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *grpc_auth_v1_Peer_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &src_proto_grpc_auth_v1_authz_policy_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "grpc.auth.v1.Peer");
+}
+
+UPB_INLINE const upb_msgdef *grpc_auth_v1_Header_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &src_proto_grpc_auth_v1_authz_policy_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "grpc.auth.v1.Header");
+}
+
+UPB_INLINE const upb_msgdef *grpc_auth_v1_Request_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &src_proto_grpc_auth_v1_authz_policy_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "grpc.auth.v1.Request");
+}
+
+UPB_INLINE const upb_msgdef *grpc_auth_v1_Rule_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &src_proto_grpc_auth_v1_authz_policy_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "grpc.auth.v1.Rule");
+}
+
+UPB_INLINE const upb_msgdef *grpc_auth_v1_AuthorizationPolicy_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &src_proto_grpc_auth_v1_authz_policy_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "grpc.auth.v1.AuthorizationPolicy");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* SRC_PROTO_GRPC_AUTH_V1_AUTHZ_POLICY_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c
deleted file mode 100644
index c6ce1dd..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/authority.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include "upb/def.h"
-#include "udpa/core/v1/authority.upbdefs.h"
-
-extern upb_def_init udpa_annotations_status_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
-extern const upb_msglayout udpa_core_v1_Authority_msginit;
-
-static const upb_msglayout *layouts[1] = {
-  &udpa_core_v1_Authority_msginit,
-};
-
-static const char descriptor[208] = {'\n', '\034', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '.', 
-'p', 'r', 'o', 't', 'o', '\022', '\014', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '\032', '\035', 'u', 'd', 'p', 'a', 
-'/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', 
-'\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', 
-'\"', '(', '\n', '\t', 'A', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', 
-'(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', 'B', '8', '\n', '\034', 'c', 'o', 'm', '.', 
-'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', 'B', 
-'\016', 'A', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\010', '\001', 
-'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
-};
-
-static upb_def_init *deps[3] = {
-  &udpa_annotations_status_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
-  NULL
-};
-
-upb_def_init udpa_core_v1_authority_proto_upbdefinit = {
-  deps,
-  layouts,
-  "udpa/core/v1/authority.proto",
-  UPB_STRVIEW_INIT(descriptor, 208)
-};
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h
deleted file mode 100644
index 300938d..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/authority.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_AUTHORITY_PROTO_UPBDEFS_H_
-#define UDPA_CORE_V1_AUTHORITY_PROTO_UPBDEFS_H_
-
-#include "upb/def.h"
-#include "upb/port_def.inc"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "upb/def.h"
-
-#include "upb/port_def.inc"
-
-extern upb_def_init udpa_core_v1_authority_proto_upbdefinit;
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_Authority_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_authority_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.Authority");
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_AUTHORITY_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c
deleted file mode 100644
index 3d07ae6..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/collection_entry.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include "upb/def.h"
-#include "udpa/core/v1/collection_entry.upbdefs.h"
-
-extern upb_def_init google_protobuf_any_proto_upbdefinit;
-extern upb_def_init udpa_annotations_status_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_resource_locator_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
-extern const upb_msglayout udpa_core_v1_CollectionEntry_msginit;
-extern const upb_msglayout udpa_core_v1_CollectionEntry_InlineEntry_msginit;
-
-static const upb_msglayout *layouts[2] = {
-  &udpa_core_v1_CollectionEntry_msginit,
-  &udpa_core_v1_CollectionEntry_InlineEntry_msginit,
-};
-
-static const char descriptor[571] = {'\n', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'c', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 
-'_', 'e', 'n', 't', 'r', 'y', '.', 'p', 'r', 'o', 't', 'o', '\022', '\014', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', 
-'1', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 
-'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 
-'t', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 
-'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 
-'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\305', '\002', '\n', 
-'\017', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 't', 'r', 'y', '\022', '9', '\n', '\007', 'l', 'o', 'c', 'a', 't', 
-'o', 'r', '\030', '\001', ' ', '\001', '(', '\013', '2', '\035', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 
-'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'H', '\000', 'R', '\007', 'l', 'o', 'c', 'a', 't', 'o', 'r', 
-'\022', 'N', '\n', '\014', 'i', 'n', 'l', 'i', 'n', 'e', '_', 'e', 'n', 't', 'r', 'y', '\030', '\002', ' ', '\001', '(', '\013', '2', ')', '.', 
-'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 
-'t', 'r', 'y', '.', 'I', 'n', 'l', 'i', 'n', 'e', 'E', 'n', 't', 'r', 'y', 'H', '\000', 'R', '\013', 'i', 'n', 'l', 'i', 'n', 'e', 
-'E', 'n', 't', 'r', 'y', '\032', '\213', '\001', '\n', '\013', 'I', 'n', 'l', 'i', 'n', 'e', 'E', 'n', 't', 'r', 'y', '\022', '0', '\n', '\004', 
-'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'B', '\034', '\372', 'B', '\031', 'r', '\027', '2', '\025', '^', '[', '0', '-', '9', 'a', 
-'-', 'z', 'A', '-', 'Z', '_', '\\', '-', '\\', '.', '~', ':', ']', '+', '$', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\030', '\n', '\007', 
-'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', '0', '\n', 
-'\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
-'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'B', '\031', '\n', 
-'\022', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'B', 
-'>', '\n', '\034', 'c', 'o', 'm', '.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'u', 'd', 'p', 'a', '.', 'c', 
-'o', 'r', 'e', '.', 'v', '1', 'B', '\024', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 't', 'r', 'y', 'P', 'r', 
-'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\010', '\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
-};
-
-static upb_def_init *deps[5] = {
-  &google_protobuf_any_proto_upbdefinit,
-  &udpa_annotations_status_proto_upbdefinit,
-  &udpa_core_v1_resource_locator_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
-  NULL
-};
-
-upb_def_init udpa_core_v1_collection_entry_proto_upbdefinit = {
-  deps,
-  layouts,
-  "udpa/core/v1/collection_entry.proto",
-  UPB_STRVIEW_INIT(descriptor, 571)
-};
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h
deleted file mode 100644
index 7864b1f..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/collection_entry.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_COLLECTION_ENTRY_PROTO_UPBDEFS_H_
-#define UDPA_CORE_V1_COLLECTION_ENTRY_PROTO_UPBDEFS_H_
-
-#include "upb/def.h"
-#include "upb/port_def.inc"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "upb/def.h"
-
-#include "upb/port_def.inc"
-
-extern upb_def_init udpa_core_v1_collection_entry_proto_upbdefinit;
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_CollectionEntry_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_collection_entry_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.CollectionEntry");
-}
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_CollectionEntry_InlineEntry_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_collection_entry_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.CollectionEntry.InlineEntry");
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_COLLECTION_ENTRY_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c
deleted file mode 100644
index 4b6beaf..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/context_params.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include "upb/def.h"
-#include "udpa/core/v1/context_params.upbdefs.h"
-
-extern upb_def_init udpa_annotations_status_proto_upbdefinit;
-extern const upb_msglayout udpa_core_v1_ContextParams_msginit;
-extern const upb_msglayout udpa_core_v1_ContextParams_ParamsEntry_msginit;
-
-static const upb_msglayout *layouts[2] = {
-  &udpa_core_v1_ContextParams_msginit,
-  &udpa_core_v1_ContextParams_ParamsEntry_msginit,
-};
-
-static const char descriptor[292] = {'\n', '!', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'p', 'a', 
-'r', 'a', 'm', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\014', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '\032', 
-'\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 
-'p', 'r', 'o', 't', 'o', '\"', '\213', '\001', '\n', '\r', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', '\022', '?', 
-'\n', '\006', 'p', 'a', 'r', 'a', 'm', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '\'', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 
-'e', '.', 'v', '1', '.', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', '.', 'P', 'a', 'r', 'a', 'm', 's', 
-'E', 'n', 't', 'r', 'y', 'R', '\006', 'p', 'a', 'r', 'a', 'm', 's', '\032', '9', '\n', '\013', 'P', 'a', 'r', 'a', 'm', 's', 'E', 'n', 
-'t', 'r', 'y', '\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '\024', '\n', '\005', 
-'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', 'B', '<', '\n', 
-'\034', 'c', 'o', 'm', '.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 
-'e', '.', 'v', '1', 'B', '\022', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', 'P', 'r', 'o', 't', 'o', 'P', 
-'\001', '\272', '\200', '\310', '\321', '\006', '\002', '\010', '\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
-};
-
-static upb_def_init *deps[2] = {
-  &udpa_annotations_status_proto_upbdefinit,
-  NULL
-};
-
-upb_def_init udpa_core_v1_context_params_proto_upbdefinit = {
-  deps,
-  layouts,
-  "udpa/core/v1/context_params.proto",
-  UPB_STRVIEW_INIT(descriptor, 292)
-};
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h
deleted file mode 100644
index 8c988cf..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/context_params.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_CONTEXT_PARAMS_PROTO_UPBDEFS_H_
-#define UDPA_CORE_V1_CONTEXT_PARAMS_PROTO_UPBDEFS_H_
-
-#include "upb/def.h"
-#include "upb/port_def.inc"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "upb/def.h"
-
-#include "upb/port_def.inc"
-
-extern upb_def_init udpa_core_v1_context_params_proto_upbdefinit;
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_ContextParams_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_context_params_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.ContextParams");
-}
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_ContextParams_ParamsEntry_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_context_params_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.ContextParams.ParamsEntry");
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_CONTEXT_PARAMS_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c
deleted file mode 100644
index 702f4c0..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include "upb/def.h"
-#include "udpa/core/v1/resource.upbdefs.h"
-
-extern upb_def_init google_protobuf_any_proto_upbdefinit;
-extern upb_def_init udpa_annotations_status_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_resource_name_proto_upbdefinit;
-extern const upb_msglayout udpa_core_v1_Resource_msginit;
-
-static const upb_msglayout *layouts[1] = {
-  &udpa_core_v1_Resource_msginit,
-};
-
-static const char descriptor[337] = {'\n', '\033', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 
-'r', 'o', 't', 'o', '\022', '\014', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 
-'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 
-'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 
-'o', '\032', ' ', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 
-'n', 'a', 'm', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\206', '\001', '\n', '\010', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', '\022', '.', 
-'\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\032', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 
-'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\030', '\n', '\007', 
-'v', 'e', 'r', 's', 'i', 'o', 'n', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', '0', '\n', 
-'\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 
-'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'B', '7', '\n', 
-'\034', 'c', 'o', 'm', '.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 
-'e', '.', 'v', '1', 'B', '\r', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', 
-'\006', '\002', '\010', '\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
-};
-
-static upb_def_init *deps[4] = {
-  &google_protobuf_any_proto_upbdefinit,
-  &udpa_annotations_status_proto_upbdefinit,
-  &udpa_core_v1_resource_name_proto_upbdefinit,
-  NULL
-};
-
-upb_def_init udpa_core_v1_resource_proto_upbdefinit = {
-  deps,
-  layouts,
-  "udpa/core/v1/resource.proto",
-  UPB_STRVIEW_INIT(descriptor, 337)
-};
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h
deleted file mode 100644
index de8cfc7..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_RESOURCE_PROTO_UPBDEFS_H_
-#define UDPA_CORE_V1_RESOURCE_PROTO_UPBDEFS_H_
-
-#include "upb/def.h"
-#include "upb/port_def.inc"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "upb/def.h"
-
-#include "upb/port_def.inc"
-
-extern upb_def_init udpa_core_v1_resource_proto_upbdefinit;
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_Resource_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_resource_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.Resource");
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_RESOURCE_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c
deleted file mode 100644
index 80c1124..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource_locator.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include "upb/def.h"
-#include "udpa/core/v1/resource_locator.upbdefs.h"
-
-extern upb_def_init udpa_annotations_status_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_context_params_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_msginit;
-extern const upb_msglayout udpa_core_v1_ResourceLocator_Directive_msginit;
-
-static const upb_msglayout *layouts[2] = {
-  &udpa_core_v1_ResourceLocator_msginit,
-  &udpa_core_v1_ResourceLocator_Directive_msginit,
-};
-
-static const char descriptor[756] = {'\n', '#', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'l', 
-'o', 'c', 'a', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\014', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', 
-'1', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 
-'s', '.', 'p', 'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'c', 'o', 'n', 
-'t', 'e', 'x', 't', '_', 'p', 'a', 'r', 'a', 'm', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 
-'t', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\233', '\004', '\n', '\017', 'R', 'e', 's', 
-'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', '\022', 'F', '\n', '\006', 's', 'c', 'h', 'e', 'm', 'e', '\030', '\001', ' ', 
-'\001', '(', '\016', '2', '$', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 
-'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', '.', 'S', 'c', 'h', 'e', 'm', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', 
-'\001', 'R', '\006', 's', 'c', 'h', 'e', 'm', 'e', '\022', '\030', '\n', '\002', 'i', 'd', '\030', '\002', ' ', '\003', '(', '\t', 'B', '\010', '\372', 'B', 
-'\005', '\222', '\001', '\002', '\010', '\001', 'R', '\002', 'i', 'd', '\022', '\034', '\n', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\030', '\003', 
-' ', '\001', '(', '\t', 'R', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\022', ',', '\n', '\r', 'r', 'e', 's', 'o', 'u', 'r', 
-'c', 'e', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\014', 'r', 
-'e', 's', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', '\022', 'B', '\n', '\r', 'e', 'x', 'a', 'c', 't', '_', 'c', 'o', 'n', 't', 
-'e', 'x', 't', '\030', '\005', ' ', '\001', '(', '\013', '2', '\033', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 
-'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', 'H', '\000', 'R', '\014', 'e', 'x', 'a', 'c', 't', 'C', 'o', 'n', 
-'t', 'e', 'x', 't', '\022', 'G', '\n', '\n', 'd', 'i', 'r', 'e', 'c', 't', 'i', 'v', 'e', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', 
-'\'', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 
-'c', 'a', 't', 'o', 'r', '.', 'D', 'i', 'r', 'e', 'c', 't', 'i', 'v', 'e', 'R', '\n', 'd', 'i', 'r', 'e', 'c', 't', 'i', 'v', 
-'e', 's', '\032', '\211', '\001', '\n', '\t', 'D', 'i', 'r', 'e', 'c', 't', 'i', 'v', 'e', '\022', '1', '\n', '\003', 'a', 'l', 't', '\030', '\001', 
-' ', '\001', '(', '\013', '2', '\035', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'R', 'e', 's', 'o', 'u', 
-'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'H', '\000', 'R', '\003', 'a', 'l', 't', '\022', '7', '\n', '\005', 'e', 'n', 't', 'r', 
-'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\037', '\372', 'B', '\034', 'r', '\032', '\020', '\001', '2', '\026', '^', '[', '0', '-', '9', 'a', '-', 
-'z', 'A', '-', 'Z', '_', '\\', '-', '\\', '.', '/', '~', ':', ']', '+', '$', 'H', '\000', 'R', '\005', 'e', 'n', 't', 'r', 'y', 'B', 
-'\020', '\n', '\t', 'd', 'i', 'r', 'e', 'c', 't', 'i', 'v', 'e', '\022', '\003', '\370', 'B', '\001', '\"', '&', '\n', '\006', 'S', 'c', 'h', 'e', 
-'m', 'e', '\022', '\010', '\n', '\004', 'U', 'D', 'P', 'A', '\020', '\000', '\022', '\010', '\n', '\004', 'H', 'T', 'T', 'P', '\020', '\001', '\022', '\010', '\n', 
-'\004', 'F', 'I', 'L', 'E', '\020', '\002', 'B', '\031', '\n', '\027', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'p', 'a', 'r', 'a', 'm', '_', 
-'s', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'B', '>', '\n', '\034', 'c', 'o', 'm', '.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 
-'d', 'p', 'a', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', 'B', '\024', 'R', 'e', 's', 'o', 'u', 'r', 'c', 
-'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\010', '\001', 'b', '\006', 
-'p', 'r', 'o', 't', 'o', '3', 
-};
-
-static upb_def_init *deps[4] = {
-  &udpa_annotations_status_proto_upbdefinit,
-  &udpa_core_v1_context_params_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
-  NULL
-};
-
-upb_def_init udpa_core_v1_resource_locator_proto_upbdefinit = {
-  deps,
-  layouts,
-  "udpa/core/v1/resource_locator.proto",
-  UPB_STRVIEW_INIT(descriptor, 756)
-};
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h
deleted file mode 100644
index 439d10a..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource_locator.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_RESOURCE_LOCATOR_PROTO_UPBDEFS_H_
-#define UDPA_CORE_V1_RESOURCE_LOCATOR_PROTO_UPBDEFS_H_
-
-#include "upb/def.h"
-#include "upb/port_def.inc"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "upb/def.h"
-
-#include "upb/port_def.inc"
-
-extern upb_def_init udpa_core_v1_resource_locator_proto_upbdefinit;
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_ResourceLocator_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_resource_locator_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.ResourceLocator");
-}
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_ResourceLocator_Directive_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_resource_locator_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.ResourceLocator.Directive");
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_RESOURCE_LOCATOR_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c
deleted file mode 100644
index 6d80f98..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource_name.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#include "upb/def.h"
-#include "udpa/core/v1/resource_name.upbdefs.h"
-
-extern upb_def_init udpa_annotations_status_proto_upbdefinit;
-extern upb_def_init udpa_core_v1_context_params_proto_upbdefinit;
-extern upb_def_init validate_validate_proto_upbdefinit;
-extern const upb_msglayout udpa_core_v1_ResourceName_msginit;
-
-static const upb_msglayout *layouts[1] = {
-  &udpa_core_v1_ResourceName_msginit,
-};
-
-static const char descriptor[382] = {'\n', ' ', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 
-'a', 'm', 'e', '.', 'p', 'r', 'o', 't', 'o', '\022', '\014', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '\032', '\035', 
-'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 
-'r', 'o', 't', 'o', '\032', '!', 'u', 'd', 'p', 'a', '/', 'c', 'o', 'r', 'e', '/', 'v', '1', '/', 'c', 'o', 'n', 't', 'e', 'x', 
-'t', '_', 'p', 'a', 'r', 'a', 'm', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 
-'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\253', '\001', '\n', '\014', 'R', 'e', 's', 'o', 'u', 'r', 
-'c', 'e', 'N', 'a', 'm', 'e', '\022', '\030', '\n', '\002', 'i', 'd', '\030', '\001', ' ', '\003', '(', '\t', 'B', '\010', '\372', 'B', '\005', '\222', '\001', 
-'\002', '\010', '\001', 'R', '\002', 'i', 'd', '\022', '\034', '\n', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\030', '\002', ' ', '\001', '(', 
-'\t', 'R', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\022', ',', '\n', '\r', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 
-'t', 'y', 'p', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\014', 'r', 'e', 's', 'o', 
-'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', '\022', '5', '\n', '\007', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\004', ' ', '\001', '(', '\013', 
-'2', '\033', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', '.', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 
-'r', 'a', 'm', 's', 'R', '\007', 'c', 'o', 'n', 't', 'e', 'x', 't', 'B', ';', '\n', '\034', 'c', 'o', 'm', '.', 'g', 'i', 't', 'h', 
-'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'u', 'd', 'p', 'a', '.', 'c', 'o', 'r', 'e', '.', 'v', '1', 'B', '\021', 'R', 'e', 's', 
-'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\010', '\001', 'b', 
-'\006', 'p', 'r', 'o', 't', 'o', '3', 
-};
-
-static upb_def_init *deps[4] = {
-  &udpa_annotations_status_proto_upbdefinit,
-  &udpa_core_v1_context_params_proto_upbdefinit,
-  &validate_validate_proto_upbdefinit,
-  NULL
-};
-
-upb_def_init udpa_core_v1_resource_name_proto_upbdefinit = {
-  deps,
-  layouts,
-  "udpa/core/v1/resource_name.proto",
-  UPB_STRVIEW_INIT(descriptor, 382)
-};
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h
deleted file mode 100644
index 6e0b573..0000000
--- a/grpc/src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This file was generated by upbc (the upb compiler) from the input
- * file:
- *
- *     udpa/core/v1/resource_name.proto
- *
- * Do not edit -- your changes will be discarded when the file is
- * regenerated. */
-
-#ifndef UDPA_CORE_V1_RESOURCE_NAME_PROTO_UPBDEFS_H_
-#define UDPA_CORE_V1_RESOURCE_NAME_PROTO_UPBDEFS_H_
-
-#include "upb/def.h"
-#include "upb/port_def.inc"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "upb/def.h"
-
-#include "upb/port_def.inc"
-
-extern upb_def_init udpa_core_v1_resource_name_proto_upbdefinit;
-
-UPB_INLINE const upb_msgdef *udpa_core_v1_ResourceName_getmsgdef(upb_symtab *s) {
-  _upb_symtab_loaddefinit(s, &udpa_core_v1_resource_name_proto_upbdefinit);
-  return upb_symtab_lookupmsg(s, "udpa.core.v1.ResourceName");
-}
-
-#ifdef __cplusplus
-}  /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
-
-#endif  /* UDPA_CORE_V1_RESOURCE_NAME_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c
new file mode 100644
index 0000000..f786bff
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c
@@ -0,0 +1,44 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     udpa/type/v1/typed_struct.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "udpa/type/v1/typed_struct.upbdefs.h"
+
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern upb_def_init google_protobuf_struct_proto_upbdefinit;
+extern const upb_msglayout udpa_type_v1_TypedStruct_msginit;
+
+static const upb_msglayout *layouts[1] = {
+  &udpa_type_v1_TypedStruct_msginit,
+};
+
+static const char descriptor[251] = {'\n', '\037', 'u', 'd', 'p', 'a', '/', 't', 'y', 'p', 'e', '/', 'v', '1', '/', 't', 'y', 'p', 'e', 'd', '_', 's', 't', 'r', 'u', 
+'c', 't', '.', 'p', 'r', 'o', 't', 'o', '\022', '\014', 'u', 'd', 'p', 'a', '.', 't', 'y', 'p', 'e', '.', 'v', '1', '\032', '\027', 'v', 
+'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\032', '\034', 'g', 
+'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 's', 't', 'r', 'u', 'c', 't', '.', 'p', 'r', 'o', 
+'t', 'o', '\"', 'W', '\n', '\013', 'T', 'y', 'p', 'e', 'd', 'S', 't', 'r', 'u', 'c', 't', '\022', '\031', '\n', '\010', 't', 'y', 'p', 'e', 
+'_', 'u', 'r', 'l', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\007', 't', 'y', 'p', 'e', 'U', 'r', 'l', '\022', '-', '\n', '\005', 'v', 'a', 
+'l', 'u', 'e', '\030', '\002', ' ', '\001', '(', '\013', '2', '\027', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 
+'u', 'f', '.', 'S', 't', 'r', 'u', 'c', 't', 'R', '\005', 'v', 'a', 'l', 'u', 'e', 'B', '2', '\n', '\034', 'c', 'o', 'm', '.', 'g', 
+'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'u', 'd', 'p', 'a', '.', 't', 'y', 'p', 'e', '.', 'v', '1', 'B', '\020', 
+'T', 'y', 'p', 'e', 'd', 'S', 't', 'r', 'u', 'c', 't', 'P', 'r', 'o', 't', 'o', 'P', '\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', 
+'3', 
+};
+
+static upb_def_init *deps[3] = {
+  &validate_validate_proto_upbdefinit,
+  &google_protobuf_struct_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init udpa_type_v1_typed_struct_proto_upbdefinit = {
+  deps,
+  layouts,
+  "udpa/type/v1/typed_struct.proto",
+  UPB_STRVIEW_INIT(descriptor, 251)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h
new file mode 100644
index 0000000..d30baef
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h
@@ -0,0 +1,35 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     udpa/type/v1/typed_struct.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef UDPA_TYPE_V1_TYPED_STRUCT_PROTO_UPBDEFS_H_
+#define UDPA_TYPE_V1_TYPED_STRUCT_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init udpa_type_v1_typed_struct_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *udpa_type_v1_TypedStruct_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &udpa_type_v1_typed_struct_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "udpa.type.v1.TypedStruct");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* UDPA_TYPE_V1_TYPED_STRUCT_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/validate/validate.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/validate/validate.upbdefs.c
index af02b2b..dc751fa 100644
--- a/grpc/src/core/ext/upbdefs-generated/validate/validate.upbdefs.c
+++ b/grpc/src/core/ext/upbdefs-generated/validate/validate.upbdefs.c
@@ -62,7 +62,7 @@
   &validate_TimestampRules_msginit,
 };
 
-static const char descriptor[5699] = {'\n', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', 
+static const char descriptor[5759] = {'\n', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', 
 '\022', '\010', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '\032', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 
 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '\036', 'g', 'o', 'o', 'g', 
 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '.', 'p', 'r', 'o', 't', 
@@ -281,15 +281,18 @@
 'H', 'T', 'T', 'P', '_', 'H', 'E', 'A', 'D', 'E', 'R', '_', 'V', 'A', 'L', 'U', 'E', '\020', '\002', ':', '<', '\n', '\010', 'd', 'i', 
 's', 'a', 'b', 'l', 'e', 'd', '\022', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 
 'M', 'e', 's', 's', 'a', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\030', '\257', '\010', ' ', '\001', '(', '\010', 'R', '\010', 'd', 'i', 
-'s', 'a', 'b', 'l', 'e', 'd', ':', ':', '\n', '\010', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd', '\022', '\035', '.', 'g', 'o', 'o', 'g', 
-'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', 'o', 'n', 's', '\030', 
-'\257', '\010', ' ', '\001', '(', '\010', 'R', '\010', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd', ':', 'J', '\n', '\005', 'r', 'u', 'l', 'e', 's', 
-'\022', '\035', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 
-'p', 't', 'i', 'o', 'n', 's', '\030', '\257', '\010', ' ', '\001', '(', '\013', '2', '\024', '.', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 
-'F', 'i', 'e', 'l', 'd', 'R', 'u', 'l', 'e', 's', 'R', '\005', 'r', 'u', 'l', 'e', 's', 'B', 'P', '\n', '\032', 'i', 'o', '.', 'e', 
-'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'p', 'g', 'v', '.', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 'Z', '2', 'g', 
-'i', 't', 'h', 'u', 'b', '.', 'c', 'o', 'm', '/', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '/', 'p', 'r', 'o', 't', 
-'o', 'c', '-', 'g', 'e', 'n', '-', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 
+'s', 'a', 'b', 'l', 'e', 'd', ':', ':', '\n', '\007', 'i', 'g', 'n', 'o', 'r', 'e', 'd', '\022', '\037', '.', 'g', 'o', 'o', 'g', 'l', 
+'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 's', 's', 'a', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 
+'\030', '\260', '\010', ' ', '\001', '(', '\010', 'R', '\007', 'i', 'g', 'n', 'o', 'r', 'e', 'd', ':', ':', '\n', '\010', 'r', 'e', 'q', 'u', 'i', 
+'r', 'e', 'd', '\022', '\035', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'O', 'n', 'e', 
+'o', 'f', 'O', 'p', 't', 'i', 'o', 'n', 's', '\030', '\257', '\010', ' ', '\001', '(', '\010', 'R', '\010', 'r', 'e', 'q', 'u', 'i', 'r', 'e', 
+'d', ':', 'J', '\n', '\005', 'r', 'u', 'l', 'e', 's', '\022', '\035', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
+'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '\030', '\257', '\010', ' ', '\001', '(', '\013', '2', '\024', 
+'.', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'F', 'i', 'e', 'l', 'd', 'R', 'u', 'l', 'e', 's', 'R', '\005', 'r', 'u', 'l', 
+'e', 's', 'B', 'P', '\n', '\032', 'i', 'o', '.', 'e', 'n', 'v', 'o', 'y', 'p', 'r', 'o', 'x', 'y', '.', 'p', 'g', 'v', '.', 'v', 
+'a', 'l', 'i', 'd', 'a', 't', 'e', 'Z', '2', 'g', 'i', 't', 'h', 'u', 'b', '.', 'c', 'o', 'm', '/', 'e', 'n', 'v', 'o', 'y', 
+'p', 'r', 'o', 'x', 'y', '/', 'p', 'r', 'o', 't', 'o', 'c', '-', 'g', 'e', 'n', '-', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 
+'/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', 
 };
 
 static upb_def_init *deps[4] = {
@@ -303,5 +306,5 @@
   deps,
   layouts,
   "validate/validate.proto",
-  UPB_STRVIEW_INIT(descriptor, 5699)
+  UPB_STRVIEW_INIT(descriptor, 5759)
 };
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c
new file mode 100644
index 0000000..699ae7d
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c
@@ -0,0 +1,42 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/authority.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "xds/core/v3/authority.upbdefs.h"
+
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout xds_core_v3_Authority_msginit;
+
+static const upb_msglayout *layouts[1] = {
+  &xds_core_v3_Authority_msginit,
+};
+
+static const char descriptor[205] = {'\n', '\033', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '.', 'p', 
+'r', 'o', 't', 'o', '\022', '\013', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 
+'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 
+'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '(', 
+'\n', '\t', 'A', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\022', '\033', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 
+'B', '\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\004', 'n', 'a', 'm', 'e', 'B', '7', '\n', '\033', 'c', 'o', 'm', '.', 'g', 'i', 
+'t', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', '\016', 'A', 'u', 
+'t', 'h', 'o', 'r', 'i', 't', 'y', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\010', '\001', 'b', '\006', 'p', 
+'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[3] = {
+  &udpa_annotations_status_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init xds_core_v3_authority_proto_upbdefinit = {
+  deps,
+  layouts,
+  "xds/core/v3/authority.proto",
+  UPB_STRVIEW_INIT(descriptor, 205)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h
new file mode 100644
index 0000000..191ee65
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h
@@ -0,0 +1,35 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/authority.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_AUTHORITY_PROTO_UPBDEFS_H_
+#define XDS_CORE_V3_AUTHORITY_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init xds_core_v3_authority_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *xds_core_v3_Authority_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_authority_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.Authority");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_AUTHORITY_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c
new file mode 100644
index 0000000..93d0581
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c
@@ -0,0 +1,62 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/collection_entry.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "xds/core/v3/collection_entry.upbdefs.h"
+
+extern upb_def_init google_protobuf_any_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init xds_core_v3_resource_locator_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout xds_core_v3_CollectionEntry_msginit;
+extern const upb_msglayout xds_core_v3_CollectionEntry_InlineEntry_msginit;
+
+static const upb_msglayout *layouts[2] = {
+  &xds_core_v3_CollectionEntry_msginit,
+  &xds_core_v3_CollectionEntry_InlineEntry_msginit,
+};
+
+static const char descriptor[565] = {'\n', '\"', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'c', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', '_', 
+'e', 'n', 't', 'r', 'y', '.', 'p', 'r', 'o', 't', 'o', '\022', '\013', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', 
+'\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 
+'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 
+'s', '.', 'p', 'r', 'o', 't', 'o', '\032', '\"', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'r', 'e', 's', 'o', 
+'u', 'r', 'c', 'e', '_', 'l', 'o', 'c', 'a', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 
+'a', 't', 'e', '/', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\303', '\002', '\n', '\017', 'C', 'o', 
+'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 't', 'r', 'y', '\022', '8', '\n', '\007', 'l', 'o', 'c', 'a', 't', 'o', 'r', '\030', 
+'\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'e', 's', 'o', 'u', 
+'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'H', '\000', 'R', '\007', 'l', 'o', 'c', 'a', 't', 'o', 'r', '\022', 'M', '\n', '\014', 
+'i', 'n', 'l', 'i', 'n', 'e', '_', 'e', 'n', 't', 'r', 'y', '\030', '\002', ' ', '\001', '(', '\013', '2', '(', '.', 'x', 'd', 's', '.', 
+'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 't', 'r', 'y', '.', 'I', 
+'n', 'l', 'i', 'n', 'e', 'E', 'n', 't', 'r', 'y', 'H', '\000', 'R', '\013', 'i', 'n', 'l', 'i', 'n', 'e', 'E', 'n', 't', 'r', 'y', 
+'\032', '\213', '\001', '\n', '\013', 'I', 'n', 'l', 'i', 'n', 'e', 'E', 'n', 't', 'r', 'y', '\022', '0', '\n', '\004', 'n', 'a', 'm', 'e', '\030', 
+'\001', ' ', '\001', '(', '\t', 'B', '\034', '\372', 'B', '\031', 'r', '\027', '2', '\025', '^', '[', '0', '-', '9', 'a', '-', 'z', 'A', '-', 'Z', 
+'_', '\\', '-', '\\', '.', '~', ':', ']', '+', '$', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\030', '\n', '\007', 'v', 'e', 'r', 's', 'i', 
+'o', 'n', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', '0', '\n', '\010', 'r', 'e', 's', 'o', 
+'u', 'r', 'c', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 
+'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'B', '\031', '\n', '\022', 'r', 'e', 's', 'o', 
+'u', 'r', 'c', 'e', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', '\022', '\003', '\370', 'B', '\001', 'B', '=', '\n', '\033', 'c', 'o', 
+'m', '.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
+'B', '\024', 'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'E', 'n', 't', 'r', 'y', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', 
+'\200', '\310', '\321', '\006', '\002', '\010', '\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[5] = {
+  &google_protobuf_any_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &xds_core_v3_resource_locator_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init xds_core_v3_collection_entry_proto_upbdefinit = {
+  deps,
+  layouts,
+  "xds/core/v3/collection_entry.proto",
+  UPB_STRVIEW_INIT(descriptor, 565)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h
new file mode 100644
index 0000000..3efc453
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h
@@ -0,0 +1,40 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/collection_entry.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_COLLECTION_ENTRY_PROTO_UPBDEFS_H_
+#define XDS_CORE_V3_COLLECTION_ENTRY_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init xds_core_v3_collection_entry_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *xds_core_v3_CollectionEntry_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_collection_entry_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.CollectionEntry");
+}
+
+UPB_INLINE const upb_msgdef *xds_core_v3_CollectionEntry_InlineEntry_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_collection_entry_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.CollectionEntry.InlineEntry");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_COLLECTION_ENTRY_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c
new file mode 100644
index 0000000..0c6584b
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c
@@ -0,0 +1,45 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/context_params.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "xds/core/v3/context_params.upbdefs.h"
+
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern const upb_msglayout xds_core_v3_ContextParams_msginit;
+extern const upb_msglayout xds_core_v3_ContextParams_ParamsEntry_msginit;
+
+static const upb_msglayout *layouts[2] = {
+  &xds_core_v3_ContextParams_msginit,
+  &xds_core_v3_ContextParams_ParamsEntry_msginit,
+};
+
+static const char descriptor[288] = {'\n', ' ', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'p', 'a', 'r', 
+'a', 'm', 's', '.', 'p', 'r', 'o', 't', 'o', '\022', '\013', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', '\035', 'u', 
+'d', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 
+'o', 't', 'o', '\"', '\212', '\001', '\n', '\r', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', '\022', '>', '\n', '\006', 
+'p', 'a', 'r', 'a', 'm', 's', '\030', '\001', ' ', '\003', '(', '\013', '2', '&', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', 
+'3', '.', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', '.', 'P', 'a', 'r', 'a', 'm', 's', 'E', 'n', 't', 
+'r', 'y', 'R', '\006', 'p', 'a', 'r', 'a', 'm', 's', '\032', '9', '\n', '\013', 'P', 'a', 'r', 'a', 'm', 's', 'E', 'n', 't', 'r', 'y', 
+'\022', '\020', '\n', '\003', 'k', 'e', 'y', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\003', 'k', 'e', 'y', '\022', '\024', '\n', '\005', 'v', 'a', 'l', 
+'u', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\005', 'v', 'a', 'l', 'u', 'e', ':', '\002', '8', '\001', 'B', ';', '\n', '\033', 'c', 'o', 
+'m', '.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 
+'B', '\022', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', 
+'\321', '\006', '\002', '\010', '\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[2] = {
+  &udpa_annotations_status_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init xds_core_v3_context_params_proto_upbdefinit = {
+  deps,
+  layouts,
+  "xds/core/v3/context_params.proto",
+  UPB_STRVIEW_INIT(descriptor, 288)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h
new file mode 100644
index 0000000..e52928d
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h
@@ -0,0 +1,40 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/context_params.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_CONTEXT_PARAMS_PROTO_UPBDEFS_H_
+#define XDS_CORE_V3_CONTEXT_PARAMS_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init xds_core_v3_context_params_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *xds_core_v3_ContextParams_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_context_params_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.ContextParams");
+}
+
+UPB_INLINE const upb_msgdef *xds_core_v3_ContextParams_ParamsEntry_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_context_params_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.ContextParams.ParamsEntry");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_CONTEXT_PARAMS_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c
new file mode 100644
index 0000000..d299981
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c
@@ -0,0 +1,49 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "xds/core/v3/resource.upbdefs.h"
+
+extern upb_def_init google_protobuf_any_proto_upbdefinit;
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init xds_core_v3_resource_name_proto_upbdefinit;
+extern const upb_msglayout xds_core_v3_Resource_msginit;
+
+static const upb_msglayout *layouts[1] = {
+  &xds_core_v3_Resource_msginit,
+};
+
+static const char descriptor[332] = {'\n', '\032', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '.', 'p', 'r', 
+'o', 't', 'o', '\022', '\013', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', '\031', 'g', 'o', 'o', 'g', 'l', 'e', '/', 
+'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'a', 'n', 'y', '.', 'p', 'r', 'o', 't', 'o', '\032', '\035', 'u', 'd', 'p', 'a', '/', 
+'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', 
+'\037', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 'm', 
+'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\205', '\001', '\n', '\010', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', '\022', '-', '\n', '\004', 'n', 
+'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\013', '2', '\031', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 
+'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\030', '\n', '\007', 'v', 'e', 'r', 's', 
+'i', 'o', 'n', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'v', 'e', 'r', 's', 'i', 'o', 'n', '\022', '0', '\n', '\010', 'r', 'e', 's', 
+'o', 'u', 'r', 'c', 'e', '\030', '\003', ' ', '\001', '(', '\013', '2', '\024', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 
+'o', 'b', 'u', 'f', '.', 'A', 'n', 'y', 'R', '\010', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'B', '6', '\n', '\033', 'c', 'o', 'm', 
+'.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', 
+'\r', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', '\310', '\321', '\006', '\002', '\010', '\001', 'b', 
+'\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[4] = {
+  &google_protobuf_any_proto_upbdefinit,
+  &udpa_annotations_status_proto_upbdefinit,
+  &xds_core_v3_resource_name_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init xds_core_v3_resource_proto_upbdefinit = {
+  deps,
+  layouts,
+  "xds/core/v3/resource.proto",
+  UPB_STRVIEW_INIT(descriptor, 332)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h
new file mode 100644
index 0000000..d508465
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h
@@ -0,0 +1,35 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_RESOURCE_PROTO_UPBDEFS_H_
+#define XDS_CORE_V3_RESOURCE_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init xds_core_v3_resource_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *xds_core_v3_Resource_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_resource_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.Resource");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_RESOURCE_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c
new file mode 100644
index 0000000..fefa5a2
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c
@@ -0,0 +1,67 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource_locator.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "xds/core/v3/resource_locator.upbdefs.h"
+
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init xds_core_v3_context_params_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout xds_core_v3_ResourceLocator_msginit;
+extern const upb_msglayout xds_core_v3_ResourceLocator_Directive_msginit;
+
+static const upb_msglayout *layouts[2] = {
+  &xds_core_v3_ResourceLocator_msginit,
+  &xds_core_v3_ResourceLocator_Directive_msginit,
+};
+
+static const char descriptor[739] = {'\n', '\"', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'l', 'o', 
+'c', 'a', 't', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\013', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', 
+'\035', 'u', 'd', 'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 
+'p', 'r', 'o', 't', 'o', '\032', ' ', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'c', 'o', 'n', 't', 'e', 'x', 
+'t', '_', 'p', 'a', 'r', 'a', 'm', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 
+'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\216', '\004', '\n', '\017', 'R', 'e', 's', 'o', 'u', 'r', 
+'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', '\022', 'E', '\n', '\006', 's', 'c', 'h', 'e', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\016', 
+'2', '#', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 
+'c', 'a', 't', 'o', 'r', '.', 'S', 'c', 'h', 'e', 'm', 'e', 'B', '\010', '\372', 'B', '\005', '\202', '\001', '\002', '\020', '\001', 'R', '\006', 's', 
+'c', 'h', 'e', 'm', 'e', '\022', '\016', '\n', '\002', 'i', 'd', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\002', 'i', 'd', '\022', '\034', '\n', '\t', 
+'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 
+'y', '\022', ',', '\n', '\r', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\001', '(', '\t', 'B', 
+'\007', '\372', 'B', '\004', 'r', '\002', '\020', '\001', 'R', '\014', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', '\022', 'A', '\n', 
+'\r', 'e', 'x', 'a', 'c', 't', '_', 'c', 'o', 'n', 't', 'e', 'x', 't', '\030', '\005', ' ', '\001', '(', '\013', '2', '\032', '.', 'x', 'd', 
+'s', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', 'H', '\000', 
+'R', '\014', 'e', 'x', 'a', 'c', 't', 'C', 'o', 'n', 't', 'e', 'x', 't', '\022', 'F', '\n', '\n', 'd', 'i', 'r', 'e', 'c', 't', 'i', 
+'v', 'e', 's', '\030', '\006', ' ', '\003', '(', '\013', '2', '&', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '.', 'R', 
+'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', '.', 'D', 'i', 'r', 'e', 'c', 't', 'i', 'v', 'e', 'R', 
+'\n', 'd', 'i', 'r', 'e', 'c', 't', 'i', 'v', 'e', 's', '\032', '\210', '\001', '\n', '\t', 'D', 'i', 'r', 'e', 'c', 't', 'i', 'v', 'e', 
+'\022', '0', '\n', '\003', 'a', 'l', 't', '\030', '\001', ' ', '\001', '(', '\013', '2', '\034', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 
+'v', '3', '.', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'H', '\000', 'R', '\003', 'a', 'l', 't', 
+'\022', '7', '\n', '\005', 'e', 'n', 't', 'r', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'B', '\037', '\372', 'B', '\034', 'r', '\032', '\020', '\001', '2', 
+'\026', '^', '[', '0', '-', '9', 'a', '-', 'z', 'A', '-', 'Z', '_', '\\', '-', '\\', '.', '/', '~', ':', ']', '+', '$', 'H', '\000', 
+'R', '\005', 'e', 'n', 't', 'r', 'y', 'B', '\020', '\n', '\t', 'd', 'i', 'r', 'e', 'c', 't', 'i', 'v', 'e', '\022', '\003', '\370', 'B', '\001', 
+'\"', '\'', '\n', '\006', 'S', 'c', 'h', 'e', 'm', 'e', '\022', '\t', '\n', '\005', 'X', 'D', 'S', 'T', 'P', '\020', '\000', '\022', '\010', '\n', '\004', 
+'H', 'T', 'T', 'P', '\020', '\001', '\022', '\010', '\n', '\004', 'F', 'I', 'L', 'E', '\020', '\002', 'B', '\031', '\n', '\027', 'c', 'o', 'n', 't', 'e', 
+'x', 't', '_', 'p', 'a', 'r', 'a', 'm', '_', 's', 'p', 'e', 'c', 'i', 'f', 'i', 'e', 'r', 'B', '=', '\n', '\033', 'c', 'o', 'm', 
+'.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', 'B', 
+'\024', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'L', 'o', 'c', 'a', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'P', '\001', '\272', '\200', 
+'\310', '\321', '\006', '\002', '\010', '\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[4] = {
+  &udpa_annotations_status_proto_upbdefinit,
+  &xds_core_v3_context_params_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init xds_core_v3_resource_locator_proto_upbdefinit = {
+  deps,
+  layouts,
+  "xds/core/v3/resource_locator.proto",
+  UPB_STRVIEW_INIT(descriptor, 739)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h
new file mode 100644
index 0000000..32e622a
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h
@@ -0,0 +1,40 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource_locator.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_RESOURCE_LOCATOR_PROTO_UPBDEFS_H_
+#define XDS_CORE_V3_RESOURCE_LOCATOR_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init xds_core_v3_resource_locator_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *xds_core_v3_ResourceLocator_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_resource_locator_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.ResourceLocator");
+}
+
+UPB_INLINE const upb_msgdef *xds_core_v3_ResourceLocator_Directive_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_resource_locator_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.ResourceLocator.Directive");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_RESOURCE_LOCATOR_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c
new file mode 100644
index 0000000..7b27e3d
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c
@@ -0,0 +1,50 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource_name.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include "upb/def.h"
+#include "xds/core/v3/resource_name.upbdefs.h"
+
+extern upb_def_init udpa_annotations_status_proto_upbdefinit;
+extern upb_def_init xds_core_v3_context_params_proto_upbdefinit;
+extern upb_def_init validate_validate_proto_upbdefinit;
+extern const upb_msglayout xds_core_v3_ResourceName_msginit;
+
+static const upb_msglayout *layouts[1] = {
+  &xds_core_v3_ResourceName_msginit,
+};
+
+static const char descriptor[367] = {'\n', '\037', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 'n', 'a', 
+'m', 'e', '.', 'p', 'r', 'o', 't', 'o', '\022', '\013', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', '3', '\032', '\035', 'u', 'd', 
+'p', 'a', '/', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 's', '/', 's', 't', 'a', 't', 'u', 's', '.', 'p', 'r', 'o', 
+'t', 'o', '\032', ' ', 'x', 'd', 's', '/', 'c', 'o', 'r', 'e', '/', 'v', '3', '/', 'c', 'o', 'n', 't', 'e', 'x', 't', '_', 'p', 
+'a', 'r', 'a', 'm', 's', '.', 'p', 'r', 'o', 't', 'o', '\032', '\027', 'v', 'a', 'l', 'i', 'd', 'a', 't', 'e', '/', 'v', 'a', 'l', 
+'i', 'd', 'a', 't', 'e', '.', 'p', 'r', 'o', 't', 'o', '\"', '\240', '\001', '\n', '\014', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 
+'a', 'm', 'e', '\022', '\016', '\n', '\002', 'i', 'd', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\002', 'i', 'd', '\022', '\034', '\n', '\t', 'a', 'u', 
+'t', 'h', 'o', 'r', 'i', 't', 'y', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\t', 'a', 'u', 't', 'h', 'o', 'r', 'i', 't', 'y', '\022', 
+',', '\n', '\r', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', '_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'B', '\007', '\372', 
+'B', '\004', 'r', '\002', '\020', '\001', 'R', '\014', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'T', 'y', 'p', 'e', '\022', '4', '\n', '\007', 'c', 
+'o', 'n', 't', 'e', 'x', 't', '\030', '\004', ' ', '\001', '(', '\013', '2', '\032', '.', 'x', 'd', 's', '.', 'c', 'o', 'r', 'e', '.', 'v', 
+'3', '.', 'C', 'o', 'n', 't', 'e', 'x', 't', 'P', 'a', 'r', 'a', 'm', 's', 'R', '\007', 'c', 'o', 'n', 't', 'e', 'x', 't', 'B', 
+':', '\n', '\033', 'c', 'o', 'm', '.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'u', 'd', 'p', 'a', '.', 'x', 'd', 's', '.', 'c', 'o', 
+'r', 'e', '.', 'v', '3', 'B', '\021', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 'N', 'a', 'm', 'e', 'P', 'r', 'o', 't', 'o', 'P', 
+'\001', '\272', '\200', '\310', '\321', '\006', '\002', '\010', '\001', 'b', '\006', 'p', 'r', 'o', 't', 'o', '3', 
+};
+
+static upb_def_init *deps[4] = {
+  &udpa_annotations_status_proto_upbdefinit,
+  &xds_core_v3_context_params_proto_upbdefinit,
+  &validate_validate_proto_upbdefinit,
+  NULL
+};
+
+upb_def_init xds_core_v3_resource_name_proto_upbdefinit = {
+  deps,
+  layouts,
+  "xds/core/v3/resource_name.proto",
+  UPB_STRVIEW_INIT(descriptor, 367)
+};
diff --git a/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h
new file mode 100644
index 0000000..b52df05
--- /dev/null
+++ b/grpc/src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h
@@ -0,0 +1,35 @@
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     xds/core/v3/resource_name.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef XDS_CORE_V3_RESOURCE_NAME_PROTO_UPBDEFS_H_
+#define XDS_CORE_V3_RESOURCE_NAME_PROTO_UPBDEFS_H_
+
+#include "upb/def.h"
+#include "upb/port_def.inc"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upb/def.h"
+
+#include "upb/port_def.inc"
+
+extern upb_def_init xds_core_v3_resource_name_proto_upbdefinit;
+
+UPB_INLINE const upb_msgdef *xds_core_v3_ResourceName_getmsgdef(upb_symtab *s) {
+  _upb_symtab_loaddefinit(s, &xds_core_v3_resource_name_proto_upbdefinit);
+  return upb_symtab_lookupmsg(s, "xds.core.v3.ResourceName");
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif  /* XDS_CORE_V3_RESOURCE_NAME_PROTO_UPBDEFS_H_ */
diff --git a/grpc/src/core/ext/xds/certificate_provider_factory.h b/grpc/src/core/ext/xds/certificate_provider_factory.h
index 84c219e..e9bba79 100644
--- a/grpc/src/core/ext/xds/certificate_provider_factory.h
+++ b/grpc/src/core/ext/xds/certificate_provider_factory.h
@@ -49,7 +49,7 @@
   virtual const char* name() const = 0;
 
   virtual RefCountedPtr<Config> CreateCertificateProviderConfig(
-      const Json& config_json, grpc_error** error) = 0;
+      const Json& config_json, grpc_error_handle* error) = 0;
 
   // Create a CertificateProvider instance from config.
   virtual RefCountedPtr<grpc_tls_certificate_provider>
diff --git a/grpc/src/core/ext/xds/certificate_provider_store.h b/grpc/src/core/ext/xds/certificate_provider_store.h
index 0954bc5..fb6ca72 100644
--- a/grpc/src/core/ext/xds/certificate_provider_store.h
+++ b/grpc/src/core/ext/xds/certificate_provider_store.h
@@ -92,7 +92,7 @@
   };
 
   RefCountedPtr<CertificateProviderWrapper> CreateCertificateProviderLocked(
-      absl::string_view key);
+      absl::string_view key) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   // Releases a previously created certificate provider from the certificate
   // provider map if the value matches \a wrapper.
@@ -101,10 +101,10 @@
 
   Mutex mu_;
   // Map of plugin configurations
-  PluginDefinitionMap plugin_config_map_;
+  PluginDefinitionMap plugin_config_map_ ABSL_GUARDED_BY(mu_);
   // Underlying map for the providers.
   std::map<absl::string_view, CertificateProviderWrapper*>
-      certificate_providers_map_;
+      certificate_providers_map_ ABSL_GUARDED_BY(mu_);
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/xds/file_watcher_certificate_provider_factory.cc b/grpc/src/core/ext/xds/file_watcher_certificate_provider_factory.cc
index a5250eb..7a793b0 100644
--- a/grpc/src/core/ext/xds/file_watcher_certificate_provider_factory.cc
+++ b/grpc/src/core/ext/xds/file_watcher_certificate_provider_factory.cc
@@ -64,14 +64,14 @@
 
 RefCountedPtr<FileWatcherCertificateProviderFactory::Config>
 FileWatcherCertificateProviderFactory::Config::Parse(const Json& config_json,
-                                                     grpc_error** error) {
+                                                     grpc_error_handle* error) {
   auto config = MakeRefCounted<FileWatcherCertificateProviderFactory::Config>();
   if (config_json.type() != Json::Type::OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "error:config type should be OBJECT.");
     return nullptr;
   }
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   ParseJsonObjectField(config_json.object_value(), "certificate_file",
                        &config->identity_cert_file_, &error_list, false);
   ParseJsonObjectField(config_json.object_value(), "private_key_file",
@@ -112,7 +112,7 @@
 
 RefCountedPtr<CertificateProviderFactory::Config>
 FileWatcherCertificateProviderFactory::CreateCertificateProviderConfig(
-    const Json& config_json, grpc_error** error) {
+    const Json& config_json, grpc_error_handle* error) {
   return FileWatcherCertificateProviderFactory::Config::Parse(config_json,
                                                               error);
 }
diff --git a/grpc/src/core/ext/xds/file_watcher_certificate_provider_factory.h b/grpc/src/core/ext/xds/file_watcher_certificate_provider_factory.h
index c570062..13e10de 100644
--- a/grpc/src/core/ext/xds/file_watcher_certificate_provider_factory.h
+++ b/grpc/src/core/ext/xds/file_watcher_certificate_provider_factory.h
@@ -31,7 +31,7 @@
   class Config : public CertificateProviderFactory::Config {
    public:
     static RefCountedPtr<Config> Parse(const Json& config_json,
-                                       grpc_error** error);
+                                       grpc_error_handle* error);
 
     const char* name() const override;
 
@@ -58,7 +58,7 @@
 
   RefCountedPtr<CertificateProviderFactory::Config>
   CreateCertificateProviderConfig(const Json& config_json,
-                                  grpc_error** error) override;
+                                  grpc_error_handle* error) override;
 
   RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
       RefCountedPtr<CertificateProviderFactory::Config> config) override;
diff --git a/grpc/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc b/grpc/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
index c1b7b84..6e63ae4 100644
--- a/grpc/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
+++ b/grpc/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
@@ -52,10 +52,10 @@
   return "{}";
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectStsService(
     const Json::Object& sts_service) {
-  std::vector<grpc_error*> error_list_sts_service;
+  std::vector<grpc_error_handle> error_list_sts_service;
   if (!ParseJsonObjectField(sts_service, "token_exchange_service_uri",
                             &sts_config_.token_exchange_service_uri,
                             &error_list_sts_service, false)) {
@@ -89,14 +89,14 @@
   return error_list_sts_service;
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectCallCredentials(
     const Json::Object& call_credentials) {
-  std::vector<grpc_error*> error_list_call_credentials;
+  std::vector<grpc_error_handle> error_list_call_credentials;
   const Json::Object* sts_service = nullptr;
   if (ParseJsonObjectField(call_credentials, "sts_service", &sts_service,
                            &error_list_call_credentials)) {
-    std::vector<grpc_error*> error_list_sts_service =
+    std::vector<grpc_error_handle> error_list_sts_service =
         ParseJsonObjectStsService(*sts_service);
     if (!error_list_sts_service.empty()) {
       error_list_call_credentials.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -106,10 +106,10 @@
   return error_list_call_credentials;
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGoogleGrpc(
     const Json::Object& google_grpc) {
-  std::vector<grpc_error*> error_list_google_grpc;
+  std::vector<grpc_error_handle> error_list_google_grpc;
   if (!ParseJsonObjectField(google_grpc, "target_uri", &endpoint_,
                             &error_list_google_grpc, false)) {
     endpoint_ = "meshca.googleapis.com";  // Default target
@@ -124,7 +124,7 @@
       const Json::Object* call_credentials = nullptr;
       if (ExtractJsonType((*call_credentials_array)[0], "call_credentials[0]",
                           &call_credentials, &error_list_google_grpc)) {
-        std::vector<grpc_error*> error_list_call_credentials =
+        std::vector<grpc_error_handle> error_list_call_credentials =
             ParseJsonObjectCallCredentials(*call_credentials);
         if (!error_list_call_credentials.empty()) {
           error_list_google_grpc.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -137,14 +137,14 @@
   return error_list_google_grpc;
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGrpcServices(
     const Json::Object& grpc_service) {
-  std::vector<grpc_error*> error_list_grpc_services;
+  std::vector<grpc_error_handle> error_list_grpc_services;
   const Json::Object* google_grpc = nullptr;
   if (ParseJsonObjectField(grpc_service, "google_grpc", &google_grpc,
                            &error_list_grpc_services)) {
-    std::vector<grpc_error*> error_list_google_grpc =
+    std::vector<grpc_error_handle> error_list_google_grpc =
         ParseJsonObjectGoogleGrpc(*google_grpc);
     if (!error_list_google_grpc.empty()) {
       error_list_grpc_services.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -158,10 +158,10 @@
   return error_list_grpc_services;
 }
 
-std::vector<grpc_error*>
+std::vector<grpc_error_handle>
 GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectServer(
     const Json::Object& server) {
-  std::vector<grpc_error*> error_list_server;
+  std::vector<grpc_error_handle> error_list_server;
   std::string api_type;
   if (ParseJsonObjectField(server, "api_type", &api_type, &error_list_server,
                            false)) {
@@ -180,7 +180,7 @@
       const Json::Object* grpc_service = nullptr;
       if (ExtractJsonType((*grpc_services)[0], "grpc_services[0]",
                           &grpc_service, &error_list_server)) {
-        std::vector<grpc_error*> error_list_grpc_services =
+        std::vector<grpc_error_handle> error_list_grpc_services =
             ParseJsonObjectGrpcServices(*grpc_service);
         if (!error_list_grpc_services.empty()) {
           error_list_server.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
@@ -193,8 +193,8 @@
 }
 
 RefCountedPtr<GoogleMeshCaCertificateProviderFactory::Config>
-GoogleMeshCaCertificateProviderFactory::Config::Parse(const Json& config_json,
-                                                      grpc_error** error) {
+GoogleMeshCaCertificateProviderFactory::Config::Parse(
+    const Json& config_json, grpc_error_handle* error) {
   auto config =
       MakeRefCounted<GoogleMeshCaCertificateProviderFactory::Config>();
   if (config_json.type() != Json::Type::OBJECT) {
@@ -202,11 +202,11 @@
         "error:config type should be OBJECT.");
     return nullptr;
   }
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   const Json::Object* server = nullptr;
   if (ParseJsonObjectField(config_json.object_value(), "server", &server,
                            &error_list)) {
-    std::vector<grpc_error*> error_list_server =
+    std::vector<grpc_error_handle> error_list_server =
         config->ParseJsonObjectServer(*server);
     if (!error_list_server.empty()) {
       error_list.push_back(
@@ -257,7 +257,7 @@
 
 RefCountedPtr<CertificateProviderFactory::Config>
 GoogleMeshCaCertificateProviderFactory::CreateCertificateProviderConfig(
-    const Json& config_json, grpc_error** error) {
+    const Json& config_json, grpc_error_handle* error) {
   return GoogleMeshCaCertificateProviderFactory::Config::Parse(config_json,
                                                                error);
 }
diff --git a/grpc/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h b/grpc/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h
index f2765d6..7a33f97 100644
--- a/grpc/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h
+++ b/grpc/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h
@@ -63,19 +63,20 @@
     const std::string& location() const { return location_; }
 
     static RefCountedPtr<Config> Parse(const Json& config_json,
-                                       grpc_error** error);
+                                       grpc_error_handle* error);
 
    private:
     // Helpers for parsing the config
-    std::vector<grpc_error*> ParseJsonObjectStsService(
+    std::vector<grpc_error_handle> ParseJsonObjectStsService(
         const Json::Object& sts_service);
-    std::vector<grpc_error*> ParseJsonObjectCallCredentials(
+    std::vector<grpc_error_handle> ParseJsonObjectCallCredentials(
         const Json::Object& call_credentials);
-    std::vector<grpc_error*> ParseJsonObjectGoogleGrpc(
+    std::vector<grpc_error_handle> ParseJsonObjectGoogleGrpc(
         const Json::Object& google_grpc);
-    std::vector<grpc_error*> ParseJsonObjectGrpcServices(
+    std::vector<grpc_error_handle> ParseJsonObjectGrpcServices(
         const Json::Object& grpc_service);
-    std::vector<grpc_error*> ParseJsonObjectServer(const Json::Object& server);
+    std::vector<grpc_error_handle> ParseJsonObjectServer(
+        const Json::Object& server);
 
     std::string endpoint_;
     StsConfig sts_config_;
@@ -90,10 +91,10 @@
 
   RefCountedPtr<CertificateProviderFactory::Config>
   CreateCertificateProviderConfig(const Json& config_json,
-                                  grpc_error** error) override;
+                                  grpc_error_handle* error) override;
 
   RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
-      RefCountedPtr<CertificateProviderFactory::Config> config) override {
+      RefCountedPtr<CertificateProviderFactory::Config> /*config*/) override {
     // TODO(yashykt) : To be implemented
     return nullptr;
   }
diff --git a/grpc/src/core/ext/xds/xds_api.cc b/grpc/src/core/ext/xds/xds_api.cc
index e9403c2..e51bc07 100644
--- a/grpc/src/core/ext/xds/xds_api.cc
+++ b/grpc/src/core/ext/xds/xds_api.cc
@@ -28,26 +28,13 @@
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_join.h"
 #include "absl/strings/str_split.h"
-
-#include "upb/upb.hpp"
-
-#include <grpc/impl/codegen/log.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/ext/xds/xds_api.h"
-#include "src/core/lib/gpr/env.h"
-#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/slice/slice_utils.h"
-
+#include "envoy/admin/v3/config_dump.upb.h"
 #include "envoy/config/cluster/v3/circuit_breaker.upb.h"
 #include "envoy/config/cluster/v3/cluster.upb.h"
 #include "envoy/config/cluster/v3/cluster.upbdefs.h"
 #include "envoy/config/core/v3/address.upb.h"
 #include "envoy/config/core/v3/base.upb.h"
+#include "envoy/config/core/v3/base.upbdefs.h"
 #include "envoy/config/core/v3/config_source.upb.h"
 #include "envoy/config/core/v3/health_check.upb.h"
 #include "envoy/config/core/v3/protocol.upb.h"
@@ -57,12 +44,19 @@
 #include "envoy/config/endpoint/v3/load_report.upb.h"
 #include "envoy/config/listener/v3/api_listener.upb.h"
 #include "envoy/config/listener/v3/listener.upb.h"
+#include "envoy/config/listener/v3/listener.upbdefs.h"
+#include "envoy/config/listener/v3/listener_components.upb.h"
 #include "envoy/config/route/v3/route.upb.h"
 #include "envoy/config/route/v3/route.upbdefs.h"
 #include "envoy/config/route/v3/route_components.upb.h"
+#include "envoy/config/route/v3/route_components.upbdefs.h"
+#include "envoy/extensions/clusters/aggregate/v3/cluster.upb.h"
+#include "envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h"
 #include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h"
+#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h"
 #include "envoy/extensions/transport_sockets/tls/v3/common.upb.h"
 #include "envoy/extensions/transport_sockets/tls/v3/tls.upb.h"
+#include "envoy/extensions/transport_sockets/tls/v3/tls.upbdefs.h"
 #include "envoy/service/cluster/v3/cds.upb.h"
 #include "envoy/service/cluster/v3/cds.upbdefs.h"
 #include "envoy/service/discovery/v3/discovery.upb.h"
@@ -74,6 +68,8 @@
 #include "envoy/service/load_stats/v3/lrs.upbdefs.h"
 #include "envoy/service/route/v3/rds.upb.h"
 #include "envoy/service/route/v3/rds.upbdefs.h"
+#include "envoy/service/status/v3/csds.upb.h"
+#include "envoy/service/status/v3/csds.upbdefs.h"
 #include "envoy/type/matcher/v3/regex.upb.h"
 #include "envoy/type/matcher/v3/string.upb.h"
 #include "envoy/type/v3/percent.upb.h"
@@ -81,18 +77,49 @@
 #include "google/protobuf/any.upb.h"
 #include "google/protobuf/duration.upb.h"
 #include "google/protobuf/struct.upb.h"
+#include "google/protobuf/timestamp.upb.h"
 #include "google/protobuf/wrappers.upb.h"
 #include "google/rpc/status.upb.h"
+#include "udpa/type/v1/typed_struct.upb.h"
 #include "upb/text_encode.h"
 #include "upb/upb.h"
+#include "upb/upb.hpp"
+
+#include <grpc/impl/codegen/log.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/xds/xds_api.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/host_port.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
+#include "src/core/lib/slice/slice_utils.h"
 
 namespace grpc_core {
 
-// TODO (donnadionne): Check to see if timeout is enabled, this will be
-// removed once timeout feature is fully integration-tested and enabled by
+// TODO(donnadionne): Check to see if cluster types aggregate_cluster and
+// logical_dns are enabled, this will be
+// removed once the cluster types are fully integration-tested and enabled by
 // default.
-bool XdsTimeoutEnabled() {
-  char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_ENABLE_TIMEOUT");
+bool XdsAggregateAndLogicalDnsClusterEnabled() {
+  char* value = gpr_getenv(
+      "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
+  bool parsed_value;
+  bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
+  gpr_free(value);
+  return parse_succeeded && parsed_value;
+}
+
+// TODO(donnadionne): Check to see if ring hash policy is enabled, this will be
+// removed once ring hash policy is fully integration-tested and enabled by
+// default.
+bool XdsRingHashEnabled() {
+  char* value = gpr_getenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH");
   bool parsed_value;
   bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
   gpr_free(value);
@@ -111,160 +138,80 @@
 }
 
 //
-// XdsApi::Route::Matchers::PathMatcher
+// XdsApi::Route::HashPolicy
 //
 
-XdsApi::Route::Matchers::PathMatcher::PathMatcher(const PathMatcher& other)
-    : type(other.type), case_sensitive(other.case_sensitive) {
-  if (type == PathMatcherType::REGEX) {
-    RE2::Options options;
-    options.set_case_sensitive(case_sensitive);
-    regex_matcher =
-        absl::make_unique<RE2>(other.regex_matcher->pattern(), options);
-  } else {
-    string_matcher = other.string_matcher;
+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::Matchers::PathMatcher& XdsApi::Route::Matchers::PathMatcher::
-operator=(const PathMatcher& other) {
+XdsApi::Route::HashPolicy& XdsApi::Route::HashPolicy::operator=(
+    const HashPolicy& other) {
   type = other.type;
-  case_sensitive = other.case_sensitive;
-  if (type == PathMatcherType::REGEX) {
-    RE2::Options options;
-    options.set_case_sensitive(case_sensitive);
-    regex_matcher =
-        absl::make_unique<RE2>(other.regex_matcher->pattern(), options);
-  } else {
-    string_matcher = other.string_matcher;
+  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;
 }
 
-bool XdsApi::Route::Matchers::PathMatcher::operator==(
-    const PathMatcher& other) const {
+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 (case_sensitive != other.case_sensitive) return false;
-  if (type == PathMatcherType::REGEX) {
-    // Should never be null.
-    if (regex_matcher == nullptr || other.regex_matcher == nullptr) {
-      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 regex_matcher->pattern() == other.regex_matcher->pattern();
   }
-  return string_matcher == other.string_matcher;
+  return true;
 }
 
-std::string XdsApi::Route::Matchers::PathMatcher::ToString() const {
-  std::string path_type_string;
+std::string XdsApi::Route::HashPolicy::ToString() const {
+  std::vector<std::string> contents;
   switch (type) {
-    case PathMatcherType::PATH:
-      path_type_string = "path match";
+    case Type::HEADER:
+      contents.push_back("type=HEADER");
       break;
-    case PathMatcherType::PREFIX:
-      path_type_string = "prefix match";
-      break;
-    case PathMatcherType::REGEX:
-      path_type_string = "regex match";
-      break;
-    default:
+    case Type::CHANNEL_ID:
+      contents.push_back("type=CHANNEL_ID");
       break;
   }
-  return absl::StrFormat("Path %s:%s%s", path_type_string,
-                         type == PathMatcherType::REGEX
-                             ? regex_matcher->pattern()
-                             : string_matcher,
-                         case_sensitive ? "" : "[case_sensitive=false]");
-}
-
-//
-// XdsApi::Route::Matchers::HeaderMatcher
-//
-
-XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcher(
-    const HeaderMatcher& other)
-    : name(other.name), type(other.type), invert_match(other.invert_match) {
-  switch (type) {
-    case HeaderMatcherType::REGEX:
-      regex_match = absl::make_unique<RE2>(other.regex_match->pattern());
-      break;
-    case HeaderMatcherType::RANGE:
-      range_start = other.range_start;
-      range_end = other.range_end;
-      break;
-    case HeaderMatcherType::PRESENT:
-      present_match = other.present_match;
-      break;
-    default:
-      string_matcher = other.string_matcher;
+  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));
   }
-}
-
-XdsApi::Route::Matchers::HeaderMatcher& XdsApi::Route::Matchers::HeaderMatcher::
-operator=(const HeaderMatcher& other) {
-  name = other.name;
-  type = other.type;
-  invert_match = other.invert_match;
-  switch (type) {
-    case HeaderMatcherType::REGEX:
-      regex_match = absl::make_unique<RE2>(other.regex_match->pattern());
-      break;
-    case HeaderMatcherType::RANGE:
-      range_start = other.range_start;
-      range_end = other.range_end;
-      break;
-    case HeaderMatcherType::PRESENT:
-      present_match = other.present_match;
-      break;
-    default:
-      string_matcher = other.string_matcher;
-  }
-  return *this;
-}
-
-bool XdsApi::Route::Matchers::HeaderMatcher::operator==(
-    const HeaderMatcher& other) const {
-  if (name != other.name) return false;
-  if (type != other.type) return false;
-  if (invert_match != other.invert_match) return false;
-  switch (type) {
-    case HeaderMatcherType::REGEX:
-      return regex_match->pattern() != other.regex_match->pattern();
-    case HeaderMatcherType::RANGE:
-      return range_start != other.range_start && range_end != other.range_end;
-    case HeaderMatcherType::PRESENT:
-      return present_match != other.present_match;
-    default:
-      return string_matcher != other.string_matcher;
-  }
-}
-
-std::string XdsApi::Route::Matchers::HeaderMatcher::ToString() const {
-  switch (type) {
-    case HeaderMatcherType::EXACT:
-      return absl::StrFormat("Header exact match:%s %s:%s",
-                             invert_match ? " not" : "", name, string_matcher);
-    case HeaderMatcherType::REGEX:
-      return absl::StrFormat("Header regex match:%s %s:%s",
-                             invert_match ? " not" : "", name,
-                             regex_match->pattern());
-    case HeaderMatcherType::RANGE:
-      return absl::StrFormat("Header range match:%s %s:[%d, %d)",
-                             invert_match ? " not" : "", name, range_start,
-                             range_end);
-    case HeaderMatcherType::PRESENT:
-      return absl::StrFormat("Header present match:%s %s:%s",
-                             invert_match ? " not" : "", name,
-                             present_match ? "true" : "false");
-    case HeaderMatcherType::PREFIX:
-      return absl::StrFormat("Header prefix match:%s %s:%s",
-                             invert_match ? " not" : "", name, string_matcher);
-    case HeaderMatcherType::SUFFIX:
-      return absl::StrFormat("Header suffix match:%s %s:%s",
-                             invert_match ? " not" : "", name, string_matcher);
-    default:
-      return "";
-  }
+  return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
 }
 
 //
@@ -273,7 +220,8 @@
 
 std::string XdsApi::Route::Matchers::ToString() const {
   std::vector<std::string> contents;
-  contents.push_back(path_matcher.ToString());
+  contents.push_back(
+      absl::StrFormat("PathMatcher{%s}", path_matcher.ToString()));
   for (const HeaderMatcher& header_matcher : header_matchers) {
     contents.push_back(header_matcher.ToString());
   }
@@ -285,12 +233,28 @@
 }
 
 std::string XdsApi::Route::ClusterWeight::ToString() const {
-  return absl::StrFormat("{cluster=%s, weight=%d}", name, weight);
+  std::vector<std::string> contents;
+  contents.push_back(absl::StrCat("cluster=", name));
+  contents.push_back(absl::StrCat("weight=", weight));
+  if (!typed_per_filter_config.empty()) {
+    std::vector<std::string> parts;
+    for (const auto& p : typed_per_filter_config) {
+      const std::string& key = p.first;
+      const auto& config = p.second;
+      parts.push_back(absl::StrCat(key, "=", config.ToString()));
+    }
+    contents.push_back(absl::StrCat("typed_per_filter_config={",
+                                    absl::StrJoin(parts, ", "), "}"));
+  }
+  return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
 }
 
 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));
   }
@@ -300,6 +264,15 @@
   if (max_stream_duration.has_value()) {
     contents.push_back(max_stream_duration->ToString());
   }
+  if (!typed_per_filter_config.empty()) {
+    contents.push_back("typed_per_filter_config={");
+    for (const auto& p : typed_per_filter_config) {
+      const std::string& name = p.first;
+      const auto& config = p.second;
+      contents.push_back(absl::StrCat("  ", name, "=", config.ToString()));
+    }
+    contents.push_back("}");
+  }
   return absl::StrJoin(contents, "\n");
 }
 
@@ -322,6 +295,14 @@
       vhosts.push_back("\n    }\n");
     }
     vhosts.push_back("  ]\n");
+    vhosts.push_back("  typed_per_filter_config={\n");
+    for (const auto& p : vhost.typed_per_filter_config) {
+      const std::string& name = p.first;
+      const auto& config = p.second;
+      vhosts.push_back(
+          absl::StrCat("    ", name, "=", config.ToString(), "\n"));
+    }
+    vhosts.push_back("  }\n");
     vhosts.push_back("]\n");
   }
   return absl::StrJoin(vhosts, "");
@@ -426,102 +407,6 @@
 }
 
 //
-// XdsApi::StringMatcher
-//
-
-XdsApi::StringMatcher::StringMatcher(StringMatcherType type,
-                                     const std::string& matcher,
-                                     bool ignore_case)
-    : type_(type), ignore_case_(ignore_case) {
-  if (type_ == StringMatcherType::SAFE_REGEX) {
-    regex_matcher_ = absl::make_unique<RE2>(matcher);
-  } else {
-    string_matcher_ = matcher;
-  }
-}
-
-XdsApi::StringMatcher::StringMatcher(const StringMatcher& other)
-    : type_(other.type_), ignore_case_(other.ignore_case_) {
-  switch (type_) {
-    case StringMatcherType::SAFE_REGEX:
-      regex_matcher_ = absl::make_unique<RE2>(other.regex_matcher_->pattern());
-      break;
-    default:
-      string_matcher_ = other.string_matcher_;
-  }
-}
-
-XdsApi::StringMatcher& XdsApi::StringMatcher::operator=(
-    const StringMatcher& other) {
-  type_ = other.type_;
-  switch (type_) {
-    case StringMatcherType::SAFE_REGEX:
-      regex_matcher_ = absl::make_unique<RE2>(other.regex_matcher_->pattern());
-      break;
-    default:
-      string_matcher_ = other.string_matcher_;
-  }
-  ignore_case_ = other.ignore_case_;
-  return *this;
-}
-
-bool XdsApi::StringMatcher::operator==(const StringMatcher& other) const {
-  if (type_ != other.type_ || ignore_case_ != other.ignore_case_) return false;
-  switch (type_) {
-    case StringMatcherType::SAFE_REGEX:
-      return regex_matcher_->pattern() == other.regex_matcher_->pattern();
-    default:
-      return string_matcher_ == other.string_matcher_;
-  }
-}
-
-bool XdsApi::StringMatcher::Match(absl::string_view value) const {
-  switch (type_) {
-    case XdsApi::StringMatcher::StringMatcherType::EXACT:
-      return ignore_case_ ? absl::EqualsIgnoreCase(value, string_matcher_)
-                          : value == string_matcher_;
-    case XdsApi::StringMatcher::StringMatcherType::PREFIX:
-      return ignore_case_ ? absl::StartsWithIgnoreCase(value, string_matcher_)
-                          : absl::StartsWith(value, string_matcher_);
-    case XdsApi::StringMatcher::StringMatcherType::SUFFIX:
-      return ignore_case_ ? absl::EndsWithIgnoreCase(value, string_matcher_)
-                          : absl::EndsWith(value, string_matcher_);
-    case XdsApi::StringMatcher::StringMatcherType::CONTAINS:
-      return ignore_case_
-                 ? absl::StrContains(absl::AsciiStrToLower(value),
-                                     absl::AsciiStrToLower(string_matcher_))
-                 : absl::StrContains(value, string_matcher_);
-    case XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX:
-      // ignore_case_ is ignored for SAFE_REGEX
-      return RE2::FullMatch(std::string(value), *regex_matcher_);
-    default:
-      return false;
-  }
-}
-
-std::string XdsApi::StringMatcher::ToString() const {
-  switch (type_) {
-    case StringMatcherType::EXACT:
-      return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_,
-                             ignore_case_ ? ", ignore_case" : "");
-    case StringMatcherType::PREFIX:
-      return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_,
-                             ignore_case_ ? ", ignore_case" : "");
-    case StringMatcherType::SUFFIX:
-      return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_,
-                             ignore_case_ ? ", ignore_case" : "");
-    case StringMatcherType::CONTAINS:
-      return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_,
-                             ignore_case_ ? ", ignore_case" : "");
-    case StringMatcherType::SAFE_REGEX:
-      return absl::StrFormat("StringMatcher{safe_regex=%s}",
-                             regex_matcher_->pattern());
-    default:
-      return "";
-  }
-}
-
-//
 // XdsApi::CommonTlsContext::CertificateValidationContext
 //
 
@@ -610,6 +495,204 @@
 }
 
 //
+// XdsApi::DownstreamTlsContext
+//
+
+std::string XdsApi::DownstreamTlsContext::ToString() const {
+  return absl::StrFormat("common_tls_context=%s, require_client_certificate=%s",
+                         common_tls_context.ToString(),
+                         require_client_certificate ? "true" : "false");
+}
+
+bool XdsApi::DownstreamTlsContext::Empty() const {
+  return common_tls_context.Empty();
+}
+
+//
+// XdsApi::LdsUpdate::HttpConnectionManager
+//
+
+std::string XdsApi::LdsUpdate::HttpConnectionManager::ToString() const {
+  absl::InlinedVector<std::string, 4> contents;
+  contents.push_back(absl::StrFormat(
+      "route_config_name=%s",
+      !route_config_name.empty() ? route_config_name.c_str() : "<inlined>"));
+  contents.push_back(absl::StrFormat("http_max_stream_duration=%s",
+                                     http_max_stream_duration.ToString()));
+  if (rds_update.has_value()) {
+    contents.push_back(
+        absl::StrFormat("rds_update=%s", rds_update->ToString()));
+  }
+  if (!http_filters.empty()) {
+    std::vector<std::string> filter_strings;
+    for (const auto& http_filter : http_filters) {
+      filter_strings.push_back(http_filter.ToString());
+    }
+    contents.push_back(absl::StrCat("http_filters=[",
+                                    absl::StrJoin(filter_strings, ", "), "]"));
+  }
+  return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
+}
+
+//
+// XdsApi::LdsUpdate::HttpFilter
+//
+
+std::string XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter::ToString()
+    const {
+  return absl::StrCat("{name=", name, ", config=", config.ToString(), "}");
+}
+
+//
+// XdsApi::LdsUpdate::FilterChainData
+//
+
+std::string XdsApi::LdsUpdate::FilterChainData::ToString() const {
+  return absl::StrCat(
+      "{downstream_tls_context=", downstream_tls_context.ToString(),
+      " http_connection_manager=", http_connection_manager.ToString(), "}");
+}
+
+//
+// XdsApi::LdsUpdate::FilterChainMap::CidrRange
+//
+
+std::string XdsApi::LdsUpdate::FilterChainMap::CidrRange::ToString() const {
+  return absl::StrCat(
+      "{address_prefix=", grpc_sockaddr_to_string(&address, false),
+      ", prefix_len=", prefix_len, "}");
+}
+
+//
+// FilterChain
+//
+
+struct FilterChain {
+  struct FilterChainMatch {
+    uint32_t destination_port = 0;
+    std::vector<XdsApi::LdsUpdate::FilterChainMap::CidrRange> prefix_ranges;
+    XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType source_type =
+        XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::kAny;
+    std::vector<XdsApi::LdsUpdate::FilterChainMap::CidrRange>
+        source_prefix_ranges;
+    std::vector<uint32_t> source_ports;
+    std::vector<std::string> server_names;
+    std::string transport_protocol;
+    std::vector<std::string> application_protocols;
+
+    std::string ToString() const;
+  } filter_chain_match;
+
+  std::shared_ptr<XdsApi::LdsUpdate::FilterChainData> filter_chain_data;
+};
+
+std::string FilterChain::FilterChainMatch::ToString() const {
+  absl::InlinedVector<std::string, 8> contents;
+  if (destination_port != 0) {
+    contents.push_back(absl::StrCat("destination_port=", destination_port));
+  }
+  if (!prefix_ranges.empty()) {
+    std::vector<std::string> prefix_ranges_content;
+    for (const auto& range : prefix_ranges) {
+      prefix_ranges_content.push_back(range.ToString());
+    }
+    contents.push_back(absl::StrCat(
+        "prefix_ranges={", absl::StrJoin(prefix_ranges_content, ", "), "}"));
+  }
+  if (source_type == XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::
+                         kSameIpOrLoopback) {
+    contents.push_back("source_type=SAME_IP_OR_LOOPBACK");
+  } else if (source_type == XdsApi::LdsUpdate::FilterChainMap::
+                                ConnectionSourceType::kExternal) {
+    contents.push_back("source_type=EXTERNAL");
+  }
+  if (!source_prefix_ranges.empty()) {
+    std::vector<std::string> source_prefix_ranges_content;
+    for (const auto& range : source_prefix_ranges) {
+      source_prefix_ranges_content.push_back(range.ToString());
+    }
+    contents.push_back(
+        absl::StrCat("source_prefix_ranges={",
+                     absl::StrJoin(source_prefix_ranges_content, ", "), "}"));
+  }
+  if (!source_ports.empty()) {
+    contents.push_back(
+        absl::StrCat("source_ports={", absl::StrJoin(source_ports, ", "), "}"));
+  }
+  if (!server_names.empty()) {
+    contents.push_back(
+        absl::StrCat("server_names={", absl::StrJoin(server_names, ", "), "}"));
+  }
+  if (!transport_protocol.empty()) {
+    contents.push_back(absl::StrCat("transport_protocol=", transport_protocol));
+  }
+  if (!application_protocols.empty()) {
+    contents.push_back(absl::StrCat("application_protocols={",
+                                    absl::StrJoin(application_protocols, ", "),
+                                    "}"));
+  }
+  return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
+}
+
+//
+// XdsApi::LdsUpdate::FilterChainMap
+//
+
+std::string XdsApi::LdsUpdate::FilterChainMap::ToString() const {
+  std::vector<std::string> contents;
+  for (const auto& destination_ip : destination_ip_vector) {
+    for (int source_type = 0; source_type < 3; ++source_type) {
+      for (const auto& source_ip :
+           destination_ip.source_types_array[source_type]) {
+        for (const auto& source_port_pair : source_ip.ports_map) {
+          FilterChain::FilterChainMatch filter_chain_match;
+          if (destination_ip.prefix_range.has_value()) {
+            filter_chain_match.prefix_ranges.push_back(
+                *destination_ip.prefix_range);
+          }
+          filter_chain_match.source_type = static_cast<
+              XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType>(
+              source_type);
+          if (source_ip.prefix_range.has_value()) {
+            filter_chain_match.source_prefix_ranges.push_back(
+                *source_ip.prefix_range);
+          }
+          if (source_port_pair.first != 0) {
+            filter_chain_match.source_ports.push_back(source_port_pair.first);
+          }
+          contents.push_back(absl::StrCat(
+              "{filter_chain_match=", filter_chain_match.ToString(),
+              ", filter_chain=", source_port_pair.second.data->ToString(),
+              "}"));
+        }
+      }
+    }
+  }
+  return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
+}
+
+//
+// XdsApi::LdsUpdate
+//
+
+std::string XdsApi::LdsUpdate::ToString() const {
+  absl::InlinedVector<std::string, 4> contents;
+  if (type == ListenerType::kTcpListener) {
+    contents.push_back(absl::StrCat("address=", address));
+    contents.push_back(
+        absl::StrCat("filter_chain_map=", filter_chain_map.ToString()));
+    if (default_filter_chain.has_value()) {
+      contents.push_back(absl::StrCat("default_filter_chain=",
+                                      default_filter_chain->ToString()));
+    }
+  } else if (type == ListenerType::kHttpApiListener) {
+    contents.push_back(absl::StrFormat("http_connection_manager=%s",
+                                       http_connection_manager.ToString()));
+  }
+  return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
+}
+
+//
 // XdsApi::CdsUpdate
 //
 
@@ -724,8 +807,13 @@
 const char* kEdsV2TypeUrl =
     "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment";
 
-bool IsLds(absl::string_view type_url) {
-  return type_url == XdsApi::kLdsTypeUrl || type_url == kLdsV2TypeUrl;
+bool IsLds(absl::string_view type_url, bool* is_v2 = nullptr) {
+  if (type_url == XdsApi::kLdsTypeUrl) return true;
+  if (type_url == kLdsV2TypeUrl) {
+    if (is_v2 != nullptr) *is_v2 = true;
+    return true;
+  }
+  return false;
 }
 
 bool IsRds(absl::string_view type_url) {
@@ -749,39 +837,67 @@
       node_(node),
       build_version_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING, " ",
                                   grpc_version_string())),
-      user_agent_name_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING)) {}
+      user_agent_name_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING)) {
+  // Populate upb symtab with xDS proto messages that we want to print
+  // properly in logs.
+  // Note: This won't actually work properly until upb adds support for
+  // Any fields in textproto printing (internal b/178821188).
+  envoy_config_listener_v3_Listener_getmsgdef(symtab_.ptr());
+  envoy_config_route_v3_RouteConfiguration_getmsgdef(symtab_.ptr());
+  envoy_config_cluster_v3_Cluster_getmsgdef(symtab_.ptr());
+  envoy_extensions_clusters_aggregate_v3_ClusterConfig_getmsgdef(symtab_.ptr());
+  envoy_config_cluster_v3_Cluster_getmsgdef(symtab_.ptr());
+  envoy_config_endpoint_v3_ClusterLoadAssignment_getmsgdef(symtab_.ptr());
+  envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_getmsgdef(
+      symtab_.ptr());
+  envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_getmsgdef(
+      symtab_.ptr());
+  // Load HTTP filter proto messages into the upb symtab.
+  XdsHttpFilterRegistry::PopulateSymtab(symtab_.ptr());
+}
 
 namespace {
 
+struct EncodingContext {
+  XdsClient* client;
+  TraceFlag* tracer;
+  upb_symtab* symtab;
+  upb_arena* arena;
+  bool use_v3;
+};
+
 // Works for both std::string and absl::string_view.
 template <typename T>
 inline upb_strview StdStringToUpbString(const T& str) {
   return upb_strview_make(str.data(), str.size());
 }
 
-void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
-                           const Json& value);
+void PopulateMetadataValue(const EncodingContext& context,
+                           google_protobuf_Value* value_pb, const Json& value);
 
-void PopulateListValue(upb_arena* arena, google_protobuf_ListValue* list_value,
+void PopulateListValue(const EncodingContext& context,
+                       google_protobuf_ListValue* list_value,
                        const Json::Array& values) {
   for (const auto& value : values) {
-    auto* value_pb = google_protobuf_ListValue_add_values(list_value, arena);
-    PopulateMetadataValue(arena, value_pb, value);
+    auto* value_pb =
+        google_protobuf_ListValue_add_values(list_value, context.arena);
+    PopulateMetadataValue(context, value_pb, value);
   }
 }
 
-void PopulateMetadata(upb_arena* arena, google_protobuf_Struct* metadata_pb,
+void PopulateMetadata(const EncodingContext& context,
+                      google_protobuf_Struct* metadata_pb,
                       const Json::Object& metadata) {
   for (const auto& p : metadata) {
-    google_protobuf_Value* value = google_protobuf_Value_new(arena);
-    PopulateMetadataValue(arena, value, p.second);
+    google_protobuf_Value* value = google_protobuf_Value_new(context.arena);
+    PopulateMetadataValue(context, value, p.second);
     google_protobuf_Struct_fields_set(
-        metadata_pb, StdStringToUpbString(p.first), value, arena);
+        metadata_pb, StdStringToUpbString(p.first), value, context.arena);
   }
 }
 
-void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
-                           const Json& value) {
+void PopulateMetadataValue(const EncodingContext& context,
+                           google_protobuf_Value* value_pb, const Json& value) {
   switch (value.type()) {
     case Json::Type::JSON_NULL:
       google_protobuf_Value_set_null_value(value_pb, 0);
@@ -802,14 +918,14 @@
       break;
     case Json::Type::OBJECT: {
       google_protobuf_Struct* struct_value =
-          google_protobuf_Value_mutable_struct_value(value_pb, arena);
-      PopulateMetadata(arena, struct_value, value.object_value());
+          google_protobuf_Value_mutable_struct_value(value_pb, context.arena);
+      PopulateMetadata(context, struct_value, value.object_value());
       break;
     }
     case Json::Type::ARRAY: {
       google_protobuf_ListValue* list_value =
-          google_protobuf_Value_mutable_list_value(value_pb, arena);
-      PopulateListValue(arena, list_value, value.array_value());
+          google_protobuf_Value_mutable_list_value(value_pb, context.arena);
+      PopulateListValue(context, list_value, value.array_value());
       break;
     }
   }
@@ -836,7 +952,8 @@
          EncodeVarint(str.size()) + str;
 }
 
-void PopulateBuildVersion(upb_arena* arena, envoy_config_core_v3_Node* node_msg,
+void PopulateBuildVersion(const EncodingContext& context,
+                          envoy_config_core_v3_Node* node_msg,
                           const std::string& build_version) {
   std::string encoded_build_version = EncodeStringField(5, build_version);
   // TODO(roth): This should use upb_msg_addunknown(), but that API is
@@ -844,10 +961,11 @@
   // API for now.  Change this once we upgrade to a version of upb that
   // fixes this bug.
   _upb_msg_addunknown(node_msg, encoded_build_version.data(),
-                      encoded_build_version.size(), arena);
+                      encoded_build_version.size(), context.arena);
 }
 
-void PopulateNode(upb_arena* arena, const XdsBootstrap::Node* node, bool use_v3,
+void PopulateNode(const EncodingContext& context,
+                  const XdsBootstrap::Node* node,
                   const std::string& build_version,
                   const std::string& user_agent_name,
                   envoy_config_core_v3_Node* node_msg) {
@@ -862,13 +980,13 @@
     }
     if (!node->metadata.object_value().empty()) {
       google_protobuf_Struct* metadata =
-          envoy_config_core_v3_Node_mutable_metadata(node_msg, arena);
-      PopulateMetadata(arena, metadata, node->metadata.object_value());
+          envoy_config_core_v3_Node_mutable_metadata(node_msg, context.arena);
+      PopulateMetadata(context, metadata, node->metadata.object_value());
     }
     if (!node->locality_region.empty() || !node->locality_zone.empty() ||
-        !node->locality_subzone.empty()) {
+        !node->locality_sub_zone.empty()) {
       envoy_config_core_v3_Locality* locality =
-          envoy_config_core_v3_Node_mutable_locality(node_msg, arena);
+          envoy_config_core_v3_Node_mutable_locality(node_msg, context.arena);
       if (!node->locality_region.empty()) {
         envoy_config_core_v3_Locality_set_region(
             locality, StdStringToUpbString(node->locality_region));
@@ -877,14 +995,14 @@
         envoy_config_core_v3_Locality_set_zone(
             locality, StdStringToUpbString(node->locality_zone));
       }
-      if (!node->locality_subzone.empty()) {
+      if (!node->locality_sub_zone.empty()) {
         envoy_config_core_v3_Locality_set_sub_zone(
-            locality, StdStringToUpbString(node->locality_subzone));
+            locality, StdStringToUpbString(node->locality_sub_zone));
       }
     }
   }
-  if (!use_v3) {
-    PopulateBuildVersion(arena, node_msg, build_version);
+  if (!context.use_v3) {
+    PopulateBuildVersion(context, node_msg, build_version);
   }
   envoy_config_core_v3_Node_set_user_agent_name(
       node_msg, StdStringToUpbString(user_agent_name));
@@ -892,7 +1010,7 @@
       node_msg, upb_strview_makez(grpc_version_string()));
   envoy_config_core_v3_Node_add_client_features(
       node_msg, upb_strview_makez("envoy.lb.does_not_support_overprovisioning"),
-      arena);
+      context.arena);
 }
 
 inline absl::string_view UpbStringToAbsl(const upb_strview& str) {
@@ -904,24 +1022,25 @@
 }
 
 void MaybeLogDiscoveryRequest(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
+    const EncodingContext& context,
     const envoy_service_discovery_v3_DiscoveryRequest* request) {
-  if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
+  if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
     const upb_msgdef* msg_type =
-        envoy_service_discovery_v3_DiscoveryRequest_getmsgdef(symtab);
+        envoy_service_discovery_v3_DiscoveryRequest_getmsgdef(context.symtab);
     char buf[10240];
     upb_text_encode(request, msg_type, nullptr, 0, buf, sizeof(buf));
-    gpr_log(GPR_DEBUG, "[xds_client %p] constructed ADS request: %s", client,
-            buf);
+    gpr_log(GPR_DEBUG, "[xds_client %p] constructed ADS request: %s",
+            context.client, buf);
   }
 }
 
 grpc_slice SerializeDiscoveryRequest(
-    upb_arena* arena, envoy_service_discovery_v3_DiscoveryRequest* request) {
+    const EncodingContext& context,
+    envoy_service_discovery_v3_DiscoveryRequest* request) {
   size_t output_length;
   char* output = envoy_service_discovery_v3_DiscoveryRequest_serialize(
-      request, arena, &output_length);
+      request, context.arena, &output_length);
   return grpc_slice_from_copied_buffer(output, output_length);
 }
 
@@ -949,9 +1068,11 @@
 grpc_slice XdsApi::CreateAdsRequest(
     const XdsBootstrap::XdsServer& server, const std::string& type_url,
     const std::set<absl::string_view>& resource_names,
-    const std::string& version, const std::string& nonce, grpc_error* error,
-    bool populate_node) {
+    const std::string& version, const std::string& nonce,
+    grpc_error_handle error, bool populate_node) {
   upb::Arena arena;
+  const EncodingContext context = {client_, tracer_, symtab_.ptr(), arena.ptr(),
+                                   server.ShouldUseV3()};
   // Create a request.
   envoy_service_discovery_v3_DiscoveryRequest* request =
       envoy_service_discovery_v3_DiscoveryRequest_new(arena.ptr());
@@ -971,6 +1092,7 @@
         request, StdStringToUpbString(nonce));
   }
   // Set error_detail if it's a NACK.
+  std::string error_string_storage;
   if (error != GRPC_ERROR_NONE) {
     google_rpc_Status* error_detail =
         envoy_service_discovery_v3_DiscoveryRequest_mutable_error_detail(
@@ -981,12 +1103,9 @@
     // generate them in the parsing code, and then use that here.
     google_rpc_Status_set_code(error_detail, GRPC_STATUS_INVALID_ARGUMENT);
     // Error description comes from the error that was passed in.
-    grpc_slice error_description_slice;
-    GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
-                                  &error_description_slice));
-    upb_strview error_description_strview =
-        StdStringToUpbString(StringViewFromSlice(error_description_slice));
-    google_rpc_Status_set_message(error_detail, error_description_strview);
+    error_string_storage = grpc_error_std_string(error);
+    upb_strview error_description = StdStringToUpbString(error_string_storage);
+    google_rpc_Status_set_message(error_detail, error_description);
     GRPC_ERROR_UNREF(error);
   }
   // Populate node.
@@ -994,79 +1113,102 @@
     envoy_config_core_v3_Node* node_msg =
         envoy_service_discovery_v3_DiscoveryRequest_mutable_node(request,
                                                                  arena.ptr());
-    PopulateNode(arena.ptr(), node_, server.ShouldUseV3(), build_version_,
-                 user_agent_name_, node_msg);
+    PopulateNode(context, node_, build_version_, user_agent_name_, node_msg);
   }
   // Add resource_names.
   for (const auto& resource_name : resource_names) {
     envoy_service_discovery_v3_DiscoveryRequest_add_resource_names(
         request, StdStringToUpbString(resource_name), arena.ptr());
   }
-  MaybeLogDiscoveryRequest(client_, tracer_, symtab_.ptr(), request);
-  return SerializeDiscoveryRequest(arena.ptr(), request);
+  MaybeLogDiscoveryRequest(context, request);
+  return SerializeDiscoveryRequest(context, request);
 }
 
 namespace {
 
 void MaybeLogDiscoveryResponse(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
+    const EncodingContext& context,
     const envoy_service_discovery_v3_DiscoveryResponse* response) {
-  if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
+  if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
     const upb_msgdef* msg_type =
-        envoy_service_discovery_v3_DiscoveryResponse_getmsgdef(symtab);
+        envoy_service_discovery_v3_DiscoveryResponse_getmsgdef(context.symtab);
     char buf[10240];
     upb_text_encode(response, msg_type, nullptr, 0, buf, sizeof(buf));
-    gpr_log(GPR_DEBUG, "[xds_client %p] received response: %s", client, buf);
-  }
-}
-
-void MaybeLogRouteConfiguration(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
-    const envoy_config_route_v3_RouteConfiguration* route_config) {
-  if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
-      gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
-    const upb_msgdef* msg_type =
-        envoy_config_route_v3_RouteConfiguration_getmsgdef(symtab);
-    char buf[10240];
-    upb_text_encode(route_config, msg_type, nullptr, 0, buf, sizeof(buf));
-    gpr_log(GPR_DEBUG, "[xds_client %p] RouteConfiguration: %s", client, buf);
-  }
-}
-
-void MaybeLogCluster(XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
-                     const envoy_config_cluster_v3_Cluster* cluster) {
-  if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
-      gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
-    const upb_msgdef* msg_type =
-        envoy_config_cluster_v3_Cluster_getmsgdef(symtab);
-    char buf[10240];
-    upb_text_encode(cluster, msg_type, nullptr, 0, buf, sizeof(buf));
-    gpr_log(GPR_DEBUG, "[xds_client %p] Cluster: %s", client, buf);
-  }
-}
-
-void MaybeLogClusterLoadAssignment(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
-    const envoy_config_endpoint_v3_ClusterLoadAssignment* cla) {
-  if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
-      gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
-    const upb_msgdef* msg_type =
-        envoy_config_endpoint_v3_ClusterLoadAssignment_getmsgdef(symtab);
-    char buf[10240];
-    upb_text_encode(cla, msg_type, nullptr, 0, buf, sizeof(buf));
-    gpr_log(GPR_DEBUG, "[xds_client %p] ClusterLoadAssignment: %s", client,
+    gpr_log(GPR_DEBUG, "[xds_client %p] received response: %s", context.client,
             buf);
   }
 }
 
-grpc_error* RoutePathMatchParse(const envoy_config_route_v3_RouteMatch* match,
-                                XdsApi::Route* route, bool* ignore_route) {
-  auto* case_sensitive = envoy_config_route_v3_RouteMatch_case_sensitive(match);
-  if (case_sensitive != nullptr) {
-    route->matchers.path_matcher.case_sensitive =
-        google_protobuf_BoolValue_value(case_sensitive);
+void MaybeLogHttpConnectionManager(
+    const EncodingContext& context,
+    const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager*
+        http_connection_manager_config) {
+  if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
+      gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
+    const upb_msgdef* msg_type =
+        envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_getmsgdef(
+            context.symtab);
+    char buf[10240];
+    upb_text_encode(http_connection_manager_config, msg_type, nullptr, 0, buf,
+                    sizeof(buf));
+    gpr_log(GPR_DEBUG, "[xds_client %p] HttpConnectionManager: %s",
+            context.client, buf);
   }
+}
+
+void MaybeLogRouteConfiguration(
+    const EncodingContext& context,
+    const envoy_config_route_v3_RouteConfiguration* route_config) {
+  if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
+      gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
+    const upb_msgdef* msg_type =
+        envoy_config_route_v3_RouteConfiguration_getmsgdef(context.symtab);
+    char buf[10240];
+    upb_text_encode(route_config, msg_type, nullptr, 0, buf, sizeof(buf));
+    gpr_log(GPR_DEBUG, "[xds_client %p] RouteConfiguration: %s", context.client,
+            buf);
+  }
+}
+
+void MaybeLogCluster(const EncodingContext& context,
+                     const envoy_config_cluster_v3_Cluster* cluster) {
+  if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
+      gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
+    const upb_msgdef* msg_type =
+        envoy_config_cluster_v3_Cluster_getmsgdef(context.symtab);
+    char buf[10240];
+    upb_text_encode(cluster, msg_type, nullptr, 0, buf, sizeof(buf));
+    gpr_log(GPR_DEBUG, "[xds_client %p] Cluster: %s", context.client, buf);
+  }
+}
+
+void MaybeLogClusterLoadAssignment(
+    const EncodingContext& context,
+    const envoy_config_endpoint_v3_ClusterLoadAssignment* cla) {
+  if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
+      gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
+    const upb_msgdef* msg_type =
+        envoy_config_endpoint_v3_ClusterLoadAssignment_getmsgdef(
+            context.symtab);
+    char buf[10240];
+    upb_text_encode(cla, msg_type, nullptr, 0, buf, sizeof(buf));
+    gpr_log(GPR_DEBUG, "[xds_client %p] ClusterLoadAssignment: %s",
+            context.client, buf);
+  }
+}
+
+grpc_error_handle RoutePathMatchParse(
+    const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route,
+    bool* ignore_route) {
+  auto* case_sensitive_ptr =
+      envoy_config_route_v3_RouteMatch_case_sensitive(match);
+  bool case_sensitive = true;
+  if (case_sensitive_ptr != nullptr) {
+    case_sensitive = google_protobuf_BoolValue_value(case_sensitive_ptr);
+  }
+  StringMatcher::Type type;
+  std::string match_string;
   if (envoy_config_route_v3_RouteMatch_has_prefix(match)) {
     absl::string_view prefix =
         UpbStringToAbsl(envoy_config_route_v3_RouteMatch_prefix(match));
@@ -1091,9 +1233,8 @@
         return GRPC_ERROR_NONE;
       }
     }
-    route->matchers.path_matcher.type =
-        XdsApi::Route::Matchers::PathMatcher::PathMatcherType::PREFIX;
-    route->matchers.path_matcher.string_matcher = std::string(prefix);
+    type = StringMatcher::Type::kPrefix;
+    match_string = std::string(prefix);
   } else if (envoy_config_route_v3_RouteMatch_has_path(match)) {
     absl::string_view path =
         UpbStringToAbsl(envoy_config_route_v3_RouteMatch_path(match));
@@ -1126,102 +1267,99 @@
       *ignore_route = true;
       return GRPC_ERROR_NONE;
     }
-    route->matchers.path_matcher.type =
-        XdsApi::Route::Matchers::PathMatcher::PathMatcherType::PATH;
-    route->matchers.path_matcher.string_matcher = std::string(path);
+    type = StringMatcher::Type::kExact;
+    match_string = std::string(path);
   } else if (envoy_config_route_v3_RouteMatch_has_safe_regex(match)) {
     const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
         envoy_config_route_v3_RouteMatch_safe_regex(match);
     GPR_ASSERT(regex_matcher != nullptr);
-    std::string matcher = UpbStringToStdString(
+    type = StringMatcher::Type::kSafeRegex;
+    match_string = UpbStringToStdString(
         envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
-    RE2::Options options;
-    options.set_case_sensitive(route->matchers.path_matcher.case_sensitive);
-    auto regex = absl::make_unique<RE2>(std::move(matcher), options);
-    if (!regex->ok()) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "Invalid regex string specified in path matcher.");
-    }
-    route->matchers.path_matcher.type =
-        XdsApi::Route::Matchers::PathMatcher::PathMatcherType::REGEX;
-    route->matchers.path_matcher.regex_matcher = std::move(regex);
   } else {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Invalid route path specifier specified.");
   }
+  absl::StatusOr<StringMatcher> string_matcher =
+      StringMatcher::Create(type, match_string, case_sensitive);
+  if (!string_matcher.ok()) {
+    return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        absl::StrCat("path matcher: ", string_matcher.status().message())
+            .c_str());
+    ;
+  }
+  route->matchers.path_matcher = std::move(string_matcher.value());
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* RouteHeaderMatchersParse(
+grpc_error_handle RouteHeaderMatchersParse(
     const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route) {
   size_t size;
   const envoy_config_route_v3_HeaderMatcher* const* headers =
       envoy_config_route_v3_RouteMatch_headers(match, &size);
   for (size_t i = 0; i < size; ++i) {
     const envoy_config_route_v3_HeaderMatcher* header = headers[i];
-    XdsApi::Route::Matchers::HeaderMatcher header_matcher;
-    header_matcher.name =
+    const std::string name =
         UpbStringToStdString(envoy_config_route_v3_HeaderMatcher_name(header));
+    HeaderMatcher::Type type;
+    std::string match_string;
+    int64_t range_start = 0;
+    int64_t range_end = 0;
+    bool present_match = false;
     if (envoy_config_route_v3_HeaderMatcher_has_exact_match(header)) {
-      header_matcher.type =
-          XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::EXACT;
-      header_matcher.string_matcher = UpbStringToStdString(
+      type = HeaderMatcher::Type::kExact;
+      match_string = UpbStringToStdString(
           envoy_config_route_v3_HeaderMatcher_exact_match(header));
     } else if (envoy_config_route_v3_HeaderMatcher_has_safe_regex_match(
                    header)) {
       const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
           envoy_config_route_v3_HeaderMatcher_safe_regex_match(header);
       GPR_ASSERT(regex_matcher != nullptr);
-      const std::string matcher = UpbStringToStdString(
+      type = HeaderMatcher::Type::kSafeRegex;
+      match_string = UpbStringToStdString(
           envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher));
-      std::unique_ptr<RE2> regex = absl::make_unique<RE2>(matcher);
-      if (!regex->ok()) {
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "Invalid regex string specified in header matcher.");
-      }
-      header_matcher.type =
-          XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::REGEX;
-      header_matcher.regex_match = std::move(regex);
     } else if (envoy_config_route_v3_HeaderMatcher_has_range_match(header)) {
-      header_matcher.type =
-          XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::RANGE;
+      type = HeaderMatcher::Type::kRange;
       const envoy_type_v3_Int64Range* range_matcher =
           envoy_config_route_v3_HeaderMatcher_range_match(header);
-      header_matcher.range_start =
-          envoy_type_v3_Int64Range_start(range_matcher);
-      header_matcher.range_end = envoy_type_v3_Int64Range_end(range_matcher);
-      if (header_matcher.range_end < header_matcher.range_start) {
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "Invalid range header matcher specifier specified: end "
-            "cannot be smaller than start.");
-      }
+      range_start = envoy_type_v3_Int64Range_start(range_matcher);
+      range_end = envoy_type_v3_Int64Range_end(range_matcher);
     } else if (envoy_config_route_v3_HeaderMatcher_has_present_match(header)) {
-      header_matcher.type =
-          XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::PRESENT;
-      header_matcher.present_match =
-          envoy_config_route_v3_HeaderMatcher_present_match(header);
+      type = HeaderMatcher::Type::kPresent;
+      present_match = envoy_config_route_v3_HeaderMatcher_present_match(header);
     } else if (envoy_config_route_v3_HeaderMatcher_has_prefix_match(header)) {
-      header_matcher.type =
-          XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::PREFIX;
-      header_matcher.string_matcher = UpbStringToStdString(
+      type = HeaderMatcher::Type::kPrefix;
+      match_string = UpbStringToStdString(
           envoy_config_route_v3_HeaderMatcher_prefix_match(header));
     } else if (envoy_config_route_v3_HeaderMatcher_has_suffix_match(header)) {
-      header_matcher.type =
-          XdsApi::Route::Matchers::HeaderMatcher::HeaderMatcherType::SUFFIX;
-      header_matcher.string_matcher = UpbStringToStdString(
+      type = HeaderMatcher::Type::kSuffix;
+      match_string = UpbStringToStdString(
           envoy_config_route_v3_HeaderMatcher_suffix_match(header));
+    } else if (envoy_config_route_v3_HeaderMatcher_has_contains_match(header)) {
+      type = HeaderMatcher::Type::kContains;
+      match_string = UpbStringToStdString(
+          envoy_config_route_v3_HeaderMatcher_contains_match(header));
     } else {
       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "Invalid route header matcher specified.");
     }
-    header_matcher.invert_match =
+    bool invert_match =
         envoy_config_route_v3_HeaderMatcher_invert_match(header);
-    route->matchers.header_matchers.emplace_back(std::move(header_matcher));
+    absl::StatusOr<HeaderMatcher> header_matcher =
+        HeaderMatcher::Create(name, type, match_string, range_start, range_end,
+                              present_match, invert_match);
+    if (!header_matcher.ok()) {
+      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("header matcher: ", header_matcher.status().message())
+              .c_str());
+    }
+    route->matchers.header_matchers.emplace_back(
+        std::move(header_matcher.value()));
   }
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* RouteRuntimeFractionParse(
+grpc_error_handle RouteRuntimeFractionParse(
     const envoy_config_route_v3_RouteMatch* match, XdsApi::Route* route) {
   const envoy_config_core_v3_RuntimeFractionalPercent* runtime_fraction =
       envoy_config_route_v3_RouteMatch_runtime_fraction(match);
@@ -1254,8 +1392,98 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* RouteActionParse(const envoy_config_route_v3_Route* route_msg,
-                             XdsApi::Route* route, bool* ignore_route) {
+grpc_error_handle ExtractHttpFilterTypeName(const EncodingContext& context,
+                                            const google_protobuf_Any* any,
+                                            absl::string_view* filter_type) {
+  *filter_type = UpbStringToAbsl(google_protobuf_Any_type_url(any));
+  if (*filter_type == "type.googleapis.com/udpa.type.v1.TypedStruct") {
+    upb_strview any_value = google_protobuf_Any_value(any);
+    const auto* typed_struct = udpa_type_v1_TypedStruct_parse(
+        any_value.data, any_value.size, context.arena);
+    if (typed_struct == nullptr) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "could not parse TypedStruct from filter config");
+    }
+    *filter_type =
+        UpbStringToAbsl(udpa_type_v1_TypedStruct_type_url(typed_struct));
+  }
+  *filter_type = absl::StripPrefix(*filter_type, "type.googleapis.com/");
+  return GRPC_ERROR_NONE;
+}
+
+template <typename ParentType, typename EntryType>
+grpc_error_handle ParseTypedPerFilterConfig(
+    const EncodingContext& context, const ParentType* parent,
+    const EntryType* (*entry_func)(const ParentType*, size_t*),
+    upb_strview (*key_func)(const EntryType*),
+    const google_protobuf_Any* (*value_func)(const EntryType*),
+    XdsApi::TypedPerFilterConfig* typed_per_filter_config) {
+  size_t filter_it = UPB_MAP_BEGIN;
+  while (true) {
+    const auto* filter_entry = entry_func(parent, &filter_it);
+    if (filter_entry == nullptr) break;
+    absl::string_view key = UpbStringToAbsl(key_func(filter_entry));
+    if (key.empty()) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("empty filter name in map");
+    }
+    const google_protobuf_Any* any = value_func(filter_entry);
+    GPR_ASSERT(any != nullptr);
+    absl::string_view filter_type =
+        UpbStringToAbsl(google_protobuf_Any_type_url(any));
+    if (filter_type.empty()) {
+      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("no filter config specified for filter name ", key)
+              .c_str());
+    }
+    bool is_optional = false;
+    if (filter_type ==
+        "type.googleapis.com/envoy.config.route.v3.FilterConfig") {
+      upb_strview any_value = google_protobuf_Any_value(any);
+      const auto* filter_config = envoy_config_route_v3_FilterConfig_parse(
+          any_value.data, any_value.size, context.arena);
+      if (filter_config == nullptr) {
+        return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat("could not parse FilterConfig wrapper for ", key)
+                .c_str());
+      }
+      is_optional =
+          envoy_config_route_v3_FilterConfig_is_optional(filter_config);
+      any = envoy_config_route_v3_FilterConfig_config(filter_config);
+      if (any == nullptr) {
+        if (is_optional) continue;
+        return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat("no filter config specified for filter name ", key)
+                .c_str());
+      }
+    }
+    grpc_error_handle error =
+        ExtractHttpFilterTypeName(context, any, &filter_type);
+    if (error != GRPC_ERROR_NONE) return error;
+    const XdsHttpFilterImpl* filter_impl =
+        XdsHttpFilterRegistry::GetFilterForType(filter_type);
+    if (filter_impl == nullptr) {
+      if (is_optional) continue;
+      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("no filter registered for config type ", filter_type)
+              .c_str());
+    }
+    absl::StatusOr<XdsHttpFilterImpl::FilterConfig> filter_config =
+        filter_impl->GenerateFilterConfigOverride(
+            google_protobuf_Any_value(any), context.arena);
+    if (!filter_config.ok()) {
+      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("filter config for type ", filter_type,
+                       " failed to parse: ", filter_config.status().ToString())
+              .c_str());
+    }
+    (*typed_per_filter_config)[std::string(key)] = std::move(*filter_config);
+  }
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle RouteActionParse(const EncodingContext& context,
+                                   const envoy_config_route_v3_Route* route_msg,
+                                   XdsApi::Route* route, bool* ignore_route) {
   if (!envoy_config_route_v3_Route_has_route(route_msg)) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "No RouteAction found in route.");
@@ -1307,6 +1535,17 @@
       cluster.weight = google_protobuf_UInt32Value_value(weight);
       if (cluster.weight == 0) continue;
       sum_of_weights += cluster.weight;
+      if (context.use_v3) {
+        grpc_error_handle error = ParseTypedPerFilterConfig<
+            envoy_config_route_v3_WeightedCluster_ClusterWeight,
+            envoy_config_route_v3_WeightedCluster_ClusterWeight_TypedPerFilterConfigEntry>(
+            context, cluster_weight,
+            envoy_config_route_v3_WeightedCluster_ClusterWeight_typed_per_filter_config_next,
+            envoy_config_route_v3_WeightedCluster_ClusterWeight_TypedPerFilterConfigEntry_key,
+            envoy_config_route_v3_WeightedCluster_ClusterWeight_TypedPerFilterConfigEntry_value,
+            &cluster.typed_per_filter_config);
+        if (error != GRPC_ERROR_NONE) return error;
+      }
       route->weighted_clusters.emplace_back(std::move(cluster));
     }
     if (total_weight != sum_of_weights) {
@@ -1321,7 +1560,7 @@
     // No cluster or weighted_clusters found in RouteAction, ignore this route.
     *ignore_route = true;
   }
-  if (XdsTimeoutEnabled() && !*ignore_route) {
+  if (!*ignore_route) {
     const envoy_config_route_v3_RouteAction_MaxStreamDuration*
         max_stream_duration =
             envoy_config_route_v3_RouteAction_max_stream_duration(route_action);
@@ -1342,20 +1581,102 @@
       }
     }
   }
+  // 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;
 }
 
-grpc_error* RouteConfigParse(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
+grpc_error_handle RouteConfigParse(
+    const EncodingContext& context,
     const envoy_config_route_v3_RouteConfiguration* route_config,
     XdsApi::RdsUpdate* rds_update) {
-  MaybeLogRouteConfiguration(client, tracer, symtab, route_config);
+  MaybeLogRouteConfiguration(context, route_config);
   // Get the virtual hosts.
-  size_t size;
+  size_t num_virtual_hosts;
   const envoy_config_route_v3_VirtualHost* const* virtual_hosts =
-      envoy_config_route_v3_RouteConfiguration_virtual_hosts(route_config,
-                                                             &size);
-  for (size_t i = 0; i < size; ++i) {
+      envoy_config_route_v3_RouteConfiguration_virtual_hosts(
+          route_config, &num_virtual_hosts);
+  for (size_t i = 0; i < num_virtual_hosts; ++i) {
     rds_update->virtual_hosts.emplace_back();
     XdsApi::RdsUpdate::VirtualHost& vhost = rds_update->virtual_hosts.back();
     // Parse domains.
@@ -1375,6 +1696,18 @@
     if (vhost.domains.empty()) {
       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("VirtualHost has no domains");
     }
+    // Parse typed_per_filter_config.
+    if (context.use_v3) {
+      grpc_error_handle error = ParseTypedPerFilterConfig<
+          envoy_config_route_v3_VirtualHost,
+          envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry>(
+          context, virtual_hosts[i],
+          envoy_config_route_v3_VirtualHost_typed_per_filter_config_next,
+          envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry_key,
+          envoy_config_route_v3_VirtualHost_TypedPerFilterConfigEntry_value,
+          &vhost.typed_per_filter_config);
+      if (error != GRPC_ERROR_NONE) return error;
+    }
     // Parse routes.
     size_t num_routes;
     const envoy_config_route_v3_Route* const* routes =
@@ -1387,6 +1720,9 @@
     for (size_t j = 0; j < num_routes; ++j) {
       const envoy_config_route_v3_RouteMatch* match =
           envoy_config_route_v3_Route_match(routes[j]);
+      if (match == nullptr) {
+        return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Match can't be null.");
+      }
       size_t query_parameters_size;
       static_cast<void>(envoy_config_route_v3_RouteMatch_query_parameters(
           match, &query_parameters_size));
@@ -1395,16 +1731,28 @@
       }
       XdsApi::Route route;
       bool ignore_route = false;
-      grpc_error* error = RoutePathMatchParse(match, &route, &ignore_route);
+      grpc_error_handle error =
+          RoutePathMatchParse(match, &route, &ignore_route);
       if (error != GRPC_ERROR_NONE) return error;
       if (ignore_route) continue;
       error = RouteHeaderMatchersParse(match, &route);
       if (error != GRPC_ERROR_NONE) return error;
       error = RouteRuntimeFractionParse(match, &route);
       if (error != GRPC_ERROR_NONE) return error;
-      error = RouteActionParse(routes[j], &route, &ignore_route);
+      error = RouteActionParse(context, routes[j], &route, &ignore_route);
       if (error != GRPC_ERROR_NONE) return error;
       if (ignore_route) continue;
+      if (context.use_v3) {
+        grpc_error_handle error = ParseTypedPerFilterConfig<
+            envoy_config_route_v3_Route,
+            envoy_config_route_v3_Route_TypedPerFilterConfigEntry>(
+            context, routes[j],
+            envoy_config_route_v3_Route_typed_per_filter_config_next,
+            envoy_config_route_v3_Route_TypedPerFilterConfigEntry_key,
+            envoy_config_route_v3_Route_TypedPerFilterConfigEntry_value,
+            &route.typed_per_filter_config);
+        if (error != GRPC_ERROR_NONE) return error;
+      }
       vhost.routes.emplace_back(std::move(route));
     }
     if (vhost.routes.empty()) {
@@ -1414,170 +1762,6 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* LdsResponseParse(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
-    const envoy_service_discovery_v3_DiscoveryResponse* response,
-    const std::set<absl::string_view>& expected_listener_names,
-    XdsApi::LdsUpdateMap* lds_update_map, upb_arena* arena) {
-  // Get the resources from the response.
-  size_t size;
-  const google_protobuf_Any* const* resources =
-      envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
-  for (size_t i = 0; i < size; ++i) {
-    // Check the type_url of the resource.
-    absl::string_view type_url =
-        UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
-    if (!IsLds(type_url)) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not LDS.");
-    }
-    // Decode the listener.
-    const upb_strview encoded_listener =
-        google_protobuf_Any_value(resources[i]);
-    const envoy_config_listener_v3_Listener* listener =
-        envoy_config_listener_v3_Listener_parse(encoded_listener.data,
-                                                encoded_listener.size, arena);
-    if (listener == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode listener.");
-    }
-    // Check listener name. Ignore unexpected listeners.
-    std::string listener_name =
-        UpbStringToStdString(envoy_config_listener_v3_Listener_name(listener));
-    if (expected_listener_names.find(listener_name) ==
-        expected_listener_names.end()) {
-      continue;
-    }
-    // Fail if listener name is duplicated.
-    if (lds_update_map->find(listener_name) != lds_update_map->end()) {
-      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
-          absl::StrCat("duplicate listener name \"", listener_name, "\"")
-              .c_str());
-    }
-    XdsApi::LdsUpdate& lds_update = (*lds_update_map)[listener_name];
-    // Get api_listener and decode it to http_connection_manager.
-    const envoy_config_listener_v3_ApiListener* api_listener =
-        envoy_config_listener_v3_Listener_api_listener(listener);
-    if (api_listener == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "Listener has no ApiListener.");
-    }
-    const upb_strview encoded_api_listener = google_protobuf_Any_value(
-        envoy_config_listener_v3_ApiListener_api_listener(api_listener));
-    const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager*
-        http_connection_manager =
-            envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_parse(
-                encoded_api_listener.data, encoded_api_listener.size, arena);
-    if (http_connection_manager == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "Could not parse HttpConnectionManager config from ApiListener");
-    }
-    if (XdsTimeoutEnabled()) {
-      // Obtain max_stream_duration from Http Protocol Options.
-      const envoy_config_core_v3_HttpProtocolOptions* options =
-          envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_common_http_protocol_options(
-              http_connection_manager);
-      if (options != nullptr) {
-        const google_protobuf_Duration* duration =
-            envoy_config_core_v3_HttpProtocolOptions_max_stream_duration(
-                options);
-        if (duration != nullptr) {
-          lds_update.http_max_stream_duration.seconds =
-              google_protobuf_Duration_seconds(duration);
-          lds_update.http_max_stream_duration.nanos =
-              google_protobuf_Duration_nanos(duration);
-        }
-      }
-    }
-    // Found inlined route_config. Parse it to find the cluster_name.
-    if (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_route_config(
-            http_connection_manager)) {
-      const envoy_config_route_v3_RouteConfiguration* route_config =
-          envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_config(
-              http_connection_manager);
-      XdsApi::RdsUpdate rds_update;
-      grpc_error* error =
-          RouteConfigParse(client, tracer, symtab, route_config, &rds_update);
-      if (error != GRPC_ERROR_NONE) return error;
-      lds_update.rds_update = std::move(rds_update);
-      continue;
-    }
-    // Validate that RDS must be used to get the route_config dynamically.
-    if (!envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_rds(
-            http_connection_manager)) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "HttpConnectionManager neither has inlined route_config nor RDS.");
-    }
-    const envoy_extensions_filters_network_http_connection_manager_v3_Rds* rds =
-        envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_rds(
-            http_connection_manager);
-    // Check that the ConfigSource specifies ADS.
-    const envoy_config_core_v3_ConfigSource* config_source =
-        envoy_extensions_filters_network_http_connection_manager_v3_Rds_config_source(
-            rds);
-    if (config_source == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "HttpConnectionManager missing config_source for RDS.");
-    }
-    if (!envoy_config_core_v3_ConfigSource_has_ads(config_source)) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "HttpConnectionManager ConfigSource for RDS does not specify ADS.");
-    }
-    // Get the route_config_name.
-    lds_update.route_config_name = UpbStringToStdString(
-        envoy_extensions_filters_network_http_connection_manager_v3_Rds_route_config_name(
-            rds));
-  }
-  return GRPC_ERROR_NONE;
-}
-
-grpc_error* RdsResponseParse(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
-    const envoy_service_discovery_v3_DiscoveryResponse* response,
-    const std::set<absl::string_view>& expected_route_configuration_names,
-    XdsApi::RdsUpdateMap* rds_update_map, upb_arena* arena) {
-  // Get the resources from the response.
-  size_t size;
-  const google_protobuf_Any* const* resources =
-      envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
-  for (size_t i = 0; i < size; ++i) {
-    // Check the type_url of the resource.
-    absl::string_view type_url =
-        UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
-    if (!IsRds(type_url)) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not RDS.");
-    }
-    // Decode the route_config.
-    const upb_strview encoded_route_config =
-        google_protobuf_Any_value(resources[i]);
-    const envoy_config_route_v3_RouteConfiguration* route_config =
-        envoy_config_route_v3_RouteConfiguration_parse(
-            encoded_route_config.data, encoded_route_config.size, arena);
-    if (route_config == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode route_config.");
-    }
-    // Check route_config_name. Ignore unexpected route_config.
-    std::string route_config_name = UpbStringToStdString(
-        envoy_config_route_v3_RouteConfiguration_name(route_config));
-    if (expected_route_configuration_names.find(route_config_name) ==
-        expected_route_configuration_names.end()) {
-      continue;
-    }
-    // Fail if route config name is duplicated.
-    if (rds_update_map->find(route_config_name) != rds_update_map->end()) {
-      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
-          absl::StrCat("duplicate route config name \"", route_config_name,
-                       "\"")
-              .c_str());
-    }
-    // Parse the route_config.
-    XdsApi::RdsUpdate& rds_update =
-        (*rds_update_map)[std::move(route_config_name)];
-    grpc_error* error =
-        RouteConfigParse(client, tracer, symtab, route_config, &rds_update);
-    if (error != GRPC_ERROR_NONE) return error;
-  }
-  return GRPC_ERROR_NONE;
-}
-
 XdsApi::CommonTlsContext::CertificateProviderInstance
 CertificateProviderInstanceParse(
     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_CertificateProviderInstance*
@@ -1591,11 +1775,11 @@
               certificate_provider_instance_proto))};
 }
 
-grpc_error* CommonTlsContextParse(
+grpc_error_handle CommonTlsContextParse(
     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
         common_tls_context_proto,
     XdsApi::CommonTlsContext* common_tls_context) GRPC_MUST_USE_RESULT;
-grpc_error* CommonTlsContextParse(
+grpc_error_handle CommonTlsContextParse(
     const envoy_extensions_transport_sockets_tls_v3_CommonTlsContext*
         common_tls_context_proto,
     XdsApi::CommonTlsContext* common_tls_context) {
@@ -1612,35 +1796,35 @@
           envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_match_subject_alt_names(
               default_validation_context, &len);
       for (size_t i = 0; i < len; ++i) {
-        XdsApi::StringMatcher::StringMatcherType type;
+        StringMatcher::Type type;
         std::string matcher;
         if (envoy_type_matcher_v3_StringMatcher_has_exact(
                 subject_alt_names_matchers[i])) {
-          type = XdsApi::StringMatcher::StringMatcherType::EXACT;
+          type = StringMatcher::Type::kExact;
           matcher =
               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_exact(
                   subject_alt_names_matchers[i]));
         } else if (envoy_type_matcher_v3_StringMatcher_has_prefix(
                        subject_alt_names_matchers[i])) {
-          type = XdsApi::StringMatcher::StringMatcherType::PREFIX;
+          type = StringMatcher::Type::kPrefix;
           matcher =
               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_prefix(
                   subject_alt_names_matchers[i]));
         } else if (envoy_type_matcher_v3_StringMatcher_has_suffix(
                        subject_alt_names_matchers[i])) {
-          type = XdsApi::StringMatcher::StringMatcherType::SUFFIX;
+          type = StringMatcher::Type::kSuffix;
           matcher =
               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_suffix(
                   subject_alt_names_matchers[i]));
         } else if (envoy_type_matcher_v3_StringMatcher_has_contains(
                        subject_alt_names_matchers[i])) {
-          type = XdsApi::StringMatcher::StringMatcherType::CONTAINS;
+          type = StringMatcher::Type::kContains;
           matcher =
               UpbStringToStdString(envoy_type_matcher_v3_StringMatcher_contains(
                   subject_alt_names_matchers[i]));
         } else if (envoy_type_matcher_v3_StringMatcher_has_safe_regex(
                        subject_alt_names_matchers[i])) {
-          type = XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX;
+          type = StringMatcher::Type::kSafeRegex;
           auto* regex_matcher = envoy_type_matcher_v3_StringMatcher_safe_regex(
               subject_alt_names_matchers[i]);
           matcher = UpbStringToStdString(
@@ -1651,20 +1835,22 @@
         }
         bool ignore_case = envoy_type_matcher_v3_StringMatcher_ignore_case(
             subject_alt_names_matchers[i]);
-        XdsApi::StringMatcher string_matcher(type, matcher, ignore_case);
-        if (type == XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX) {
-          if (!string_matcher.regex_matcher()->ok()) {
-            return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                "Invalid regex string specified in string matcher.");
-          }
-          if (ignore_case) {
-            return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                "StringMatcher: ignore_case has no effect for SAFE_REGEX.");
-          }
+        absl::StatusOr<StringMatcher> string_matcher =
+            StringMatcher::Create(type, matcher,
+                                  /*case_sensitive=*/!ignore_case);
+        if (!string_matcher.ok()) {
+          return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat("string matcher: ",
+                           string_matcher.status().message())
+                  .c_str());
+        }
+        if (type == StringMatcher::Type::kSafeRegex && ignore_case) {
+          return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+              "StringMatcher: ignore_case has no effect for SAFE_REGEX.");
         }
         common_tls_context->combined_validation_context
             .default_validation_context.match_subject_alt_names.push_back(
-                std::move(string_matcher));
+                std::move(string_matcher.value()));
       }
     }
     auto* validation_context_certificate_provider_instance =
@@ -1688,11 +1874,797 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* CdsResponseParse(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
+grpc_error_handle HttpConnectionManagerParse(
+    bool is_client, const EncodingContext& context,
+    const envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager*
+        http_connection_manager_proto,
+    bool is_v2,
+    XdsApi::LdsUpdate::HttpConnectionManager* http_connection_manager) {
+  MaybeLogHttpConnectionManager(context, http_connection_manager_proto);
+  // Obtain max_stream_duration from Http Protocol Options.
+  const envoy_config_core_v3_HttpProtocolOptions* options =
+      envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_common_http_protocol_options(
+          http_connection_manager_proto);
+  if (options != nullptr) {
+    const google_protobuf_Duration* duration =
+        envoy_config_core_v3_HttpProtocolOptions_max_stream_duration(options);
+    if (duration != nullptr) {
+      http_connection_manager->http_max_stream_duration.seconds =
+          google_protobuf_Duration_seconds(duration);
+      http_connection_manager->http_max_stream_duration.nanos =
+          google_protobuf_Duration_nanos(duration);
+    }
+  }
+  // Parse filters.
+  if (!is_v2) {
+    size_t num_filters = 0;
+    const auto* http_filters =
+        envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_http_filters(
+            http_connection_manager_proto, &num_filters);
+    std::set<absl::string_view> names_seen;
+    for (size_t i = 0; i < num_filters; ++i) {
+      const auto* http_filter = http_filters[i];
+      absl::string_view name = UpbStringToAbsl(
+          envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_name(
+              http_filter));
+      if (name.empty()) {
+        return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat("empty filter name at index ", i).c_str());
+      }
+      if (names_seen.find(name) != names_seen.end()) {
+        return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat("duplicate HTTP filter name: ", name).c_str());
+      }
+      names_seen.insert(name);
+      const bool is_optional =
+          envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_is_optional(
+              http_filter);
+      const google_protobuf_Any* any =
+          envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter_typed_config(
+              http_filter);
+      if (any == nullptr) {
+        if (is_optional) continue;
+        return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat("no filter config specified for filter name ", name)
+                .c_str());
+      }
+      absl::string_view filter_type;
+      grpc_error_handle error =
+          ExtractHttpFilterTypeName(context, any, &filter_type);
+      if (error != GRPC_ERROR_NONE) return error;
+      const XdsHttpFilterImpl* filter_impl =
+          XdsHttpFilterRegistry::GetFilterForType(filter_type);
+      if (filter_impl == nullptr) {
+        if (is_optional) continue;
+        return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat("no filter registered for config type ", filter_type)
+                .c_str());
+      }
+      if ((is_client && !filter_impl->IsSupportedOnClients()) ||
+          (!is_client && !filter_impl->IsSupportedOnServers())) {
+        if (is_optional) continue;
+        return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrFormat("Filter %s is not supported on %s", filter_type,
+                            is_client ? "clients" : "servers")
+                .c_str());
+      }
+      absl::StatusOr<XdsHttpFilterImpl::FilterConfig> filter_config =
+          filter_impl->GenerateFilterConfig(google_protobuf_Any_value(any),
+                                            context.arena);
+      if (!filter_config.ok()) {
+        return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat(
+                "filter config for type ", filter_type,
+                " failed to parse: ", filter_config.status().ToString())
+                .c_str());
+      }
+      http_connection_manager->http_filters.emplace_back(
+          XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter{
+              std::string(name), std::move(*filter_config)});
+    }
+  } else {
+    // If using a v2 config, we just hard-code a list containing only the
+    // router filter without actually looking at the config.  This ensures
+    // that the right thing happens in the xds resolver without having
+    // to expose whether the resource we received was v2 or v3.
+    http_connection_manager->http_filters.emplace_back(
+        XdsApi::LdsUpdate::HttpConnectionManager::HttpFilter{
+            "router", {kXdsHttpRouterFilterConfigName, Json()}});
+  }
+  if (is_client) {
+    // Found inlined route_config. Parse it to find the cluster_name.
+    if (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_route_config(
+            http_connection_manager_proto)) {
+      const envoy_config_route_v3_RouteConfiguration* route_config =
+          envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_route_config(
+              http_connection_manager_proto);
+      XdsApi::RdsUpdate rds_update;
+      grpc_error_handle error =
+          RouteConfigParse(context, route_config, &rds_update);
+      if (error != GRPC_ERROR_NONE) return error;
+      http_connection_manager->rds_update = std::move(rds_update);
+      return GRPC_ERROR_NONE;
+    }
+    // Validate that RDS must be used to get the route_config dynamically.
+    const envoy_extensions_filters_network_http_connection_manager_v3_Rds* rds =
+        envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_rds(
+            http_connection_manager_proto);
+    if (rds == nullptr) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "HttpConnectionManager neither has inlined route_config nor RDS.");
+    }
+    // Check that the ConfigSource specifies ADS.
+    const envoy_config_core_v3_ConfigSource* config_source =
+        envoy_extensions_filters_network_http_connection_manager_v3_Rds_config_source(
+            rds);
+    if (config_source == nullptr) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "HttpConnectionManager missing config_source for RDS.");
+    }
+    if (!envoy_config_core_v3_ConfigSource_has_ads(config_source)) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "HttpConnectionManager ConfigSource for RDS does not specify ADS.");
+    }
+    // Get the route_config_name.
+    http_connection_manager->route_config_name = UpbStringToStdString(
+        envoy_extensions_filters_network_http_connection_manager_v3_Rds_route_config_name(
+            rds));
+  }
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle LdsResponseParseClient(
+    const EncodingContext& context,
+    const envoy_config_listener_v3_ApiListener* api_listener, bool is_v2,
+    XdsApi::LdsUpdate* lds_update) {
+  lds_update->type = XdsApi::LdsUpdate::ListenerType::kHttpApiListener;
+  const upb_strview encoded_api_listener = google_protobuf_Any_value(
+      envoy_config_listener_v3_ApiListener_api_listener(api_listener));
+  const auto* http_connection_manager =
+      envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_parse(
+          encoded_api_listener.data, encoded_api_listener.size, context.arena);
+  if (http_connection_manager == nullptr) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Could not parse HttpConnectionManager config from ApiListener");
+  }
+  return HttpConnectionManagerParse(true /* is_client */, context,
+                                    http_connection_manager, is_v2,
+                                    &lds_update->http_connection_manager);
+}
+
+grpc_error_handle DownstreamTlsContextParse(
+    const EncodingContext& context,
+    const envoy_config_core_v3_TransportSocket* transport_socket,
+    XdsApi::DownstreamTlsContext* downstream_tls_context) {
+  absl::string_view name = UpbStringToAbsl(
+      envoy_config_core_v3_TransportSocket_name(transport_socket));
+  if (name == "envoy.transport_sockets.tls") {
+    auto* typed_config =
+        envoy_config_core_v3_TransportSocket_typed_config(transport_socket);
+    if (typed_config != nullptr) {
+      const upb_strview encoded_downstream_tls_context =
+          google_protobuf_Any_value(typed_config);
+      auto* downstream_tls_context_proto =
+          envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_parse(
+              encoded_downstream_tls_context.data,
+              encoded_downstream_tls_context.size, context.arena);
+      if (downstream_tls_context_proto == nullptr) {
+        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "Can't decode downstream tls context.");
+      }
+      auto* common_tls_context =
+          envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_common_tls_context(
+              downstream_tls_context_proto);
+      if (common_tls_context != nullptr) {
+        grpc_error_handle error = CommonTlsContextParse(
+            common_tls_context, &downstream_tls_context->common_tls_context);
+        if (error != GRPC_ERROR_NONE) return error;
+      }
+      auto* require_client_certificate =
+          envoy_extensions_transport_sockets_tls_v3_DownstreamTlsContext_require_client_certificate(
+              downstream_tls_context_proto);
+      if (require_client_certificate != nullptr) {
+        downstream_tls_context->require_client_certificate =
+            google_protobuf_BoolValue_value(require_client_certificate);
+      }
+    }
+    if (downstream_tls_context->common_tls_context
+            .tls_certificate_certificate_provider_instance.instance_name
+            .empty()) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "TLS configuration provided but no "
+          "tls_certificate_certificate_provider_instance found.");
+    }
+  }
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle CidrRangeParse(
+    const envoy_config_core_v3_CidrRange* cidr_range_proto,
+    XdsApi::LdsUpdate::FilterChainMap::CidrRange* cidr_range) {
+  std::string address_prefix = UpbStringToStdString(
+      envoy_config_core_v3_CidrRange_address_prefix(cidr_range_proto));
+  grpc_error_handle error =
+      grpc_string_to_sockaddr(&cidr_range->address, address_prefix.c_str(), 0);
+  if (error != GRPC_ERROR_NONE) return error;
+  cidr_range->prefix_len = 0;
+  auto* prefix_len_proto =
+      envoy_config_core_v3_CidrRange_prefix_len(cidr_range_proto);
+  if (prefix_len_proto != nullptr) {
+    cidr_range->prefix_len = std::min(
+        google_protobuf_UInt32Value_value(prefix_len_proto),
+        (reinterpret_cast<const grpc_sockaddr*>(cidr_range->address.addr))
+                    ->sa_family == GRPC_AF_INET
+            ? uint32_t(32)
+            : uint32_t(128));
+  }
+  // Normalize the network address by masking it with prefix_len
+  grpc_sockaddr_mask_bits(&cidr_range->address, cidr_range->prefix_len);
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle FilterChainMatchParse(
+    const envoy_config_listener_v3_FilterChainMatch* filter_chain_match_proto,
+    FilterChain::FilterChainMatch* filter_chain_match) {
+  auto* destination_port =
+      envoy_config_listener_v3_FilterChainMatch_destination_port(
+          filter_chain_match_proto);
+  if (destination_port != nullptr) {
+    filter_chain_match->destination_port =
+        google_protobuf_UInt32Value_value(destination_port);
+  }
+  size_t size = 0;
+  auto* prefix_ranges = envoy_config_listener_v3_FilterChainMatch_prefix_ranges(
+      filter_chain_match_proto, &size);
+  filter_chain_match->prefix_ranges.reserve(size);
+  for (size_t i = 0; i < size; i++) {
+    XdsApi::LdsUpdate::FilterChainMap::CidrRange cidr_range;
+    grpc_error_handle error = CidrRangeParse(prefix_ranges[i], &cidr_range);
+    if (error != GRPC_ERROR_NONE) return error;
+    filter_chain_match->prefix_ranges.push_back(cidr_range);
+  }
+  filter_chain_match->source_type =
+      static_cast<XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType>(
+          envoy_config_listener_v3_FilterChainMatch_source_type(
+              filter_chain_match_proto));
+  auto* source_prefix_ranges =
+      envoy_config_listener_v3_FilterChainMatch_source_prefix_ranges(
+          filter_chain_match_proto, &size);
+  filter_chain_match->source_prefix_ranges.reserve(size);
+  for (size_t i = 0; i < size; i++) {
+    XdsApi::LdsUpdate::FilterChainMap::CidrRange cidr_range;
+    grpc_error_handle error =
+        CidrRangeParse(source_prefix_ranges[i], &cidr_range);
+    if (error != GRPC_ERROR_NONE) return error;
+    filter_chain_match->source_prefix_ranges.push_back(cidr_range);
+  }
+  auto* source_ports = envoy_config_listener_v3_FilterChainMatch_source_ports(
+      filter_chain_match_proto, &size);
+  filter_chain_match->source_ports.reserve(size);
+  for (size_t i = 0; i < size; i++) {
+    filter_chain_match->source_ports.push_back(source_ports[i]);
+  }
+  auto* server_names = envoy_config_listener_v3_FilterChainMatch_server_names(
+      filter_chain_match_proto, &size);
+  for (size_t i = 0; i < size; i++) {
+    filter_chain_match->server_names.push_back(
+        UpbStringToStdString(server_names[i]));
+  }
+  filter_chain_match->transport_protocol = UpbStringToStdString(
+      envoy_config_listener_v3_FilterChainMatch_transport_protocol(
+          filter_chain_match_proto));
+  auto* application_protocols =
+      envoy_config_listener_v3_FilterChainMatch_application_protocols(
+          filter_chain_match_proto, &size);
+  for (size_t i = 0; i < size; i++) {
+    filter_chain_match->application_protocols.push_back(
+        UpbStringToStdString(application_protocols[i]));
+  }
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle FilterChainParse(
+    const EncodingContext& context,
+    const envoy_config_listener_v3_FilterChain* filter_chain_proto, bool is_v2,
+    FilterChain* filter_chain) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto* filter_chain_match =
+      envoy_config_listener_v3_FilterChain_filter_chain_match(
+          filter_chain_proto);
+  if (filter_chain_match != nullptr) {
+    error = FilterChainMatchParse(filter_chain_match,
+                                  &filter_chain->filter_chain_match);
+    if (error != GRPC_ERROR_NONE) return error;
+  }
+  // Parse the filters list. Currently we only support HttpConnectionManager.
+  size_t size = 0;
+  auto* filters =
+      envoy_config_listener_v3_FilterChain_filters(filter_chain_proto, &size);
+  if (size != 1) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "FilterChain should have exactly one filter: HttpConnectionManager; no "
+        "other filter is supported at the moment");
+  }
+  auto* typed_config = envoy_config_listener_v3_Filter_typed_config(filters[0]);
+  if (typed_config == nullptr) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "No typed_config found in filter.");
+  }
+  absl::string_view type_url =
+      UpbStringToAbsl(google_protobuf_Any_type_url(typed_config));
+  if (type_url !=
+      "type.googleapis.com/"
+      "envoy.extensions.filters.network.http_connection_manager.v3."
+      "HttpConnectionManager") {
+    return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        absl::StrCat("Unsupported filter type ", type_url).c_str());
+  }
+  const upb_strview encoded_http_connection_manager =
+      google_protobuf_Any_value(typed_config);
+  const auto* http_connection_manager =
+      envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_parse(
+          encoded_http_connection_manager.data,
+          encoded_http_connection_manager.size, context.arena);
+  if (http_connection_manager == nullptr) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Could not parse HttpConnectionManager config from filter "
+        "typed_config");
+  }
+  filter_chain->filter_chain_data =
+      std::make_shared<XdsApi::LdsUpdate::FilterChainData>();
+  error = HttpConnectionManagerParse(
+      false /* is_client */, context, http_connection_manager, is_v2,
+      &filter_chain->filter_chain_data->http_connection_manager);
+  if (error != GRPC_ERROR_NONE) return error;
+  // Get the DownstreamTlsContext for the filter chain
+  if (XdsSecurityEnabled()) {
+    auto* transport_socket =
+        envoy_config_listener_v3_FilterChain_transport_socket(
+            filter_chain_proto);
+    if (transport_socket != nullptr) {
+      error = DownstreamTlsContextParse(
+          context, transport_socket,
+          &filter_chain->filter_chain_data->downstream_tls_context);
+    }
+  }
+  return error;
+}
+
+grpc_error_handle AddressParse(
+    const envoy_config_core_v3_Address* address_proto, std::string* address) {
+  const auto* socket_address =
+      envoy_config_core_v3_Address_socket_address(address_proto);
+  if (socket_address == nullptr) {
+    return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        "Address does not have socket_address");
+  }
+  if (envoy_config_core_v3_SocketAddress_protocol(socket_address) !=
+      envoy_config_core_v3_SocketAddress_TCP) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "SocketAddress protocol is not TCP");
+  }
+  uint32_t port = envoy_config_core_v3_SocketAddress_port_value(socket_address);
+  if (port > 65535) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid port");
+  }
+  *address = JoinHostPort(
+      UpbStringToAbsl(
+          envoy_config_core_v3_SocketAddress_address(socket_address)),
+      port);
+  return GRPC_ERROR_NONE;
+}
+
+// An intermediate map for filter chains that we create to validate the list of
+// filter chains received from the control plane and to finally create
+// XdsApi::LdsUpdate::FilterChainMap
+struct InternalFilterChainMap {
+  using SourceIpMap =
+      std::map<std::string, XdsApi::LdsUpdate::FilterChainMap::SourceIp>;
+  using ConnectionSourceTypesArray = std::array<SourceIpMap, 3>;
+  struct DestinationIp {
+    absl::optional<XdsApi::LdsUpdate::FilterChainMap::CidrRange> prefix_range;
+    bool transport_protocol_raw_buffer_provided = false;
+    ConnectionSourceTypesArray source_types_array;
+  };
+  using DestinationIpMap = std::map<std::string, DestinationIp>;
+  DestinationIpMap destination_ip_map;
+};
+
+grpc_error_handle AddFilterChainDataForSourcePort(
+    const FilterChain& filter_chain,
+    XdsApi::LdsUpdate::FilterChainMap::SourcePortsMap* ports_map,
+    uint32_t port) {
+  auto insert_result = ports_map->emplace(
+      port, XdsApi::LdsUpdate::FilterChainMap::FilterChainDataSharedPtr{
+                filter_chain.filter_chain_data});
+  if (!insert_result.second) {
+    return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        absl::StrCat(
+            "Duplicate matching rules detected when adding filter chain: ",
+            filter_chain.filter_chain_match.ToString())
+            .c_str());
+  }
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle AddFilterChainDataForSourcePorts(
+    const FilterChain& filter_chain,
+    XdsApi::LdsUpdate::FilterChainMap::SourcePortsMap* ports_map) {
+  if (filter_chain.filter_chain_match.source_ports.empty()) {
+    return AddFilterChainDataForSourcePort(filter_chain, ports_map, 0);
+  } else {
+    for (uint32_t port : filter_chain.filter_chain_match.source_ports) {
+      grpc_error_handle error =
+          AddFilterChainDataForSourcePort(filter_chain, ports_map, port);
+      if (error != GRPC_ERROR_NONE) return error;
+    }
+  }
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle AddFilterChainDataForSourceIpRange(
+    const FilterChain& filter_chain,
+    InternalFilterChainMap::SourceIpMap* source_ip_map) {
+  if (filter_chain.filter_chain_match.source_prefix_ranges.empty()) {
+    auto insert_result = source_ip_map->emplace(
+        "", XdsApi::LdsUpdate::FilterChainMap::SourceIp());
+    return AddFilterChainDataForSourcePorts(
+        filter_chain, &insert_result.first->second.ports_map);
+  } else {
+    for (const auto& prefix_range :
+         filter_chain.filter_chain_match.source_prefix_ranges) {
+      auto insert_result = source_ip_map->emplace(
+          absl::StrCat(grpc_sockaddr_to_string(&prefix_range.address, false),
+                       "/", prefix_range.prefix_len),
+          XdsApi::LdsUpdate::FilterChainMap::SourceIp());
+      if (insert_result.second) {
+        insert_result.first->second.prefix_range.emplace(prefix_range);
+      }
+      grpc_error_handle error = AddFilterChainDataForSourcePorts(
+          filter_chain, &insert_result.first->second.ports_map);
+      if (error != GRPC_ERROR_NONE) return error;
+    }
+  }
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle AddFilterChainDataForSourceType(
+    const FilterChain& filter_chain,
+    InternalFilterChainMap::DestinationIp* destination_ip) {
+  GPR_ASSERT(static_cast<unsigned int>(
+                 filter_chain.filter_chain_match.source_type) < 3);
+  return AddFilterChainDataForSourceIpRange(
+      filter_chain, &destination_ip->source_types_array[static_cast<int>(
+                        filter_chain.filter_chain_match.source_type)]);
+}
+
+grpc_error_handle AddFilterChainDataForApplicationProtocols(
+    const FilterChain& filter_chain,
+    InternalFilterChainMap::DestinationIp* destination_ip) {
+  // Only allow filter chains that do not mention application protocols
+  if (!filter_chain.filter_chain_match.application_protocols.empty()) {
+    return GRPC_ERROR_NONE;
+  }
+  return AddFilterChainDataForSourceType(filter_chain, destination_ip);
+}
+
+grpc_error_handle AddFilterChainDataForTransportProtocol(
+    const FilterChain& filter_chain,
+    InternalFilterChainMap::DestinationIp* destination_ip) {
+  const std::string& transport_protocol =
+      filter_chain.filter_chain_match.transport_protocol;
+  // Only allow filter chains with no transport protocol or "raw_buffer"
+  if (!transport_protocol.empty() && transport_protocol != "raw_buffer") {
+    return GRPC_ERROR_NONE;
+  }
+  // If for this configuration, we've already seen filter chains that mention
+  // the transport protocol as "raw_buffer", we will never match filter chains
+  // that do not mention it.
+  if (destination_ip->transport_protocol_raw_buffer_provided &&
+      transport_protocol.empty()) {
+    return GRPC_ERROR_NONE;
+  }
+  if (!transport_protocol.empty() &&
+      !destination_ip->transport_protocol_raw_buffer_provided) {
+    destination_ip->transport_protocol_raw_buffer_provided = true;
+    // Clear out the previous entries if any since those entries did not mention
+    // "raw_buffer"
+    destination_ip->source_types_array =
+        InternalFilterChainMap::ConnectionSourceTypesArray();
+  }
+  return AddFilterChainDataForApplicationProtocols(filter_chain,
+                                                   destination_ip);
+}
+
+grpc_error_handle AddFilterChainDataForServerNames(
+    const FilterChain& filter_chain,
+    InternalFilterChainMap::DestinationIp* destination_ip) {
+  // Don't continue adding filter chains with server names mentioned
+  if (!filter_chain.filter_chain_match.server_names.empty()) {
+    return GRPC_ERROR_NONE;
+  }
+  return AddFilterChainDataForTransportProtocol(filter_chain, destination_ip);
+}
+
+grpc_error_handle AddFilterChainDataForDestinationIpRange(
+    const FilterChain& filter_chain,
+    InternalFilterChainMap::DestinationIpMap* destination_ip_map) {
+  if (filter_chain.filter_chain_match.prefix_ranges.empty()) {
+    auto insert_result = destination_ip_map->emplace(
+        "", InternalFilterChainMap::DestinationIp());
+    return AddFilterChainDataForServerNames(filter_chain,
+                                            &insert_result.first->second);
+  } else {
+    for (const auto& prefix_range :
+         filter_chain.filter_chain_match.prefix_ranges) {
+      auto insert_result = destination_ip_map->emplace(
+          absl::StrCat(grpc_sockaddr_to_string(&prefix_range.address, false),
+                       "/", prefix_range.prefix_len),
+          InternalFilterChainMap::DestinationIp());
+      if (insert_result.second) {
+        insert_result.first->second.prefix_range.emplace(prefix_range);
+      }
+      grpc_error_handle error = AddFilterChainDataForServerNames(
+          filter_chain, &insert_result.first->second);
+      if (error != GRPC_ERROR_NONE) return error;
+    }
+  }
+  return GRPC_ERROR_NONE;
+}
+
+XdsApi::LdsUpdate::FilterChainMap BuildFromInternalFilterChainMap(
+    InternalFilterChainMap* internal_filter_chain_map) {
+  XdsApi::LdsUpdate::FilterChainMap filter_chain_map;
+  for (auto& destination_ip_pair :
+       internal_filter_chain_map->destination_ip_map) {
+    XdsApi::LdsUpdate::FilterChainMap::DestinationIp destination_ip;
+    destination_ip.prefix_range = destination_ip_pair.second.prefix_range;
+    for (int i = 0; i < 3; i++) {
+      auto& source_ip_map = destination_ip_pair.second.source_types_array[i];
+      for (auto& source_ip_pair : source_ip_map) {
+        destination_ip.source_types_array[i].push_back(
+            std::move(source_ip_pair.second));
+      }
+    }
+    filter_chain_map.destination_ip_vector.push_back(std::move(destination_ip));
+  }
+  return filter_chain_map;
+}
+
+grpc_error_handle BuildFilterChainMap(
+    const std::vector<FilterChain>& filter_chains,
+    XdsApi::LdsUpdate::FilterChainMap* filter_chain_map) {
+  InternalFilterChainMap internal_filter_chain_map;
+  for (const auto& filter_chain : filter_chains) {
+    // Discard filter chain entries that specify destination port
+    if (filter_chain.filter_chain_match.destination_port != 0) continue;
+    grpc_error_handle error = AddFilterChainDataForDestinationIpRange(
+        filter_chain, &internal_filter_chain_map.destination_ip_map);
+    if (error != GRPC_ERROR_NONE) return error;
+  }
+  *filter_chain_map =
+      BuildFromInternalFilterChainMap(&internal_filter_chain_map);
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle LdsResponseParseServer(
+    const EncodingContext& context,
+    const envoy_config_listener_v3_Listener* listener, bool is_v2,
+    XdsApi::LdsUpdate* lds_update) {
+  lds_update->type = XdsApi::LdsUpdate::ListenerType::kTcpListener;
+  grpc_error_handle error =
+      AddressParse(envoy_config_listener_v3_Listener_address(listener),
+                   &lds_update->address);
+  if (error != GRPC_ERROR_NONE) return error;
+  const auto* use_original_dst =
+      envoy_config_listener_v3_Listener_use_original_dst(listener);
+  if (use_original_dst != nullptr) {
+    if (google_protobuf_BoolValue_value(use_original_dst)) {
+      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "Field \'use_original_dst\' is not supported.");
+    }
+  }
+  size_t size = 0;
+  auto* filter_chains =
+      envoy_config_listener_v3_Listener_filter_chains(listener, &size);
+  std::vector<FilterChain> parsed_filter_chains;
+  parsed_filter_chains.reserve(size);
+  for (size_t i = 0; i < size; i++) {
+    FilterChain filter_chain;
+    error = FilterChainParse(context, filter_chains[i], is_v2, &filter_chain);
+    if (error != GRPC_ERROR_NONE) return error;
+    parsed_filter_chains.push_back(std::move(filter_chain));
+  }
+  error =
+      BuildFilterChainMap(parsed_filter_chains, &lds_update->filter_chain_map);
+  if (error != GRPC_ERROR_NONE) return error;
+  auto* default_filter_chain =
+      envoy_config_listener_v3_Listener_default_filter_chain(listener);
+  if (default_filter_chain != nullptr) {
+    FilterChain filter_chain;
+    error =
+        FilterChainParse(context, default_filter_chain, is_v2, &filter_chain);
+    if (error != GRPC_ERROR_NONE) return error;
+    if (filter_chain.filter_chain_data != nullptr) {
+      lds_update->default_filter_chain =
+          std::move(*filter_chain.filter_chain_data);
+    }
+  }
+  if (size == 0 && default_filter_chain == nullptr) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No filter chain provided.");
+  }
+  return GRPC_ERROR_NONE;
+}
+
+grpc_error_handle LdsResponseParse(
+    const EncodingContext& context,
+    const envoy_service_discovery_v3_DiscoveryResponse* response,
+    const std::set<absl::string_view>& expected_listener_names,
+    XdsApi::LdsUpdateMap* lds_update_map,
+    std::set<std::string>* resource_names_failed) {
+  std::vector<grpc_error_handle> errors;
+  // Get the resources from the response.
+  size_t size;
+  const google_protobuf_Any* const* resources =
+      envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
+  for (size_t i = 0; i < size; ++i) {
+    // Check the type_url of the resource.
+    absl::string_view type_url =
+        UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
+    bool is_v2 = false;
+    if (!IsLds(type_url, &is_v2)) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("resource index ", i, ": Resource is not LDS.")
+              .c_str()));
+      continue;
+    }
+    // Decode the listener.
+    const upb_strview encoded_listener =
+        google_protobuf_Any_value(resources[i]);
+    const envoy_config_listener_v3_Listener* listener =
+        envoy_config_listener_v3_Listener_parse(
+            encoded_listener.data, encoded_listener.size, context.arena);
+    if (listener == nullptr) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("resource index ", i, ": Can't decode listener.")
+              .c_str()));
+      continue;
+    }
+    // Check listener name. Ignore unexpected listeners.
+    std::string listener_name =
+        UpbStringToStdString(envoy_config_listener_v3_Listener_name(listener));
+    if (expected_listener_names.find(listener_name) ==
+        expected_listener_names.end()) {
+      continue;
+    }
+    // Fail if listener name is duplicated.
+    if (lds_update_map->find(listener_name) != lds_update_map->end()) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("duplicate listener name \"", listener_name, "\"")
+              .c_str()));
+      resource_names_failed->insert(listener_name);
+      continue;
+    }
+    // Serialize into JSON and store it in the LdsUpdateMap
+    XdsApi::LdsResourceData& lds_resource_data =
+        (*lds_update_map)[listener_name];
+    XdsApi::LdsUpdate& lds_update = lds_resource_data.resource;
+    lds_resource_data.serialized_proto = UpbStringToStdString(encoded_listener);
+    // Check whether it's a client or server listener.
+    const envoy_config_listener_v3_ApiListener* api_listener =
+        envoy_config_listener_v3_Listener_api_listener(listener);
+    const envoy_config_core_v3_Address* address =
+        envoy_config_listener_v3_Listener_address(listener);
+    if (api_listener != nullptr && address != nullptr) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat(listener_name,
+                       ": Listener has both address and ApiListener")
+              .c_str()));
+      resource_names_failed->insert(listener_name);
+      continue;
+    }
+    if (api_listener == nullptr && address == nullptr) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat(listener_name,
+                       ": Listener has neither address nor ApiListener")
+              .c_str()));
+      resource_names_failed->insert(listener_name);
+      continue;
+    }
+    grpc_error_handle error = GRPC_ERROR_NONE;
+    if (api_listener != nullptr) {
+      error = LdsResponseParseClient(context, api_listener, is_v2, &lds_update);
+    } else {
+      error = LdsResponseParseServer(context, listener, is_v2, &lds_update);
+    }
+    if (error != GRPC_ERROR_NONE) {
+      errors.push_back(grpc_error_add_child(
+          GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat(listener_name, ": validation error").c_str()),
+          error));
+      resource_names_failed->insert(listener_name);
+    }
+  }
+  return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing LDS response", &errors);
+}
+
+grpc_error_handle RdsResponseParse(
+    const EncodingContext& context,
+    const envoy_service_discovery_v3_DiscoveryResponse* response,
+    const std::set<absl::string_view>& expected_route_configuration_names,
+    XdsApi::RdsUpdateMap* rds_update_map,
+    std::set<std::string>* resource_names_failed) {
+  std::vector<grpc_error_handle> errors;
+  // Get the resources from the response.
+  size_t size;
+  const google_protobuf_Any* const* resources =
+      envoy_service_discovery_v3_DiscoveryResponse_resources(response, &size);
+  for (size_t i = 0; i < size; ++i) {
+    // Check the type_url of the resource.
+    absl::string_view type_url =
+        UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
+    if (!IsRds(type_url)) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("resource index ", i, ": Resource is not RDS.")
+              .c_str()));
+      continue;
+    }
+    // Decode the route_config.
+    const upb_strview encoded_route_config =
+        google_protobuf_Any_value(resources[i]);
+    const envoy_config_route_v3_RouteConfiguration* route_config =
+        envoy_config_route_v3_RouteConfiguration_parse(
+            encoded_route_config.data, encoded_route_config.size,
+            context.arena);
+    if (route_config == nullptr) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("resource index ", i, ": Can't decode route_config.")
+              .c_str()));
+      continue;
+    }
+    // Check route_config_name. Ignore unexpected route_config.
+    std::string route_config_name = UpbStringToStdString(
+        envoy_config_route_v3_RouteConfiguration_name(route_config));
+    if (expected_route_configuration_names.find(route_config_name) ==
+        expected_route_configuration_names.end()) {
+      continue;
+    }
+    // Fail if route config name is duplicated.
+    if (rds_update_map->find(route_config_name) != rds_update_map->end()) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("duplicate route config name \"", route_config_name,
+                       "\"")
+              .c_str()));
+      resource_names_failed->insert(route_config_name);
+      continue;
+    }
+    // Serialize into JSON and store it in the RdsUpdateMap
+    XdsApi::RdsResourceData& rds_resource_data =
+        (*rds_update_map)[route_config_name];
+    XdsApi::RdsUpdate& rds_update = rds_resource_data.resource;
+    rds_resource_data.serialized_proto =
+        UpbStringToStdString(encoded_route_config);
+    // Parse the route_config.
+    grpc_error_handle error =
+        RouteConfigParse(context, route_config, &rds_update);
+    if (error != GRPC_ERROR_NONE) {
+      errors.push_back(grpc_error_add_child(
+          GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat(route_config_name, ": validation error").c_str()),
+          error));
+      resource_names_failed->insert(route_config_name);
+    }
+  }
+  return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing RDS response", &errors);
+}
+
+grpc_error_handle CdsResponseParse(
+    const EncodingContext& context,
     const envoy_service_discovery_v3_DiscoveryResponse* response,
     const std::set<absl::string_view>& expected_cluster_names,
-    XdsApi::CdsUpdateMap* cds_update_map, upb_arena* arena) {
+    XdsApi::CdsUpdateMap* cds_update_map,
+    std::set<std::string>* resource_names_failed) {
+  std::vector<grpc_error_handle> errors;
   // Get the resources from the response.
   size_t size;
   const google_protobuf_Any* const* resources =
@@ -1703,17 +2675,23 @@
     absl::string_view type_url =
         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
     if (!IsCds(type_url)) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not CDS.");
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("resource index ", i, ": Resource is not CDS.")
+              .c_str()));
+      continue;
     }
     // Decode the cluster.
     const upb_strview encoded_cluster = google_protobuf_Any_value(resources[i]);
     const envoy_config_cluster_v3_Cluster* cluster =
-        envoy_config_cluster_v3_Cluster_parse(encoded_cluster.data,
-                                              encoded_cluster.size, arena);
+        envoy_config_cluster_v3_Cluster_parse(
+            encoded_cluster.data, encoded_cluster.size, context.arena);
     if (cluster == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode cluster.");
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("resource index ", i, ": Can't decode cluster.")
+              .c_str()));
+      continue;
     }
-    MaybeLogCluster(client, tracer, symtab, cluster);
+    MaybeLogCluster(context, cluster);
     // Ignore unexpected cluster names.
     std::string cluster_name =
         UpbStringToStdString(envoy_config_cluster_v3_Cluster_name(cluster));
@@ -1723,41 +2701,194 @@
     }
     // Fail on duplicate resources.
     if (cds_update_map->find(cluster_name) != cds_update_map->end()) {
-      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("duplicate resource name \"", cluster_name, "\"")
-              .c_str());
+              .c_str()));
+      resource_names_failed->insert(cluster_name);
+      continue;
     }
-    XdsApi::CdsUpdate& cds_update = (*cds_update_map)[std::move(cluster_name)];
+    // Serialize into JSON and store it in the CdsUpdateMap
+    XdsApi::CdsResourceData& cds_resource_data =
+        (*cds_update_map)[cluster_name];
+    XdsApi::CdsUpdate& cds_update = cds_resource_data.resource;
+    cds_resource_data.serialized_proto = UpbStringToStdString(encoded_cluster);
     // Check the cluster_discovery_type.
-    if (!envoy_config_cluster_v3_Cluster_has_type(cluster)) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("DiscoveryType not found.");
+    if (!envoy_config_cluster_v3_Cluster_has_type(cluster) &&
+        !envoy_config_cluster_v3_Cluster_has_cluster_type(cluster)) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat(cluster_name, ": DiscoveryType not found.").c_str()));
+      resource_names_failed->insert(cluster_name);
+      continue;
     }
-    if (envoy_config_cluster_v3_Cluster_type(cluster) !=
+    if (envoy_config_cluster_v3_Cluster_type(cluster) ==
         envoy_config_cluster_v3_Cluster_EDS) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("DiscoveryType is not EDS.");
-    }
-    // Check the EDS config source.
-    const envoy_config_cluster_v3_Cluster_EdsClusterConfig* eds_cluster_config =
-        envoy_config_cluster_v3_Cluster_eds_cluster_config(cluster);
-    const envoy_config_core_v3_ConfigSource* eds_config =
-        envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_config(
-            eds_cluster_config);
-    if (!envoy_config_core_v3_ConfigSource_has_ads(eds_config)) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "EDS ConfigSource is not ADS.");
-    }
-    // Record EDS service_name (if any).
-    upb_strview service_name =
-        envoy_config_cluster_v3_Cluster_EdsClusterConfig_service_name(
-            eds_cluster_config);
-    if (service_name.size != 0) {
-      cds_update.eds_service_name = UpbStringToStdString(service_name);
+      cds_update.cluster_type = XdsApi::CdsUpdate::ClusterType::EDS;
+      // Check the EDS config source.
+      const envoy_config_cluster_v3_Cluster_EdsClusterConfig*
+          eds_cluster_config =
+              envoy_config_cluster_v3_Cluster_eds_cluster_config(cluster);
+      const envoy_config_core_v3_ConfigSource* eds_config =
+          envoy_config_cluster_v3_Cluster_EdsClusterConfig_eds_config(
+              eds_cluster_config);
+      if (!envoy_config_core_v3_ConfigSource_has_ads(eds_config)) {
+        errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat(cluster_name, ": EDS ConfigSource is not ADS.")
+                .c_str()));
+        resource_names_failed->insert(cluster_name);
+        continue;
+      }
+      // Record EDS service_name (if any).
+      upb_strview service_name =
+          envoy_config_cluster_v3_Cluster_EdsClusterConfig_service_name(
+              eds_cluster_config);
+      if (service_name.size != 0) {
+        cds_update.eds_service_name = UpbStringToStdString(service_name);
+      }
+    } else if (!XdsAggregateAndLogicalDnsClusterEnabled()) {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat(cluster_name, ": DiscoveryType is not valid.").c_str()));
+      resource_names_failed->insert(cluster_name);
+      continue;
+    } else if (envoy_config_cluster_v3_Cluster_type(cluster) ==
+               envoy_config_cluster_v3_Cluster_LOGICAL_DNS) {
+      cds_update.cluster_type = XdsApi::CdsUpdate::ClusterType::LOGICAL_DNS;
+    } else {
+      if (envoy_config_cluster_v3_Cluster_has_cluster_type(cluster)) {
+        const envoy_config_cluster_v3_Cluster_CustomClusterType*
+            custom_cluster_type =
+                envoy_config_cluster_v3_Cluster_cluster_type(cluster);
+        upb_strview type_name =
+            envoy_config_cluster_v3_Cluster_CustomClusterType_name(
+                custom_cluster_type);
+        if (UpbStringToAbsl(type_name) == "envoy.clusters.aggregate") {
+          cds_update.cluster_type = XdsApi::CdsUpdate::ClusterType::AGGREGATE;
+          // Retrieve aggregate clusters.
+          const google_protobuf_Any* typed_config =
+              envoy_config_cluster_v3_Cluster_CustomClusterType_typed_config(
+                  custom_cluster_type);
+          const upb_strview aggregate_cluster_config_upb_strview =
+              google_protobuf_Any_value(typed_config);
+          const envoy_extensions_clusters_aggregate_v3_ClusterConfig*
+              aggregate_cluster_config =
+                  envoy_extensions_clusters_aggregate_v3_ClusterConfig_parse(
+                      aggregate_cluster_config_upb_strview.data,
+                      aggregate_cluster_config_upb_strview.size, context.arena);
+          if (aggregate_cluster_config == nullptr) {
+            errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+                absl::StrCat(cluster_name, ": Can't parse aggregate cluster.")
+                    .c_str()));
+            resource_names_failed->insert(cluster_name);
+            continue;
+          }
+          size_t size;
+          const upb_strview* clusters =
+              envoy_extensions_clusters_aggregate_v3_ClusterConfig_clusters(
+                  aggregate_cluster_config, &size);
+          for (size_t i = 0; i < size; ++i) {
+            const upb_strview cluster = clusters[i];
+            cds_update.prioritized_cluster_names.emplace_back(
+                UpbStringToStdString(cluster));
+          }
+        } else {
+          errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat(cluster_name, ": DiscoveryType is not valid.")
+                  .c_str()));
+          resource_names_failed->insert(cluster_name);
+          continue;
+        }
+      } else {
+        errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat(cluster_name, ": DiscoveryType is not valid.")
+                .c_str()));
+        resource_names_failed->insert(cluster_name);
+        continue;
+      }
     }
     // Check the LB policy.
-    if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) !=
+    if (envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
         envoy_config_cluster_v3_Cluster_ROUND_ROBIN) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "LB policy is not ROUND_ROBIN.");
+      cds_update.lb_policy = "ROUND_ROBIN";
+    } else if (XdsRingHashEnabled() &&
+               envoy_config_cluster_v3_Cluster_lb_policy(cluster) ==
+                   envoy_config_cluster_v3_Cluster_RING_HASH) {
+      cds_update.lb_policy = "RING_HASH";
+      // Record ring hash lb config
+      auto* ring_hash_config =
+          envoy_config_cluster_v3_Cluster_ring_hash_lb_config(cluster);
+      if (ring_hash_config == nullptr) {
+        errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat(cluster_name,
+                         ": ring hash lb config required but not present.")
+                .c_str()));
+        resource_names_failed->insert(cluster_name);
+        continue;
+      }
+      const google_protobuf_UInt64Value* max_ring_size =
+          envoy_config_cluster_v3_Cluster_RingHashLbConfig_maximum_ring_size(
+              ring_hash_config);
+      if (max_ring_size != nullptr) {
+        cds_update.max_ring_size =
+            google_protobuf_UInt64Value_value(max_ring_size);
+        if (cds_update.max_ring_size > 8388608 ||
+            cds_update.max_ring_size == 0) {
+          errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat(
+                  cluster_name,
+                  ": max_ring_size is not in the range of 1 to 8388608.")
+                  .c_str()));
+          resource_names_failed->insert(cluster_name);
+          continue;
+        }
+      }
+      const google_protobuf_UInt64Value* min_ring_size =
+          envoy_config_cluster_v3_Cluster_RingHashLbConfig_minimum_ring_size(
+              ring_hash_config);
+      if (min_ring_size != nullptr) {
+        cds_update.min_ring_size =
+            google_protobuf_UInt64Value_value(min_ring_size);
+        if (cds_update.min_ring_size > 8388608 ||
+            cds_update.min_ring_size == 0) {
+          errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat(
+                  cluster_name,
+                  ": min_ring_size is not in the range of 1 to 8388608.")
+                  .c_str()));
+          resource_names_failed->insert(cluster_name);
+          continue;
+        }
+        if (cds_update.min_ring_size > cds_update.max_ring_size) {
+          errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat(
+                  cluster_name,
+                  ": min_ring_size cannot be greater than max_ring_size.")
+                  .c_str()));
+          resource_names_failed->insert(cluster_name);
+          continue;
+        }
+      }
+      if (envoy_config_cluster_v3_Cluster_RingHashLbConfig_hash_function(
+              ring_hash_config) ==
+          envoy_config_cluster_v3_Cluster_RingHashLbConfig_XX_HASH) {
+        cds_update.hash_function = XdsApi::CdsUpdate::HashFunction::XX_HASH;
+      } else if (
+          envoy_config_cluster_v3_Cluster_RingHashLbConfig_hash_function(
+              ring_hash_config) ==
+          envoy_config_cluster_v3_Cluster_RingHashLbConfig_MURMUR_HASH_2) {
+        cds_update.hash_function =
+            XdsApi::CdsUpdate::HashFunction::MURMUR_HASH_2;
+      } else {
+        errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat(cluster_name,
+                         ": ring hash lb config has invalid hash function.")
+                .c_str()));
+        resource_names_failed->insert(cluster_name);
+        continue;
+      }
+    } else {
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat(cluster_name, ": LB policy is not supported.").c_str()));
+      resource_names_failed->insert(cluster_name);
+      continue;
     }
     if (XdsSecurityEnabled()) {
       // Record Upstream tls context
@@ -1776,26 +2907,43 @@
             auto* upstream_tls_context =
                 envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_parse(
                     encoded_upstream_tls_context.data,
-                    encoded_upstream_tls_context.size, arena);
+                    encoded_upstream_tls_context.size, context.arena);
             if (upstream_tls_context == nullptr) {
-              return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                  "Can't decode upstream tls context.");
+              errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+                  absl::StrCat(cluster_name,
+                               ": Can't decode upstream tls context.")
+                      .c_str()));
+              resource_names_failed->insert(cluster_name);
+              continue;
             }
             auto* common_tls_context =
                 envoy_extensions_transport_sockets_tls_v3_UpstreamTlsContext_common_tls_context(
                     upstream_tls_context);
             if (common_tls_context != nullptr) {
-              grpc_error* error = CommonTlsContextParse(
+              grpc_error_handle error = CommonTlsContextParse(
                   common_tls_context, &cds_update.common_tls_context);
-              if (error != GRPC_ERROR_NONE) return error;
+              if (error != GRPC_ERROR_NONE) {
+                errors.push_back(grpc_error_add_child(
+                    GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+                        absl::StrCat(cluster_name, ": error in TLS context")
+                            .c_str()),
+                    error));
+                resource_names_failed->insert(cluster_name);
+                continue;
+              }
             }
           }
           if (cds_update.common_tls_context.combined_validation_context
                   .validation_context_certificate_provider_instance
                   .instance_name.empty()) {
-            return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                "TLS configuration provided but no "
-                "validation_context_certificate_provider_instance found.");
+            errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+                absl::StrCat(cluster_name,
+                             "TLS configuration provided but no "
+                             "validation_context_certificate_provider_instance "
+                             "found.")
+                    .c_str()));
+            resource_names_failed->insert(cluster_name);
+            continue;
           }
         }
       }
@@ -1805,8 +2953,11 @@
         envoy_config_cluster_v3_Cluster_lrs_server(cluster);
     if (lrs_server != nullptr) {
       if (!envoy_config_core_v3_ConfigSource_has_self(lrs_server)) {
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "LRS ConfigSource is not self.");
+        errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat(cluster_name, ": LRS ConfigSource is not self.")
+                .c_str()));
+        resource_names_failed->insert(cluster_name);
+        continue;
       }
       cds_update.lrs_load_reporting_server_name.emplace("");
     }
@@ -1837,10 +2988,10 @@
       }
     }
   }
-  return GRPC_ERROR_NONE;
+  return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing CDS response", &errors);
 }
 
-grpc_error* ServerAddressParseAndAppend(
+grpc_error_handle ServerAddressParseAndAppend(
     const envoy_config_endpoint_v3_LbEndpoint* lb_endpoint,
     ServerAddressList* list) {
   // If health_status is not HEALTHY or UNKNOWN, skip this endpoint.
@@ -1865,13 +3016,15 @@
   }
   // Populate grpc_resolved_address.
   grpc_resolved_address addr;
-  grpc_string_to_sockaddr(&addr, address_str.c_str(), port);
+  grpc_error_handle error =
+      grpc_string_to_sockaddr(&addr, address_str.c_str(), port);
+  if (error != GRPC_ERROR_NONE) return error;
   // Append the address to the list.
   list->emplace_back(addr, nullptr);
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* LocalityParse(
+grpc_error_handle LocalityParse(
     const envoy_config_endpoint_v3_LocalityLbEndpoints* locality_lb_endpoints,
     XdsApi::EdsUpdate::Priority::Locality* output_locality, size_t* priority) {
   // Parse LB weight.
@@ -1888,6 +3041,9 @@
   const envoy_config_core_v3_Locality* locality =
       envoy_config_endpoint_v3_LocalityLbEndpoints_locality(
           locality_lb_endpoints);
+  if (locality == nullptr) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty locality.");
+  }
   std::string region =
       UpbStringToStdString(envoy_config_core_v3_Locality_region(locality));
   std::string zone =
@@ -1902,7 +3058,7 @@
       envoy_config_endpoint_v3_LocalityLbEndpoints_lb_endpoints(
           locality_lb_endpoints, &size);
   for (size_t i = 0; i < size; ++i) {
-    grpc_error* error = ServerAddressParseAndAppend(
+    grpc_error_handle error = ServerAddressParseAndAppend(
         lb_endpoints[i], &output_locality->endpoints);
     if (error != GRPC_ERROR_NONE) return error;
   }
@@ -1912,7 +3068,7 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* DropParseAndAppend(
+grpc_error_handle DropParseAndAppend(
     const envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload*
         drop_overload,
     XdsApi::EdsUpdate::DropConfig* drop_config) {
@@ -1951,11 +3107,13 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* EdsResponseParse(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
+grpc_error_handle EdsResponseParse(
+    const EncodingContext& context,
     const envoy_service_discovery_v3_DiscoveryResponse* response,
     const std::set<absl::string_view>& expected_eds_service_names,
-    XdsApi::EdsUpdateMap* eds_update_map, upb_arena* arena) {
+    XdsApi::EdsUpdateMap* eds_update_map,
+    std::set<std::string>* resource_names_failed) {
+  std::vector<grpc_error_handle> errors;
   // Get the resources from the response.
   size_t size;
   const google_protobuf_Any* const* resources =
@@ -1965,7 +3123,10 @@
     absl::string_view type_url =
         UpbStringToAbsl(google_protobuf_Any_type_url(resources[i]));
     if (!IsEds(type_url)) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not EDS.");
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("resource index ", i, ": Resource is not EDS.")
+              .c_str()));
+      continue;
     }
     // Get the cluster_load_assignment.
     upb_strview encoded_cluster_load_assignment =
@@ -1973,13 +3134,15 @@
     envoy_config_endpoint_v3_ClusterLoadAssignment* cluster_load_assignment =
         envoy_config_endpoint_v3_ClusterLoadAssignment_parse(
             encoded_cluster_load_assignment.data,
-            encoded_cluster_load_assignment.size, arena);
+            encoded_cluster_load_assignment.size, context.arena);
     if (cluster_load_assignment == nullptr) {
-      return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "Can't parse cluster_load_assignment.");
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+          absl::StrCat("resource index ", i,
+                       ": Can't parse cluster_load_assignment.")
+              .c_str()));
+      continue;
     }
-    MaybeLogClusterLoadAssignment(client, tracer, symtab,
-                                  cluster_load_assignment);
+    MaybeLogClusterLoadAssignment(context, cluster_load_assignment);
     // Check the EDS service name.  Ignore unexpected names.
     std::string eds_service_name = UpbStringToStdString(
         envoy_config_endpoint_v3_ClusterLoadAssignment_cluster_name(
@@ -1990,22 +3153,29 @@
     }
     // Fail on duplicate resources.
     if (eds_update_map->find(eds_service_name) != eds_update_map->end()) {
-      return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+      errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("duplicate resource name \"", eds_service_name, "\"")
-              .c_str());
+              .c_str()));
+      resource_names_failed->insert(eds_service_name);
+      continue;
     }
-    XdsApi::EdsUpdate& eds_update =
-        (*eds_update_map)[std::move(eds_service_name)];
+    // Serialize into JSON and store it in the EdsUpdateMap
+    XdsApi::EdsResourceData& eds_resource_data =
+        (*eds_update_map)[eds_service_name];
+    XdsApi::EdsUpdate& eds_update = eds_resource_data.resource;
+    eds_resource_data.serialized_proto =
+        UpbStringToStdString(encoded_cluster_load_assignment);
     // Get the endpoints.
     size_t locality_size;
     const envoy_config_endpoint_v3_LocalityLbEndpoints* const* endpoints =
         envoy_config_endpoint_v3_ClusterLoadAssignment_endpoints(
             cluster_load_assignment, &locality_size);
+    grpc_error_handle error = GRPC_ERROR_NONE;
     for (size_t j = 0; j < locality_size; ++j) {
       size_t priority;
       XdsApi::EdsUpdate::Priority::Locality locality;
-      grpc_error* error = LocalityParse(endpoints[j], &locality, &priority);
-      if (error != GRPC_ERROR_NONE) return error;
+      error = LocalityParse(endpoints[j], &locality, &priority);
+      if (error != GRPC_ERROR_NONE) break;
       // Filter out locality with weight 0.
       if (locality.lb_weight == 0) continue;
       // Make sure prorities is big enough. Note that they might not
@@ -2016,10 +3186,21 @@
       eds_update.priorities[priority].localities.emplace(locality.name.get(),
                                                          std::move(locality));
     }
+    if (error != GRPC_ERROR_NONE) {
+      errors.push_back(grpc_error_add_child(
+          GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+              absl::StrCat(eds_service_name, ": locality validation error")
+                  .c_str()),
+          error));
+      resource_names_failed->insert(eds_service_name);
+      continue;
+    }
     for (const auto& priority : eds_update.priorities) {
       if (priority.localities.empty()) {
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            "EDS update includes sparse priority list");
+        errors.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+            absl::StrCat(eds_service_name, ": sparse priority list").c_str()));
+        resource_names_failed->insert(eds_service_name);
+        continue;
       }
     }
     // Get the drop config.
@@ -2034,13 +3215,22 @@
               envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_drop_overloads(
                   policy, &drop_size);
       for (size_t j = 0; j < drop_size; ++j) {
-        grpc_error* error =
+        error =
             DropParseAndAppend(drop_overload[j], eds_update.drop_config.get());
-        if (error != GRPC_ERROR_NONE) return error;
+        if (error != GRPC_ERROR_NONE) break;
+      }
+      if (error != GRPC_ERROR_NONE) {
+        errors.push_back(grpc_error_add_child(
+            GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+                absl::StrCat(eds_service_name, ": drop config validation error")
+                    .c_str()),
+            error));
+        resource_names_failed->insert(eds_service_name);
+        continue;
       }
     }
   }
-  return GRPC_ERROR_NONE;
+  return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing EDS response", &errors);
 }
 
 std::string TypeUrlInternalToExternal(absl::string_view type_url) {
@@ -2056,16 +3246,27 @@
   return std::string(type_url);
 }
 
+template <typename UpdateMap>
+void MoveUpdatesToFailedSet(UpdateMap* update_map,
+                            std::set<std::string>* resource_names_failed) {
+  for (const auto& p : *update_map) {
+    resource_names_failed->insert(p.first);
+  }
+  update_map->clear();
+}
+
 }  // namespace
 
 XdsApi::AdsParseResult XdsApi::ParseAdsResponse(
-    const grpc_slice& encoded_response,
+    const XdsBootstrap::XdsServer& server, const grpc_slice& encoded_response,
     const std::set<absl::string_view>& expected_listener_names,
     const std::set<absl::string_view>& expected_route_configuration_names,
     const std::set<absl::string_view>& expected_cluster_names,
     const std::set<absl::string_view>& expected_eds_service_names) {
   AdsParseResult result;
   upb::Arena arena;
+  const EncodingContext context = {client_, tracer_, symtab_.ptr(), arena.ptr(),
+                                   server.ShouldUseV3()};
   // Decode the response.
   const envoy_service_discovery_v3_DiscoveryResponse* response =
       envoy_service_discovery_v3_DiscoveryResponse_parse(
@@ -2077,7 +3278,7 @@
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode DiscoveryResponse.");
     return result;
   }
-  MaybeLogDiscoveryResponse(client_, tracer_, symtab_.ptr(), response);
+  MaybeLogDiscoveryResponse(context, response);
   // Record the type_url, the version_info, and the nonce of the response.
   result.type_url = TypeUrlInternalToExternal(UpbStringToAbsl(
       envoy_service_discovery_v3_DiscoveryResponse_type_url(response)));
@@ -2087,22 +3288,37 @@
       envoy_service_discovery_v3_DiscoveryResponse_nonce(response));
   // Parse the response according to the resource type.
   if (IsLds(result.type_url)) {
-    result.parse_error = LdsResponseParse(client_, tracer_, symtab_.ptr(),
-                                          response, expected_listener_names,
-                                          &result.lds_update_map, arena.ptr());
+    result.parse_error =
+        LdsResponseParse(context, response, expected_listener_names,
+                         &result.lds_update_map, &result.resource_names_failed);
+    if (result.parse_error != GRPC_ERROR_NONE) {
+      MoveUpdatesToFailedSet(&result.lds_update_map,
+                             &result.resource_names_failed);
+    }
   } else if (IsRds(result.type_url)) {
     result.parse_error =
-        RdsResponseParse(client_, tracer_, symtab_.ptr(), response,
-                         expected_route_configuration_names,
-                         &result.rds_update_map, arena.ptr());
+        RdsResponseParse(context, response, expected_route_configuration_names,
+                         &result.rds_update_map, &result.resource_names_failed);
+    if (result.parse_error != GRPC_ERROR_NONE) {
+      MoveUpdatesToFailedSet(&result.rds_update_map,
+                             &result.resource_names_failed);
+    }
   } else if (IsCds(result.type_url)) {
-    result.parse_error = CdsResponseParse(client_, tracer_, symtab_.ptr(),
-                                          response, expected_cluster_names,
-                                          &result.cds_update_map, arena.ptr());
+    result.parse_error =
+        CdsResponseParse(context, response, expected_cluster_names,
+                         &result.cds_update_map, &result.resource_names_failed);
+    if (result.parse_error != GRPC_ERROR_NONE) {
+      MoveUpdatesToFailedSet(&result.cds_update_map,
+                             &result.resource_names_failed);
+    }
   } else if (IsEds(result.type_url)) {
-    result.parse_error = EdsResponseParse(client_, tracer_, symtab_.ptr(),
-                                          response, expected_eds_service_names,
-                                          &result.eds_update_map, arena.ptr());
+    result.parse_error =
+        EdsResponseParse(context, response, expected_eds_service_names,
+                         &result.eds_update_map, &result.resource_names_failed);
+    if (result.parse_error != GRPC_ERROR_NONE) {
+      MoveUpdatesToFailedSet(&result.eds_update_map,
+                             &result.resource_names_failed);
+    }
   }
   return result;
 }
@@ -2110,25 +3326,25 @@
 namespace {
 
 void MaybeLogLrsRequest(
-    XdsClient* client, TraceFlag* tracer, upb_symtab* symtab,
+    const EncodingContext& context,
     const envoy_service_load_stats_v3_LoadStatsRequest* request) {
-  if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
+  if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) &&
       gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
     const upb_msgdef* msg_type =
-        envoy_service_load_stats_v3_LoadStatsRequest_getmsgdef(symtab);
+        envoy_service_load_stats_v3_LoadStatsRequest_getmsgdef(context.symtab);
     char buf[10240];
     upb_text_encode(request, msg_type, nullptr, 0, buf, sizeof(buf));
-    gpr_log(GPR_DEBUG, "[xds_client %p] constructed LRS request: %s", client,
-            buf);
+    gpr_log(GPR_DEBUG, "[xds_client %p] constructed LRS request: %s",
+            context.client, buf);
   }
 }
 
 grpc_slice SerializeLrsRequest(
-    const envoy_service_load_stats_v3_LoadStatsRequest* request,
-    upb_arena* arena) {
+    const EncodingContext& context,
+    const envoy_service_load_stats_v3_LoadStatsRequest* request) {
   size_t output_length;
   char* output = envoy_service_load_stats_v3_LoadStatsRequest_serialize(
-      request, arena, &output_length);
+      request, context.arena, &output_length);
   return grpc_slice_from_copied_buffer(output, output_length);
 }
 
@@ -2137,6 +3353,8 @@
 grpc_slice XdsApi::CreateLrsInitialRequest(
     const XdsBootstrap::XdsServer& server) {
   upb::Arena arena;
+  const EncodingContext context = {client_, tracer_, symtab_.ptr(), arena.ptr(),
+                                   server.ShouldUseV3()};
   // Create a request.
   envoy_service_load_stats_v3_LoadStatsRequest* request =
       envoy_service_load_stats_v3_LoadStatsRequest_new(arena.ptr());
@@ -2144,25 +3362,25 @@
   envoy_config_core_v3_Node* node_msg =
       envoy_service_load_stats_v3_LoadStatsRequest_mutable_node(request,
                                                                 arena.ptr());
-  PopulateNode(arena.ptr(), node_, server.ShouldUseV3(), build_version_,
-               user_agent_name_, node_msg);
+  PopulateNode(context, node_, build_version_, user_agent_name_, node_msg);
   envoy_config_core_v3_Node_add_client_features(
       node_msg, upb_strview_makez("envoy.lrs.supports_send_all_clusters"),
       arena.ptr());
-  MaybeLogLrsRequest(client_, tracer_, symtab_.ptr(), request);
-  return SerializeLrsRequest(request, arena.ptr());
+  MaybeLogLrsRequest(context, request);
+  return SerializeLrsRequest(context, request);
 }
 
 namespace {
 
 void LocalityStatsPopulate(
+    const EncodingContext& context,
     envoy_config_endpoint_v3_UpstreamLocalityStats* output,
     const XdsLocalityName& locality_name,
-    const XdsClusterLocalityStats::Snapshot& snapshot, upb_arena* arena) {
+    const XdsClusterLocalityStats::Snapshot& snapshot) {
   // Set locality.
   envoy_config_core_v3_Locality* locality =
-      envoy_config_endpoint_v3_UpstreamLocalityStats_mutable_locality(output,
-                                                                      arena);
+      envoy_config_endpoint_v3_UpstreamLocalityStats_mutable_locality(
+          output, context.arena);
   if (!locality_name.region().empty()) {
     envoy_config_core_v3_Locality_set_region(
         locality, StdStringToUpbString(locality_name.region()));
@@ -2190,7 +3408,7 @@
     const XdsClusterLocalityStats::BackendMetric& metric_value = p.second;
     envoy_config_endpoint_v3_EndpointLoadMetricStats* load_metric =
         envoy_config_endpoint_v3_UpstreamLocalityStats_add_load_metric_stats(
-            output, arena);
+            output, context.arena);
     envoy_config_endpoint_v3_EndpointLoadMetricStats_set_metric_name(
         load_metric, StdStringToUpbString(metric_name));
     envoy_config_endpoint_v3_EndpointLoadMetricStats_set_num_requests_finished_with_metric(
@@ -2205,6 +3423,8 @@
 grpc_slice XdsApi::CreateLrsRequest(
     ClusterLoadReportMap cluster_load_report_map) {
   upb::Arena arena;
+  const EncodingContext context = {client_, tracer_, symtab_.ptr(), arena.ptr(),
+                                   false};
   // Create a request.
   envoy_service_load_stats_v3_LoadStatsRequest* request =
       envoy_service_load_stats_v3_LoadStatsRequest_new(arena.ptr());
@@ -2231,8 +3451,7 @@
       envoy_config_endpoint_v3_UpstreamLocalityStats* locality_stats =
           envoy_config_endpoint_v3_ClusterStats_add_upstream_locality_stats(
               cluster_stats, arena.ptr());
-      LocalityStatsPopulate(locality_stats, locality_name, snapshot,
-                            arena.ptr());
+      LocalityStatsPopulate(context, locality_stats, locality_name, snapshot);
     }
     // Add dropped requests.
     uint64_t total_dropped_requests = 0;
@@ -2261,14 +3480,14 @@
     google_protobuf_Duration_set_seconds(load_report_interval, timespec.tv_sec);
     google_protobuf_Duration_set_nanos(load_report_interval, timespec.tv_nsec);
   }
-  MaybeLogLrsRequest(client_, tracer_, symtab_.ptr(), request);
-  return SerializeLrsRequest(request, arena.ptr());
+  MaybeLogLrsRequest(context, request);
+  return SerializeLrsRequest(context, request);
 }
 
-grpc_error* XdsApi::ParseLrsResponse(const grpc_slice& encoded_response,
-                                     bool* send_all_clusters,
-                                     std::set<std::string>* cluster_names,
-                                     grpc_millis* load_reporting_interval) {
+grpc_error_handle XdsApi::ParseLrsResponse(
+    const grpc_slice& encoded_response, bool* send_all_clusters,
+    std::set<std::string>* cluster_names,
+    grpc_millis* load_reporting_interval) {
   upb::Arena arena;
   // Decode the response.
   const envoy_service_load_stats_v3_LoadStatsResponse* decoded_response =
@@ -2305,4 +3524,276 @@
   return GRPC_ERROR_NONE;
 }
 
+namespace {
+google_protobuf_Timestamp* GrpcMillisToTimestamp(const EncodingContext& context,
+                                                 grpc_millis value) {
+  google_protobuf_Timestamp* timestamp =
+      google_protobuf_Timestamp_new(context.arena);
+  gpr_timespec timespec = grpc_millis_to_timespec(value, GPR_CLOCK_REALTIME);
+  google_protobuf_Timestamp_set_seconds(timestamp, timespec.tv_sec);
+  google_protobuf_Timestamp_set_nanos(timestamp, timespec.tv_nsec);
+  return timestamp;
+}
+
+envoy_admin_v3_UpdateFailureState* CreateUpdateFailureStateUpb(
+    const EncodingContext& context,
+    const XdsApi::ResourceMetadata* resource_metadata) {
+  auto* update_failure_state =
+      envoy_admin_v3_UpdateFailureState_new(context.arena);
+  envoy_admin_v3_UpdateFailureState_set_details(
+      update_failure_state,
+      StdStringToUpbString(resource_metadata->failed_details));
+  envoy_admin_v3_UpdateFailureState_set_version_info(
+      update_failure_state,
+      StdStringToUpbString(resource_metadata->failed_version));
+  envoy_admin_v3_UpdateFailureState_set_last_update_attempt(
+      update_failure_state,
+      GrpcMillisToTimestamp(context, resource_metadata->failed_update_time));
+  return update_failure_state;
+}
+
+void DumpLdsConfig(const EncodingContext& context,
+                   const XdsApi::ResourceTypeMetadata& resource_type_metadata,
+                   envoy_service_status_v3_PerXdsConfig* per_xds_config) {
+  upb_strview kLdsTypeUrlUpb = upb_strview_makez(XdsApi::kLdsTypeUrl);
+  auto* listener_config_dump =
+      envoy_service_status_v3_PerXdsConfig_mutable_listener_config(
+          per_xds_config, context.arena);
+  envoy_admin_v3_ListenersConfigDump_set_version_info(
+      listener_config_dump,
+      StdStringToUpbString(resource_type_metadata.version));
+  for (auto& p : resource_type_metadata.resource_metadata_map) {
+    absl::string_view name = p.first;
+    const XdsApi::ResourceMetadata* meta = p.second;
+    const upb_strview name_upb = StdStringToUpbString(name);
+    auto* dynamic_listener =
+        envoy_admin_v3_ListenersConfigDump_add_dynamic_listeners(
+            listener_config_dump, context.arena);
+    envoy_admin_v3_ListenersConfigDump_DynamicListener_set_name(
+        dynamic_listener, name_upb);
+    envoy_admin_v3_ListenersConfigDump_DynamicListener_set_client_status(
+        dynamic_listener, meta->client_status);
+    if (!meta->serialized_proto.empty()) {
+      // Set in-effective listeners
+      auto* dynamic_listener_state =
+          envoy_admin_v3_ListenersConfigDump_DynamicListener_mutable_active_state(
+              dynamic_listener, context.arena);
+      envoy_admin_v3_ListenersConfigDump_DynamicListenerState_set_version_info(
+          dynamic_listener_state, StdStringToUpbString(meta->version));
+      envoy_admin_v3_ListenersConfigDump_DynamicListenerState_set_last_updated(
+          dynamic_listener_state,
+          GrpcMillisToTimestamp(context, meta->update_time));
+      auto* listener_any =
+          envoy_admin_v3_ListenersConfigDump_DynamicListenerState_mutable_listener(
+              dynamic_listener_state, context.arena);
+      google_protobuf_Any_set_type_url(listener_any, kLdsTypeUrlUpb);
+      google_protobuf_Any_set_value(
+          listener_any, StdStringToUpbString(meta->serialized_proto));
+    }
+    if (meta->client_status == XdsApi::ResourceMetadata::NACKED) {
+      // Set error_state if NACKED
+      envoy_admin_v3_ListenersConfigDump_DynamicListener_set_error_state(
+          dynamic_listener, CreateUpdateFailureStateUpb(context, meta));
+    }
+  }
+}
+
+void DumpRdsConfig(const EncodingContext& context,
+                   const XdsApi::ResourceTypeMetadata& resource_type_metadata,
+                   envoy_service_status_v3_PerXdsConfig* per_xds_config) {
+  upb_strview kRdsTypeUrlUpb = upb_strview_makez(XdsApi::kRdsTypeUrl);
+  auto* route_config_dump =
+      envoy_service_status_v3_PerXdsConfig_mutable_route_config(per_xds_config,
+                                                                context.arena);
+  for (auto& p : resource_type_metadata.resource_metadata_map) {
+    absl::string_view name = p.first;
+    const XdsApi::ResourceMetadata* meta = p.second;
+    const upb_strview name_upb = StdStringToUpbString(name);
+    auto* dynamic_route_config =
+        envoy_admin_v3_RoutesConfigDump_add_dynamic_route_configs(
+            route_config_dump, context.arena);
+    envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_client_status(
+        dynamic_route_config, meta->client_status);
+    auto* route_config_any =
+        envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_mutable_route_config(
+            dynamic_route_config, context.arena);
+    if (!meta->serialized_proto.empty()) {
+      // Set in-effective route configs
+      envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_version_info(
+          dynamic_route_config, StdStringToUpbString(meta->version));
+      envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_last_updated(
+          dynamic_route_config,
+          GrpcMillisToTimestamp(context, meta->update_time));
+      google_protobuf_Any_set_type_url(route_config_any, kRdsTypeUrlUpb);
+      google_protobuf_Any_set_value(
+          route_config_any, StdStringToUpbString(meta->serialized_proto));
+    } else {
+      // If there isn't a working route config, we still need to print the
+      // name.
+      auto* route_config =
+          envoy_config_route_v3_RouteConfiguration_new(context.arena);
+      envoy_config_route_v3_RouteConfiguration_set_name(route_config, name_upb);
+      size_t length;
+      char* bytes = envoy_config_route_v3_RouteConfiguration_serialize(
+          route_config, context.arena, &length);
+      google_protobuf_Any_set_type_url(route_config_any, kRdsTypeUrlUpb);
+      google_protobuf_Any_set_value(route_config_any,
+                                    upb_strview_make(bytes, length));
+    }
+    if (meta->client_status == XdsApi::ResourceMetadata::NACKED) {
+      // Set error_state if NACKED
+      envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig_set_error_state(
+          dynamic_route_config, CreateUpdateFailureStateUpb(context, meta));
+    }
+  }
+}
+
+void DumpCdsConfig(const EncodingContext& context,
+                   const XdsApi::ResourceTypeMetadata& resource_type_metadata,
+                   envoy_service_status_v3_PerXdsConfig* per_xds_config) {
+  upb_strview kCdsTypeUrlUpb = upb_strview_makez(XdsApi::kCdsTypeUrl);
+  auto* cluster_config_dump =
+      envoy_service_status_v3_PerXdsConfig_mutable_cluster_config(
+          per_xds_config, context.arena);
+  envoy_admin_v3_ClustersConfigDump_set_version_info(
+      cluster_config_dump,
+      StdStringToUpbString(resource_type_metadata.version));
+  for (auto& p : resource_type_metadata.resource_metadata_map) {
+    absl::string_view name = p.first;
+    const XdsApi::ResourceMetadata* meta = p.second;
+    const upb_strview name_upb = StdStringToUpbString(name);
+    auto* dynamic_cluster =
+        envoy_admin_v3_ClustersConfigDump_add_dynamic_active_clusters(
+            cluster_config_dump, context.arena);
+    envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_client_status(
+        dynamic_cluster, meta->client_status);
+    auto* cluster_any =
+        envoy_admin_v3_ClustersConfigDump_DynamicCluster_mutable_cluster(
+            dynamic_cluster, context.arena);
+    if (!meta->serialized_proto.empty()) {
+      // Set in-effective clusters
+      envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_version_info(
+          dynamic_cluster, StdStringToUpbString(meta->version));
+      envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_last_updated(
+          dynamic_cluster, GrpcMillisToTimestamp(context, meta->update_time));
+      google_protobuf_Any_set_type_url(cluster_any, kCdsTypeUrlUpb);
+      google_protobuf_Any_set_value(
+          cluster_any, StdStringToUpbString(meta->serialized_proto));
+    } else {
+      // If there isn't a working cluster, we still need to print the name.
+      auto* cluster = envoy_config_cluster_v3_Cluster_new(context.arena);
+      envoy_config_cluster_v3_Cluster_set_name(cluster, name_upb);
+      size_t length;
+      char* bytes = envoy_config_cluster_v3_Cluster_serialize(
+          cluster, context.arena, &length);
+      google_protobuf_Any_set_type_url(cluster_any, kCdsTypeUrlUpb);
+      google_protobuf_Any_set_value(cluster_any,
+                                    upb_strview_make(bytes, length));
+    }
+    if (meta->client_status == XdsApi::ResourceMetadata::NACKED) {
+      // Set error_state if NACKED
+      envoy_admin_v3_ClustersConfigDump_DynamicCluster_set_error_state(
+          dynamic_cluster, CreateUpdateFailureStateUpb(context, meta));
+    }
+  }
+}
+
+void DumpEdsConfig(const EncodingContext& context,
+                   const XdsApi::ResourceTypeMetadata& resource_type_metadata,
+                   envoy_service_status_v3_PerXdsConfig* per_xds_config) {
+  upb_strview kEdsTypeUrlUpb = upb_strview_makez(XdsApi::kEdsTypeUrl);
+  auto* endpoint_config_dump =
+      envoy_service_status_v3_PerXdsConfig_mutable_endpoint_config(
+          per_xds_config, context.arena);
+  for (auto& p : resource_type_metadata.resource_metadata_map) {
+    absl::string_view name = p.first;
+    const XdsApi::ResourceMetadata* meta = p.second;
+    const upb_strview name_upb = StdStringToUpbString(name);
+    auto* dynamic_endpoint =
+        envoy_admin_v3_EndpointsConfigDump_add_dynamic_endpoint_configs(
+            endpoint_config_dump, context.arena);
+    envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_client_status(
+        dynamic_endpoint, meta->client_status);
+    auto* endpoint_any =
+        envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_mutable_endpoint_config(
+            dynamic_endpoint, context.arena);
+    if (!meta->serialized_proto.empty()) {
+      // Set in-effective endpoints
+      envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_version_info(
+          dynamic_endpoint, StdStringToUpbString(meta->version));
+      envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_last_updated(
+          dynamic_endpoint, GrpcMillisToTimestamp(context, meta->update_time));
+      google_protobuf_Any_set_type_url(endpoint_any, kEdsTypeUrlUpb);
+      google_protobuf_Any_set_value(
+          endpoint_any, StdStringToUpbString(meta->serialized_proto));
+    } else {
+      // If there isn't a working endpoint, we still need to print the name.
+      auto* cluster_load_assignment =
+          envoy_config_endpoint_v3_ClusterLoadAssignment_new(context.arena);
+      envoy_config_endpoint_v3_ClusterLoadAssignment_set_cluster_name(
+          cluster_load_assignment, name_upb);
+      size_t length;
+      char* bytes = envoy_config_endpoint_v3_ClusterLoadAssignment_serialize(
+          cluster_load_assignment, context.arena, &length);
+      google_protobuf_Any_set_type_url(endpoint_any, kEdsTypeUrlUpb);
+      google_protobuf_Any_set_value(endpoint_any,
+                                    upb_strview_make(bytes, length));
+    }
+    if (meta->client_status == XdsApi::ResourceMetadata::NACKED) {
+      // Set error_state if NACKED
+      envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig_set_error_state(
+          dynamic_endpoint, CreateUpdateFailureStateUpb(context, meta));
+    }
+  }
+}
+
+}  // namespace
+
+std::string XdsApi::AssembleClientConfig(
+    const ResourceTypeMetadataMap& resource_type_metadata_map) {
+  upb::Arena arena;
+  // Create the ClientConfig for resource metadata from XdsClient
+  auto* client_config = envoy_service_status_v3_ClientConfig_new(arena.ptr());
+  // Fill-in the node information
+  auto* node = envoy_service_status_v3_ClientConfig_mutable_node(client_config,
+                                                                 arena.ptr());
+  const EncodingContext context = {client_, tracer_, symtab_.ptr(), arena.ptr(),
+                                   true};
+  PopulateNode(context, node_, build_version_, user_agent_name_, node);
+  // Dump each xDS-type config into PerXdsConfig
+  for (auto& p : resource_type_metadata_map) {
+    absl::string_view type_url = p.first;
+    const ResourceTypeMetadata& resource_type_metadata = p.second;
+    if (type_url == kLdsTypeUrl) {
+      auto* per_xds_config =
+          envoy_service_status_v3_ClientConfig_add_xds_config(client_config,
+                                                              context.arena);
+      DumpLdsConfig(context, resource_type_metadata, per_xds_config);
+    } else if (type_url == kRdsTypeUrl) {
+      auto* per_xds_config =
+          envoy_service_status_v3_ClientConfig_add_xds_config(client_config,
+                                                              context.arena);
+      DumpRdsConfig(context, resource_type_metadata, per_xds_config);
+    } else if (type_url == kCdsTypeUrl) {
+      auto* per_xds_config =
+          envoy_service_status_v3_ClientConfig_add_xds_config(client_config,
+                                                              context.arena);
+      DumpCdsConfig(context, resource_type_metadata, per_xds_config);
+    } else if (type_url == kEdsTypeUrl) {
+      auto* per_xds_config =
+          envoy_service_status_v3_ClientConfig_add_xds_config(client_config,
+                                                              context.arena);
+      DumpEdsConfig(context, resource_type_metadata, per_xds_config);
+    } else {
+      gpr_log(GPR_ERROR, "invalid type_url %s", std::string(type_url).c_str());
+      return "";
+    }
+  }
+  // Serialize the upb message to bytes
+  size_t output_length;
+  char* output = envoy_service_status_v3_ClientConfig_serialize(
+      client_config, arena.ptr(), &output_length);
+  return std::string(output, output_length);
+}
+
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/xds/xds_api.h b/grpc/src/core/ext/xds/xds_api.h
index f2a6707..e7bf1cd 100644
--- a/grpc/src/core/ext/xds/xds_api.h
+++ b/grpc/src/core/ext/xds/xds_api.h
@@ -33,9 +33,12 @@
 
 #include <grpc/slice_buffer.h>
 
+#include "envoy/admin/v3/config_dump.upb.h"
 #include "src/core/ext/filters/client_channel/server_address.h"
 #include "src/core/ext/xds/xds_bootstrap.h"
 #include "src/core/ext/xds/xds_client_stats.h"
+#include "src/core/ext/xds/xds_http_filters.h"
+#include "src/core/lib/matchers/matchers.h"
 
 namespace grpc_core {
 
@@ -57,76 +60,58 @@
     int64_t seconds = 0;
     int32_t nanos = 0;
     bool operator==(const Duration& other) const {
-      return (seconds == other.seconds && nanos == other.nanos);
+      return seconds == other.seconds && nanos == other.nanos;
     }
     std::string ToString() const {
       return absl::StrFormat("Duration seconds: %ld, nanos %d", seconds, nanos);
     }
   };
 
+  using TypedPerFilterConfig =
+      std::map<std::string, XdsHttpFilterImpl::FilterConfig>;
+
   // TODO(donnadionne): When we can use absl::variant<>, consider using that
   // for: PathMatcher, HeaderMatcher, cluster_name and weighted_clusters
   struct Route {
     // Matchers for this route.
     struct Matchers {
-      struct PathMatcher {
-        enum class PathMatcherType {
-          PATH,    // path stored in string_matcher field
-          PREFIX,  // prefix stored in string_matcher field
-          REGEX,   // regex stored in regex_matcher field
-        };
-        PathMatcherType type;
-        std::string string_matcher;
-        std::unique_ptr<RE2> regex_matcher;
-        bool case_sensitive = true;
-
-        PathMatcher() = default;
-        PathMatcher(const PathMatcher& other);
-        PathMatcher& operator=(const PathMatcher& other);
-        bool operator==(const PathMatcher& other) const;
-        std::string ToString() const;
-      };
-
-      struct HeaderMatcher {
-        enum class HeaderMatcherType {
-          EXACT,    // value stored in string_matcher field
-          REGEX,    // uses regex_match field
-          RANGE,    // uses range_start and range_end fields
-          PRESENT,  // uses present_match field
-          PREFIX,   // prefix stored in string_matcher field
-          SUFFIX,   // suffix stored in string_matcher field
-        };
-        std::string name;
-        HeaderMatcherType type;
-        int64_t range_start;
-        int64_t range_end;
-        std::string string_matcher;
-        std::unique_ptr<RE2> regex_match;
-        bool present_match;
-        // invert_match field may or may not exisit, so initialize it to
-        // false.
-        bool invert_match = false;
-
-        HeaderMatcher() = default;
-        HeaderMatcher(const HeaderMatcher& other);
-        HeaderMatcher& operator=(const HeaderMatcher& other);
-        bool operator==(const HeaderMatcher& other) const;
-        std::string ToString() const;
-      };
-
-      PathMatcher path_matcher;
+      StringMatcher path_matcher;
       std::vector<HeaderMatcher> header_matchers;
       absl::optional<uint32_t> fraction_per_million;
 
       bool operator==(const Matchers& other) const {
-        return (path_matcher == other.path_matcher &&
-                header_matchers == other.header_matchers &&
-                fraction_per_million == other.fraction_per_million);
+        return path_matcher == other.path_matcher &&
+               header_matchers == other.header_matchers &&
+               fraction_per_million == other.fraction_per_million;
       }
       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
@@ -135,8 +120,11 @@
     struct ClusterWeight {
       std::string name;
       uint32_t weight;
+      TypedPerFilterConfig typed_per_filter_config;
+
       bool operator==(const ClusterWeight& other) const {
-        return (name == other.name && weight == other.weight);
+        return name == other.name && weight == other.weight &&
+               typed_per_filter_config == other.typed_per_filter_config;
       }
       std::string ToString() const;
     };
@@ -147,11 +135,13 @@
     // not set.
     absl::optional<Duration> max_stream_duration;
 
+    TypedPerFilterConfig typed_per_filter_config;
+
     bool operator==(const Route& other) const {
-      return (matchers == other.matchers &&
-              cluster_name == other.cluster_name &&
-              weighted_clusters == other.weighted_clusters &&
-              max_stream_duration == other.max_stream_duration);
+      return matchers == other.matchers && cluster_name == other.cluster_name &&
+             weighted_clusters == other.weighted_clusters &&
+             max_stream_duration == other.max_stream_duration &&
+             typed_per_filter_config == other.typed_per_filter_config;
     }
     std::string ToString() const;
   };
@@ -160,9 +150,11 @@
     struct VirtualHost {
       std::vector<std::string> domains;
       std::vector<Route> routes;
+      TypedPerFilterConfig typed_per_filter_config;
 
       bool operator==(const VirtualHost& other) const {
-        return domains == other.domains && routes == other.routes;
+        return domains == other.domains && routes == other.routes &&
+               typed_per_filter_config == other.typed_per_filter_config;
       }
     };
 
@@ -175,42 +167,6 @@
     VirtualHost* FindVirtualHostForDomain(const std::string& domain);
   };
 
-  class StringMatcher {
-   public:
-    enum class StringMatcherType {
-      EXACT,       // value stored in string_matcher_ field
-      PREFIX,      // value stored in string_matcher_ field
-      SUFFIX,      // value stored in string_matcher_ field
-      SAFE_REGEX,  // pattern stored in regex_matcher_ field
-      CONTAINS,    // value stored in string_matcher_ field
-    };
-
-    StringMatcher() = default;
-    StringMatcher(const StringMatcher& other);
-    StringMatcher(StringMatcherType type, const std::string& matcher,
-                  bool ignore_case = false);
-    StringMatcher& operator=(const StringMatcher& other);
-    bool operator==(const StringMatcher& other) const;
-
-    bool Match(absl::string_view value) const;
-
-    std::string ToString() const;
-
-    StringMatcherType type() const { return type_; }
-
-    // Valid for EXACT, PREFIX, SUFFIX and CONTAINS
-    const std::string& string_matcher() const { return string_matcher_; }
-
-    // Valid for SAFE_REGEX
-    RE2* regex_matcher() const { return regex_matcher_.get(); }
-
-   private:
-    StringMatcherType type_ = StringMatcherType::EXACT;
-    std::string string_matcher_;
-    std::unique_ptr<RE2> regex_matcher_;
-    bool ignore_case_ = false;
-  };
-
   struct CommonTlsContext {
     struct CertificateValidationContext {
       std::vector<StringMatcher> match_subject_alt_names;
@@ -264,30 +220,182 @@
     bool Empty() const;
   };
 
+  struct DownstreamTlsContext {
+    CommonTlsContext common_tls_context;
+    bool require_client_certificate = false;
+
+    bool operator==(const DownstreamTlsContext& other) const {
+      return common_tls_context == other.common_tls_context &&
+             require_client_certificate == other.require_client_certificate;
+    }
+
+    std::string ToString() const;
+    bool Empty() const;
+  };
+
   // TODO(roth): When we can use absl::variant<>, consider using that
   // here, to enforce the fact that only one of the two fields can be set.
   struct LdsUpdate {
-    // The name to use in the RDS request.
-    std::string route_config_name;
-    // Storing the Http Connection Manager Common Http Protocol Option
-    // max_stream_duration
-    Duration http_max_stream_duration;
-    // The RouteConfiguration to use for this listener.
-    // Present only if it is inlined in the LDS response.
-    absl::optional<RdsUpdate> rds_update;
+    enum class ListenerType {
+      kTcpListener = 0,
+      kHttpApiListener,
+    } type;
+
+    struct HttpConnectionManager {
+      // The name to use in the RDS request.
+      std::string route_config_name;
+      // Storing the Http Connection Manager Common Http Protocol Option
+      // max_stream_duration
+      Duration http_max_stream_duration;
+      // The RouteConfiguration to use for this listener.
+      // Present only if it is inlined in the LDS response.
+      absl::optional<RdsUpdate> rds_update;
+
+      struct HttpFilter {
+        std::string name;
+        XdsHttpFilterImpl::FilterConfig config;
+
+        bool operator==(const HttpFilter& other) const {
+          return name == other.name && config == other.config;
+        }
+
+        std::string ToString() const;
+      };
+      std::vector<HttpFilter> http_filters;
+
+      bool operator==(const HttpConnectionManager& other) const {
+        return route_config_name == other.route_config_name &&
+               http_max_stream_duration == other.http_max_stream_duration &&
+               rds_update == other.rds_update &&
+               http_filters == other.http_filters;
+      }
+
+      std::string ToString() const;
+    };
+
+    // Populated for type=kHttpApiListener.
+    HttpConnectionManager http_connection_manager;
+
+    // Populated for type=kTcpListener.
+    // host:port listening_address set when type is kTcpListener
+    std::string address;
+
+    struct FilterChainData {
+      DownstreamTlsContext downstream_tls_context;
+      // This is in principle the filter list.
+      // We currently require exactly one filter, which is the HCM.
+      HttpConnectionManager http_connection_manager;
+
+      bool operator==(const FilterChainData& other) const {
+        return downstream_tls_context == other.downstream_tls_context &&
+               http_connection_manager == other.http_connection_manager;
+      }
+
+      std::string ToString() const;
+    } filter_chain_data;
+
+    // A multi-level map used to determine which filter chain to use for a given
+    // incoming connection. Determining the right filter chain for a given
+    // connection checks the following properties, in order:
+    // - destination port (never matched, so not present in map)
+    // - destination IP address
+    // - server name (never matched, so not present in map)
+    // - transport protocol (allows only "raw_buffer" or unset, prefers the
+    //   former, so only one of those two types is present in map)
+    // - application protocol (never matched, so not present in map)
+    // - connection source type (any, local or external)
+    // - source IP address
+    // - source port
+    // https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/listener/v3/listener_components.proto#config-listener-v3-filterchainmatch
+    // for more details
+    struct FilterChainMap {
+      struct FilterChainDataSharedPtr {
+        std::shared_ptr<FilterChainData> data;
+        bool operator==(const FilterChainDataSharedPtr& other) const {
+          return *data == *other.data;
+        }
+      };
+      struct CidrRange {
+        grpc_resolved_address address;
+        uint32_t prefix_len;
+
+        bool operator==(const CidrRange& other) const {
+          return memcmp(&address, &other.address, sizeof(address)) == 0 &&
+                 prefix_len == other.prefix_len;
+        }
+
+        std::string ToString() const;
+      };
+      using SourcePortsMap = std::map<uint16_t, FilterChainDataSharedPtr>;
+      struct SourceIp {
+        absl::optional<CidrRange> prefix_range;
+        SourcePortsMap ports_map;
+
+        bool operator==(const SourceIp& other) const {
+          return prefix_range == other.prefix_range &&
+                 ports_map == other.ports_map;
+        }
+      };
+      using SourceIpVector = std::vector<SourceIp>;
+      enum class ConnectionSourceType {
+        kAny = 0,
+        kSameIpOrLoopback,
+        kExternal
+      };
+      using ConnectionSourceTypesArray = std::array<SourceIpVector, 3>;
+      struct DestinationIp {
+        absl::optional<CidrRange> prefix_range;
+        // We always fail match on server name, so those filter chains are not
+        // included here.
+        ConnectionSourceTypesArray source_types_array;
+
+        bool operator==(const DestinationIp& other) const {
+          return prefix_range == other.prefix_range &&
+                 source_types_array == other.source_types_array;
+        }
+      };
+      // We always fail match on destination ports map
+      using DestinationIpVector = std::vector<DestinationIp>;
+      DestinationIpVector destination_ip_vector;
+
+      bool operator==(const FilterChainMap& other) const {
+        return destination_ip_vector == other.destination_ip_vector;
+      }
+
+      std::string ToString() const;
+    } filter_chain_map;
+
+    absl::optional<FilterChainData> default_filter_chain;
 
     bool operator==(const LdsUpdate& other) const {
-      return route_config_name == other.route_config_name &&
-             rds_update == other.rds_update &&
-             http_max_stream_duration == other.http_max_stream_duration;
+      return http_connection_manager == other.http_connection_manager &&
+             address == other.address &&
+             filter_chain_map == other.filter_chain_map &&
+             default_filter_chain == other.default_filter_chain;
     }
+
+    std::string ToString() const;
   };
 
-  using LdsUpdateMap = std::map<std::string /*server_name*/, LdsUpdate>;
+  struct LdsResourceData {
+    LdsUpdate resource;
+    std::string serialized_proto;
+  };
 
-  using RdsUpdateMap = std::map<std::string /*route_config_name*/, RdsUpdate>;
+  using LdsUpdateMap = std::map<std::string /*server_name*/, LdsResourceData>;
+
+  struct RdsResourceData {
+    RdsUpdate resource;
+    std::string serialized_proto;
+  };
+
+  using RdsUpdateMap =
+      std::map<std::string /*route_config_name*/, RdsResourceData>;
 
   struct CdsUpdate {
+    enum ClusterType { EDS, LOGICAL_DNS, AGGREGATE };
+    ClusterType cluster_type;
+    // For cluster type EDS.
     // The name to use in the EDS request.
     // If empty, the cluster name will be used.
     std::string eds_service_name;
@@ -298,22 +406,39 @@
     // If set to the empty string, will use the same server we obtained the CDS
     // data from.
     absl::optional<std::string> lrs_load_reporting_server_name;
+    // The LB policy to use (e.g., "ROUND_ROBIN" or "RING_HASH").
+    std::string lb_policy;
+    // Used for RING_HASH LB policy only.
+    uint64_t min_ring_size = 1024;
+    uint64_t max_ring_size = 8388608;
+    enum HashFunction { XX_HASH, MURMUR_HASH_2 };
+    HashFunction hash_function;
     // Maximum number of outstanding requests can be made to the upstream
     // cluster.
     uint32_t max_concurrent_requests = 1024;
+    // For cluster type AGGREGATE.
+    // The prioritized list of cluster names.
+    std::vector<std::string> prioritized_cluster_names;
 
     bool operator==(const CdsUpdate& other) const {
-      return eds_service_name == other.eds_service_name &&
+      return cluster_type == other.cluster_type &&
+             eds_service_name == other.eds_service_name &&
              common_tls_context == other.common_tls_context &&
              lrs_load_reporting_server_name ==
                  other.lrs_load_reporting_server_name &&
+             prioritized_cluster_names == other.prioritized_cluster_names &&
              max_concurrent_requests == other.max_concurrent_requests;
     }
 
     std::string ToString() const;
   };
 
-  using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsUpdate>;
+  struct CdsResourceData {
+    CdsUpdate resource;
+    std::string serialized_proto;
+  };
+
+  using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsResourceData>;
 
   struct EdsUpdate {
     struct Priority {
@@ -397,7 +522,13 @@
     std::string ToString() const;
   };
 
-  using EdsUpdateMap = std::map<std::string /*eds_service_name*/, EdsUpdate>;
+  struct EdsResourceData {
+    EdsUpdate resource;
+    std::string serialized_proto;
+  };
+
+  using EdsUpdateMap =
+      std::map<std::string /*eds_service_name*/, EdsResourceData>;
 
   struct ClusterLoadReport {
     XdsClusterDropStats::Snapshot dropped_requests;
@@ -410,6 +541,85 @@
       std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>,
       ClusterLoadReport>;
 
+  // The metadata of the xDS resource; used by the xDS config dump.
+  struct ResourceMetadata {
+    // Resource status from the view of a xDS client, which tells the
+    // synchronization status between the xDS client and the xDS server.
+    enum ClientResourceStatus {
+      // Client requested this resource but hasn't received any update from
+      // management server. The client will not fail requests, but will queue
+      // them
+      // until update arrives or the client times out waiting for the resource.
+      REQUESTED = 1,
+      // This resource has been requested by the client but has either not been
+      // delivered by the server or was previously delivered by the server and
+      // then subsequently removed from resources provided by the server.
+      DOES_NOT_EXIST,
+      // Client received this resource and replied with ACK.
+      ACKED,
+      // Client received this resource and replied with NACK.
+      NACKED
+    };
+
+    // The client status of this resource.
+    ClientResourceStatus client_status = REQUESTED;
+    // The serialized bytes of the last successfully updated raw xDS resource.
+    std::string serialized_proto;
+    // The timestamp when the resource was last successfully updated.
+    grpc_millis update_time = 0;
+    // The last successfully updated version of the resource.
+    std::string version;
+    // The rejected version string of the last failed update attempt.
+    std::string failed_version;
+    // Details about the last failed update attempt.
+    std::string failed_details;
+    // Timestamp of the last failed update attempt.
+    grpc_millis failed_update_time = 0;
+  };
+  using ResourceMetadataMap =
+      std::map<absl::string_view /*resource_name*/, const ResourceMetadata*>;
+  struct ResourceTypeMetadata {
+    absl::string_view version;
+    ResourceMetadataMap resource_metadata_map;
+  };
+  using ResourceTypeMetadataMap =
+      std::map<absl::string_view /*type_url*/, ResourceTypeMetadata>;
+  static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
+                    envoy_admin_v3_REQUESTED) ==
+                    ResourceMetadata::ClientResourceStatus::REQUESTED,
+                "");
+  static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
+                    envoy_admin_v3_DOES_NOT_EXIST) ==
+                    ResourceMetadata::ClientResourceStatus::DOES_NOT_EXIST,
+                "");
+  static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
+                    envoy_admin_v3_ACKED) ==
+                    ResourceMetadata::ClientResourceStatus::ACKED,
+                "");
+  static_assert(static_cast<ResourceMetadata::ClientResourceStatus>(
+                    envoy_admin_v3_NACKED) ==
+                    ResourceMetadata::ClientResourceStatus::NACKED,
+                "");
+
+  // If the response can't be parsed at the top level, the resulting
+  // type_url will be empty.
+  // If there is any other type of validation error, the parse_error
+  // field will be set to something other than GRPC_ERROR_NONE and the
+  // resource_names_failed field will be populated.
+  // Otherwise, one of the *_update_map fields will be populated, based
+  // on the type_url field.
+  struct AdsParseResult {
+    grpc_error_handle parse_error = GRPC_ERROR_NONE;
+    std::string version;
+    std::string nonce;
+    std::string type_url;
+    LdsUpdateMap lds_update_map;
+    RdsUpdateMap rds_update_map;
+    CdsUpdateMap cds_update_map;
+    EdsUpdateMap eds_update_map;
+    std::set<std::string> resource_names_failed;
+  };
+
   XdsApi(XdsClient* client, TraceFlag* tracer, const XdsBootstrap::Node* node);
 
   // Creates an ADS request.
@@ -418,24 +628,12 @@
                               const std::string& type_url,
                               const std::set<absl::string_view>& resource_names,
                               const std::string& version,
-                              const std::string& nonce, grpc_error* error,
+                              const std::string& nonce, grpc_error_handle error,
                               bool populate_node);
 
   // Parses an ADS response.
-  // If the response can't be parsed at the top level, the resulting
-  // type_url will be empty.
-  struct AdsParseResult {
-    grpc_error* parse_error = GRPC_ERROR_NONE;
-    std::string version;
-    std::string nonce;
-    std::string type_url;
-    LdsUpdateMap lds_update_map;
-    RdsUpdateMap rds_update_map;
-    CdsUpdateMap cds_update_map;
-    EdsUpdateMap eds_update_map;
-  };
   AdsParseResult ParseAdsResponse(
-      const grpc_slice& encoded_response,
+      const XdsBootstrap::XdsServer& server, const grpc_slice& encoded_response,
       const std::set<absl::string_view>& expected_listener_names,
       const std::set<absl::string_view>& expected_route_configuration_names,
       const std::set<absl::string_view>& expected_cluster_names,
@@ -450,10 +648,14 @@
   // Parses the LRS response and returns \a
   // load_reporting_interval for client-side load reporting. If there is any
   // error, the output config is invalid.
-  grpc_error* ParseLrsResponse(const grpc_slice& encoded_response,
-                               bool* send_all_clusters,
-                               std::set<std::string>* cluster_names,
-                               grpc_millis* load_reporting_interval);
+  grpc_error_handle ParseLrsResponse(const grpc_slice& encoded_response,
+                                     bool* send_all_clusters,
+                                     std::set<std::string>* cluster_names,
+                                     grpc_millis* load_reporting_interval);
+
+  // Assemble the client config proto message and return the serialized result.
+  std::string AssembleClientConfig(
+      const ResourceTypeMetadataMap& resource_type_metadata_map);
 
  private:
   XdsClient* client_;
diff --git a/grpc/src/core/ext/xds/xds_bootstrap.cc b/grpc/src/core/ext/xds/xds_bootstrap.cc
index e48d982..33cf276 100644
--- a/grpc/src/core/ext/xds/xds_bootstrap.cc
+++ b/grpc/src/core/ext/xds/xds_bootstrap.cc
@@ -30,7 +30,6 @@
 
 #include "src/core/ext/xds/certificate_provider_registry.h"
 #include "src/core/ext/xds/xds_api.h"
-#include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "src/core/lib/security/credentials/credentials.h"
@@ -48,8 +47,8 @@
          creds_type == "fake";
 }
 
-bool XdsChannelCredsRegistry::IsValidConfig(const std::string& creds_type,
-                                            const Json& config) {
+bool XdsChannelCredsRegistry::IsValidConfig(const std::string& /*creds_type*/,
+                                            const Json& /*config*/) {
   // Currently, none of the creds types actually take a config, but we
   // ignore whatever might be specified in the bootstrap file for
   // forward compatibility reasons.
@@ -58,7 +57,7 @@
 
 RefCountedPtr<grpc_channel_credentials>
 XdsChannelCredsRegistry::MakeChannelCreds(const std::string& creds_type,
-                                          const Json& config) {
+                                          const Json& /*config*/) {
   if (creds_type == "google_default") {
     return grpc_google_default_credentials_create(nullptr);
   } else if (creds_type == "insecure") {
@@ -81,109 +80,27 @@
 // XdsBootstrap
 //
 
-namespace {
-
-std::string BootstrapString(const XdsBootstrap& bootstrap) {
-  std::vector<std::string> parts;
-  if (bootstrap.node() != nullptr) {
-    parts.push_back(absl::StrFormat(
-        "node={\n"
-        "  id=\"%s\",\n"
-        "  cluster=\"%s\",\n"
-        "  locality={\n"
-        "    region=\"%s\",\n"
-        "    zone=\"%s\",\n"
-        "    subzone=\"%s\"\n"
-        "  },\n"
-        "  metadata=%s,\n"
-        "},\n",
-        bootstrap.node()->id, bootstrap.node()->cluster,
-        bootstrap.node()->locality_region, bootstrap.node()->locality_zone,
-        bootstrap.node()->locality_subzone, bootstrap.node()->metadata.Dump()));
-  }
-  parts.push_back(absl::StrFormat(
-      "servers=[\n"
-      "  {\n"
-      "    uri=\"%s\",\n"
-      "    creds_type=%s,\n",
-      bootstrap.server().server_uri, bootstrap.server().channel_creds_type));
-  if (bootstrap.server().channel_creds_config.type() != Json::Type::JSON_NULL) {
-    parts.push_back(
-        absl::StrFormat("    creds_config=%s,",
-                        bootstrap.server().channel_creds_config.Dump()));
-  }
-  if (!bootstrap.server().server_features.empty()) {
-    parts.push_back(absl::StrCat(
-        "    server_features=[",
-        absl::StrJoin(bootstrap.server().server_features, ", "), "],\n"));
-  }
-  parts.push_back("  }\n],\n");
-  parts.push_back("certificate_providers={\n");
-  for (const auto& entry : bootstrap.certificate_providers()) {
-    parts.push_back(
-        absl::StrFormat("  %s={\n"
-                        "    plugin_name=%s\n"
-                        "    config=%s\n"
-                        "  },\n",
-                        entry.first, entry.second.plugin_name,
-                        entry.second.config->ToString()));
-  }
-  parts.push_back("}");
-  return absl::StrJoin(parts, "");
-}
-
-}  // namespace
-
-std::unique_ptr<XdsBootstrap> XdsBootstrap::ReadFromFile(XdsClient* client,
-                                                         TraceFlag* tracer,
-                                                         grpc_error** error) {
-  grpc_core::UniquePtr<char> path(gpr_getenv("GRPC_XDS_BOOTSTRAP"));
-  if (path == nullptr) {
-    *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "Environment variable GRPC_XDS_BOOTSTRAP not defined");
-    return nullptr;
-  }
-  if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
-    gpr_log(GPR_INFO,
-            "[xds_client %p] Got bootstrap file location from "
-            "GRPC_XDS_BOOTSTRAP environment variable: %s",
-            client, path.get());
-  }
-  grpc_slice contents;
-  *error = grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents);
-  if (*error != GRPC_ERROR_NONE) return nullptr;
-  absl::string_view contents_str_view = StringViewFromSlice(contents);
-  if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
-    gpr_log(GPR_DEBUG, "[xds_client %p] Bootstrap file contents: %s", client,
-            std::string(contents_str_view).c_str());
-  }
-  Json json = Json::Parse(contents_str_view, error);
-  grpc_slice_unref_internal(contents);
+std::unique_ptr<XdsBootstrap> XdsBootstrap::Create(
+    absl::string_view json_string, grpc_error_handle* error) {
+  Json json = Json::Parse(json_string, error);
   if (*error != GRPC_ERROR_NONE) {
-    grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(
-        absl::StrCat("Failed to parse bootstrap file ", path.get()).c_str(),
-        error, 1);
+    grpc_error_handle error_out =
+        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+            "Failed to parse bootstrap JSON string", error, 1);
     GRPC_ERROR_UNREF(*error);
     *error = error_out;
     return nullptr;
   }
-  std::unique_ptr<XdsBootstrap> result =
-      absl::make_unique<XdsBootstrap>(std::move(json), error);
-  if (*error == GRPC_ERROR_NONE && GRPC_TRACE_FLAG_ENABLED(*tracer)) {
-    gpr_log(GPR_INFO,
-            "[xds_client %p] Bootstrap config for creating xds client:\n%s",
-            client, BootstrapString(*result).c_str());
-  }
-  return result;
+  return absl::make_unique<XdsBootstrap>(std::move(json), error);
 }
 
-XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {
+XdsBootstrap::XdsBootstrap(Json json, grpc_error_handle* error) {
   if (json.type() != Json::Type::OBJECT) {
     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "malformed JSON in bootstrap file");
     return;
   }
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   auto it = json.mutable_object()->find("xds_servers");
   if (it == json.mutable_object()->end()) {
     error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -192,7 +109,7 @@
     error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "\"xds_servers\" field is not an array"));
   } else {
-    grpc_error* parse_error = ParseXdsServerList(&it->second);
+    grpc_error_handle parse_error = ParseXdsServerList(&it->second);
     if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
   }
   it = json.mutable_object()->find("node");
@@ -201,10 +118,20 @@
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "\"node\" field is not an object"));
     } else {
-      grpc_error* parse_error = ParseNode(&it->second);
+      grpc_error_handle parse_error = ParseNode(&it->second);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
+  it = json.mutable_object()->find("server_listener_resource_name_template");
+  if (it != json.mutable_object()->end()) {
+    if (it->second.type() != Json::Type::STRING) {
+      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "\"server_listener_resource_name_template\" field is not a string"));
+    } else {
+      server_listener_resource_name_template_ =
+          std::move(*it->second.mutable_string_value());
+    }
+  }
   if (XdsSecurityEnabled()) {
     it = json.mutable_object()->find("certificate_providers");
     if (it != json.mutable_object()->end()) {
@@ -212,7 +139,7 @@
         error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
             "\"certificate_providers\" field is not an object"));
       } else {
-        grpc_error* parse_error = ParseCertificateProviders(&it->second);
+        grpc_error_handle parse_error = ParseCertificateProviders(&it->second);
         if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
       }
     }
@@ -221,15 +148,15 @@
                                          &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseXdsServerList(Json* json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseXdsServerList(Json* json) {
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < json->mutable_array()->size(); ++i) {
     Json& child = json->mutable_array()->at(i);
     if (child.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("array element ", i, " is not an object").c_str()));
     } else {
-      grpc_error* parse_error = ParseXdsServer(&child, i);
+      grpc_error_handle parse_error = ParseXdsServer(&child, i);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
@@ -237,8 +164,8 @@
                                        &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseXdsServer(Json* json, size_t idx) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseXdsServer(Json* json, size_t idx) {
+  std::vector<grpc_error_handle> error_list;
   servers_.emplace_back();
   XdsServer& server = servers_[servers_.size() - 1];
   auto it = json->mutable_object()->find("server_uri");
@@ -259,7 +186,8 @@
     error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "\"channel_creds\" field is not an array"));
   } else {
-    grpc_error* parse_error = ParseChannelCredsArray(&it->second, &server);
+    grpc_error_handle parse_error =
+        ParseChannelCredsArray(&it->second, &server);
     if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
   }
   it = json->mutable_object()->find("server_features");
@@ -268,14 +196,15 @@
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "\"server_features\" field is not an array"));
     } else {
-      grpc_error* parse_error = ParseServerFeaturesArray(&it->second, &server);
+      grpc_error_handle parse_error =
+          ParseServerFeaturesArray(&it->second, &server);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
   // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
   // string is not static in this case.
   if (error_list.empty()) return GRPC_ERROR_NONE;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrCat("errors parsing index ", idx).c_str());
   for (size_t i = 0; i < error_list.size(); ++i) {
     error = grpc_error_add_child(error, error_list[i]);
@@ -283,16 +212,16 @@
   return error;
 }
 
-grpc_error* XdsBootstrap::ParseChannelCredsArray(Json* json,
-                                                 XdsServer* server) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseChannelCredsArray(Json* json,
+                                                       XdsServer* server) {
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < json->mutable_array()->size(); ++i) {
     Json& child = json->mutable_array()->at(i);
     if (child.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("array element ", i, " is not an object").c_str()));
     } else {
-      grpc_error* parse_error = ParseChannelCreds(&child, i, server);
+      grpc_error_handle parse_error = ParseChannelCreds(&child, i, server);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
@@ -304,9 +233,9 @@
                                        &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseChannelCreds(Json* json, size_t idx,
-                                            XdsServer* server) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseChannelCreds(Json* json, size_t idx,
+                                                  XdsServer* server) {
+  std::vector<grpc_error_handle> error_list;
   std::string type;
   auto it = json->mutable_object()->find("type");
   if (it == json->mutable_object()->end()) {
@@ -342,7 +271,7 @@
   // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
   // string is not static in this case.
   if (error_list.empty()) return GRPC_ERROR_NONE;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrCat("errors parsing index ", idx).c_str());
   for (size_t i = 0; i < error_list.size(); ++i) {
     error = grpc_error_add_child(error, error_list[i]);
@@ -350,30 +279,22 @@
   return error;
 }
 
-grpc_error* XdsBootstrap::ParseServerFeaturesArray(Json* json,
-                                                   XdsServer* server) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseServerFeaturesArray(Json* json,
+                                                         XdsServer* server) {
+  std::vector<grpc_error_handle> error_list;
   for (size_t i = 0; i < json->mutable_array()->size(); ++i) {
     Json& child = json->mutable_array()->at(i);
     if (child.type() == Json::Type::STRING &&
         child.string_value() == "xds_v3") {
-      // TODO(roth): Remove env var check once we do interop testing and
-      // are sure that the v3 code actually works.
-      grpc_core::UniquePtr<char> enable_str(
-          gpr_getenv("GRPC_XDS_EXPERIMENTAL_V3_SUPPORT"));
-      bool enabled = false;
-      if (gpr_parse_bool_value(enable_str.get(), &enabled) && enabled) {
-        server->server_features.insert(
-            std::move(*child.mutable_string_value()));
-      }
+      server->server_features.insert(std::move(*child.mutable_string_value()));
     }
   }
   return GRPC_ERROR_CREATE_FROM_VECTOR(
       "errors parsing \"server_features\" array", &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseNode(Json* json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseNode(Json* json) {
+  std::vector<grpc_error_handle> error_list;
   node_ = absl::make_unique<Node>();
   auto it = json->mutable_object()->find("id");
   if (it != json->mutable_object()->end()) {
@@ -399,7 +320,7 @@
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "\"locality\" field is not an object"));
     } else {
-      grpc_error* parse_error = ParseLocality(&it->second);
+      grpc_error_handle parse_error = ParseLocality(&it->second);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
   }
@@ -416,8 +337,8 @@
                                        &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseLocality(Json* json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseLocality(Json* json) {
+  std::vector<grpc_error_handle> error_list;
   auto it = json->mutable_object()->find("region");
   if (it != json->mutable_object()->end()) {
     if (it->second.type() != Json::Type::STRING) {
@@ -436,21 +357,21 @@
       node_->locality_zone = std::move(*it->second.mutable_string_value());
     }
   }
-  it = json->mutable_object()->find("subzone");
+  it = json->mutable_object()->find("sub_zone");
   if (it != json->mutable_object()->end()) {
     if (it->second.type() != Json::Type::STRING) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-          "\"subzone\" field is not a string"));
+          "\"sub_zone\" field is not a string"));
     } else {
-      node_->locality_subzone = std::move(*it->second.mutable_string_value());
+      node_->locality_sub_zone = std::move(*it->second.mutable_string_value());
     }
   }
   return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"locality\" object",
                                        &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseCertificateProviders(Json* json) {
-  std::vector<grpc_error*> error_list;
+grpc_error_handle XdsBootstrap::ParseCertificateProviders(Json* json) {
+  std::vector<grpc_error_handle> error_list;
   for (auto& certificate_provider : *(json->mutable_object())) {
     if (certificate_provider.second.type() != Json::Type::OBJECT) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -458,7 +379,7 @@
                        "\" is not an object")
               .c_str()));
     } else {
-      grpc_error* parse_error = ParseCertificateProvider(
+      grpc_error_handle parse_error = ParseCertificateProvider(
           certificate_provider.first, &certificate_provider.second);
       if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
     }
@@ -467,9 +388,9 @@
       "errors parsing \"certificate_providers\" object", &error_list);
 }
 
-grpc_error* XdsBootstrap::ParseCertificateProvider(
+grpc_error_handle XdsBootstrap::ParseCertificateProvider(
     const std::string& instance_name, Json* certificate_provider_json) {
-  std::vector<grpc_error*> error_list;
+  std::vector<grpc_error_handle> error_list;
   auto it = certificate_provider_json->mutable_object()->find("plugin_name");
   if (it == certificate_provider_json->mutable_object()->end()) {
     error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -490,14 +411,14 @@
           error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "\"config\" field is not an object"));
         } else {
-          grpc_error* parse_error = GRPC_ERROR_NONE;
+          grpc_error_handle parse_error = GRPC_ERROR_NONE;
           config = factory->CreateCertificateProviderConfig(it->second,
                                                             &parse_error);
           if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
         }
       } else {
         // "config" is an optional field, so create an empty JSON object.
-        grpc_error* parse_error = GRPC_ERROR_NONE;
+        grpc_error_handle parse_error = GRPC_ERROR_NONE;
         config = factory->CreateCertificateProviderConfig(Json::Object(),
                                                           &parse_error);
         if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
@@ -509,7 +430,7 @@
   // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
   // string is not static in this case.
   if (error_list.empty()) return GRPC_ERROR_NONE;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
       absl::StrCat("errors parsing element \"", instance_name, "\"").c_str());
   for (size_t i = 0; i < error_list.size(); ++i) {
     error = grpc_error_add_child(error, error_list[i]);
@@ -517,4 +438,56 @@
   return error;
 }
 
+std::string XdsBootstrap::ToString() const {
+  std::vector<std::string> parts;
+  if (node_ != nullptr) {
+    parts.push_back(absl::StrFormat(
+        "node={\n"
+        "  id=\"%s\",\n"
+        "  cluster=\"%s\",\n"
+        "  locality={\n"
+        "    region=\"%s\",\n"
+        "    zone=\"%s\",\n"
+        "    sub_zone=\"%s\"\n"
+        "  },\n"
+        "  metadata=%s,\n"
+        "},\n",
+        node_->id, node_->cluster, node_->locality_region, node_->locality_zone,
+        node_->locality_sub_zone, node_->metadata.Dump()));
+  }
+  parts.push_back(
+      absl::StrFormat("servers=[\n"
+                      "  {\n"
+                      "    uri=\"%s\",\n"
+                      "    creds_type=%s,\n",
+                      server().server_uri, server().channel_creds_type));
+  if (server().channel_creds_config.type() != Json::Type::JSON_NULL) {
+    parts.push_back(absl::StrFormat("    creds_config=%s,",
+                                    server().channel_creds_config.Dump()));
+  }
+  if (!server().server_features.empty()) {
+    parts.push_back(absl::StrCat("    server_features=[",
+                                 absl::StrJoin(server().server_features, ", "),
+                                 "],\n"));
+  }
+  parts.push_back("  }\n],\n");
+  if (!server_listener_resource_name_template_.empty()) {
+    parts.push_back(
+        absl::StrFormat("server_listener_resource_name_template=\"%s\",\n",
+                        server_listener_resource_name_template_));
+  }
+  parts.push_back("certificate_providers={\n");
+  for (const auto& entry : certificate_providers_) {
+    parts.push_back(
+        absl::StrFormat("  %s={\n"
+                        "    plugin_name=%s\n"
+                        "    config=%s\n"
+                        "  },\n",
+                        entry.first, entry.second.plugin_name,
+                        entry.second.config->ToString()));
+  }
+  parts.push_back("}");
+  return absl::StrJoin(parts, "");
+}
+
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/xds/xds_bootstrap.h b/grpc/src/core/ext/xds/xds_bootstrap.h
index 969d5d5..eff5e7a 100644
--- a/grpc/src/core/ext/xds/xds_bootstrap.h
+++ b/grpc/src/core/ext/xds/xds_bootstrap.h
@@ -54,7 +54,7 @@
     std::string cluster;
     std::string locality_region;
     std::string locality_zone;
-    std::string locality_subzone;
+    std::string locality_sub_zone;
     Json metadata;
   };
 
@@ -67,19 +67,24 @@
     bool ShouldUseV3() const;
   };
 
+  // Creates bootstrap object from json_string.
   // If *error is not GRPC_ERROR_NONE after returning, then there was an
-  // error reading the file.
-  static std::unique_ptr<XdsBootstrap> ReadFromFile(XdsClient* client,
-                                                    TraceFlag* tracer,
-                                                    grpc_error** error);
+  // error parsing the contents.
+  static std::unique_ptr<XdsBootstrap> Create(absl::string_view json_string,
+                                              grpc_error_handle* error);
 
-  // Do not instantiate directly -- use ReadFromFile() above instead.
-  XdsBootstrap(Json json, grpc_error** error);
+  // Do not instantiate directly -- use Create() above instead.
+  XdsBootstrap(Json json, grpc_error_handle* error);
+
+  std::string ToString() const;
 
   // TODO(roth): We currently support only one server. Fix this when we
   // add support for fallback for the xds channel.
   const XdsServer& server() const { return servers_[0]; }
   const Node* node() const { return node_.get(); }
+  const std::string& server_listener_resource_name_template() const {
+    return server_listener_resource_name_template_;
+  }
 
   const CertificateProviderStore::PluginDefinitionMap& certificate_providers()
       const {
@@ -87,19 +92,21 @@
   }
 
  private:
-  grpc_error* ParseXdsServerList(Json* json);
-  grpc_error* ParseXdsServer(Json* json, size_t idx);
-  grpc_error* ParseChannelCredsArray(Json* json, XdsServer* server);
-  grpc_error* ParseChannelCreds(Json* json, size_t idx, XdsServer* server);
-  grpc_error* ParseServerFeaturesArray(Json* json, XdsServer* server);
-  grpc_error* ParseNode(Json* json);
-  grpc_error* ParseLocality(Json* json);
-  grpc_error* ParseCertificateProviders(Json* json);
-  grpc_error* ParseCertificateProvider(const std::string& instance_name,
-                                       Json* certificate_provider_json);
+  grpc_error_handle ParseXdsServerList(Json* json);
+  grpc_error_handle ParseXdsServer(Json* json, size_t idx);
+  grpc_error_handle ParseChannelCredsArray(Json* json, XdsServer* server);
+  grpc_error_handle ParseChannelCreds(Json* json, size_t idx,
+                                      XdsServer* server);
+  grpc_error_handle ParseServerFeaturesArray(Json* json, XdsServer* server);
+  grpc_error_handle ParseNode(Json* json);
+  grpc_error_handle ParseLocality(Json* json);
+  grpc_error_handle ParseCertificateProviders(Json* json);
+  grpc_error_handle ParseCertificateProvider(const std::string& instance_name,
+                                             Json* certificate_provider_json);
 
   absl::InlinedVector<XdsServer, 1> servers_;
   std::unique_ptr<Node> node_;
+  std::string server_listener_resource_name_template_;
   CertificateProviderStore::PluginDefinitionMap certificate_providers_;
 };
 
diff --git a/grpc/src/core/ext/xds/xds_certificate_provider.cc b/grpc/src/core/ext/xds/xds_certificate_provider.cc
index f285b6d..ce1ba67 100644
--- a/grpc/src/core/ext/xds/xds_certificate_provider.cc
+++ b/grpc/src/core/ext/xds/xds_certificate_provider.cc
@@ -37,23 +37,24 @@
   // presently, the watcher is immediately deleted when
   // CancelTlsCertificatesWatch() is called, but that can potentially change in
   // the future.
-  explicit RootCertificatesWatcher(
-      RefCountedPtr<grpc_tls_certificate_distributor> parent)
-      : parent_(std::move(parent)) {}
+  RootCertificatesWatcher(
+      RefCountedPtr<grpc_tls_certificate_distributor> parent,
+      std::string cert_name)
+      : parent_(std::move(parent)), cert_name_(std::move(cert_name)) {}
 
   void OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
                              absl::optional<PemKeyCertPairList>
                              /* key_cert_pairs */) override {
     if (root_certs.has_value()) {
-      parent_->SetKeyMaterials("", std::string(root_certs.value()),
+      parent_->SetKeyMaterials(cert_name_, std::string(root_certs.value()),
                                absl::nullopt);
     }
   }
 
-  void OnError(grpc_error* root_cert_error,
-               grpc_error* identity_cert_error) override {
+  void OnError(grpc_error_handle root_cert_error,
+               grpc_error_handle identity_cert_error) override {
     if (root_cert_error != GRPC_ERROR_NONE) {
-      parent_->SetErrorForCert("", root_cert_error /* pass the ref */,
+      parent_->SetErrorForCert(cert_name_, root_cert_error /* pass the ref */,
                                absl::nullopt);
     }
     GRPC_ERROR_UNREF(identity_cert_error);
@@ -61,6 +62,7 @@
 
  private:
   RefCountedPtr<grpc_tls_certificate_distributor> parent_;
+  std::string cert_name_;
 };
 
 class IdentityCertificatesWatcher
@@ -71,22 +73,23 @@
   // presently, the watcher is immediately deleted when
   // CancelTlsCertificatesWatch() is called, but that can potentially change in
   // the future.
-  explicit IdentityCertificatesWatcher(
-      RefCountedPtr<grpc_tls_certificate_distributor> parent)
-      : parent_(std::move(parent)) {}
+  IdentityCertificatesWatcher(
+      RefCountedPtr<grpc_tls_certificate_distributor> parent,
+      std::string cert_name)
+      : parent_(std::move(parent)), cert_name_(std::move(cert_name)) {}
 
   void OnCertificatesChanged(
       absl::optional<absl::string_view> /* root_certs */,
       absl::optional<PemKeyCertPairList> key_cert_pairs) override {
     if (key_cert_pairs.has_value()) {
-      parent_->SetKeyMaterials("", absl::nullopt, key_cert_pairs);
+      parent_->SetKeyMaterials(cert_name_, absl::nullopt, key_cert_pairs);
     }
   }
 
-  void OnError(grpc_error* root_cert_error,
-               grpc_error* identity_cert_error) override {
+  void OnError(grpc_error_handle root_cert_error,
+               grpc_error_handle identity_cert_error) override {
     if (identity_cert_error != GRPC_ERROR_NONE) {
-      parent_->SetErrorForCert("", absl::nullopt,
+      parent_->SetErrorForCert(cert_name_, absl::nullopt,
                                identity_cert_error /* pass the ref */);
     }
     GRPC_ERROR_UNREF(root_cert_error);
@@ -94,34 +97,35 @@
 
  private:
   RefCountedPtr<grpc_tls_certificate_distributor> parent_;
+  std::string cert_name_;
 };
 
 }  // namespace
 
-XdsCertificateProvider::XdsCertificateProvider(
-    absl::string_view root_cert_name,
-    RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor,
-    absl::string_view identity_cert_name,
-    RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor,
-    std::vector<XdsApi::StringMatcher> san_matchers)
-    : root_cert_name_(root_cert_name),
-      identity_cert_name_(identity_cert_name),
-      root_cert_distributor_(std::move(root_cert_distributor)),
-      identity_cert_distributor_(std::move(identity_cert_distributor)),
-      san_matchers_(std::move(san_matchers)),
-      distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {
-  distributor_->SetWatchStatusCallback(
-      absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
+//
+// XdsCertificateProvider::ClusterCertificateState
+//
+
+XdsCertificateProvider::ClusterCertificateState::~ClusterCertificateState() {
+  if (root_cert_watcher_ != nullptr) {
+    root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
+  }
+  if (identity_cert_watcher_ != nullptr) {
+    identity_cert_distributor_->CancelTlsCertificatesWatch(
+        identity_cert_watcher_);
+  }
 }
 
-XdsCertificateProvider::~XdsCertificateProvider() {
-  distributor_->SetWatchStatusCallback(nullptr);
+bool XdsCertificateProvider::ClusterCertificateState::IsSafeToRemove() const {
+  return !watching_root_certs_ && !watching_identity_certs_ &&
+         root_cert_distributor_ == nullptr &&
+         identity_cert_distributor_ == nullptr;
 }
 
-void XdsCertificateProvider::UpdateRootCertNameAndDistributor(
-    absl::string_view root_cert_name,
-    RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
-  MutexLock lock(&mu_);
+void XdsCertificateProvider::ClusterCertificateState::
+    UpdateRootCertNameAndDistributor(
+        const std::string& cert_name, absl::string_view root_cert_name,
+        RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
   if (root_cert_name_ == root_cert_name &&
       root_cert_distributor_ == root_cert_distributor) {
     return;
@@ -133,10 +137,10 @@
       root_cert_distributor_->CancelTlsCertificatesWatch(root_cert_watcher_);
     }
     if (root_cert_distributor != nullptr) {
-      UpdateRootCertWatcher(root_cert_distributor.get());
+      UpdateRootCertWatcher(cert_name, root_cert_distributor.get());
     } else {
       root_cert_watcher_ = nullptr;
-      distributor_->SetErrorForCert(
+      xds_certificate_provider_->distributor_->SetErrorForCert(
           "",
           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "No certificate provider available for root certificates"),
@@ -147,10 +151,11 @@
   root_cert_distributor_ = std::move(root_cert_distributor);
 }
 
-void XdsCertificateProvider::UpdateIdentityCertNameAndDistributor(
-    absl::string_view identity_cert_name,
-    RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor) {
-  MutexLock lock(&mu_);
+void XdsCertificateProvider::ClusterCertificateState::
+    UpdateIdentityCertNameAndDistributor(
+        const std::string& cert_name, absl::string_view identity_cert_name,
+        RefCountedPtr<grpc_tls_certificate_distributor>
+            identity_cert_distributor) {
   if (identity_cert_name_ == identity_cert_name &&
       identity_cert_distributor_ == identity_cert_distributor) {
     return;
@@ -163,10 +168,10 @@
           identity_cert_watcher_);
     }
     if (identity_cert_distributor != nullptr) {
-      UpdateIdentityCertWatcher(identity_cert_distributor.get());
+      UpdateIdentityCertWatcher(cert_name, identity_cert_distributor.get());
     } else {
       identity_cert_watcher_ = nullptr;
-      distributor_->SetErrorForCert(
+      xds_certificate_provider_->distributor_->SetErrorForCert(
           "", absl::nullopt,
           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "No certificate provider available for identity certificates"));
@@ -176,42 +181,45 @@
   identity_cert_distributor_ = std::move(identity_cert_distributor);
 }
 
-void XdsCertificateProvider::UpdateSubjectAlternativeNameMatchers(
-    std::vector<XdsApi::StringMatcher> matchers) {
-  MutexLock lock(&san_matchers_mu_);
-  san_matchers_ = std::move(matchers);
+void XdsCertificateProvider::ClusterCertificateState::UpdateRootCertWatcher(
+    const std::string& cert_name,
+    grpc_tls_certificate_distributor* root_cert_distributor) {
+  auto watcher = absl::make_unique<RootCertificatesWatcher>(
+      xds_certificate_provider_->distributor_, cert_name);
+  root_cert_watcher_ = watcher.get();
+  root_cert_distributor->WatchTlsCertificates(std::move(watcher),
+                                              root_cert_name_, absl::nullopt);
 }
 
-void XdsCertificateProvider::WatchStatusCallback(std::string cert_name,
-                                                 bool root_being_watched,
-                                                 bool identity_being_watched) {
+void XdsCertificateProvider::ClusterCertificateState::UpdateIdentityCertWatcher(
+    const std::string& cert_name,
+    grpc_tls_certificate_distributor* identity_cert_distributor) {
+  auto watcher = absl::make_unique<IdentityCertificatesWatcher>(
+      xds_certificate_provider_->distributor_, cert_name);
+  identity_cert_watcher_ = watcher.get();
+  identity_cert_distributor->WatchTlsCertificates(
+      std::move(watcher), absl::nullopt, identity_cert_name_);
+}
+
+void XdsCertificateProvider::ClusterCertificateState::WatchStatusCallback(
+    const std::string& cert_name, bool root_being_watched,
+    bool identity_being_watched) {
   // We aren't specially handling the case where root_cert_distributor is same
   // as identity_cert_distributor. Always using two separate watchers
   // irrespective of the fact results in a straightforward design, and using a
   // single watcher does not seem to provide any benefit other than cutting down
   // on the number of callbacks.
-  MutexLock lock(&mu_);
-  if (!cert_name.empty()) {
-    grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
-        absl::StrCat("Illegal certificate name: \'", cert_name,
-                     "\'. Should be empty.")
-            .c_str());
-    distributor_->SetErrorForCert(cert_name, GRPC_ERROR_REF(error),
-                                  GRPC_ERROR_REF(error));
-    GRPC_ERROR_UNREF(error);
-    return;
-  }
   if (root_being_watched && !watching_root_certs_) {
     // We need to start watching root certs.
     watching_root_certs_ = true;
     if (root_cert_distributor_ == nullptr) {
-      distributor_->SetErrorForCert(
-          "",
+      xds_certificate_provider_->distributor_->SetErrorForCert(
+          cert_name,
           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "No certificate provider available for root certificates"),
           absl::nullopt);
     } else {
-      UpdateRootCertWatcher(root_cert_distributor_.get());
+      UpdateRootCertWatcher(cert_name, root_cert_distributor_.get());
     }
   } else if (!root_being_watched && watching_root_certs_) {
     // We need to cancel root certs watch.
@@ -225,12 +233,12 @@
   if (identity_being_watched && !watching_identity_certs_) {
     watching_identity_certs_ = true;
     if (identity_cert_distributor_ == nullptr) {
-      distributor_->SetErrorForCert(
-          "", absl::nullopt,
+      xds_certificate_provider_->distributor_->SetErrorForCert(
+          cert_name, absl::nullopt,
           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "No certificate provider available for identity certificates"));
     } else {
-      UpdateIdentityCertWatcher(identity_cert_distributor_.get());
+      UpdateIdentityCertWatcher(cert_name, identity_cert_distributor_.get());
     }
   } else if (!identity_being_watched && watching_identity_certs_) {
     watching_identity_certs_ = false;
@@ -243,20 +251,118 @@
   }
 }
 
-void XdsCertificateProvider::UpdateRootCertWatcher(
-    grpc_tls_certificate_distributor* root_cert_distributor) {
-  auto watcher = absl::make_unique<RootCertificatesWatcher>(distributor());
-  root_cert_watcher_ = watcher.get();
-  root_cert_distributor->WatchTlsCertificates(std::move(watcher),
-                                              root_cert_name_, absl::nullopt);
+//
+// XdsCertificateProvider
+//
+
+XdsCertificateProvider::XdsCertificateProvider()
+    : distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {
+  distributor_->SetWatchStatusCallback(
+      absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
 }
 
-void XdsCertificateProvider::UpdateIdentityCertWatcher(
-    grpc_tls_certificate_distributor* identity_cert_distributor) {
-  auto watcher = absl::make_unique<IdentityCertificatesWatcher>(distributor());
-  identity_cert_watcher_ = watcher.get();
-  identity_cert_distributor->WatchTlsCertificates(
-      std::move(watcher), absl::nullopt, identity_cert_name_);
+XdsCertificateProvider::~XdsCertificateProvider() {
+  distributor_->SetWatchStatusCallback(nullptr);
+}
+
+bool XdsCertificateProvider::ProvidesRootCerts(const std::string& cert_name) {
+  MutexLock lock(&mu_);
+  auto it = certificate_state_map_.find(cert_name);
+  if (it == certificate_state_map_.end()) return false;
+  return it->second->ProvidesRootCerts();
+}
+
+void XdsCertificateProvider::UpdateRootCertNameAndDistributor(
+    const std::string& cert_name, absl::string_view root_cert_name,
+    RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
+  MutexLock lock(&mu_);
+  auto it = certificate_state_map_.find(cert_name);
+  if (it == certificate_state_map_.end()) {
+    it = certificate_state_map_
+             .emplace(cert_name,
+                      absl::make_unique<ClusterCertificateState>(this))
+             .first;
+  }
+  it->second->UpdateRootCertNameAndDistributor(cert_name, root_cert_name,
+                                               root_cert_distributor);
+  // Delete unused entries.
+  if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
+}
+
+bool XdsCertificateProvider::ProvidesIdentityCerts(
+    const std::string& cert_name) {
+  MutexLock lock(&mu_);
+  auto it = certificate_state_map_.find(cert_name);
+  if (it == certificate_state_map_.end()) return false;
+  return it->second->ProvidesIdentityCerts();
+}
+
+void XdsCertificateProvider::UpdateIdentityCertNameAndDistributor(
+    const std::string& cert_name, absl::string_view identity_cert_name,
+    RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor) {
+  MutexLock lock(&mu_);
+  auto it = certificate_state_map_.find(cert_name);
+  if (it == certificate_state_map_.end()) {
+    it = certificate_state_map_
+             .emplace(cert_name,
+                      absl::make_unique<ClusterCertificateState>(this))
+             .first;
+  }
+  it->second->UpdateIdentityCertNameAndDistributor(
+      cert_name, identity_cert_name, identity_cert_distributor);
+  // Delete unused entries.
+  if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
+}
+
+bool XdsCertificateProvider::GetRequireClientCertificate(
+    const std::string& cert_name) {
+  MutexLock lock(&mu_);
+  auto it = certificate_state_map_.find(cert_name);
+  if (it == certificate_state_map_.end()) return false;
+  return it->second->require_client_certificate();
+}
+
+void XdsCertificateProvider::UpdateRequireClientCertificate(
+    const std::string& cert_name, bool require_client_certificate) {
+  MutexLock lock(&mu_);
+  auto it = certificate_state_map_.find(cert_name);
+  if (it == certificate_state_map_.end()) return;
+  it->second->set_require_client_certificate(require_client_certificate);
+}
+
+std::vector<StringMatcher> XdsCertificateProvider::GetSanMatchers(
+    const std::string& cluster) {
+  MutexLock lock(&san_matchers_mu_);
+  auto it = san_matcher_map_.find(cluster);
+  if (it == san_matcher_map_.end()) return {};
+  return it->second;
+}
+
+void XdsCertificateProvider::UpdateSubjectAlternativeNameMatchers(
+    const std::string& cluster, std::vector<StringMatcher> matchers) {
+  MutexLock lock(&san_matchers_mu_);
+  if (matchers.empty()) {
+    san_matcher_map_.erase(cluster);
+  } else {
+    san_matcher_map_[cluster] = std::move(matchers);
+  }
+}
+
+void XdsCertificateProvider::WatchStatusCallback(std::string cert_name,
+                                                 bool root_being_watched,
+                                                 bool identity_being_watched) {
+  MutexLock lock(&mu_);
+  auto it = certificate_state_map_.find(cert_name);
+  if (it == certificate_state_map_.end()) {
+    it = certificate_state_map_
+             .emplace(cert_name,
+                      absl::make_unique<ClusterCertificateState>(this))
+             .first;
+  }
+  it->second->WatchStatusCallback(cert_name, root_being_watched,
+                                  identity_being_watched);
+  // Delete unused entries.
+  if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it);
 }
 
 namespace {
diff --git a/grpc/src/core/ext/xds/xds_certificate_provider.h b/grpc/src/core/ext/xds/xds_certificate_provider.h
index 4d13423..2f50883 100644
--- a/grpc/src/core/ext/xds/xds_certificate_provider.h
+++ b/grpc/src/core/ext/xds/xds_certificate_provider.h
@@ -31,44 +31,34 @@
 
 class XdsCertificateProvider : public grpc_tls_certificate_provider {
  public:
-  XdsCertificateProvider(
-      absl::string_view root_cert_name,
-      RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor,
-      absl::string_view identity_cert_name,
-      RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor,
-      std::vector<XdsApi::StringMatcher> san_matchers);
-
+  XdsCertificateProvider();
   ~XdsCertificateProvider() override;
 
-  void UpdateRootCertNameAndDistributor(
-      absl::string_view root_cert_name,
-      RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor);
-  void UpdateIdentityCertNameAndDistributor(
-      absl::string_view identity_cert_name,
-      RefCountedPtr<grpc_tls_certificate_distributor>
-          identity_cert_distributor);
-  void UpdateSubjectAlternativeNameMatchers(
-      std::vector<XdsApi::StringMatcher> matchers);
-
   grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor()
       const override {
     return distributor_;
   }
 
-  bool ProvidesRootCerts() {
-    MutexLock lock(&mu_);
-    return root_cert_distributor_ != nullptr;
-  }
+  bool ProvidesRootCerts(const std::string& cert_name);
+  void UpdateRootCertNameAndDistributor(
+      const std::string& cert_name, absl::string_view root_cert_name,
+      RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor);
 
-  bool ProvidesIdentityCerts() {
-    MutexLock lock(&mu_);
-    return identity_cert_distributor_ != nullptr;
-  }
+  bool ProvidesIdentityCerts(const std::string& cert_name);
+  void UpdateIdentityCertNameAndDistributor(
+      const std::string& cert_name, absl::string_view identity_cert_name,
+      RefCountedPtr<grpc_tls_certificate_distributor>
+          identity_cert_distributor);
 
-  std::vector<XdsApi::StringMatcher> subject_alternative_name_matchers() {
-    MutexLock lock(&san_matchers_mu_);
-    return san_matchers_;
-  }
+  bool GetRequireClientCertificate(const std::string& cert_name);
+  // Updating \a require_client_certificate for a non-existing \a cert_name has
+  // no effect.
+  void UpdateRequireClientCertificate(const std::string& cert_name,
+                                      bool require_client_certificate);
+
+  std::vector<StringMatcher> GetSanMatchers(const std::string& cluster);
+  void UpdateSubjectAlternativeNameMatchers(
+      const std::string& cluster, std::vector<StringMatcher> matchers);
 
   grpc_arg MakeChannelArg() const;
 
@@ -76,14 +66,73 @@
       const grpc_channel_args* args);
 
  private:
+  class ClusterCertificateState {
+   public:
+    explicit ClusterCertificateState(
+        XdsCertificateProvider* xds_certificate_provider)
+        : xds_certificate_provider_(xds_certificate_provider) {}
+
+    ~ClusterCertificateState();
+
+    // Returns true if the certs aren't being watched and there are no
+    // distributors configured.
+    bool IsSafeToRemove() const;
+
+    bool ProvidesRootCerts() const { return root_cert_distributor_ != nullptr; }
+    bool ProvidesIdentityCerts() const {
+      return identity_cert_distributor_ != nullptr;
+    }
+
+    void UpdateRootCertNameAndDistributor(
+        const std::string& cert_name, absl::string_view root_cert_name,
+        RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor);
+    void UpdateIdentityCertNameAndDistributor(
+        const std::string& cert_name, absl::string_view identity_cert_name,
+        RefCountedPtr<grpc_tls_certificate_distributor>
+            identity_cert_distributor);
+
+    void UpdateRootCertWatcher(
+        const std::string& cert_name,
+        grpc_tls_certificate_distributor* root_cert_distributor);
+    void UpdateIdentityCertWatcher(
+        const std::string& cert_name,
+        grpc_tls_certificate_distributor* identity_cert_distributor);
+
+    bool require_client_certificate() const {
+      return require_client_certificate_;
+    }
+    void set_require_client_certificate(bool require_client_certificate) {
+      require_client_certificate_ = require_client_certificate;
+    }
+
+    void WatchStatusCallback(const std::string& cert_name,
+                             bool root_being_watched,
+                             bool identity_being_watched);
+
+   private:
+    XdsCertificateProvider* xds_certificate_provider_;
+    bool watching_root_certs_ = false;
+    bool watching_identity_certs_ = false;
+    std::string root_cert_name_;
+    std::string identity_cert_name_;
+    RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor_;
+    RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor_;
+    grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
+        root_cert_watcher_ = nullptr;
+    grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
+        identity_cert_watcher_ = nullptr;
+    bool require_client_certificate_ = false;
+  };
+
   void WatchStatusCallback(std::string cert_name, bool root_being_watched,
                            bool identity_being_watched);
-  void UpdateRootCertWatcher(
-      grpc_tls_certificate_distributor* root_cert_distributor);
-  void UpdateIdentityCertWatcher(
-      grpc_tls_certificate_distributor* identity_cert_distributor);
+
+  RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
 
   Mutex mu_;
+  std::map<std::string /*cert_name*/, std::unique_ptr<ClusterCertificateState>>
+      certificate_state_map_ ABSL_GUARDED_BY(mu_);
+
   // Use a separate mutex for san_matchers_ to avoid deadlocks since
   // san_matchers_ needs to be accessed when a handshake is being done and we
   // run into a possible deadlock scenario if using the same mutex. The mutex
@@ -93,18 +142,8 @@
   // -> HandshakeManager::Add() -> SecurityHandshaker::DoHandshake() ->
   // subject_alternative_names_matchers()
   Mutex san_matchers_mu_;
-  bool watching_root_certs_ = false;
-  bool watching_identity_certs_ = false;
-  std::string root_cert_name_;
-  std::string identity_cert_name_;
-  RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor_;
-  RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor_;
-  std::vector<XdsApi::StringMatcher> san_matchers_;
-  RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
-  grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
-      root_cert_watcher_ = nullptr;
-  grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
-      identity_cert_watcher_ = nullptr;
+  std::map<std::string /*cluster_name*/, std::vector<StringMatcher>>
+      san_matcher_map_ ABSL_GUARDED_BY(san_matchers_mu_);
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/xds/xds_channel_args.h b/grpc/src/core/ext/xds/xds_channel_args.h
index a258940..ea6c862 100644
--- a/grpc/src/core/ext/xds/xds_channel_args.h
+++ b/grpc/src/core/ext/xds/xds_channel_args.h
@@ -17,8 +17,11 @@
 #ifndef GRPC_CORE_EXT_XDS_XDS_CHANNEL_ARGS_H
 #define GRPC_CORE_EXT_XDS_XDS_CHANNEL_ARGS_H
 
-// Pointer channel arg containing a ref to the XdsClient object.
-#define GRPC_ARG_XDS_CLIENT "grpc.xds_client"
+// Specifies channel args for the xDS client.
+// Used only when GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG
+// is set.
+#define GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS \
+  "grpc.xds_client_channel_args"
 
 // Timeout in milliseconds to wait for a resource to be returned from
 // the xds server before assuming that it does not exist.
diff --git a/grpc/src/core/ext/xds/xds_client.cc b/grpc/src/core/ext/xds/xds_client.cc
index b31bbbd..d354999 100644
--- a/grpc/src/core/ext/xds/xds_client.cc
+++ b/grpc/src/core/ext/xds/xds_client.cc
@@ -1,20 +1,18 @@
-/*
- *
- * 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.
- *
- */
+//
+// 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>
 
@@ -35,19 +33,22 @@
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/client_channel/service_config.h"
 #include "src/core/ext/xds/xds_api.h"
+#include "src/core/ext/xds/xds_bootstrap.h"
 #include "src/core/ext/xds/xds_channel_args.h"
 #include "src/core/ext/xds/xds_client.h"
 #include "src/core/ext/xds/xds_client_stats.h"
+#include "src/core/ext/xds/xds_http_filters.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
@@ -70,8 +71,9 @@
 namespace {
 
 Mutex* g_mu = nullptr;
-const grpc_channel_args* g_channel_args = nullptr;
-XdsClient* g_xds_client = nullptr;
+const grpc_channel_args* g_channel_args ABSL_GUARDED_BY(*g_mu) = nullptr;
+XdsClient* g_xds_client ABSL_GUARDED_BY(*g_mu) = nullptr;
+char* g_fallback_bootstrap_config ABSL_GUARDED_BY(*g_mu) = nullptr;
 
 }  // namespace
 
@@ -99,8 +101,8 @@
  private:
   void StartNewCallLocked();
   void StartRetryTimerLocked();
-  static void OnRetryTimer(void* arg, grpc_error* error);
-  void OnRetryTimerLocked(grpc_error* error);
+  static void OnRetryTimer(void* arg, grpc_error_handle error);
+  void OnRetryTimerLocked(grpc_error_handle error);
 
   // The wrapped xds call that talks to the xds server. It's instantiated
   // every time we start a new call. It's null during call retry backoff.
@@ -132,9 +134,11 @@
   XdsClient* xds_client() const { return chand()->xds_client(); }
   bool seen_response() const { return seen_response_; }
 
-  void Subscribe(const std::string& type_url, const std::string& name);
-  void Unsubscribe(const std::string& type_url, const std::string& name,
-                   bool delay_unsubscription);
+  void SubscribeLocked(const std::string& type_url, const std::string& name)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  void UnsubscribeLocked(const std::string& type_url, const std::string& name,
+                         bool delay_unsubscription)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
   bool HasSubscribedResources() const;
 
@@ -175,7 +179,7 @@
     }
 
    private:
-    static void OnTimer(void* arg, grpc_error* error) {
+    static void OnTimer(void* arg, grpc_error_handle error) {
       ResourceState* self = static_cast<ResourceState*>(arg);
       {
         MutexLock lock(&self->ads_calld_->xds_client()->mu_);
@@ -185,36 +189,43 @@
       self->Unref(DEBUG_LOCATION, "timer");
     }
 
-    void OnTimerLocked(grpc_error* error) {
+    void OnTimerLocked(grpc_error_handle error)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_) {
       if (error == GRPC_ERROR_NONE && timer_pending_) {
         timer_pending_ = false;
-        grpc_error* watcher_error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        grpc_error_handle watcher_error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
             absl::StrFormat(
                 "timeout obtaining resource {type=%s name=%s} from xds server",
                 type_url_, name_)
                 .c_str());
+        watcher_error = grpc_error_set_int(
+            watcher_error, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
         if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
           gpr_log(GPR_INFO, "[xds_client %p] %s", ads_calld_->xds_client(),
-                  grpc_error_string(watcher_error));
+                  grpc_error_std_string(watcher_error).c_str());
         }
         if (type_url_ == XdsApi::kLdsTypeUrl) {
           ListenerState& state = ads_calld_->xds_client()->listener_map_[name_];
+          state.meta.client_status = XdsApi::ResourceMetadata::DOES_NOT_EXIST;
           for (const auto& p : state.watchers) {
             p.first->OnError(GRPC_ERROR_REF(watcher_error));
           }
         } else if (type_url_ == XdsApi::kRdsTypeUrl) {
           RouteConfigState& state =
               ads_calld_->xds_client()->route_config_map_[name_];
+          state.meta.client_status = XdsApi::ResourceMetadata::DOES_NOT_EXIST;
           for (const auto& p : state.watchers) {
             p.first->OnError(GRPC_ERROR_REF(watcher_error));
           }
         } else if (type_url_ == XdsApi::kCdsTypeUrl) {
           ClusterState& state = ads_calld_->xds_client()->cluster_map_[name_];
+          state.meta.client_status = XdsApi::ResourceMetadata::DOES_NOT_EXIST;
           for (const auto& p : state.watchers) {
             p.first->OnError(GRPC_ERROR_REF(watcher_error));
           }
         } else if (type_url_ == XdsApi::kEdsTypeUrl) {
           EndpointState& state = ads_calld_->xds_client()->endpoint_map_[name_];
+          state.meta.client_status = XdsApi::ResourceMetadata::DOES_NOT_EXIST;
           for (const auto& p : state.watchers) {
             p.first->OnError(GRPC_ERROR_REF(watcher_error));
           }
@@ -241,26 +252,38 @@
 
     // Nonce and error for this resource type.
     std::string nonce;
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
 
     // Subscribed resources of this type.
     std::map<std::string /* name */, OrphanablePtr<ResourceState>>
         subscribed_resources;
   };
 
-  void SendMessageLocked(const std::string& type_url);
+  void SendMessageLocked(const std::string& type_url)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
-  void AcceptLdsUpdate(XdsApi::LdsUpdateMap lds_update_map);
-  void AcceptRdsUpdate(XdsApi::RdsUpdateMap rds_update_map);
-  void AcceptCdsUpdate(XdsApi::CdsUpdateMap cds_update_map);
-  void AcceptEdsUpdate(XdsApi::EdsUpdateMap eds_update_map);
+  void AcceptLdsUpdateLocked(std::string version, grpc_millis update_time,
+                             XdsApi::LdsUpdateMap lds_update_map)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  void AcceptRdsUpdateLocked(std::string version, grpc_millis update_time,
+                             XdsApi::RdsUpdateMap rds_update_map)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  void AcceptCdsUpdateLocked(std::string version, grpc_millis update_time,
+                             XdsApi::CdsUpdateMap cds_update_map)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  void AcceptEdsUpdateLocked(std::string version, grpc_millis update_time,
+                             XdsApi::EdsUpdateMap eds_update_map)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
-  static void OnRequestSent(void* arg, grpc_error* error);
-  void OnRequestSentLocked(grpc_error* error);
-  static void OnResponseReceived(void* arg, grpc_error* error);
-  bool OnResponseReceivedLocked();
-  static void OnStatusReceived(void* arg, grpc_error* error);
-  void OnStatusReceivedLocked(grpc_error* error);
+  static void OnRequestSent(void* arg, grpc_error_handle error);
+  void OnRequestSentLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  static void OnResponseReceived(void* arg, grpc_error_handle error);
+  bool OnResponseReceivedLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  static void OnStatusReceived(void* arg, grpc_error_handle error);
+  void OnStatusReceivedLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
   bool IsCurrentCallOnChannel() const;
 
@@ -333,12 +356,15 @@
     void Orphan() override;
 
    private:
-    void ScheduleNextReportLocked();
-    static void OnNextReportTimer(void* arg, grpc_error* error);
-    bool OnNextReportTimerLocked(grpc_error* error);
-    bool SendReportLocked();
-    static void OnReportDone(void* arg, grpc_error* error);
-    bool OnReportDoneLocked(grpc_error* error);
+    void ScheduleNextReportLocked()
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+    static void OnNextReportTimer(void* arg, grpc_error_handle error);
+    bool OnNextReportTimerLocked(grpc_error_handle error)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+    bool SendReportLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+    static void OnReportDone(void* arg, grpc_error_handle error);
+    bool OnReportDoneLocked(grpc_error_handle error)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
     bool IsCurrentReporterOnCall() const {
       return this == parent_->reporter_.get();
@@ -357,12 +383,15 @@
     grpc_closure on_report_done_;
   };
 
-  static void OnInitialRequestSent(void* arg, grpc_error* error);
-  void OnInitialRequestSentLocked();
-  static void OnResponseReceived(void* arg, grpc_error* error);
-  bool OnResponseReceivedLocked();
-  static void OnStatusReceived(void* arg, grpc_error* error);
-  void OnStatusReceivedLocked(grpc_error* error);
+  static void OnInitialRequestSent(void* arg, grpc_error_handle error);
+  void OnInitialRequestSentLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  static void OnResponseReceived(void* arg, grpc_error_handle error);
+  bool OnResponseReceivedLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+  static void OnStatusReceived(void* arg, grpc_error_handle error);
+  void OnStatusReceivedLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
   bool IsCurrentCallOnChannel() const;
 
@@ -418,7 +447,7 @@
               "[xds_client %p] xds channel in state:TRANSIENT_FAILURE "
               "status_message:(%s)",
               parent_->xds_client(), status.ToString().c_str());
-      parent_->xds_client()->NotifyOnErrorLocked(
+      parent_->xds_client_->NotifyOnErrorLocked(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING(
               "xds channel in TRANSIENT_FAILURE"));
     }
@@ -433,26 +462,13 @@
 
 namespace {
 
-grpc_channel* CreateXdsChannel(const XdsBootstrap::XdsServer& server) {
-  // Build channel args.
-  absl::InlinedVector<grpc_arg, 2> args_to_add = {
-      grpc_channel_arg_integer_create(
-          const_cast<char*>(GRPC_ARG_KEEPALIVE_TIME_MS),
-          5 * 60 * GPR_MS_PER_SEC),
-      grpc_channel_arg_integer_create(
-          const_cast<char*>(GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL), 1),
-  };
-  grpc_channel_args* new_args = grpc_channel_args_copy_and_add(
-      g_channel_args, args_to_add.data(), args_to_add.size());
-  // Create channel creds.
+grpc_channel* CreateXdsChannel(grpc_channel_args* args,
+                               const XdsBootstrap::XdsServer& server) {
   RefCountedPtr<grpc_channel_credentials> channel_creds =
       XdsChannelCredsRegistry::MakeChannelCreds(server.channel_creds_type,
                                                 server.channel_creds_config);
-  // Create channel.
-  grpc_channel* channel = grpc_secure_channel_create(
-      channel_creds.get(), server.server_uri.c_str(), new_args, nullptr);
-  grpc_channel_args_destroy(new_args);
-  return channel;
+  return grpc_secure_channel_create(channel_creds.get(),
+                                    server.server_uri.c_str(), args, nullptr);
 }
 
 }  // namespace
@@ -469,7 +485,7 @@
     gpr_log(GPR_INFO, "[xds_client %p] creating channel to %s",
             xds_client_.get(), server.server_uri.c_str());
   }
-  channel_ = CreateXdsChannel(server);
+  channel_ = CreateXdsChannel(xds_client_->args_, server);
   GPR_ASSERT(channel_ != nullptr);
   StartConnectivityWatchLocked();
 }
@@ -502,7 +518,7 @@
 }
 
 bool XdsClient::ChannelState::HasActiveAdsCall() const {
-  return ads_calld_->calld() != nullptr;
+  return ads_calld_ != nullptr && ads_calld_->calld() != nullptr;
 }
 
 void XdsClient::ChannelState::MaybeStartLrsCall() {
@@ -514,24 +530,22 @@
 void XdsClient::ChannelState::StopLrsCall() { lrs_calld_.reset(); }
 
 void XdsClient::ChannelState::StartConnectivityWatchLocked() {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel_));
-  GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
+  ClientChannel* client_channel = ClientChannel::GetFromChannel(channel_);
+  GPR_ASSERT(client_channel != nullptr);
   watcher_ = new StateWatcher(Ref(DEBUG_LOCATION, "ChannelState+watch"));
-  grpc_client_channel_start_connectivity_watch(
-      client_channel_elem, GRPC_CHANNEL_IDLE,
+  client_channel->AddConnectivityWatcher(
+      GRPC_CHANNEL_IDLE,
       OrphanablePtr<AsyncConnectivityStateWatcherInterface>(watcher_));
 }
 
 void XdsClient::ChannelState::CancelConnectivityWatchLocked() {
-  grpc_channel_element* client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel_));
-  GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
-  grpc_client_channel_stop_connectivity_watch(client_channel_elem, watcher_);
+  ClientChannel* client_channel = ClientChannel::GetFromChannel(channel_);
+  GPR_ASSERT(client_channel != nullptr);
+  client_channel->RemoveConnectivityWatcher(watcher_);
 }
 
-void XdsClient::ChannelState::Subscribe(const std::string& type_url,
-                                        const std::string& name) {
+void XdsClient::ChannelState::SubscribeLocked(const std::string& type_url,
+                                              const std::string& name) {
   if (ads_calld_ == nullptr) {
     // Start the ADS call if this is the first request.
     ads_calld_.reset(new RetryableCall<AdsCallState>(
@@ -545,16 +559,16 @@
   // because when the call is restarted it will resend all necessary requests.
   if (ads_calld() == nullptr) return;
   // Subscribe to this resource if the ADS call is active.
-  ads_calld()->Subscribe(type_url, name);
+  ads_calld()->SubscribeLocked(type_url, name);
 }
 
-void XdsClient::ChannelState::Unsubscribe(const std::string& type_url,
-                                          const std::string& name,
-                                          bool delay_unsubscription) {
+void XdsClient::ChannelState::UnsubscribeLocked(const std::string& type_url,
+                                                const std::string& name,
+                                                bool delay_unsubscription) {
   if (ads_calld_ != nullptr) {
     auto* calld = ads_calld_->calld();
     if (calld != nullptr) {
-      calld->Unsubscribe(type_url, name, delay_unsubscription);
+      calld->UnsubscribeLocked(type_url, name, delay_unsubscription);
       if (!calld->HasSubscribedResources()) ads_calld_.reset();
     }
   }
@@ -637,7 +651,7 @@
 
 template <typename T>
 void XdsClient::ChannelState::RetryableCall<T>::OnRetryTimer(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   RetryableCall* calld = static_cast<RetryableCall*>(arg);
   {
     MutexLock lock(&calld->chand_->xds_client()->mu_);
@@ -648,7 +662,7 @@
 
 template <typename T>
 void XdsClient::ChannelState::RetryableCall<T>::OnRetryTimerLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   retry_timer_callback_pending_ = false;
   if (!shutting_down_ && error == GRPC_ERROR_NONE) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -716,16 +730,16 @@
   GRPC_CLOSURE_INIT(&on_request_sent_, OnRequestSent, this,
                     grpc_schedule_on_exec_ctx);
   for (const auto& p : xds_client()->listener_map_) {
-    Subscribe(XdsApi::kLdsTypeUrl, std::string(p.first));
+    SubscribeLocked(XdsApi::kLdsTypeUrl, std::string(p.first));
   }
   for (const auto& p : xds_client()->route_config_map_) {
-    Subscribe(XdsApi::kRdsTypeUrl, std::string(p.first));
+    SubscribeLocked(XdsApi::kRdsTypeUrl, std::string(p.first));
   }
   for (const auto& p : xds_client()->cluster_map_) {
-    Subscribe(XdsApi::kCdsTypeUrl, std::string(p.first));
+    SubscribeLocked(XdsApi::kCdsTypeUrl, std::string(p.first));
   }
   for (const auto& p : xds_client()->endpoint_map_) {
-    Subscribe(XdsApi::kEdsTypeUrl, std::string(p.first));
+    SubscribeLocked(XdsApi::kEdsTypeUrl, std::string(p.first));
   }
   // Op: recv initial metadata.
   op = ops;
@@ -789,7 +803,8 @@
 }
 
 void XdsClient::ChannelState::AdsCallState::SendMessageLocked(
-    const std::string& type_url) {
+    const std::string& type_url)
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_) {
   // Buffer message sending if an existing message is in flight.
   if (send_message_payload_ != nullptr) {
     buffered_requests_.insert(type_url);
@@ -814,7 +829,7 @@
             "error=%s resources=%s",
             xds_client(), type_url.c_str(),
             xds_client()->resource_version_map_[type_url].c_str(),
-            state.nonce.c_str(), grpc_error_string(state.error),
+            state.nonce.c_str(), grpc_error_std_string(state.error).c_str(),
             absl::StrJoin(resource_names, " ").c_str());
   }
   GRPC_ERROR_UNREF(state.error);
@@ -841,7 +856,7 @@
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::Subscribe(
+void XdsClient::ChannelState::AdsCallState::SubscribeLocked(
     const std::string& type_url, const std::string& name) {
   auto& state = state_map_[type_url].subscribed_resources[name];
   if (state == nullptr) {
@@ -851,7 +866,7 @@
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::Unsubscribe(
+void XdsClient::ChannelState::AdsCallState::UnsubscribeLocked(
     const std::string& type_url, const std::string& name,
     bool delay_unsubscription) {
   state_map_[type_url].subscribed_resources.erase(name);
@@ -865,7 +880,24 @@
   return false;
 }
 
-void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
+namespace {
+
+// Build a resource metadata struct for ADS result accepting methods and CSDS.
+XdsApi::ResourceMetadata CreateResourceMetadataAcked(
+    std::string serialized_proto, std::string version,
+    grpc_millis update_time) {
+  XdsApi::ResourceMetadata resource_metadata;
+  resource_metadata.serialized_proto = std::move(serialized_proto);
+  resource_metadata.update_time = update_time;
+  resource_metadata.version = std::move(version);
+  resource_metadata.client_status = XdsApi::ResourceMetadata::ACKED;
+  return resource_metadata;
+}
+
+}  // namespace
+
+void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdateLocked(
+    std::string version, grpc_millis update_time,
     XdsApi::LdsUpdateMap lds_update_map) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     gpr_log(GPR_INFO,
@@ -877,23 +909,17 @@
   std::set<std::string> rds_resource_names_seen;
   for (auto& p : lds_update_map) {
     const std::string& listener_name = p.first;
-    XdsApi::LdsUpdate& lds_update = p.second;
+    XdsApi::LdsUpdate& lds_update = p.second.resource;
     auto& state = lds_state.subscribed_resources[listener_name];
     if (state != nullptr) state->Finish();
     if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
-      gpr_log(GPR_INFO, "[xds_client %p] LDS resource %s: route_config_name=%s",
-              xds_client(), listener_name.c_str(),
-              (!lds_update.route_config_name.empty()
-                   ? lds_update.route_config_name.c_str()
-                   : "<inlined>"));
-      if (lds_update.rds_update.has_value()) {
-        gpr_log(GPR_INFO, "RouteConfiguration: %s",
-                lds_update.rds_update->ToString().c_str());
-      }
+      gpr_log(GPR_INFO, "[xds_client %p] LDS resource %s: %s", xds_client(),
+              listener_name.c_str(), lds_update.ToString().c_str());
     }
     // Record the RDS resource names seen.
-    if (!lds_update.route_config_name.empty()) {
-      rds_resource_names_seen.insert(lds_update.route_config_name);
+    if (!lds_update.http_connection_manager.route_config_name.empty()) {
+      rds_resource_names_seen.insert(
+          lds_update.http_connection_manager.route_config_name);
     }
     // Ignore identical update.
     ListenerState& listener_state = xds_client()->listener_map_[listener_name];
@@ -909,6 +935,8 @@
     }
     // Update the listener state.
     listener_state.update = std::move(lds_update);
+    listener_state.meta = CreateResourceMetadataAcked(
+        std::move(p.second.serialized_proto), version, update_time);
     // Notify watchers.
     for (const auto& p : listener_state.watchers) {
       p.first->OnListenerChanged(*listener_state.update);
@@ -952,7 +980,8 @@
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate(
+void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdateLocked(
+    std::string version, grpc_millis update_time,
     XdsApi::RdsUpdateMap rds_update_map) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     gpr_log(GPR_INFO,
@@ -963,7 +992,7 @@
   auto& rds_state = state_map_[XdsApi::kRdsTypeUrl];
   for (auto& p : rds_update_map) {
     const std::string& route_config_name = p.first;
-    XdsApi::RdsUpdate& rds_update = p.second;
+    XdsApi::RdsUpdate& rds_update = p.second.resource;
     auto& state = rds_state.subscribed_resources[route_config_name];
     if (state != nullptr) state->Finish();
     if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -984,6 +1013,8 @@
     }
     // Update the cache.
     route_config_state.update = std::move(rds_update);
+    route_config_state.meta = CreateResourceMetadataAcked(
+        std::move(p.second.serialized_proto), version, update_time);
     // Notify all watchers.
     for (const auto& p : route_config_state.watchers) {
       p.first->OnRouteConfigChanged(*route_config_state.update);
@@ -991,7 +1022,8 @@
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
+void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdateLocked(
+    std::string version, grpc_millis update_time,
     XdsApi::CdsUpdateMap cds_update_map) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     gpr_log(GPR_INFO,
@@ -1003,7 +1035,7 @@
   std::set<std::string> eds_resource_names_seen;
   for (auto& p : cds_update_map) {
     const char* cluster_name = p.first.c_str();
-    XdsApi::CdsUpdate& cds_update = p.second;
+    XdsApi::CdsUpdate& cds_update = p.second.resource;
     auto& state = cds_state.subscribed_resources[cluster_name];
     if (state != nullptr) state->Finish();
     if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -1027,6 +1059,8 @@
     }
     // Update the cluster state.
     cluster_state.update = std::move(cds_update);
+    cluster_state.meta = CreateResourceMetadataAcked(
+        std::move(p.second.serialized_proto), version, update_time);
     // Notify all watchers.
     for (const auto& p : cluster_state.watchers) {
       p.first->OnClusterChanged(cluster_state.update.value());
@@ -1069,7 +1103,8 @@
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
+void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdateLocked(
+    std::string version, grpc_millis update_time,
     XdsApi::EdsUpdateMap eds_update_map) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     gpr_log(GPR_INFO,
@@ -1080,7 +1115,7 @@
   auto& eds_state = state_map_[XdsApi::kEdsTypeUrl];
   for (auto& p : eds_update_map) {
     const char* eds_service_name = p.first.c_str();
-    XdsApi::EdsUpdate& eds_update = p.second;
+    XdsApi::EdsUpdate& eds_update = p.second.resource;
     auto& state = eds_state.subscribed_resources[eds_service_name];
     if (state != nullptr) state->Finish();
     if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -1101,6 +1136,8 @@
     }
     // Update the cluster state.
     endpoint_state.update = std::move(eds_update);
+    endpoint_state.meta = CreateResourceMetadataAcked(
+        std::move(p.second.serialized_proto), version, update_time);
     // Notify all watchers.
     for (const auto& p : endpoint_state.watchers) {
       p.first->OnEndpointChanged(endpoint_state.update.value());
@@ -1108,8 +1145,8 @@
   }
 }
 
-void XdsClient::ChannelState::AdsCallState::OnRequestSent(void* arg,
-                                                          grpc_error* error) {
+void XdsClient::ChannelState::AdsCallState::OnRequestSent(
+    void* arg, grpc_error_handle error) {
   AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
   {
     MutexLock lock(&ads_calld->xds_client()->mu_);
@@ -1119,7 +1156,7 @@
 }
 
 void XdsClient::ChannelState::AdsCallState::OnRequestSentLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (IsCurrentCallOnChannel() && error == GRPC_ERROR_NONE) {
     // Clean up the sent message.
     grpc_byte_buffer_destroy(send_message_payload_);
@@ -1143,7 +1180,7 @@
 }
 
 void XdsClient::ChannelState::AdsCallState::OnResponseReceived(
-    void* arg, grpc_error* /* error */) {
+    void* arg, grpc_error_handle /* error */) {
   AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
   bool done;
   {
@@ -1167,7 +1204,8 @@
   recv_message_payload_ = nullptr;
   // Parse and validate the response.
   XdsApi::AdsParseResult result = xds_client()->api_.ParseAdsResponse(
-      response_slice, ResourceNamesForRequest(XdsApi::kLdsTypeUrl),
+      chand()->server_, response_slice,
+      ResourceNamesForRequest(XdsApi::kLdsTypeUrl),
       ResourceNamesForRequest(XdsApi::kRdsTypeUrl),
       ResourceNamesForRequest(XdsApi::kCdsTypeUrl),
       ResourceNamesForRequest(XdsApi::kEdsTypeUrl));
@@ -1176,14 +1214,17 @@
     // Ignore unparsable response.
     gpr_log(GPR_ERROR,
             "[xds_client %p] Error parsing ADS response (%s) -- ignoring",
-            xds_client(), grpc_error_string(result.parse_error));
+            xds_client(), grpc_error_std_string(result.parse_error).c_str());
     GRPC_ERROR_UNREF(result.parse_error);
   } else {
+    grpc_millis update_time = grpc_core::ExecCtx::Get()->Now();
     // Update nonce.
     auto& state = state_map_[result.type_url];
     state.nonce = std::move(result.nonce);
     // NACK or ACK the response.
     if (result.parse_error != GRPC_ERROR_NONE) {
+      xds_client()->UpdateResourceMetadataWithFailedParseResultLocked(
+          update_time, result);
       GRPC_ERROR_UNREF(state.error);
       state.error = result.parse_error;
       // NACK unacceptable update.
@@ -1191,19 +1232,24 @@
               "[xds_client %p] ADS response invalid for resource type %s "
               "version %s, will NACK: nonce=%s error=%s",
               xds_client(), result.type_url.c_str(), result.version.c_str(),
-              state.nonce.c_str(), grpc_error_string(result.parse_error));
+              state.nonce.c_str(),
+              grpc_error_std_string(result.parse_error).c_str());
       SendMessageLocked(result.type_url);
     } else {
       seen_response_ = true;
       // Accept the ADS response according to the type_url.
       if (result.type_url == XdsApi::kLdsTypeUrl) {
-        AcceptLdsUpdate(std::move(result.lds_update_map));
+        AcceptLdsUpdateLocked(result.version, update_time,
+                              std::move(result.lds_update_map));
       } else if (result.type_url == XdsApi::kRdsTypeUrl) {
-        AcceptRdsUpdate(std::move(result.rds_update_map));
+        AcceptRdsUpdateLocked(result.version, update_time,
+                              std::move(result.rds_update_map));
       } else if (result.type_url == XdsApi::kCdsTypeUrl) {
-        AcceptCdsUpdate(std::move(result.cds_update_map));
+        AcceptCdsUpdateLocked(result.version, update_time,
+                              std::move(result.cds_update_map));
       } else if (result.type_url == XdsApi::kEdsTypeUrl) {
-        AcceptEdsUpdate(std::move(result.eds_update_map));
+        AcceptEdsUpdateLocked(result.version, update_time,
+                              std::move(result.eds_update_map));
       }
       xds_client()->resource_version_map_[result.type_url] =
           std::move(result.version);
@@ -1234,7 +1280,7 @@
 }
 
 void XdsClient::ChannelState::AdsCallState::OnStatusReceived(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
   {
     MutexLock lock(&ads_calld->xds_client()->mu_);
@@ -1244,14 +1290,14 @@
 }
 
 void XdsClient::ChannelState::AdsCallState::OnStatusReceivedLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     char* status_details = grpc_slice_to_c_string(status_details_);
     gpr_log(GPR_INFO,
             "[xds_client %p] ADS call status received. Status = %d, details "
             "= '%s', (chand: %p, ads_calld: %p, call: %p), error '%s'",
             xds_client(), status_code_, status_details, chand(), this, call_,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     gpr_free(status_details);
   }
   // Ignore status from a stale call.
@@ -1306,7 +1352,7 @@
 }
 
 void XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimer(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   Reporter* self = static_cast<Reporter*>(arg);
   bool done;
   {
@@ -1317,7 +1363,7 @@
 }
 
 bool XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimerLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   next_report_timer_callback_pending_ = false;
   if (error != GRPC_ERROR_NONE || !IsCurrentReporterOnCall()) {
     GRPC_ERROR_UNREF(error);
@@ -1382,7 +1428,7 @@
 }
 
 void XdsClient::ChannelState::LrsCallState::Reporter::OnReportDone(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   Reporter* self = static_cast<Reporter*>(arg);
   bool done;
   {
@@ -1393,7 +1439,7 @@
 }
 
 bool XdsClient::ChannelState::LrsCallState::Reporter::OnReportDoneLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   grpc_byte_buffer_destroy(parent_->send_message_payload_);
   parent_->send_message_payload_ = nullptr;
   // If there are no more registered stats to report, cancel the call.
@@ -1563,7 +1609,7 @@
 }
 
 void XdsClient::ChannelState::LrsCallState::OnInitialRequestSent(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
   {
     MutexLock lock(&lrs_calld->xds_client()->mu_);
@@ -1580,7 +1626,7 @@
 }
 
 void XdsClient::ChannelState::LrsCallState::OnResponseReceived(
-    void* arg, grpc_error* /*error*/) {
+    void* arg, grpc_error_handle /*error*/) {
   LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
   bool done;
   {
@@ -1608,13 +1654,13 @@
     bool send_all_clusters = false;
     std::set<std::string> new_cluster_names;
     grpc_millis new_load_reporting_interval;
-    grpc_error* parse_error = xds_client()->api_.ParseLrsResponse(
+    grpc_error_handle parse_error = xds_client()->api_.ParseLrsResponse(
         response_slice, &send_all_clusters, &new_cluster_names,
         &new_load_reporting_interval);
     if (parse_error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR,
               "[xds_client %p] LRS response parsing failed. error=%s",
-              xds_client(), grpc_error_string(parse_error));
+              xds_client(), grpc_error_std_string(parse_error).c_str());
       GRPC_ERROR_UNREF(parse_error);
       return;
     }
@@ -1683,7 +1729,7 @@
 }
 
 void XdsClient::ChannelState::LrsCallState::OnStatusReceived(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
   {
     MutexLock lock(&lrs_calld->xds_client()->mu_);
@@ -1693,7 +1739,7 @@
 }
 
 void XdsClient::ChannelState::LrsCallState::OnStatusReceivedLocked(
-    grpc_error* error) {
+    grpc_error_handle error) {
   GPR_ASSERT(call_ != nullptr);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     char* status_details = grpc_slice_to_c_string(status_details_);
@@ -1701,7 +1747,7 @@
             "[xds_client %p] LRS call status received. Status = %d, details "
             "= '%s', (chand: %p, calld: %p, call: %p), error '%s'",
             xds_client(), status_code_, status_details, chand(), this, call_,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     gpr_free(status_details);
   }
   // Ignore status from a stale call.
@@ -1726,36 +1772,41 @@
 
 namespace {
 
-grpc_millis GetRequestTimeout() {
+grpc_millis GetRequestTimeout(const grpc_channel_args* args) {
   return grpc_channel_args_find_integer(
-      g_channel_args, GRPC_ARG_XDS_RESOURCE_DOES_NOT_EXIST_TIMEOUT_MS,
+      args, GRPC_ARG_XDS_RESOURCE_DOES_NOT_EXIST_TIMEOUT_MS,
       {15000, 0, INT_MAX});
 }
 
+grpc_channel_args* ModifyChannelArgs(const grpc_channel_args* args) {
+  absl::InlinedVector<grpc_arg, 2> args_to_add = {
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_KEEPALIVE_TIME_MS),
+          5 * 60 * GPR_MS_PER_SEC),
+      grpc_channel_arg_integer_create(
+          const_cast<char*>(GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL), 1),
+  };
+  return grpc_channel_args_copy_and_add(args, args_to_add.data(),
+                                        args_to_add.size());
+}
+
 }  // namespace
 
-XdsClient::XdsClient(grpc_error** error)
+XdsClient::XdsClient(std::unique_ptr<XdsBootstrap> bootstrap,
+                     const grpc_channel_args* args)
     : DualRefCounted<XdsClient>(
           GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_refcount_trace) ? "XdsClient"
                                                                   : nullptr),
-      request_timeout_(GetRequestTimeout()),
+      bootstrap_(std::move(bootstrap)),
+      args_(ModifyChannelArgs(args)),
+      request_timeout_(GetRequestTimeout(args)),
       interested_parties_(grpc_pollset_set_create()),
-      bootstrap_(
-          XdsBootstrap::ReadFromFile(this, &grpc_xds_client_trace, error)),
       certificate_provider_store_(MakeOrphanable<CertificateProviderStore>(
-          bootstrap_ == nullptr
-              ? CertificateProviderStore::PluginDefinitionMap()
-              : bootstrap_->certificate_providers())),
-      api_(this, &grpc_xds_client_trace,
-           bootstrap_ == nullptr ? nullptr : bootstrap_->node()) {
+          bootstrap_->certificate_providers())),
+      api_(this, &grpc_xds_client_trace, bootstrap_->node()) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     gpr_log(GPR_INFO, "[xds_client %p] creating xds client", this);
   }
-  if (*error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "[xds_client %p] failed to read bootstrap file: %s",
-            this, grpc_error_string(*error));
-    return;
-  }
   // Create ChannelState object.
   chand_ = MakeOrphanable<ChannelState>(
       WeakRef(DEBUG_LOCATION, "XdsClient+ChannelState"), bootstrap_->server());
@@ -1765,11 +1816,13 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
     gpr_log(GPR_INFO, "[xds_client %p] destroying xds client", this);
   }
+  grpc_channel_args_destroy(args_);
   grpc_pollset_set_destroy(interested_parties_);
 }
 
 void XdsClient::AddChannelzLinkage(
     channelz::ChannelNode* parent_channelz_node) {
+  MutexLock lock(&mu_);
   channelz::ChannelNode* xds_channelz_node =
       grpc_channel_get_channelz_node(chand_->channel());
   if (xds_channelz_node != nullptr) {
@@ -1779,6 +1832,7 @@
 
 void XdsClient::RemoveChannelzLinkage(
     channelz::ChannelNode* parent_channelz_node) {
+  MutexLock lock(&mu_);
   channelz::ChannelNode* xds_channelz_node =
       grpc_channel_get_channelz_node(chand_->channel());
   if (xds_channelz_node != nullptr) {
@@ -1829,7 +1883,7 @@
     }
     w->OnListenerChanged(*listener_state.update);
   }
-  chand_->Subscribe(XdsApi::kLdsTypeUrl, listener_name_str);
+  chand_->SubscribeLocked(XdsApi::kLdsTypeUrl, listener_name_str);
 }
 
 void XdsClient::CancelListenerDataWatch(absl::string_view listener_name,
@@ -1844,8 +1898,8 @@
     listener_state.watchers.erase(it);
     if (listener_state.watchers.empty()) {
       listener_map_.erase(listener_name_str);
-      chand_->Unsubscribe(XdsApi::kLdsTypeUrl, listener_name_str,
-                          delay_unsubscription);
+      chand_->UnsubscribeLocked(XdsApi::kLdsTypeUrl, listener_name_str,
+                                delay_unsubscription);
     }
   }
 }
@@ -1869,7 +1923,7 @@
     }
     w->OnRouteConfigChanged(*route_config_state.update);
   }
-  chand_->Subscribe(XdsApi::kRdsTypeUrl, route_config_name_str);
+  chand_->SubscribeLocked(XdsApi::kRdsTypeUrl, route_config_name_str);
 }
 
 void XdsClient::CancelRouteConfigDataWatch(absl::string_view route_config_name,
@@ -1885,8 +1939,8 @@
     route_config_state.watchers.erase(it);
     if (route_config_state.watchers.empty()) {
       route_config_map_.erase(route_config_name_str);
-      chand_->Unsubscribe(XdsApi::kRdsTypeUrl, route_config_name_str,
-                          delay_unsubscription);
+      chand_->UnsubscribeLocked(XdsApi::kRdsTypeUrl, route_config_name_str,
+                                delay_unsubscription);
     }
   }
 }
@@ -1908,7 +1962,7 @@
     }
     w->OnClusterChanged(cluster_state.update.value());
   }
-  chand_->Subscribe(XdsApi::kCdsTypeUrl, cluster_name_str);
+  chand_->SubscribeLocked(XdsApi::kCdsTypeUrl, cluster_name_str);
 }
 
 void XdsClient::CancelClusterDataWatch(absl::string_view cluster_name,
@@ -1923,8 +1977,8 @@
     cluster_state.watchers.erase(it);
     if (cluster_state.watchers.empty()) {
       cluster_map_.erase(cluster_name_str);
-      chand_->Unsubscribe(XdsApi::kCdsTypeUrl, cluster_name_str,
-                          delay_unsubscription);
+      chand_->UnsubscribeLocked(XdsApi::kCdsTypeUrl, cluster_name_str,
+                                delay_unsubscription);
     }
   }
 }
@@ -1946,7 +2000,7 @@
     }
     w->OnEndpointChanged(endpoint_state.update.value());
   }
-  chand_->Subscribe(XdsApi::kEdsTypeUrl, eds_service_name_str);
+  chand_->SubscribeLocked(XdsApi::kEdsTypeUrl, eds_service_name_str);
 }
 
 void XdsClient::CancelEndpointDataWatch(absl::string_view eds_service_name,
@@ -1961,8 +2015,8 @@
     endpoint_state.watchers.erase(it);
     if (endpoint_state.watchers.empty()) {
       endpoint_map_.erase(eds_service_name_str);
-      chand_->Unsubscribe(XdsApi::kEdsTypeUrl, eds_service_name_str,
-                          delay_unsubscription);
+      chand_->UnsubscribeLocked(XdsApi::kEdsTypeUrl, eds_service_name_str,
+                                delay_unsubscription);
     }
   }
 }
@@ -2089,7 +2143,7 @@
   }
 }
 
-void XdsClient::NotifyOnErrorLocked(grpc_error* error) {
+void XdsClient::NotifyOnErrorLocked(grpc_error_handle error) {
   for (const auto& p : listener_map_) {
     const ListenerState& listener_state = p.second;
     for (const auto& p : listener_state.watchers) {
@@ -2198,25 +2252,190 @@
   return snapshot_map;
 }
 
+void XdsClient::UpdateResourceMetadataWithFailedParseResultLocked(
+    grpc_millis update_time, const XdsApi::AdsParseResult& result) {
+  // ADS update is rejected and the resource names in the failed update is
+  // available.
+  std::string details = grpc_error_std_string(result.parse_error);
+  for (auto& name : result.resource_names_failed) {
+    XdsApi::ResourceMetadata* resource_metadata = nullptr;
+    if (result.type_url == XdsApi::kLdsTypeUrl) {
+      auto it = listener_map_.find(name);
+      if (it != listener_map_.end()) {
+        resource_metadata = &it->second.meta;
+      }
+    } else if (result.type_url == XdsApi::kRdsTypeUrl) {
+      auto it = route_config_map_.find(name);
+      if (route_config_map_.find(name) != route_config_map_.end()) {
+        resource_metadata = &it->second.meta;
+      }
+    } else if (result.type_url == XdsApi::kCdsTypeUrl) {
+      auto it = cluster_map_.find(name);
+      if (cluster_map_.find(name) != cluster_map_.end()) {
+        resource_metadata = &it->second.meta;
+      }
+    } else if (result.type_url == XdsApi::kEdsTypeUrl) {
+      auto it = endpoint_map_.find(name);
+      if (endpoint_map_.find(name) != endpoint_map_.end()) {
+        resource_metadata = &it->second.meta;
+      }
+    }
+    if (resource_metadata == nullptr) {
+      return;
+    }
+    resource_metadata->client_status = XdsApi::ResourceMetadata::NACKED;
+    resource_metadata->failed_version = result.version;
+    resource_metadata->failed_details = details;
+    resource_metadata->failed_update_time = update_time;
+  }
+}
+
+std::string XdsClient::DumpClientConfigBinary() {
+  MutexLock lock(&mu_);
+  XdsApi::ResourceTypeMetadataMap resource_type_metadata_map;
+  // Update per-xds-type version if available, this version corresponding to the
+  // last successful ADS update version.
+  for (auto& p : resource_version_map_) {
+    resource_type_metadata_map[p.first].version = p.second;
+  }
+  // Collect resource metadata from listeners
+  auto& lds_map =
+      resource_type_metadata_map[XdsApi::kLdsTypeUrl].resource_metadata_map;
+  for (auto& p : listener_map_) {
+    lds_map[p.first] = &p.second.meta;
+  }
+  // Collect resource metadata from route configs
+  auto& rds_map =
+      resource_type_metadata_map[XdsApi::kRdsTypeUrl].resource_metadata_map;
+  for (auto& p : route_config_map_) {
+    rds_map[p.first] = &p.second.meta;
+  }
+  // Collect resource metadata from clusters
+  auto& cds_map =
+      resource_type_metadata_map[XdsApi::kCdsTypeUrl].resource_metadata_map;
+  for (auto& p : cluster_map_) {
+    cds_map[p.first] = &p.second.meta;
+  }
+  // Collect resource metadata from endpoints
+  auto& eds_map =
+      resource_type_metadata_map[XdsApi::kEdsTypeUrl].resource_metadata_map;
+  for (auto& p : endpoint_map_) {
+    eds_map[p.first] = &p.second.meta;
+  }
+  // Assemble config dump messages
+  return api_.AssembleClientConfig(resource_type_metadata_map);
+}
+
 //
 // accessors for global state
 //
 
-void XdsClientGlobalInit() { g_mu = new Mutex; }
-
-void XdsClientGlobalShutdown() {
-  delete g_mu;
-  g_mu = nullptr;
+void XdsClientGlobalInit() {
+  g_mu = new Mutex;
+  XdsHttpFilterRegistry::Init();
 }
 
-RefCountedPtr<XdsClient> XdsClient::GetOrCreate(grpc_error** error) {
-  MutexLock lock(g_mu);
-  if (g_xds_client != nullptr) {
-    auto xds_client = g_xds_client->RefIfNonZero();
-    if (xds_client != nullptr) return xds_client;
+// TODO(roth): Find a better way to clear the fallback config that does
+// not require using ABSL_NO_THREAD_SAFETY_ANALYSIS.
+void XdsClientGlobalShutdown() ABSL_NO_THREAD_SAFETY_ANALYSIS {
+  gpr_free(g_fallback_bootstrap_config);
+  g_fallback_bootstrap_config = nullptr;
+  delete g_mu;
+  g_mu = nullptr;
+  XdsHttpFilterRegistry::Shutdown();
+}
+
+namespace {
+
+std::string GetBootstrapContents(const char* fallback_config,
+                                 grpc_error_handle* error) {
+  // First, try GRPC_XDS_BOOTSTRAP env var.
+  grpc_core::UniquePtr<char> path(gpr_getenv("GRPC_XDS_BOOTSTRAP"));
+  if (path != nullptr) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
+      gpr_log(GPR_INFO,
+              "Got bootstrap file location from GRPC_XDS_BOOTSTRAP "
+              "environment variable: %s",
+              path.get());
+    }
+    grpc_slice contents;
+    *error =
+        grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents);
+    if (*error != GRPC_ERROR_NONE) return "";
+    std::string contents_str(StringViewFromSlice(contents));
+    grpc_slice_unref_internal(contents);
+    return contents_str;
   }
-  auto xds_client = MakeRefCounted<XdsClient>(error);
-  g_xds_client = xds_client.get();
+  // Next, try GRPC_XDS_BOOTSTRAP_CONFIG env var.
+  grpc_core::UniquePtr<char> env_config(
+      gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG"));
+  if (env_config != nullptr) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
+      gpr_log(GPR_INFO,
+              "Got bootstrap contents from GRPC_XDS_BOOTSTRAP_CONFIG "
+              "environment variable");
+    }
+    return env_config.get();
+  }
+  // Finally, try fallback config.
+  if (fallback_config != nullptr) {
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
+      gpr_log(GPR_INFO, "Got bootstrap contents from fallback config");
+    }
+    return fallback_config;
+  }
+  // No bootstrap config found.
+  *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+      "Environment variables GRPC_XDS_BOOTSTRAP or GRPC_XDS_BOOTSTRAP_CONFIG "
+      "not defined");
+  return "";
+}
+
+}  // namespace
+
+RefCountedPtr<XdsClient> XdsClient::GetOrCreate(const grpc_channel_args* args,
+                                                grpc_error_handle* error) {
+  RefCountedPtr<XdsClient> xds_client;
+  // If getting bootstrap from channel args, create a local XdsClient
+  // instance for the channel or server instead of using the global instance.
+  const char* bootstrap_config = grpc_channel_args_find_string(
+      args, GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG);
+  if (bootstrap_config != nullptr) {
+    std::unique_ptr<XdsBootstrap> bootstrap =
+        XdsBootstrap::Create(bootstrap_config, error);
+    if (*error == GRPC_ERROR_NONE) {
+      grpc_channel_args* xds_channel_args =
+          grpc_channel_args_find_pointer<grpc_channel_args>(
+              args,
+              GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS);
+      return MakeRefCounted<XdsClient>(std::move(bootstrap), xds_channel_args);
+    }
+    return nullptr;
+  }
+  // Otherwise, use the global instance.
+  {
+    MutexLock lock(g_mu);
+    if (g_xds_client != nullptr) {
+      auto xds_client = g_xds_client->RefIfNonZero();
+      if (xds_client != nullptr) return xds_client;
+    }
+    // Find bootstrap contents.
+    std::string bootstrap_contents =
+        GetBootstrapContents(g_fallback_bootstrap_config, error);
+    if (*error != GRPC_ERROR_NONE) return nullptr;
+    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
+      gpr_log(GPR_INFO, "xDS bootstrap contents: %s",
+              bootstrap_contents.c_str());
+    }
+    // Parse bootstrap.
+    std::unique_ptr<XdsBootstrap> bootstrap =
+        XdsBootstrap::Create(bootstrap_contents, error);
+    if (*error != GRPC_ERROR_NONE) return nullptr;
+    // Instantiate XdsClient.
+    xds_client =
+        MakeRefCounted<XdsClient>(std::move(bootstrap), g_channel_args);
+    g_xds_client = xds_client.get();
+  }
   return xds_client;
 }
 
@@ -2232,6 +2451,66 @@
   g_xds_client = nullptr;
 }
 
+void SetXdsFallbackBootstrapConfig(const char* config) {
+  MutexLock lock(g_mu);
+  gpr_free(g_fallback_bootstrap_config);
+  g_fallback_bootstrap_config = gpr_strdup(config);
+}
+
 }  // namespace internal
 
+//
+// embedding XdsClient in channel args
+//
+
+#define GRPC_ARG_XDS_CLIENT "grpc.internal.xds_client"
+
+namespace {
+
+void* XdsClientArgCopy(void* p) {
+  XdsClient* xds_client = static_cast<XdsClient*>(p);
+  xds_client->Ref(DEBUG_LOCATION, "channel arg").release();
+  return p;
+}
+
+void XdsClientArgDestroy(void* p) {
+  XdsClient* xds_client = static_cast<XdsClient*>(p);
+  xds_client->Unref(DEBUG_LOCATION, "channel arg");
+}
+
+int XdsClientArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
+
+const grpc_arg_pointer_vtable kXdsClientArgVtable = {
+    XdsClientArgCopy, XdsClientArgDestroy, XdsClientArgCmp};
+
+}  // namespace
+
+grpc_arg XdsClient::MakeChannelArg() const {
+  return grpc_channel_arg_pointer_create(const_cast<char*>(GRPC_ARG_XDS_CLIENT),
+                                         const_cast<XdsClient*>(this),
+                                         &kXdsClientArgVtable);
+}
+
+RefCountedPtr<XdsClient> XdsClient::GetFromChannelArgs(
+    const grpc_channel_args& args) {
+  XdsClient* xds_client =
+      grpc_channel_args_find_pointer<XdsClient>(&args, GRPC_ARG_XDS_CLIENT);
+  if (xds_client == nullptr) return nullptr;
+  return xds_client->Ref(DEBUG_LOCATION, "GetFromChannelArgs");
+}
+
 }  // namespace grpc_core
+
+// The returned bytes may contain NULL(0), so we can't use c-string.
+grpc_slice grpc_dump_xds_configs() {
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  auto xds_client = grpc_core::XdsClient::GetOrCreate(nullptr, &error);
+  if (error != GRPC_ERROR_NONE) {
+    // If we isn't using xDS, just return an empty string.
+    GRPC_ERROR_UNREF(error);
+    return grpc_empty_slice();
+  }
+  return grpc_slice_from_cpp_string(xds_client->DumpClientConfigBinary());
+}
diff --git a/grpc/src/core/ext/xds/xds_client.h b/grpc/src/core/ext/xds/xds_client.h
index f1c6467..0ee84e7 100644
--- a/grpc/src/core/ext/xds/xds_client.h
+++ b/grpc/src/core/ext/xds/xds_client.h
@@ -48,7 +48,7 @@
    public:
     virtual ~ListenerWatcherInterface() = default;
     virtual void OnListenerChanged(XdsApi::LdsUpdate listener) = 0;
-    virtual void OnError(grpc_error* error) = 0;
+    virtual void OnError(grpc_error_handle error) = 0;
     virtual void OnResourceDoesNotExist() = 0;
   };
 
@@ -57,7 +57,7 @@
    public:
     virtual ~RouteConfigWatcherInterface() = default;
     virtual void OnRouteConfigChanged(XdsApi::RdsUpdate route_config) = 0;
-    virtual void OnError(grpc_error* error) = 0;
+    virtual void OnError(grpc_error_handle error) = 0;
     virtual void OnResourceDoesNotExist() = 0;
   };
 
@@ -66,7 +66,7 @@
    public:
     virtual ~ClusterWatcherInterface() = default;
     virtual void OnClusterChanged(XdsApi::CdsUpdate cluster_data) = 0;
-    virtual void OnError(grpc_error* error) = 0;
+    virtual void OnError(grpc_error_handle error) = 0;
     virtual void OnResourceDoesNotExist() = 0;
   };
 
@@ -75,19 +75,27 @@
    public:
     virtual ~EndpointWatcherInterface() = default;
     virtual void OnEndpointChanged(XdsApi::EdsUpdate update) = 0;
-    virtual void OnError(grpc_error* error) = 0;
+    virtual void OnError(grpc_error_handle error) = 0;
     virtual void OnResourceDoesNotExist() = 0;
   };
 
   // Factory function to get or create the global XdsClient instance.
   // If *error is not GRPC_ERROR_NONE upon return, then there was
   // an error initializing the client.
-  static RefCountedPtr<XdsClient> GetOrCreate(grpc_error** error);
+  static RefCountedPtr<XdsClient> GetOrCreate(const grpc_channel_args* args,
+                                              grpc_error_handle* error);
 
-  // Callers should not instantiate directly.  Use GetOrCreate() instead.
-  explicit XdsClient(grpc_error** error);
+  // Most callers should not instantiate directly.  Use GetOrCreate() instead.
+  XdsClient(std::unique_ptr<XdsBootstrap> bootstrap,
+            const grpc_channel_args* args);
   ~XdsClient() override;
 
+  const XdsBootstrap& bootstrap() const {
+    // bootstrap_ is guaranteed to be non-null since XdsClient::GetOrCreate()
+    // would return a null object if bootstrap_ was null.
+    return *bootstrap_;
+  }
+
   CertificateProviderStore& certificate_provider_store() {
     return *certificate_provider_store_;
   }
@@ -185,6 +193,20 @@
   // Resets connection backoff state.
   void ResetBackoff();
 
+  // Dumps the active xDS config in JSON format.
+  // Individual xDS resource is encoded as envoy.admin.v3.*ConfigDump. Returns
+  // envoy.service.status.v3.ClientConfig which also includes the config
+  // status (e.g., CLIENT_REQUESTED, CLIENT_ACKED, CLIENT_NACKED).
+  //
+  // Expected to be invoked by wrapper languages in their CSDS service
+  // implementation.
+  std::string DumpClientConfigBinary();
+
+  // Helpers for encoding the XdsClient object in channel args.
+  grpc_arg MakeChannelArg() const;
+  static RefCountedPtr<XdsClient> GetFromChannelArgs(
+      const grpc_channel_args& args);
+
  private:
   // Contains a channel to the xds server and all the data related to the
   // channel.  Holds a ref to the xds client object.
@@ -215,14 +237,17 @@
     void MaybeStartLrsCall();
     void StopLrsCall();
 
+    bool HasAdsCall() const;
     bool HasActiveAdsCall() const;
 
     void StartConnectivityWatchLocked();
     void CancelConnectivityWatchLocked();
 
-    void Subscribe(const std::string& type_url, const std::string& name);
-    void Unsubscribe(const std::string& type_url, const std::string& name,
-                     bool delay_unsubscription);
+    void SubscribeLocked(const std::string& type_url, const std::string& name)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
+    void UnsubscribeLocked(const std::string& type_url, const std::string& name,
+                           bool delay_unsubscription)
+        ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsClient::mu_);
 
    private:
     class StateWatcher;
@@ -248,6 +273,7 @@
         watchers;
     // The latest data seen from LDS.
     absl::optional<XdsApi::LdsUpdate> update;
+    XdsApi::ResourceMetadata meta;
   };
 
   struct RouteConfigState {
@@ -256,6 +282,7 @@
         watchers;
     // The latest data seen from RDS.
     absl::optional<XdsApi::RdsUpdate> update;
+    XdsApi::ResourceMetadata meta;
   };
 
   struct ClusterState {
@@ -263,6 +290,7 @@
         watchers;
     // The latest data seen from CDS.
     absl::optional<XdsApi::CdsUpdate> update;
+    XdsApi::ResourceMetadata meta;
   };
 
   struct EndpointState {
@@ -271,6 +299,7 @@
         watchers;
     // The latest data seen from EDS.
     absl::optional<XdsApi::EdsUpdate> update;
+    XdsApi::ResourceMetadata meta;
   };
 
   struct LoadReportState {
@@ -288,49 +317,63 @@
   };
 
   // Sends an error notification to all watchers.
-  void NotifyOnErrorLocked(grpc_error* error);
+  void NotifyOnErrorLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   XdsApi::ClusterLoadReportMap BuildLoadReportSnapshotLocked(
-      bool send_all_clusters, const std::set<std::string>& clusters);
+      bool send_all_clusters, const std::set<std::string>& clusters)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
+  void UpdateResourceMetadataWithFailedParseResultLocked(
+      grpc_millis update_time, const XdsApi::AdsParseResult& result)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
+
+  std::unique_ptr<XdsBootstrap> bootstrap_;
+  grpc_channel_args* args_;
   const grpc_millis request_timeout_;
   grpc_pollset_set* interested_parties_;
-  std::unique_ptr<XdsBootstrap> bootstrap_;
   OrphanablePtr<CertificateProviderStore> certificate_provider_store_;
   XdsApi api_;
 
   Mutex mu_;
 
   // The channel for communicating with the xds server.
-  OrphanablePtr<ChannelState> chand_;
+  OrphanablePtr<ChannelState> chand_ ABSL_GUARDED_BY(mu_);
 
   // One entry for each watched LDS resource.
-  std::map<std::string /*listener_name*/, ListenerState> listener_map_;
+  std::map<std::string /*listener_name*/, ListenerState> listener_map_
+      ABSL_GUARDED_BY(mu_);
   // One entry for each watched RDS resource.
   std::map<std::string /*route_config_name*/, RouteConfigState>
-      route_config_map_;
+      route_config_map_ ABSL_GUARDED_BY(mu_);
   // One entry for each watched CDS resource.
-  std::map<std::string /*cluster_name*/, ClusterState> cluster_map_;
+  std::map<std::string /*cluster_name*/, ClusterState> cluster_map_
+      ABSL_GUARDED_BY(mu_);
   // One entry for each watched EDS resource.
-  std::map<std::string /*eds_service_name*/, EndpointState> endpoint_map_;
+  std::map<std::string /*eds_service_name*/, EndpointState> endpoint_map_
+      ABSL_GUARDED_BY(mu_);
 
   // Load report data.
   std::map<
       std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>,
       LoadReportState>
-      load_report_map_;
+      load_report_map_ ABSL_GUARDED_BY(mu_);
 
   // Stores the most recent accepted resource version for each resource type.
-  std::map<std::string /*type*/, std::string /*version*/> resource_version_map_;
+  std::map<std::string /*type*/, std::string /*version*/> resource_version_map_
+      ABSL_GUARDED_BY(mu_);
 
-  bool shutting_down_ = false;
+  bool shutting_down_ ABSL_GUARDED_BY(mu_) = false;
 };
 
 namespace internal {
 void SetXdsChannelArgsForTest(grpc_channel_args* args);
 void UnsetGlobalXdsClientForTest();
+// Sets bootstrap config to be used when no env var is set.
+// Does not take ownership of config.
+void SetXdsFallbackBootstrapConfig(const char* config);
 }  // namespace internal
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_EXT_XDS_XDS_CLIENT_H */
+#endif  // GRPC_CORE_EXT_XDS_XDS_CLIENT_H
diff --git a/grpc/src/core/ext/xds/xds_client_stats.cc b/grpc/src/core/ext/xds/xds_client_stats.cc
index de401a7..c38ded2 100644
--- a/grpc/src/core/ext/xds/xds_client_stats.cc
+++ b/grpc/src/core/ext/xds/xds_client_stats.cc
@@ -137,7 +137,8 @@
                        // not related to a single reporting interval.
                        total_requests_in_progress_.Load(MemoryOrder::RELAXED),
                        GetAndResetCounter(&total_error_requests_),
-                       GetAndResetCounter(&total_issued_requests_)};
+                       GetAndResetCounter(&total_issued_requests_),
+                       {}};
   MutexLock lock(&backend_metrics_mu_);
   snapshot.backend_metrics = std::move(backend_metrics_);
   return snapshot;
diff --git a/grpc/src/core/ext/xds/xds_client_stats.h b/grpc/src/core/ext/xds/xds_client_stats.h
index 523ef11..b300fc5 100644
--- a/grpc/src/core/ext/xds/xds_client_stats.h
+++ b/grpc/src/core/ext/xds/xds_client_stats.h
@@ -56,10 +56,10 @@
     }
   };
 
-  XdsLocalityName(std::string region, std::string zone, std::string subzone)
+  XdsLocalityName(std::string region, std::string zone, std::string sub_zone)
       : region_(std::move(region)),
         zone_(std::move(zone)),
-        sub_zone_(std::move(subzone)) {}
+        sub_zone_(std::move(sub_zone)) {}
 
   bool operator==(const XdsLocalityName& other) const {
     return region_ == other.region_ && zone_ == other.zone_ &&
@@ -149,7 +149,7 @@
   // dropped_requests can be accessed by both the picker (from data plane
   // mutex) and the load reporting thread (from the control plane combiner).
   Mutex mu_;
-  CategorizedDropsMap categorized_drops_;
+  CategorizedDropsMap categorized_drops_ ABSL_GUARDED_BY(mu_);
 };
 
 // Locality stats for an xds cluster.
@@ -231,7 +231,8 @@
   // call's recv_trailing_metadata (not from the control plane work serializer)
   // and the load reporting thread (from the control plane work serializer).
   Mutex backend_metrics_mu_;
-  std::map<std::string, BackendMetric> backend_metrics_;
+  std::map<std::string, BackendMetric> backend_metrics_
+      ABSL_GUARDED_BY(backend_metrics_mu_);
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/ext/xds/xds_http_fault_filter.cc b/grpc/src/core/ext/xds/xds_http_fault_filter.cc
new file mode 100644
index 0000000..64b7a2b
--- /dev/null
+++ b/grpc/src/core/ext/xds/xds_http_fault_filter.cc
@@ -0,0 +1,226 @@
+//
+// Copyright 2021 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>
+
+#include "src/core/ext/xds/xds_http_fault_filter.h"
+
+#include <grpc/grpc.h>
+
+#include <string>
+
+#include "absl/status/statusor.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "envoy/extensions/filters/common/fault/v3/fault.upb.h"
+#include "envoy/extensions/filters/http/fault/v3/fault.upb.h"
+#include "envoy/extensions/filters/http/fault/v3/fault.upbdefs.h"
+#include "envoy/type/v3/percent.upb.h"
+#include "google/protobuf/any.upb.h"
+#include "google/protobuf/duration.upb.h"
+#include "google/protobuf/wrappers.upb.h"
+#include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
+#include "src/core/ext/xds/xds_http_filters.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/transport/status_conversion.h"
+#include "upb/def.h"
+
+namespace grpc_core {
+
+const char* kXdsHttpFaultFilterConfigName =
+    "envoy.extensions.filters.http.fault.v3.HTTPFault";
+
+namespace {
+
+uint32_t GetDenominator(const envoy_type_v3_FractionalPercent* fraction) {
+  if (fraction != nullptr) {
+    const auto denominator =
+        static_cast<envoy_type_v3_FractionalPercent_DenominatorType>(
+            envoy_type_v3_FractionalPercent_denominator(fraction));
+    switch (denominator) {
+      case envoy_type_v3_FractionalPercent_MILLION:
+        return 1000000;
+      case envoy_type_v3_FractionalPercent_TEN_THOUSAND:
+        return 10000;
+      case envoy_type_v3_FractionalPercent_HUNDRED:
+      default:
+        return 100;
+    }
+  }
+  // Use 100 as the default denominator
+  return 100;
+}
+
+absl::StatusOr<Json> ParseHttpFaultIntoJson(upb_strview serialized_http_fault,
+                                            upb_arena* arena) {
+  auto* http_fault = envoy_extensions_filters_http_fault_v3_HTTPFault_parse(
+      serialized_http_fault.data, serialized_http_fault.size, arena);
+  if (http_fault == nullptr) {
+    return absl::InvalidArgumentError(
+        "could not parse fault injection filter config");
+  }
+  // NOTE(lidiz): Here, we are manually translating the upb messages into the
+  // JSON form of the filter config as part of method config, which will be
+  // directly used later by service config. In this way, we can validate the
+  // filter configs, and NACK if needed. It also allows the service config to
+  // function independently without xDS, but not the other way around.
+  // NOTE(lidiz): please refer to FaultInjectionPolicy for ground truth
+  // definitions, located at:
+  // src/core/ext/filters/fault_injection/service_config_parser.h
+  Json::Object fault_injection_policy_json;
+  // Section 1: Parse the abort injection config
+  const auto* fault_abort =
+      envoy_extensions_filters_http_fault_v3_HTTPFault_abort(http_fault);
+  if (fault_abort != nullptr) {
+    grpc_status_code abort_grpc_status_code = GRPC_STATUS_OK;
+    // Try if gRPC status code is set first
+    int abort_grpc_status_code_raw =
+        envoy_extensions_filters_http_fault_v3_FaultAbort_grpc_status(
+            fault_abort);
+    if (abort_grpc_status_code_raw != 0) {
+      if (!grpc_status_code_from_int(abort_grpc_status_code_raw,
+                                     &abort_grpc_status_code)) {
+        return absl::InvalidArgumentError(absl::StrCat(
+            "invalid gRPC status code: ", abort_grpc_status_code_raw));
+      }
+    } else {
+      // if gRPC status code is empty, check http status
+      int abort_http_status_code =
+          envoy_extensions_filters_http_fault_v3_FaultAbort_http_status(
+              fault_abort);
+      if (abort_http_status_code != 0 and abort_http_status_code != 200) {
+        abort_grpc_status_code =
+            grpc_http2_status_to_grpc_status(abort_http_status_code);
+      }
+    }
+    // Set the abort_code, even if it's OK
+    fault_injection_policy_json["abortCode"] =
+        grpc_status_code_to_string(abort_grpc_status_code);
+    // Set the headers if we enabled header abort injection control
+    if (envoy_extensions_filters_http_fault_v3_FaultAbort_has_header_abort(
+            fault_abort)) {
+      fault_injection_policy_json["abortCodeHeader"] =
+          "x-envoy-fault-abort-grpc-request";
+      fault_injection_policy_json["abortPercentageHeader"] =
+          "x-envoy-fault-abort-percentage";
+    }
+    // Set the fraction percent
+    auto* percent =
+        envoy_extensions_filters_http_fault_v3_FaultAbort_percentage(
+            fault_abort);
+    fault_injection_policy_json["abortPercentageNumerator"] =
+        Json(envoy_type_v3_FractionalPercent_numerator(percent));
+    fault_injection_policy_json["abortPercentageDenominator"] =
+        Json(GetDenominator(percent));
+  }
+  // Section 2: Parse the delay injection config
+  const auto* fault_delay =
+      envoy_extensions_filters_http_fault_v3_HTTPFault_delay(http_fault);
+  if (fault_delay != nullptr) {
+    // Parse the delay duration
+    const auto* delay_duration =
+        envoy_extensions_filters_common_fault_v3_FaultDelay_fixed_delay(
+            fault_delay);
+    if (delay_duration != nullptr) {
+      fault_injection_policy_json["delay"] = absl::StrFormat(
+          "%d.%09ds", google_protobuf_Duration_seconds(delay_duration),
+          google_protobuf_Duration_nanos(delay_duration));
+    }
+    // Set the headers if we enabled header delay injection control
+    if (envoy_extensions_filters_common_fault_v3_FaultDelay_has_header_delay(
+            fault_delay)) {
+      fault_injection_policy_json["delayHeader"] =
+          "x-envoy-fault-delay-request";
+      fault_injection_policy_json["delayPercentageHeader"] =
+          "x-envoy-fault-delay-request-percentage";
+    }
+    // Set the fraction percent
+    auto* percent =
+        envoy_extensions_filters_common_fault_v3_FaultDelay_percentage(
+            fault_delay);
+    fault_injection_policy_json["delayPercentageNumerator"] =
+        Json(envoy_type_v3_FractionalPercent_numerator(percent));
+    fault_injection_policy_json["delayPercentageDenominator"] =
+        Json(GetDenominator(percent));
+  }
+  // Section 3: Parse the maximum active faults
+  const auto* max_fault_wrapper =
+      envoy_extensions_filters_http_fault_v3_HTTPFault_max_active_faults(
+          http_fault);
+  if (max_fault_wrapper != nullptr) {
+    fault_injection_policy_json["maxFaults"] =
+        google_protobuf_UInt32Value_value(max_fault_wrapper);
+  }
+  return fault_injection_policy_json;
+}
+
+}  // namespace
+
+void XdsHttpFaultFilter::PopulateSymtab(upb_symtab* symtab) const {
+  envoy_extensions_filters_http_fault_v3_HTTPFault_getmsgdef(symtab);
+}
+
+absl::StatusOr<XdsHttpFilterImpl::FilterConfig>
+XdsHttpFaultFilter::GenerateFilterConfig(upb_strview serialized_filter_config,
+                                         upb_arena* arena) const {
+  absl::StatusOr<Json> parse_result =
+      ParseHttpFaultIntoJson(serialized_filter_config, arena);
+  if (!parse_result.ok()) {
+    return parse_result.status();
+  }
+  return FilterConfig{kXdsHttpFaultFilterConfigName, std::move(*parse_result)};
+}
+
+absl::StatusOr<XdsHttpFilterImpl::FilterConfig>
+XdsHttpFaultFilter::GenerateFilterConfigOverride(
+    upb_strview serialized_filter_config, upb_arena* arena) const {
+  // HTTPFault filter has the same message type in HTTP connection manager's
+  // filter config and in overriding filter config field.
+  return GenerateFilterConfig(serialized_filter_config, arena);
+}
+
+const grpc_channel_filter* XdsHttpFaultFilter::channel_filter() const {
+  return &FaultInjectionFilterVtable;
+}
+
+grpc_channel_args* XdsHttpFaultFilter::ModifyChannelArgs(
+    grpc_channel_args* args) const {
+  grpc_arg args_to_add = grpc_channel_arg_integer_create(
+      const_cast<char*>(GRPC_ARG_PARSE_FAULT_INJECTION_METHOD_CONFIG), 1);
+  grpc_channel_args* new_args =
+      grpc_channel_args_copy_and_add(args, &args_to_add, 1);
+  // Since this function takes the ownership of the channel args, it needs to
+  // deallocate the old ones to prevent leak.
+  grpc_channel_args_destroy(args);
+  return new_args;
+}
+
+absl::StatusOr<XdsHttpFilterImpl::ServiceConfigJsonEntry>
+XdsHttpFaultFilter::GenerateServiceConfig(
+    const FilterConfig& hcm_filter_config,
+    const FilterConfig* filter_config_override) const {
+  Json policy_json = filter_config_override != nullptr
+                         ? filter_config_override->config
+                         : hcm_filter_config.config;
+  // The policy JSON may be empty, that's allowed.
+  return ServiceConfigJsonEntry{"faultInjectionPolicy", policy_json.Dump()};
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/ext/xds/xds_http_fault_filter.h b/grpc/src/core/ext/xds/xds_http_fault_filter.h
new file mode 100644
index 0000000..60c4952
--- /dev/null
+++ b/grpc/src/core/ext/xds/xds_http_fault_filter.h
@@ -0,0 +1,63 @@
+//
+// Copyright 2021 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_XDS_XDS_HTTP_FAULT_FILTER_H
+#define GRPC_CORE_EXT_XDS_XDS_HTTP_FAULT_FILTER_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc.h>
+
+#include "absl/status/statusor.h"
+#include "src/core/ext/xds/xds_http_filters.h"
+#include "upb/def.h"
+
+namespace grpc_core {
+
+extern const char* kXdsHttpFaultFilterConfigName;
+
+class XdsHttpFaultFilter : public XdsHttpFilterImpl {
+ public:
+  // Overrides the PopulateSymtab method
+  void PopulateSymtab(upb_symtab* symtab) const override;
+
+  // Overrides the GenerateFilterConfig method
+  absl::StatusOr<FilterConfig> GenerateFilterConfig(
+      upb_strview serialized_filter_config, upb_arena* arena) const override;
+
+  // Overrides the GenerateFilterConfigOverride method
+  absl::StatusOr<FilterConfig> GenerateFilterConfigOverride(
+      upb_strview serialized_filter_config, upb_arena* arena) const override;
+
+  // Overrides the channel_filter method
+  const grpc_channel_filter* channel_filter() const override;
+
+  // Overrides the ModifyChannelArgs method
+  grpc_channel_args* ModifyChannelArgs(grpc_channel_args* args) const override;
+
+  // Overrides the GenerateServiceConfig method
+  absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
+      const FilterConfig& hcm_filter_config,
+      const FilterConfig* filter_config_override) const override;
+
+  bool IsSupportedOnClients() const override { return true; }
+
+  bool IsSupportedOnServers() const override { return false; }
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_EXT_XDS_XDS_HTTP_FAULT_FILTER_H */
diff --git a/grpc/src/core/ext/xds/xds_http_filters.cc b/grpc/src/core/ext/xds/xds_http_filters.cc
new file mode 100644
index 0000000..9bd4858
--- /dev/null
+++ b/grpc/src/core/ext/xds/xds_http_filters.cc
@@ -0,0 +1,114 @@
+//
+// Copyright 2021 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>
+
+#include "src/core/ext/xds/xds_http_filters.h"
+
+#include "envoy/extensions/filters/http/router/v3/router.upb.h"
+#include "envoy/extensions/filters/http/router/v3/router.upbdefs.h"
+#include "src/core/ext/xds/xds_http_fault_filter.h"
+
+namespace grpc_core {
+
+const char* kXdsHttpRouterFilterConfigName =
+    "envoy.extensions.filters.http.router.v3.Router";
+
+namespace {
+
+class XdsHttpRouterFilter : public XdsHttpFilterImpl {
+ public:
+  void PopulateSymtab(upb_symtab* symtab) const override {
+    envoy_extensions_filters_http_router_v3_Router_getmsgdef(symtab);
+  }
+
+  absl::StatusOr<FilterConfig> GenerateFilterConfig(
+      upb_strview serialized_filter_config, upb_arena* arena) const override {
+    if (envoy_extensions_filters_http_router_v3_Router_parse(
+            serialized_filter_config.data, serialized_filter_config.size,
+            arena) == nullptr) {
+      return absl::InvalidArgumentError("could not parse router filter config");
+    }
+    return FilterConfig{kXdsHttpRouterFilterConfigName, Json()};
+  }
+
+  absl::StatusOr<FilterConfig> GenerateFilterConfigOverride(
+      upb_strview /*serialized_filter_config*/,
+      upb_arena* /*arena*/) const override {
+    return absl::InvalidArgumentError(
+        "router filter does not support config override");
+  }
+
+  // No-op -- this filter is special-cased by the xds resolver.
+  const grpc_channel_filter* channel_filter() const override { return nullptr; }
+
+  // No-op -- this filter is special-cased by the xds resolver.
+  absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
+      const FilterConfig& /*hcm_filter_config*/,
+      const FilterConfig* /*filter_config_override*/) const override {
+    return absl::UnimplementedError("router filter should never be called");
+  }
+
+  bool IsSupportedOnClients() const override { return true; }
+
+  bool IsSupportedOnServers() const override { return true; }
+};
+
+using FilterOwnerList = std::vector<std::unique_ptr<XdsHttpFilterImpl>>;
+using FilterRegistryMap = std::map<absl::string_view, XdsHttpFilterImpl*>;
+
+FilterOwnerList* g_filters = nullptr;
+FilterRegistryMap* g_filter_registry = nullptr;
+
+}  // namespace
+
+void XdsHttpFilterRegistry::RegisterFilter(
+    std::unique_ptr<XdsHttpFilterImpl> filter,
+    const std::set<absl::string_view>& config_proto_type_names) {
+  for (auto config_proto_type_name : config_proto_type_names) {
+    (*g_filter_registry)[config_proto_type_name] = filter.get();
+  }
+  g_filters->push_back(std::move(filter));
+}
+
+const XdsHttpFilterImpl* XdsHttpFilterRegistry::GetFilterForType(
+    absl::string_view proto_type_name) {
+  auto it = g_filter_registry->find(proto_type_name);
+  if (it == g_filter_registry->end()) return nullptr;
+  return it->second;
+}
+
+void XdsHttpFilterRegistry::PopulateSymtab(upb_symtab* symtab) {
+  for (const auto& filter : *g_filters) {
+    filter->PopulateSymtab(symtab);
+  }
+}
+
+void XdsHttpFilterRegistry::Init() {
+  g_filters = new FilterOwnerList;
+  g_filter_registry = new FilterRegistryMap;
+  RegisterFilter(absl::make_unique<XdsHttpRouterFilter>(),
+                 {kXdsHttpRouterFilterConfigName});
+  RegisterFilter(absl::make_unique<XdsHttpFaultFilter>(),
+                 {kXdsHttpFaultFilterConfigName});
+}
+
+void XdsHttpFilterRegistry::Shutdown() {
+  delete g_filter_registry;
+  delete g_filters;
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/ext/xds/xds_http_filters.h b/grpc/src/core/ext/xds/xds_http_filters.h
new file mode 100644
index 0000000..3324196
--- /dev/null
+++ b/grpc/src/core/ext/xds/xds_http_filters.h
@@ -0,0 +1,130 @@
+//
+// Copyright 2021 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_XDS_XDS_HTTP_FILTERS_H
+#define GRPC_CORE_EXT_XDS_XDS_HTTP_FILTERS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "absl/status/statusor.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "google/protobuf/any.upb.h"
+#include "upb/def.h"
+
+#include <grpc/grpc.h>
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/json/json.h"
+
+namespace grpc_core {
+
+extern const char* kXdsHttpRouterFilterConfigName;
+
+class XdsHttpFilterImpl {
+ public:
+  struct FilterConfig {
+    absl::string_view config_proto_type_name;
+    Json config;
+
+    bool operator==(const FilterConfig& other) const {
+      return config_proto_type_name == other.config_proto_type_name &&
+             config == other.config;
+    }
+    std::string ToString() const {
+      return absl::StrCat("{config_proto_type_name=", config_proto_type_name,
+                          " config=", config.Dump(), "}");
+    }
+  };
+
+  // Service config data for the filter, returned by GenerateServiceConfig().
+  struct ServiceConfigJsonEntry {
+    // The top-level field name in the method config.
+    // Filter implementations should use their primary config proto type
+    // name for this.
+    // The value of this field in the method config will be a JSON array,
+    // which will be populated with the elements returned by each filter
+    // instance.
+    std::string service_config_field_name;
+    // The element to add to the JSON array.
+    std::string element;
+  };
+
+  virtual ~XdsHttpFilterImpl() = default;
+
+  // Loads the proto message into the upb symtab.
+  virtual void PopulateSymtab(upb_symtab* symtab) const = 0;
+
+  // Generates a Config from the xDS filter config proto.
+  // Used for the top-level config in the HCM HTTP filter list.
+  virtual absl::StatusOr<FilterConfig> GenerateFilterConfig(
+      upb_strview serialized_filter_config, upb_arena* arena) const = 0;
+
+  // Generates a Config from the xDS filter config proto.
+  // Used for the typed_per_filter_config override in VirtualHost and Route.
+  virtual absl::StatusOr<FilterConfig> GenerateFilterConfigOverride(
+      upb_strview serialized_filter_config, upb_arena* arena) const = 0;
+
+  // C-core channel filter implementation.
+  virtual const grpc_channel_filter* channel_filter() const = 0;
+
+  // Modifies channel args that may affect service config parsing (not
+  // visible to the channel as a whole).
+  // Takes ownership of args.  Caller takes ownership of return value.
+  virtual grpc_channel_args* ModifyChannelArgs(grpc_channel_args* args) const {
+    return args;
+  }
+
+  // Function to convert the Configs into a JSON string to be added to the
+  // per-method part of the service config.
+  // The hcm_filter_config comes from the HttpConnectionManager config.
+  // The filter_config_override comes from the first of the ClusterWeight,
+  // Route, or VirtualHost entries that it is found in, or null if
+  // there is no override in any of those locations.
+  virtual absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
+      const FilterConfig& hcm_filter_config,
+      const FilterConfig* filter_config_override) const = 0;
+
+  // Returns true if the filter is supported on clients; false otherwise
+  virtual bool IsSupportedOnClients() const = 0;
+
+  // Returns true if the filter is supported on servers; false otherwise
+  virtual bool IsSupportedOnServers() const = 0;
+};
+
+class XdsHttpFilterRegistry {
+ public:
+  static void RegisterFilter(
+      std::unique_ptr<XdsHttpFilterImpl> filter,
+      const std::set<absl::string_view>& config_proto_type_names);
+
+  static const XdsHttpFilterImpl* GetFilterForType(
+      absl::string_view proto_type_name);
+
+  static void PopulateSymtab(upb_symtab* symtab);
+
+  // Global init and shutdown.
+  static void Init();
+  static void Shutdown();
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_EXT_XDS_XDS_HTTP_FILTERS_H */
diff --git a/grpc/src/core/ext/xds/xds_server_config_fetcher.cc b/grpc/src/core/ext/xds/xds_server_config_fetcher.cc
index 5c5e8ee..962731f 100644
--- a/grpc/src/core/ext/xds/xds_server_config_fetcher.cc
+++ b/grpc/src/core/ext/xds/xds_server_config_fetcher.cc
@@ -18,32 +18,354 @@
 
 #include <grpc/support/port_platform.h>
 
+#include "absl/strings/str_replace.h"
+
+#include "src/core/ext/xds/xds_certificate_provider.h"
 #include "src/core/ext/xds/xds_client.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gprpp/host_port.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
+#include "src/core/lib/security/credentials/xds/xds_credentials.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/server.h"
+#include "src/core/lib/uri/uri_parser.h"
 
 namespace grpc_core {
+
+TraceFlag grpc_xds_server_config_fetcher_trace(false,
+                                               "xds_server_config_fetcher");
+
 namespace {
 
+class FilterChainMatchManager
+    : public grpc_server_config_fetcher::ConnectionManager {
+ public:
+  FilterChainMatchManager(
+      RefCountedPtr<XdsClient> xds_client,
+      XdsApi::LdsUpdate::FilterChainMap filter_chain_map,
+      absl::optional<XdsApi::LdsUpdate::FilterChainData> default_filter_chain)
+      : xds_client_(xds_client),
+        filter_chain_map_(std::move(filter_chain_map)),
+        default_filter_chain_(std::move(default_filter_chain)) {}
+
+  absl::StatusOr<grpc_channel_args*> UpdateChannelArgsForConnection(
+      grpc_channel_args* args, grpc_endpoint* tcp) override;
+
+  const XdsApi::LdsUpdate::FilterChainMap& filter_chain_map() const {
+    return filter_chain_map_;
+  }
+
+  const absl::optional<XdsApi::LdsUpdate::FilterChainData>&
+  default_filter_chain() const {
+    return default_filter_chain_;
+  }
+
+ private:
+  struct CertificateProviders {
+    // We need to save our own refs to the root and instance certificate
+    // providers since the xds certificate provider just stores a ref to their
+    // distributors.
+    RefCountedPtr<grpc_tls_certificate_provider> root;
+    RefCountedPtr<grpc_tls_certificate_provider> instance;
+    RefCountedPtr<XdsCertificateProvider> xds;
+  };
+
+  absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
+  CreateOrGetXdsCertificateProviderFromFilterChainData(
+      const XdsApi::LdsUpdate::FilterChainData* filter_chain);
+
+  const RefCountedPtr<XdsClient> xds_client_;
+  const XdsApi::LdsUpdate::FilterChainMap filter_chain_map_;
+  const absl::optional<XdsApi::LdsUpdate::FilterChainData>
+      default_filter_chain_;
+  Mutex mu_;
+  std::map<const XdsApi::LdsUpdate::FilterChainData*, CertificateProviders>
+      certificate_providers_map_ ABSL_GUARDED_BY(mu_);
+};
+
+bool IsLoopbackIp(const grpc_resolved_address* address) {
+  const grpc_sockaddr* sock_addr =
+      reinterpret_cast<const grpc_sockaddr*>(&address->addr);
+  if (sock_addr->sa_family == GRPC_AF_INET) {
+    const grpc_sockaddr_in* addr4 =
+        reinterpret_cast<const grpc_sockaddr_in*>(sock_addr);
+    if (addr4->sin_addr.s_addr == grpc_htonl(INADDR_LOOPBACK)) {
+      return true;
+    }
+  } else if (sock_addr->sa_family == GRPC_AF_INET6) {
+    const grpc_sockaddr_in6* addr6 =
+        reinterpret_cast<const grpc_sockaddr_in6*>(sock_addr);
+    if (memcmp(&addr6->sin6_addr, &in6addr_loopback,
+               sizeof(in6addr_loopback)) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourcePort(
+    const XdsApi::LdsUpdate::FilterChainMap::SourcePortsMap& source_ports_map,
+    absl::string_view port_str) {
+  int port = 0;
+  if (!absl::SimpleAtoi(port_str, &port)) return nullptr;
+  auto it = source_ports_map.find(port);
+  if (it != source_ports_map.end()) {
+    return it->second.data.get();
+  }
+  // Search for the catch-all port 0 since we didn't get a direct match
+  it = source_ports_map.find(0);
+  if (it != source_ports_map.end()) {
+    return it->second.data.get();
+  }
+  return nullptr;
+}
+
+const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourceIp(
+    const XdsApi::LdsUpdate::FilterChainMap::SourceIpVector& source_ip_vector,
+    const grpc_resolved_address* source_ip, absl::string_view port) {
+  const XdsApi::LdsUpdate::FilterChainMap::SourceIp* best_match = nullptr;
+  for (const auto& entry : source_ip_vector) {
+    // Special case for catch-all
+    if (!entry.prefix_range.has_value()) {
+      if (best_match == nullptr) {
+        best_match = &entry;
+      }
+      continue;
+    }
+    if (best_match != nullptr && best_match->prefix_range.has_value() &&
+        best_match->prefix_range->prefix_len >=
+            entry.prefix_range->prefix_len) {
+      continue;
+    }
+    if (grpc_sockaddr_match_subnet(source_ip, &entry.prefix_range->address,
+                                   entry.prefix_range->prefix_len)) {
+      best_match = &entry;
+    }
+  }
+  if (best_match == nullptr) return nullptr;
+  return FindFilterChainDataForSourcePort(best_match->ports_map, port);
+}
+
+const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForSourceType(
+    const XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceTypesArray&
+        source_types_array,
+    grpc_endpoint* tcp, absl::string_view destination_ip) {
+  auto source_uri = URI::Parse(grpc_endpoint_get_peer(tcp));
+  if (!source_uri.ok() ||
+      (source_uri->scheme() != "ipv4" && source_uri->scheme() != "ipv6")) {
+    return nullptr;
+  }
+  std::string host;
+  std::string port;
+  if (!SplitHostPort(source_uri->path(), &host, &port)) {
+    return nullptr;
+  }
+  grpc_resolved_address source_addr;
+  grpc_error_handle error = grpc_string_to_sockaddr(
+      &source_addr, host.c_str(), 0 /* port doesn't matter here */);
+  if (error != GRPC_ERROR_NONE) {
+    gpr_log(GPR_DEBUG, "Could not parse string to socket address: %s",
+            host.c_str());
+    GRPC_ERROR_UNREF(error);
+    return nullptr;
+  }
+  // Use kAny only if kSameIporLoopback and kExternal are empty
+  if (source_types_array[static_cast<int>(
+                             XdsApi::LdsUpdate::FilterChainMap::
+                                 ConnectionSourceType::kSameIpOrLoopback)]
+          .empty() &&
+      source_types_array[static_cast<int>(XdsApi::LdsUpdate::FilterChainMap::
+                                              ConnectionSourceType::kExternal)]
+          .empty()) {
+    return FindFilterChainDataForSourceIp(
+        source_types_array[static_cast<int>(
+            XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::kAny)],
+        &source_addr, port);
+  }
+  if (IsLoopbackIp(&source_addr) || host == destination_ip) {
+    return FindFilterChainDataForSourceIp(
+        source_types_array[static_cast<int>(
+            XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::
+                kSameIpOrLoopback)],
+        &source_addr, port);
+  } else {
+    return FindFilterChainDataForSourceIp(
+        source_types_array[static_cast<int>(
+            XdsApi::LdsUpdate::FilterChainMap::ConnectionSourceType::
+                kExternal)],
+        &source_addr, port);
+  }
+}
+
+const XdsApi::LdsUpdate::FilterChainData* FindFilterChainDataForDestinationIp(
+    const XdsApi::LdsUpdate::FilterChainMap::DestinationIpVector
+        destination_ip_vector,
+    grpc_endpoint* tcp) {
+  auto destination_uri = URI::Parse(grpc_endpoint_get_local_address(tcp));
+  if (!destination_uri.ok() || (destination_uri->scheme() != "ipv4" &&
+                                destination_uri->scheme() != "ipv6")) {
+    return nullptr;
+  }
+  std::string host;
+  std::string port;
+  if (!SplitHostPort(destination_uri->path(), &host, &port)) {
+    return nullptr;
+  }
+  grpc_resolved_address destination_addr;
+  grpc_error_handle error = grpc_string_to_sockaddr(
+      &destination_addr, host.c_str(), 0 /* port doesn't matter here */);
+  if (error != GRPC_ERROR_NONE) {
+    gpr_log(GPR_DEBUG, "Could not parse string to socket address: %s",
+            host.c_str());
+    GRPC_ERROR_UNREF(error);
+    return nullptr;
+  }
+  const XdsApi::LdsUpdate::FilterChainMap::DestinationIp* best_match = nullptr;
+  for (const auto& entry : destination_ip_vector) {
+    // Special case for catch-all
+    if (!entry.prefix_range.has_value()) {
+      if (best_match == nullptr) {
+        best_match = &entry;
+      }
+      continue;
+    }
+    if (best_match != nullptr && best_match->prefix_range.has_value() &&
+        best_match->prefix_range->prefix_len >=
+            entry.prefix_range->prefix_len) {
+      continue;
+    }
+    if (grpc_sockaddr_match_subnet(&destination_addr,
+                                   &entry.prefix_range->address,
+                                   entry.prefix_range->prefix_len)) {
+      best_match = &entry;
+    }
+  }
+  if (best_match == nullptr) return nullptr;
+  return FindFilterChainDataForSourceType(best_match->source_types_array, tcp,
+                                          host);
+}
+
+absl::StatusOr<RefCountedPtr<XdsCertificateProvider>>
+FilterChainMatchManager::CreateOrGetXdsCertificateProviderFromFilterChainData(
+    const XdsApi::LdsUpdate::FilterChainData* filter_chain) {
+  MutexLock lock(&mu_);
+  auto it = certificate_providers_map_.find(filter_chain);
+  if (it != certificate_providers_map_.end()) {
+    return it->second.xds;
+  }
+  CertificateProviders certificate_providers;
+  // Configure root cert.
+  absl::string_view root_provider_instance_name =
+      filter_chain->downstream_tls_context.common_tls_context
+          .combined_validation_context
+          .validation_context_certificate_provider_instance.instance_name;
+  absl::string_view root_provider_cert_name =
+      filter_chain->downstream_tls_context.common_tls_context
+          .combined_validation_context
+          .validation_context_certificate_provider_instance.certificate_name;
+  if (!root_provider_instance_name.empty()) {
+    certificate_providers.root =
+        xds_client_->certificate_provider_store()
+            .CreateOrGetCertificateProvider(root_provider_instance_name);
+    if (certificate_providers.root == nullptr) {
+      return absl::NotFoundError(
+          absl::StrCat("Certificate provider instance name: \"",
+                       root_provider_instance_name, "\" not recognized."));
+    }
+  }
+  // Configure identity cert.
+  absl::string_view identity_provider_instance_name =
+      filter_chain->downstream_tls_context.common_tls_context
+          .tls_certificate_certificate_provider_instance.instance_name;
+  absl::string_view identity_provider_cert_name =
+      filter_chain->downstream_tls_context.common_tls_context
+          .tls_certificate_certificate_provider_instance.certificate_name;
+  if (!identity_provider_instance_name.empty()) {
+    certificate_providers.instance =
+        xds_client_->certificate_provider_store()
+            .CreateOrGetCertificateProvider(identity_provider_instance_name);
+    if (certificate_providers.instance == nullptr) {
+      return absl::NotFoundError(
+          absl::StrCat("Certificate provider instance name: \"",
+                       identity_provider_instance_name, "\" not recognized."));
+    }
+  }
+  certificate_providers.xds = MakeRefCounted<XdsCertificateProvider>();
+  certificate_providers.xds->UpdateRootCertNameAndDistributor(
+      "", root_provider_cert_name,
+      certificate_providers.root == nullptr
+          ? nullptr
+          : certificate_providers.root->distributor());
+  certificate_providers.xds->UpdateIdentityCertNameAndDistributor(
+      "", identity_provider_cert_name,
+      certificate_providers.instance == nullptr
+          ? nullptr
+          : certificate_providers.instance->distributor());
+  certificate_providers.xds->UpdateRequireClientCertificate(
+      "", filter_chain->downstream_tls_context.require_client_certificate);
+  auto xds_certificate_provider = certificate_providers.xds;
+  certificate_providers_map_.emplace(filter_chain,
+                                     std::move(certificate_providers));
+  return xds_certificate_provider;
+}
+
+absl::StatusOr<grpc_channel_args*>
+FilterChainMatchManager::UpdateChannelArgsForConnection(grpc_channel_args* args,
+                                                        grpc_endpoint* tcp) {
+  const auto* filter_chain = FindFilterChainDataForDestinationIp(
+      filter_chain_map_.destination_ip_vector, tcp);
+  if (filter_chain == nullptr && default_filter_chain_.has_value()) {
+    filter_chain = &default_filter_chain_.value();
+  }
+  if (filter_chain == nullptr) {
+    grpc_channel_args_destroy(args);
+    return absl::UnavailableError("No matching filter chain found");
+  }
+  // Nothing to update if credentials are not xDS.
+  grpc_server_credentials* server_creds =
+      grpc_find_server_credentials_in_args(args);
+  if (server_creds == nullptr || server_creds->type() != kCredentialsTypeXds) {
+    return args;
+  }
+  absl::StatusOr<RefCountedPtr<XdsCertificateProvider>> result =
+      CreateOrGetXdsCertificateProviderFromFilterChainData(filter_chain);
+  if (!result.ok()) {
+    grpc_channel_args_destroy(args);
+    return result.status();
+  }
+  RefCountedPtr<XdsCertificateProvider> xds_certificate_provider =
+      std::move(*result);
+  GPR_ASSERT(xds_certificate_provider != nullptr);
+  grpc_arg arg_to_add = xds_certificate_provider->MakeChannelArg();
+  grpc_channel_args* updated_args =
+      grpc_channel_args_copy_and_add(args, &arg_to_add, 1);
+  grpc_channel_args_destroy(args);
+  return updated_args;
+}
+
 class XdsServerConfigFetcher : public grpc_server_config_fetcher {
  public:
-  explicit XdsServerConfigFetcher(RefCountedPtr<XdsClient> xds_client)
-      : xds_client_(std::move(xds_client)) {
+  explicit XdsServerConfigFetcher(RefCountedPtr<XdsClient> xds_client,
+                                  grpc_server_xds_status_notifier notifier)
+      : xds_client_(std::move(xds_client)), serving_status_notifier_(notifier) {
     GPR_ASSERT(xds_client_ != nullptr);
   }
 
-  void StartWatch(std::string listening_address,
+  void StartWatch(std::string listening_address, grpc_channel_args* args,
                   std::unique_ptr<grpc_server_config_fetcher::WatcherInterface>
                       watcher) override {
     grpc_server_config_fetcher::WatcherInterface* watcher_ptr = watcher.get();
-    auto listener_watcher =
-        absl::make_unique<ListenerWatcher>(std::move(watcher));
+    auto listener_watcher = absl::make_unique<ListenerWatcher>(
+        std::move(watcher), args, xds_client_, serving_status_notifier_,
+        listening_address);
     auto* listener_watcher_ptr = listener_watcher.get();
-    // TODO(yashykt): Get the resource name id from bootstrap
-    xds_client_->WatchListenerData(
-        absl::StrCat("grpc/server?xds.resource.listening_address=",
-                     listening_address),
-        std::move(listener_watcher));
+    listening_address = absl::StrReplaceAll(
+        xds_client_->bootstrap().server_listener_resource_name_template(),
+        {{"%s", listening_address}});
+    xds_client_->WatchListenerData(listening_address,
+                                   std::move(listener_watcher));
     MutexLock lock(&mu_);
     auto& watcher_state = watchers_[watcher_ptr];
     watcher_state.listening_address = listening_address;
@@ -73,32 +395,114 @@
    public:
     explicit ListenerWatcher(
         std::unique_ptr<grpc_server_config_fetcher::WatcherInterface>
-            server_config_watcher)
-        : server_config_watcher_(std::move(server_config_watcher)) {}
+            server_config_watcher,
+        grpc_channel_args* args, RefCountedPtr<XdsClient> xds_client,
+        grpc_server_xds_status_notifier serving_status_notifier,
+        std::string listening_address)
+        : server_config_watcher_(std::move(server_config_watcher)),
+          args_(args),
+          xds_client_(std::move(xds_client)),
+          serving_status_notifier_(serving_status_notifier),
+          listening_address_(std::move(listening_address)) {}
+
+    ~ListenerWatcher() override { grpc_channel_args_destroy(args_); }
+
+    // Deleted due to special handling required for args_. Copy the channel args
+    // if we ever need these.
+    ListenerWatcher(const ListenerWatcher&) = delete;
+    ListenerWatcher& operator=(const ListenerWatcher&) = delete;
 
     void OnListenerChanged(XdsApi::LdsUpdate listener) override {
-      // TODO(yashykt): Construct channel args according to received update
-      server_config_watcher_->UpdateConfig(nullptr);
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_server_config_fetcher_trace)) {
+        gpr_log(
+            GPR_INFO,
+            "[ListenerWatcher %p] Received LDS update from xds client %p: %s",
+            this, xds_client_.get(), listener.ToString().c_str());
+      }
+      if (listener.address != listening_address_) {
+        OnFatalError(absl::FailedPreconditionError(
+            "Address in LDS update does not match listening address"));
+        return;
+      }
+      if (filter_chain_match_manager_ == nullptr) {
+        if (serving_status_notifier_.on_serving_status_update != nullptr) {
+          serving_status_notifier_.on_serving_status_update(
+              serving_status_notifier_.user_data, listening_address_.c_str(),
+              GRPC_STATUS_OK, "");
+        } else {
+          gpr_log(GPR_INFO,
+                  "xDS Listener resource obtained; will start serving on %s",
+                  listening_address_.c_str());
+        }
+      }
+      if (filter_chain_match_manager_ == nullptr ||
+          !(listener.filter_chain_map ==
+                filter_chain_match_manager_->filter_chain_map() &&
+            listener.default_filter_chain ==
+                filter_chain_match_manager_->default_filter_chain())) {
+        filter_chain_match_manager_ = MakeRefCounted<FilterChainMatchManager>(
+            xds_client_, std::move(listener.filter_chain_map),
+            std::move(listener.default_filter_chain));
+        server_config_watcher_->UpdateConnectionManager(
+            filter_chain_match_manager_);
+      }
     }
 
-    void OnError(grpc_error* error) override {
-      gpr_log(GPR_ERROR, "ListenerWatcher:%p XdsClient reports error: %s", this,
-              grpc_error_string(error));
+    void OnError(grpc_error_handle error) override {
+      if (filter_chain_match_manager_ != nullptr) {
+        gpr_log(GPR_ERROR,
+                "ListenerWatcher:%p XdsClient reports error: %s for %s; "
+                "ignoring in favor of existing resource",
+                this, grpc_error_std_string(error).c_str(),
+                listening_address_.c_str());
+      } else {
+        if (serving_status_notifier_.on_serving_status_update != nullptr) {
+          serving_status_notifier_.on_serving_status_update(
+              serving_status_notifier_.user_data, listening_address_.c_str(),
+              GRPC_STATUS_UNAVAILABLE, grpc_error_std_string(error).c_str());
+        } else {
+          gpr_log(
+              GPR_ERROR,
+              "ListenerWatcher:%p error obtaining xDS Listener resource: %s; "
+              "not serving on %s",
+              this, grpc_error_std_string(error).c_str(),
+              listening_address_.c_str());
+        }
+      }
       GRPC_ERROR_UNREF(error);
-      // TODO(yashykt): We might want to bubble this error to the application.
+    }
+
+    void OnFatalError(absl::Status status) {
+      gpr_log(
+          GPR_ERROR,
+          "ListenerWatcher:%p Encountered fatal error %s; not serving on %s",
+          this, status.ToString().c_str(), listening_address_.c_str());
+      if (filter_chain_match_manager_ != nullptr) {
+        // The server has started listening already, so we need to gracefully
+        // stop serving.
+        server_config_watcher_->StopServing();
+        filter_chain_match_manager_.reset();
+      }
+      if (serving_status_notifier_.on_serving_status_update != nullptr) {
+        serving_status_notifier_.on_serving_status_update(
+            serving_status_notifier_.user_data, listening_address_.c_str(),
+            static_cast<grpc_status_code>(status.raw_code()),
+            std::string(status.message()).c_str());
+      }
     }
 
     void OnResourceDoesNotExist() override {
-      gpr_log(GPR_ERROR,
-              "ListenerWatcher:%p XdsClient reports requested listener does "
-              "not exist",
-              this);
-      // TODO(yashykt): We might want to bubble this error to the application.
+      OnFatalError(absl::NotFoundError("Requested listener does not exist"));
     }
 
    private:
     std::unique_ptr<grpc_server_config_fetcher::WatcherInterface>
         server_config_watcher_;
+    grpc_channel_args* args_;
+    RefCountedPtr<XdsClient> xds_client_;
+    grpc_server_xds_status_notifier serving_status_notifier_;
+    std::string listening_address_;
+    RefCountedPtr<FilterChainMatchManager> filter_chain_match_manager_;
   };
 
   struct WatcherState {
@@ -107,25 +511,36 @@
   };
 
   RefCountedPtr<XdsClient> xds_client_;
+  grpc_server_xds_status_notifier serving_status_notifier_;
   Mutex mu_;
   std::map<grpc_server_config_fetcher::WatcherInterface*, WatcherState>
-      watchers_;
+      watchers_ ABSL_GUARDED_BY(mu_);
 };
 
 }  // namespace
 }  // namespace grpc_core
 
-grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create() {
+grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create(
+    grpc_server_xds_status_notifier notifier, const grpc_channel_args* args) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   GRPC_API_TRACE("grpc_server_config_fetcher_xds_create()", 0, ());
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::RefCountedPtr<grpc_core::XdsClient> xds_client =
-      grpc_core::XdsClient::GetOrCreate(&error);
+      grpc_core::XdsClient::GetOrCreate(args, &error);
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "Failed to create xds client: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
+    GRPC_ERROR_UNREF(error);
     return nullptr;
   }
-  return new grpc_core::XdsServerConfigFetcher(std::move(xds_client));
+  if (xds_client->bootstrap()
+          .server_listener_resource_name_template()
+          .empty()) {
+    gpr_log(GPR_ERROR,
+            "server_listener_resource_name_template not provided in bootstrap "
+            "file.");
+    return nullptr;
+  }
+  return new grpc_core::XdsServerConfigFetcher(std::move(xds_client), notifier);
 }
diff --git a/grpc/src/core/lib/iomgr/parse_address.cc b/grpc/src/core/lib/address_utils/parse_address.cc
similarity index 89%
rename from grpc/src/core/lib/iomgr/parse_address.cc
rename to grpc/src/core/lib/address_utils/parse_address.cc
index 9afac74..98dd1bc 100644
--- a/grpc/src/core/lib/iomgr/parse_address.cc
+++ b/grpc/src/core/lib/address_utils/parse_address.cc
@@ -18,7 +18,7 @@
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/lib/iomgr/parse_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -52,10 +52,10 @@
             uri.scheme().c_str());
     return false;
   }
-  grpc_error* error =
+  grpc_error_handle error =
       grpc_core::UnixSockaddrPopulate(uri.path(), resolved_addr);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "%s", grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return false;
   }
@@ -69,10 +69,10 @@
             uri.scheme().c_str());
     return false;
   }
-  grpc_error* error =
+  grpc_error_handle error =
       grpc_core::UnixAbstractSockaddrPopulate(uri.path(), resolved_addr);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "%s", grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return false;
   }
@@ -81,8 +81,8 @@
 
 namespace grpc_core {
 
-grpc_error* UnixSockaddrPopulate(absl::string_view path,
-                                 grpc_resolved_address* resolved_addr) {
+grpc_error_handle UnixSockaddrPopulate(absl::string_view path,
+                                       grpc_resolved_address* resolved_addr) {
   struct sockaddr_un* un =
       reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
   const size_t maxlen = sizeof(un->sun_path) - 1;
@@ -99,8 +99,8 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
-                                         grpc_resolved_address* resolved_addr) {
+grpc_error_handle UnixAbstractSockaddrPopulate(
+    absl::string_view path, grpc_resolved_address* resolved_addr) {
   struct sockaddr_un* un =
       reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
   const size_t maxlen = sizeof(un->sun_path) - 1;
@@ -122,25 +122,25 @@
 
 #else  /* GRPC_HAVE_UNIX_SOCKET */
 
-bool grpc_parse_unix(const grpc_core::URI& uri,
-                     grpc_resolved_address* resolved_addr) {
+bool grpc_parse_unix(const grpc_core::URI& /* uri */,
+                     grpc_resolved_address* /* resolved_addr */) {
   abort();
 }
 
-bool grpc_parse_unix_abstract(const grpc_core::URI& uri,
-                              grpc_resolved_address* resolved_addr) {
+bool grpc_parse_unix_abstract(const grpc_core::URI& /* uri */,
+                              grpc_resolved_address* /* resolved_addr */) {
   abort();
 }
 
 namespace grpc_core {
 
-grpc_error* UnixSockaddrPopulate(absl::string_view path,
-                                 grpc_resolved_address* resolved_addr) {
+grpc_error_handle UnixSockaddrPopulate(
+    absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
   abort();
 }
 
-grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
-                                         grpc_resolved_address* resolved_addr) {
+grpc_error_handle UnixAbstractSockaddrPopulate(
+    absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
   abort();
 }
 
diff --git a/grpc/src/core/lib/iomgr/parse_address.h b/grpc/src/core/lib/address_utils/parse_address.h
similarity index 86%
rename from grpc/src/core/lib/iomgr/parse_address.h
rename to grpc/src/core/lib/address_utils/parse_address.h
index 870afef..92409b7 100644
--- a/grpc/src/core/lib/iomgr/parse_address.h
+++ b/grpc/src/core/lib/address_utils/parse_address.h
@@ -16,8 +16,8 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_IOMGR_PARSE_ADDRESS_H
-#define GRPC_CORE_LIB_IOMGR_PARSE_ADDRESS_H
+#ifndef GRPC_CORE_LIB_ADDRESS_UTILS_PARSE_ADDRESS_H
+#define GRPC_CORE_LIB_ADDRESS_UTILS_PARSE_ADDRESS_H
 
 #include <grpc/support/port_platform.h>
 
@@ -64,14 +64,14 @@
 namespace grpc_core {
 
 /** Populate \a resolved_addr to be a unix socket at |path| */
-grpc_error* UnixSockaddrPopulate(absl::string_view path,
-                                 grpc_resolved_address* resolved_addr);
+grpc_error_handle UnixSockaddrPopulate(absl::string_view path,
+                                       grpc_resolved_address* resolved_addr);
 
 /** Populate \a resolved_addr to be a unix socket in the abstract namespace
  * at |path| */
-grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
-                                         grpc_resolved_address* resolved_addr);
+grpc_error_handle UnixAbstractSockaddrPopulate(
+    absl::string_view path, grpc_resolved_address* resolved_addr);
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_LIB_IOMGR_PARSE_ADDRESS_H */
+#endif /* GRPC_CORE_LIB_ADDRESS_UTILS_PARSE_ADDRESS_H */
diff --git a/grpc/src/core/lib/iomgr/sockaddr_utils.cc b/grpc/src/core/lib/address_utils/sockaddr_utils.cc
similarity index 69%
rename from grpc/src/core/lib/iomgr/sockaddr_utils.cc
rename to grpc/src/core/lib/address_utils/sockaddr_utils.cc
index 6d90c13..888cd1a 100644
--- a/grpc/src/core/lib/iomgr/sockaddr_utils.cc
+++ b/grpc/src/core/lib/address_utils/sockaddr_utils.cc
@@ -18,7 +18,7 @@
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 
 #include <errno.h>
 #include <inttypes.h>
@@ -183,7 +183,7 @@
   if (ip != nullptr && grpc_inet_ntop(addr->sa_family, ip, ntop_buf,
                                       sizeof(ntop_buf)) != nullptr) {
     if (sin6_scope_id != 0) {
-      // Enclose sin6_scope_id with the format defined in RFC 6784 section 2.
+      // Enclose sin6_scope_id with the format defined in RFC 6874 section 2.
       std::string host_with_scope =
           absl::StrFormat("%s%%25%" PRIu32, ntop_buf, sin6_scope_id);
       out = grpc_core::JoinHostPort(host_with_scope, port);
@@ -198,8 +198,8 @@
   return out;
 }
 
-void grpc_string_to_sockaddr(grpc_resolved_address* out, const char* addr,
-                             int port) {
+grpc_error_handle grpc_string_to_sockaddr(grpc_resolved_address* out,
+                                          const char* addr, int port) {
   memset(out, 0, sizeof(grpc_resolved_address));
   grpc_sockaddr_in6* addr6 = reinterpret_cast<grpc_sockaddr_in6*>(out->addr);
   grpc_sockaddr_in* addr4 = reinterpret_cast<grpc_sockaddr_in*>(out->addr);
@@ -210,9 +210,11 @@
     addr4->sin_family = GRPC_AF_INET;
     out->len = sizeof(grpc_sockaddr_in);
   } else {
-    GPR_ASSERT(0);
+    return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+        absl::StrCat("Failed to parse address:", addr).c_str());
   }
   grpc_sockaddr_set_port(out, port);
+  return GRPC_ERROR_NONE;
 }
 
 std::string grpc_sockaddr_to_uri(const grpc_resolved_address* resolved_addr) {
@@ -294,3 +296,104 @@
       return 0;
   }
 }
+
+std::string grpc_sockaddr_get_packed_host(
+    const grpc_resolved_address* resolved_addr) {
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+  if (addr->sa_family == GRPC_AF_INET) {
+    const grpc_sockaddr_in* addr4 =
+        reinterpret_cast<const grpc_sockaddr_in*>(addr);
+    const char* addr_bytes = reinterpret_cast<const char*>(&addr4->sin_addr);
+    return std::string(addr_bytes, 4);
+  } else if (addr->sa_family == GRPC_AF_INET6) {
+    const grpc_sockaddr_in6* addr6 =
+        reinterpret_cast<const grpc_sockaddr_in6*>(addr);
+    const char* addr_bytes = reinterpret_cast<const char*>(&addr6->sin6_addr);
+    return std::string(addr_bytes, 16);
+  } else {
+    GPR_ASSERT(false);
+  }
+}
+
+void grpc_sockaddr_mask_bits(grpc_resolved_address* address,
+                             uint32_t mask_bits) {
+  grpc_sockaddr* addr = reinterpret_cast<grpc_sockaddr*>(address->addr);
+  if (addr->sa_family == GRPC_AF_INET) {
+    grpc_sockaddr_in* addr4 = reinterpret_cast<grpc_sockaddr_in*>(addr);
+    if (mask_bits == 0) {
+      memset(&addr4->sin_addr, 0, sizeof(addr4->sin_addr));
+      return;
+    } else if (mask_bits >= 32) {
+      return;
+    }
+    uint32_t mask_ip_addr = (~(uint32_t(0))) << (32 - mask_bits);
+    addr4->sin_addr.s_addr &= grpc_htonl(mask_ip_addr);
+  } else if (addr->sa_family == GRPC_AF_INET6) {
+    grpc_sockaddr_in6* addr6 = reinterpret_cast<grpc_sockaddr_in6*>(addr);
+    if (mask_bits == 0) {
+      memset(&addr6->sin6_addr, 0, sizeof(addr6->sin6_addr));
+      return;
+    } else if (mask_bits >= 128) {
+      return;
+    }
+    // We cannot use s6_addr32 since it is not defined on all platforms that we
+    // need it on.
+    uint32_t address_parts[4];
+    GPR_ASSERT(sizeof(addr6->sin6_addr) == sizeof(address_parts));
+    memcpy(address_parts, &addr6->sin6_addr, sizeof(grpc_in6_addr));
+    if (mask_bits <= 32) {
+      uint32_t mask_ip_addr = (~(uint32_t(0))) << (32 - mask_bits);
+      address_parts[0] &= grpc_htonl(mask_ip_addr);
+      memset(&address_parts[1], 0, sizeof(uint32_t));
+      memset(&address_parts[2], 0, sizeof(uint32_t));
+      memset(&address_parts[3], 0, sizeof(uint32_t));
+    } else if (mask_bits <= 64) {
+      mask_bits -= 32;
+      uint32_t mask_ip_addr = (~(uint32_t(0))) << (32 - mask_bits);
+      address_parts[1] &= grpc_htonl(mask_ip_addr);
+      memset(&address_parts[2], 0, sizeof(uint32_t));
+      memset(&address_parts[3], 0, sizeof(uint32_t));
+    } else if (mask_bits <= 96) {
+      mask_bits -= 64;
+      uint32_t mask_ip_addr = (~(uint32_t(0))) << (32 - mask_bits);
+      address_parts[2] &= grpc_htonl(mask_ip_addr);
+      memset(&address_parts[3], 0, sizeof(uint32_t));
+    } else {
+      mask_bits -= 96;
+      uint32_t mask_ip_addr = (~(uint32_t(0))) << (32 - mask_bits);
+      address_parts[3] &= grpc_htonl(mask_ip_addr);
+    }
+    memcpy(&addr6->sin6_addr, address_parts, sizeof(grpc_in6_addr));
+  }
+}
+
+bool grpc_sockaddr_match_subnet(const grpc_resolved_address* address,
+                                const grpc_resolved_address* subnet_address,
+                                uint32_t mask_bits) {
+  auto* addr = reinterpret_cast<const grpc_sockaddr*>(address->addr);
+  auto* subnet_addr =
+      reinterpret_cast<const grpc_sockaddr*>(subnet_address->addr);
+  if (addr->sa_family != subnet_addr->sa_family) return false;
+  grpc_resolved_address masked_address;
+  memcpy(&masked_address, address, sizeof(grpc_resolved_address));
+  addr = reinterpret_cast<grpc_sockaddr*>((&masked_address)->addr);
+  grpc_sockaddr_mask_bits(&masked_address, mask_bits);
+  if (addr->sa_family == GRPC_AF_INET) {
+    auto* addr4 = reinterpret_cast<const grpc_sockaddr_in*>(addr);
+    auto* subnet_addr4 = reinterpret_cast<const grpc_sockaddr_in*>(subnet_addr);
+    if (memcmp(&addr4->sin_addr, &subnet_addr4->sin_addr,
+               sizeof(addr4->sin_addr)) == 0) {
+      return true;
+    }
+  } else if (addr->sa_family == GRPC_AF_INET6) {
+    auto* addr6 = reinterpret_cast<const grpc_sockaddr_in6*>(addr);
+    auto* subnet_addr6 =
+        reinterpret_cast<const grpc_sockaddr_in6*>(subnet_addr);
+    if (memcmp(&addr6->sin6_addr, &subnet_addr6->sin6_addr,
+               sizeof(addr6->sin6_addr)) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
diff --git a/grpc/src/core/lib/iomgr/sockaddr_utils.h b/grpc/src/core/lib/address_utils/sockaddr_utils.h
similarity index 67%
rename from grpc/src/core/lib/iomgr/sockaddr_utils.h
rename to grpc/src/core/lib/address_utils/sockaddr_utils.h
index ba91e56..e8bf79f 100644
--- a/grpc/src/core/lib/iomgr/sockaddr_utils.h
+++ b/grpc/src/core/lib/address_utils/sockaddr_utils.h
@@ -16,8 +16,8 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H
-#define GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H
+#ifndef GRPC_CORE_LIB_ADDRESS_UTILS_SOCKADDR_UTILS_H
+#define GRPC_CORE_LIB_ADDRESS_UTILS_SOCKADDR_UTILS_H
 
 #include <grpc/support/port_platform.h>
 
@@ -64,10 +64,12 @@
 // If the normalize flag is enabled, ::ffff:0.0.0.0/96 IPv6 addresses are
 // displayed as plain IPv4.
 std::string grpc_sockaddr_to_string(const grpc_resolved_address* addr,
-                                    bool normalize);
+                                    bool normalize) GRPC_MUST_USE_RESULT;
 
-void grpc_string_to_sockaddr(grpc_resolved_address* out, const char* addr,
-                             int port);
+// Newer form of grpc_string_to_sockaddr which returns an error instead of
+// crashing if \a addr is not IPv6/IPv6
+grpc_error_handle grpc_string_to_sockaddr(grpc_resolved_address* out,
+                                          const char* addr, int port);
 
 /* Returns the URI string corresponding to \a addr */
 std::string grpc_sockaddr_to_uri(const grpc_resolved_address* addr);
@@ -77,4 +79,22 @@
 
 int grpc_sockaddr_get_family(const grpc_resolved_address* resolved_addr);
 
-#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H */
+std::string grpc_sockaddr_get_packed_host(
+    const grpc_resolved_address* resolved_addr);
+
+// Applies a mask of \a mask_bits to IPv4/IPv6 addresses. Has no effect if the
+// address type is not IPv4/IPv6.
+void grpc_sockaddr_mask_bits(grpc_resolved_address* address,
+                             uint32_t mask_bits);
+
+// If \a address is IPv4/IPv6, checks if the IP address falls in the CIDR
+// specified by \a subnet_address and \a mask_bits.
+// Returns false if \a address is not an IPv4/IPv6 address. The ports (if set)
+// are ignored for matching purposes. Note that, \a subnet_address should be
+// normalized, i.e., `grpc_sockaddr_mask_bits` should have been called on it if
+// necessary.
+bool grpc_sockaddr_match_subnet(const grpc_resolved_address* address,
+                                const grpc_resolved_address* subnet_address,
+                                uint32_t mask_bits);
+
+#endif /* GRPC_CORE_LIB_ADDRESS_UTILS_SOCKADDR_UTILS_H */
diff --git a/grpc/src/core/lib/channel/channel_stack.cc b/grpc/src/core/lib/channel/channel_stack.cc
index e9b3489..122d7a9 100644
--- a/grpc/src/core/lib/channel/channel_stack.cc
+++ b/grpc/src/core/lib/channel/channel_stack.cc
@@ -81,12 +81,24 @@
   return grpc_channel_stack_element(channel_stack, channel_stack->count - 1);
 }
 
+size_t grpc_channel_stack_filter_instance_number(
+    grpc_channel_stack* channel_stack, grpc_channel_element* elem) {
+  size_t num_found = 0;
+  for (size_t i = 0; i < channel_stack->count; ++i) {
+    grpc_channel_element* element =
+        grpc_channel_stack_element(channel_stack, i);
+    if (element == elem) break;
+    if (element->filter == elem->filter) ++num_found;
+  }
+  return num_found;
+}
+
 grpc_call_element* grpc_call_stack_element(grpc_call_stack* call_stack,
                                            size_t index) {
   return CALL_ELEMS_FROM_STACK(call_stack) + index;
 }
 
-grpc_error* grpc_channel_stack_init(
+grpc_error_handle grpc_channel_stack_init(
     int initial_refs, grpc_iomgr_cb_func destroy, void* destroy_arg,
     const grpc_channel_filter** filters, size_t filter_count,
     const grpc_channel_args* channel_args, grpc_transport* optional_transport,
@@ -108,7 +120,7 @@
                                              sizeof(grpc_channel_element));
 
   /* init per-filter data */
-  grpc_error* first_error = GRPC_ERROR_NONE;
+  grpc_error_handle first_error = GRPC_ERROR_NONE;
   for (i = 0; i < filter_count; i++) {
     args.channel_stack = stack;
     args.channel_args = channel_args;
@@ -117,7 +129,8 @@
     args.is_last = i == (filter_count - 1);
     elems[i].filter = filters[i];
     elems[i].channel_data = user_data;
-    grpc_error* error = elems[i].filter->init_channel_elem(&elems[i], &args);
+    grpc_error_handle error =
+        elems[i].filter->init_channel_elem(&elems[i], &args);
     if (error != GRPC_ERROR_NONE) {
       if (first_error == GRPC_ERROR_NONE) {
         first_error = error;
@@ -149,10 +162,10 @@
   }
 }
 
-grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
-                                 int initial_refs, grpc_iomgr_cb_func destroy,
-                                 void* destroy_arg,
-                                 const grpc_call_element_args* elem_args) {
+grpc_error_handle grpc_call_stack_init(
+    grpc_channel_stack* channel_stack, int initial_refs,
+    grpc_iomgr_cb_func destroy, void* destroy_arg,
+    const grpc_call_element_args* elem_args) {
   grpc_channel_element* channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
   size_t count = channel_stack->count;
   grpc_call_element* call_elems;
@@ -166,7 +179,7 @@
               GPR_ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
 
   /* init per-filter data */
-  grpc_error* first_error = GRPC_ERROR_NONE;
+  grpc_error_handle first_error = GRPC_ERROR_NONE;
   for (size_t i = 0; i < count; i++) {
     call_elems[i].filter = channel_elems[i].filter;
     call_elems[i].channel_data = channel_elems[i].channel_data;
@@ -175,7 +188,7 @@
         GPR_ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
   }
   for (size_t i = 0; i < count; i++) {
-    grpc_error* error =
+    grpc_error_handle error =
         call_elems[i].filter->init_call_elem(&call_elems[i], elem_args);
     if (error != GRPC_ERROR_NONE) {
       if (first_error == GRPC_ERROR_NONE) {
diff --git a/grpc/src/core/lib/channel/channel_stack.h b/grpc/src/core/lib/channel/channel_stack.h
index e297df9..4832303 100644
--- a/grpc/src/core/lib/channel/channel_stack.h
+++ b/grpc/src/core/lib/channel/channel_stack.h
@@ -125,8 +125,8 @@
      transport and is on the server. Most filters want to ignore this
      argument.
      Implementations may assume that elem->call_data is all zeros. */
-  grpc_error* (*init_call_elem)(grpc_call_element* elem,
-                                const grpc_call_element_args* args);
+  grpc_error_handle (*init_call_elem)(grpc_call_element* elem,
+                                      const grpc_call_element_args* args);
   void (*set_pollset_or_pollset_set)(grpc_call_element* elem,
                                      grpc_polling_entity* pollent);
   /* Destroy per call data.
@@ -148,8 +148,8 @@
      useful for asserting correct configuration by upper layer code.
      The filter does not need to do any chaining.
      Implementations may assume that elem->channel_data is all zeros. */
-  grpc_error* (*init_channel_elem)(grpc_channel_element* elem,
-                                   grpc_channel_element_args* args);
+  grpc_error_handle (*init_channel_elem)(grpc_channel_element* elem,
+                                         grpc_channel_element_args* args);
   /* Destroy per channel data.
      The filter does not need to do any chaining */
   void (*destroy_channel_elem)(grpc_channel_element* elem);
@@ -204,6 +204,13 @@
 /* Get the last channel element in a channel stack */
 grpc_channel_element* grpc_channel_stack_last_element(
     grpc_channel_stack* stack);
+
+// A utility function for a filter to determine how many other instances
+// of the same filter exist above it in the same stack.  Intended to be
+// used in the filter's init_channel_elem() method.
+size_t grpc_channel_stack_filter_instance_number(
+    grpc_channel_stack* channel_stack, grpc_channel_element* elem);
+
 /* Get a call stack element given a call stack and an index */
 grpc_call_element* grpc_call_stack_element(grpc_call_stack* stack, size_t i);
 
@@ -211,7 +218,7 @@
 size_t grpc_channel_stack_size(const grpc_channel_filter** filters,
                                size_t filter_count);
 /* Initialize a channel stack given some filters */
-grpc_error* grpc_channel_stack_init(
+grpc_error_handle grpc_channel_stack_init(
     int initial_refs, grpc_iomgr_cb_func destroy, void* destroy_arg,
     const grpc_channel_filter** filters, size_t filter_count,
     const grpc_channel_args* args, grpc_transport* optional_transport,
@@ -222,10 +229,11 @@
 /* Initialize a call stack given a channel stack. transport_server_data is
    expected to be NULL on a client, or an opaque transport owned pointer on the
    server. */
-grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
-                                 int initial_refs, grpc_iomgr_cb_func destroy,
-                                 void* destroy_arg,
-                                 const grpc_call_element_args* elem_args);
+grpc_error_handle grpc_call_stack_init(grpc_channel_stack* channel_stack,
+                                       int initial_refs,
+                                       grpc_iomgr_cb_func destroy,
+                                       void* destroy_arg,
+                                       const grpc_call_element_args* elem_args);
 /* Set a pollset or a pollset_set for a call stack: must occur before the first
  * op is started */
 void grpc_call_stack_set_pollset_or_pollset_set(grpc_call_stack* call_stack,
diff --git a/grpc/src/core/lib/channel/channel_stack_builder.cc b/grpc/src/core/lib/channel/channel_stack_builder.cc
index 8b3008f..7f7cf75 100644
--- a/grpc/src/core/lib/channel/channel_stack_builder.cc
+++ b/grpc/src/core/lib/channel/channel_stack_builder.cc
@@ -267,7 +267,7 @@
   gpr_free(builder);
 }
 
-grpc_error* grpc_channel_stack_builder_finish(
+grpc_error_handle grpc_channel_stack_builder_finish(
     grpc_channel_stack_builder* builder, size_t prefix_bytes, int initial_refs,
     grpc_iomgr_cb_func destroy, void* destroy_arg, void** result) {
   // count the number of filters
@@ -294,7 +294,7 @@
   grpc_channel_stack* channel_stack = reinterpret_cast<grpc_channel_stack*>(
       static_cast<char*>(*result) + prefix_bytes);
   // and initialize it
-  grpc_error* error = grpc_channel_stack_init(
+  grpc_error_handle error = grpc_channel_stack_init(
       initial_refs, destroy, destroy_arg == nullptr ? *result : destroy_arg,
       filters, num_filters, builder->args, builder->transport, builder->name,
       channel_stack);
diff --git a/grpc/src/core/lib/channel/channel_stack_builder.h b/grpc/src/core/lib/channel/channel_stack_builder.h
index 89c30e0..6782a14 100644
--- a/grpc/src/core/lib/channel/channel_stack_builder.h
+++ b/grpc/src/core/lib/channel/channel_stack_builder.h
@@ -156,7 +156,7 @@
 /// Returns the base pointer of the allocated block
 /// \a initial_refs, \a destroy, \a destroy_arg are as per
 /// grpc_channel_stack_init
-grpc_error* grpc_channel_stack_builder_finish(
+grpc_error_handle grpc_channel_stack_builder_finish(
     grpc_channel_stack_builder* builder, size_t prefix_bytes, int initial_refs,
     grpc_iomgr_cb_func destroy, void* destroy_arg, void** result);
 
diff --git a/grpc/src/core/lib/channel/channelz.cc b/grpc/src/core/lib/channel/channelz.cc
index 188203c..452d664 100644
--- a/grpc/src/core/lib/channel/channelz.cc
+++ b/grpc/src/core/lib/channel/channelz.cc
@@ -20,16 +20,19 @@
 
 #include "src/core/lib/channel/channelz.h"
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "absl/strings/escaping.h"
 #include "absl/strings/strip.h"
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channelz_registry.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gpr/string.h"
@@ -39,6 +42,7 @@
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/slice/b64.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/channel.h"
@@ -337,6 +341,83 @@
 }
 
 //
+// SocketNode::Security::Tls
+//
+
+Json SocketNode::Security::Tls::RenderJson() {
+  Json::Object data;
+  if (type == NameType::kStandardName) {
+    data["standard_name"] = name;
+  } else if (type == NameType::kOtherName) {
+    data["other_name"] = name;
+  }
+  if (!local_certificate.empty()) {
+    data["local_certificate"] = absl::Base64Escape(local_certificate);
+  }
+  if (!remote_certificate.empty()) {
+    data["remote_certificate"] = absl::Base64Escape(remote_certificate);
+  }
+  return data;
+}
+
+//
+// SocketNode::Security
+//
+
+Json SocketNode::Security::RenderJson() {
+  Json::Object data;
+  switch (type) {
+    case ModelType::kUnset:
+      break;
+    case ModelType::kTls:
+      if (tls) {
+        data["tls"] = tls->RenderJson();
+      }
+      break;
+    case ModelType::kOther:
+      if (other) {
+        data["other"] = *other;
+      }
+      break;
+  }
+  return data;
+}
+
+namespace {
+
+void* SecurityArgCopy(void* p) {
+  SocketNode::Security* xds_certificate_provider =
+      static_cast<SocketNode::Security*>(p);
+  return xds_certificate_provider->Ref().release();
+}
+
+void SecurityArgDestroy(void* p) {
+  SocketNode::Security* xds_certificate_provider =
+      static_cast<SocketNode::Security*>(p);
+  xds_certificate_provider->Unref();
+}
+
+int SecurityArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
+
+const grpc_arg_pointer_vtable kChannelArgVtable = {
+    SecurityArgCopy, SecurityArgDestroy, SecurityArgCmp};
+
+}  // namespace
+
+grpc_arg SocketNode::Security::MakeChannelArg() const {
+  return grpc_channel_arg_pointer_create(
+      const_cast<char*>(GRPC_ARG_CHANNELZ_SECURITY),
+      const_cast<SocketNode::Security*>(this), &kChannelArgVtable);
+}
+
+RefCountedPtr<SocketNode::Security> SocketNode::Security::GetFromChannelArgs(
+    const grpc_channel_args* args) {
+  Security* security = grpc_channel_args_find_pointer<Security>(
+      args, GRPC_ARG_CHANNELZ_SECURITY);
+  return security != nullptr ? security->Ref() : nullptr;
+}
+
+//
 // SocketNode
 //
 
@@ -356,13 +437,22 @@
     if (!port.empty()) {
       port_num = atoi(port.data());
     }
-    char* b64_host = grpc_base64_encode(host.data(), host.size(), false, false);
-    data["tcpip_address"] = Json::Object{
-        {"port", port_num},
-        {"ip_address", b64_host},
-    };
-    gpr_free(b64_host);
-  } else if (uri.ok() && uri->scheme() == "unix") {
+    grpc_resolved_address resolved_host;
+    grpc_error_handle error =
+        grpc_string_to_sockaddr(&resolved_host, host.c_str(), port_num);
+    if (error == GRPC_ERROR_NONE) {
+      std::string packed_host = grpc_sockaddr_get_packed_host(&resolved_host);
+      std::string b64_host = absl::Base64Escape(packed_host);
+      data["tcpip_address"] = Json::Object{
+          {"port", port_num},
+          {"ip_address", b64_host},
+      };
+      (*json)[name] = std::move(data);
+      return;
+    }
+    GRPC_ERROR_UNREF(error);
+  }
+  if (uri.ok() && uri->scheme() == "unix") {
     data["uds_address"] = Json::Object{
         {"filename", uri->path()},
     };
@@ -376,10 +466,12 @@
 
 }  // namespace
 
-SocketNode::SocketNode(std::string local, std::string remote, std::string name)
+SocketNode::SocketNode(std::string local, std::string remote, std::string name,
+                       RefCountedPtr<Security> security)
     : BaseNode(EntityType::kSocket, std::move(name)),
       local_(std::move(local)),
-      remote_(std::move(remote)) {}
+      remote_(std::move(remote)),
+      security_(std::move(security)) {}
 
 void SocketNode::RecordStreamStartedFromLocal() {
   streams_started_.FetchAdd(1, MemoryOrder::RELAXED);
@@ -467,6 +559,10 @@
        }},
       {"data", std::move(data)},
   };
+  if (security_ != nullptr &&
+      security_->type != SocketNode::Security::ModelType::kUnset) {
+    object["security"] = security_->RenderJson();
+  }
   PopulateSocketAddressJson(&object, "remote", remote_.c_str());
   PopulateSocketAddressJson(&object, "local", local_.c_str());
   return object;
diff --git a/grpc/src/core/lib/channel/channelz.h b/grpc/src/core/lib/channel/channelz.h
index 3c55873..a0a449e 100644
--- a/grpc/src/core/lib/channel/channelz.h
+++ b/grpc/src/core/lib/channel/channelz.h
@@ -27,6 +27,7 @@
 #include <string>
 
 #include "absl/container/inlined_vector.h"
+#include "absl/types/optional.h"
 
 #include "src/core/lib/channel/channel_trace.h"
 #include "src/core/lib/gpr/time_precise.h"
@@ -268,10 +269,37 @@
   std::map<intptr_t, RefCountedPtr<ListenSocketNode>> child_listen_sockets_;
 };
 
+#define GRPC_ARG_CHANNELZ_SECURITY "grpc.internal.channelz_security"
+
 // Handles channelz bookkeeping for sockets
 class SocketNode : public BaseNode {
  public:
-  SocketNode(std::string local, std::string remote, std::string name);
+  struct Security : public RefCounted<Security> {
+    struct Tls {
+      enum class NameType { kUnset = 0, kStandardName = 1, kOtherName = 2 };
+      NameType type = NameType::kUnset;
+      // Holds the value of standard_name or other_names if type is not kUnset.
+      std::string name;
+      std::string local_certificate;
+      std::string remote_certificate;
+
+      Json RenderJson();
+    };
+    enum class ModelType { kUnset = 0, kTls = 1, kOther = 2 };
+    ModelType type = ModelType::kUnset;
+    absl::optional<Tls> tls;
+    absl::optional<Json> other;
+
+    Json RenderJson();
+
+    grpc_arg MakeChannelArg() const;
+
+    static RefCountedPtr<Security> GetFromChannelArgs(
+        const grpc_channel_args* args);
+  };
+
+  SocketNode(std::string local, std::string remote, std::string name,
+             RefCountedPtr<Security> security);
   ~SocketNode() override {}
 
   Json RenderJson() override;
@@ -305,6 +333,7 @@
   Atomic<gpr_cycle_counter> last_message_received_cycle_{0};
   std::string local_;
   std::string remote_;
+  RefCountedPtr<Security> const security_;
 };
 
 // Handles channelz bookkeeping for listen sockets
diff --git a/grpc/src/core/lib/channel/channelz_registry.cc b/grpc/src/core/lib/channel/channelz_registry.cc
index 6eea6eb..c76b5b4 100644
--- a/grpc/src/core/lib/channel/channelz_registry.cc
+++ b/grpc/src/core/lib/channel/channelz_registry.cc
@@ -181,18 +181,24 @@
 }  // namespace grpc_core
 
 char* grpc_channelz_get_top_channels(intptr_t start_channel_id) {
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
   return gpr_strdup(
       grpc_core::channelz::ChannelzRegistry::GetTopChannels(start_channel_id)
           .c_str());
 }
 
 char* grpc_channelz_get_servers(intptr_t start_server_id) {
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
   return gpr_strdup(
       grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id)
           .c_str());
 }
 
 char* grpc_channelz_get_server(intptr_t server_id) {
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> server_node =
       grpc_core::channelz::ChannelzRegistry::Get(server_id);
   if (server_node == nullptr ||
@@ -209,6 +215,8 @@
 char* grpc_channelz_get_server_sockets(intptr_t server_id,
                                        intptr_t start_socket_id,
                                        intptr_t max_results) {
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
   // Validate inputs before handing them of to the renderer.
   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> base_node =
       grpc_core::channelz::ChannelzRegistry::Get(server_id);
@@ -226,6 +234,8 @@
 }
 
 char* grpc_channelz_get_channel(intptr_t channel_id) {
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> channel_node =
       grpc_core::channelz::ChannelzRegistry::Get(channel_id);
   if (channel_node == nullptr ||
@@ -242,6 +252,8 @@
 }
 
 char* grpc_channelz_get_subchannel(intptr_t subchannel_id) {
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> subchannel_node =
       grpc_core::channelz::ChannelzRegistry::Get(subchannel_id);
   if (subchannel_node == nullptr ||
@@ -256,6 +268,8 @@
 }
 
 char* grpc_channelz_get_socket(intptr_t socket_id) {
+  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
+  grpc_core::ExecCtx exec_ctx;
   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> socket_node =
       grpc_core::channelz::ChannelzRegistry::Get(socket_id);
   if (socket_node == nullptr ||
diff --git a/grpc/src/core/lib/channel/connected_channel.cc b/grpc/src/core/lib/channel/connected_channel.cc
index be74d9e..12b3d78 100644
--- a/grpc/src/core/lib/channel/connected_channel.cc
+++ b/grpc/src/core/lib/channel/connected_channel.cc
@@ -53,13 +53,13 @@
   callback_state recv_trailing_metadata_ready;
 } call_data;
 
-static void run_in_call_combiner(void* arg, grpc_error* error) {
+static void run_in_call_combiner(void* arg, grpc_error_handle error) {
   callback_state* state = static_cast<callback_state*>(arg);
   GRPC_CALL_COMBINER_START(state->call_combiner, state->original_closure,
                            GRPC_ERROR_REF(error), state->reason);
 }
 
-static void run_cancel_in_call_combiner(void* arg, grpc_error* error) {
+static void run_cancel_in_call_combiner(void* arg, grpc_error_handle error) {
   run_in_call_combiner(arg, error);
   gpr_free(arg);
 }
@@ -146,7 +146,7 @@
 }
 
 /* Constructor for call_data */
-static grpc_error* connected_channel_init_call_elem(
+static grpc_error_handle connected_channel_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
@@ -179,7 +179,7 @@
 }
 
 /* Constructor for channel_data */
-static grpc_error* connected_channel_init_channel_elem(
+static grpc_error_handle connected_channel_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   channel_data* cd = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(args->is_last);
diff --git a/grpc/src/core/lib/channel/handshaker.cc b/grpc/src/core/lib/channel/handshaker.cc
index 8d1d45e..632d286 100644
--- a/grpc/src/core/lib/channel/handshaker.cc
+++ b/grpc/src/core/lib/channel/handshaker.cc
@@ -53,45 +53,7 @@
 
 }  // namespace
 
-HandshakeManager::HandshakeManager() { gpr_mu_init(&mu_); }
-
-/// Add \a mgr to the server side list of all pending handshake managers, the
-/// list starts with \a *head.
-// Not thread-safe. Caller needs to synchronize.
-void HandshakeManager::AddToPendingMgrList(HandshakeManager** head) {
-  GPR_ASSERT(prev_ == nullptr);
-  GPR_ASSERT(next_ == nullptr);
-  next_ = *head;
-  if (*head) {
-    (*head)->prev_ = this;
-  }
-  *head = this;
-}
-
-/// Remove \a mgr from the server side list of all pending handshake managers.
-// Not thread-safe. Caller needs to synchronize.
-void HandshakeManager::RemoveFromPendingMgrList(HandshakeManager** head) {
-  if (next_ != nullptr) {
-    next_->prev_ = prev_;
-  }
-  if (prev_ != nullptr) {
-    prev_->next_ = next_;
-  } else {
-    GPR_ASSERT(*head == this);
-    *head = next_;
-  }
-}
-
-/// Shutdown all pending handshake managers starting at head on the server
-/// side. Not thread-safe. Caller needs to synchronize.
-void HandshakeManager::ShutdownAllPending(grpc_error* why) {
-  auto* head = this;
-  while (head != nullptr) {
-    head->Shutdown(GRPC_ERROR_REF(why));
-    head = head->next_;
-  }
-  GRPC_ERROR_UNREF(why);
-}
+HandshakeManager::HandshakeManager() {}
 
 void HandshakeManager::Add(RefCountedPtr<Handshaker> handshaker) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_handshaker_trace)) {
@@ -104,12 +66,9 @@
   handshakers_.push_back(std::move(handshaker));
 }
 
-HandshakeManager::~HandshakeManager() {
-  handshakers_.clear();
-  gpr_mu_destroy(&mu_);
-}
+HandshakeManager::~HandshakeManager() { handshakers_.clear(); }
 
-void HandshakeManager::Shutdown(grpc_error* why) {
+void HandshakeManager::Shutdown(grpc_error_handle why) {
   {
     MutexLock lock(&mu_);
     // Shutdown the handshaker that's currently in progress, if any.
@@ -124,12 +83,12 @@
 // Helper function to call either the next handshaker or the
 // on_handshake_done callback.
 // Returns true if we've scheduled the on_handshake_done callback.
-bool HandshakeManager::CallNextHandshakerLocked(grpc_error* error) {
+bool HandshakeManager::CallNextHandshakerLocked(grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_handshaker_trace)) {
     gpr_log(GPR_INFO,
             "handshake_manager %p: error=%s shutdown=%d index=%" PRIuPTR
             ", args=%s",
-            this, grpc_error_string(error), is_shutdown_, index_,
+            this, grpc_error_std_string(error).c_str(), is_shutdown_, index_,
             HandshakerArgsString(&args_).c_str());
   }
   GPR_ASSERT(index_ <= handshakers_.size());
@@ -162,7 +121,7 @@
       gpr_log(GPR_INFO,
               "handshake_manager %p: handshaking complete -- scheduling "
               "on_handshake_done with error=%s",
-              this, grpc_error_string(error));
+              this, grpc_error_std_string(error).c_str());
     }
     // Cancel deadline timer, since we're invoking the on_handshake_done
     // callback now.
@@ -183,7 +142,8 @@
   return is_shutdown_;
 }
 
-void HandshakeManager::CallNextHandshakerFn(void* arg, grpc_error* error) {
+void HandshakeManager::CallNextHandshakerFn(void* arg,
+                                            grpc_error_handle error) {
   auto* mgr = static_cast<HandshakeManager*>(arg);
   bool done;
   {
@@ -198,7 +158,7 @@
   }
 }
 
-void HandshakeManager::OnTimeoutFn(void* arg, grpc_error* error) {
+void HandshakeManager::OnTimeoutFn(void* arg, grpc_error_handle error) {
   auto* mgr = static_cast<HandshakeManager*>(arg);
   if (error == GRPC_ERROR_NONE) {  // Timer fired, rather than being cancelled
     mgr->Shutdown(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake timed out"));
@@ -216,7 +176,6 @@
   {
     MutexLock lock(&mu_);
     GPR_ASSERT(index_ == 0);
-    GPR_ASSERT(!is_shutdown_);
     // Construct handshaker args.  These will be passed through all
     // handshakers and eventually be freed by the on_handshake_done callback.
     args_.endpoint = endpoint;
diff --git a/grpc/src/core/lib/channel/handshaker.h b/grpc/src/core/lib/channel/handshaker.h
index 541f38e..b6b69da 100644
--- a/grpc/src/core/lib/channel/handshaker.h
+++ b/grpc/src/core/lib/channel/handshaker.h
@@ -78,7 +78,7 @@
 class Handshaker : public RefCounted<Handshaker> {
  public:
   ~Handshaker() override = default;
-  virtual void Shutdown(grpc_error* why) = 0;
+  virtual void Shutdown(grpc_error_handle why) = 0;
   virtual void DoHandshake(grpc_tcp_server_acceptor* acceptor,
                            grpc_closure* on_handshake_done,
                            HandshakerArgs* args) = 0;
@@ -94,26 +94,13 @@
   HandshakeManager();
   ~HandshakeManager() override;
 
-  /// Add \a mgr to the server side list of all pending handshake managers, the
-  /// list starts with \a *head.
-  // Not thread-safe. Caller needs to synchronize.
-  void AddToPendingMgrList(HandshakeManager** head);
-
-  /// Remove \a mgr from the server side list of all pending handshake managers.
-  // Not thread-safe. Caller needs to synchronize.
-  void RemoveFromPendingMgrList(HandshakeManager** head);
-
-  /// Shutdown all pending handshake managers starting at head on the server
-  /// side. Not thread-safe. Caller needs to synchronize.
-  void ShutdownAllPending(grpc_error* why);
-
   /// Adds a handshaker to the handshake manager.
   /// Takes ownership of \a handshaker.
   void Add(RefCountedPtr<Handshaker> handshaker);
 
   /// Shuts down the handshake manager (e.g., to clean up when the operation is
   /// aborted in the middle).
-  void Shutdown(grpc_error* why);
+  void Shutdown(grpc_error_handle why);
 
   /// Invokes handshakers in the order they were added.
   /// Takes ownership of \a endpoint, and then passes that ownership to
@@ -133,18 +120,18 @@
                    grpc_iomgr_cb_func on_handshake_done, void* user_data);
 
  private:
-  bool CallNextHandshakerLocked(grpc_error* error);
+  bool CallNextHandshakerLocked(grpc_error_handle error);
 
   // A function used as the handshaker-done callback when chaining
   // handshakers together.
-  static void CallNextHandshakerFn(void* arg, grpc_error* error);
+  static void CallNextHandshakerFn(void* arg, grpc_error_handle error);
 
   // Callback invoked when deadline is exceeded.
-  static void OnTimeoutFn(void* arg, grpc_error* error);
+  static void OnTimeoutFn(void* arg, grpc_error_handle error);
 
   static const size_t HANDSHAKERS_INIT_SIZE = 2;
 
-  gpr_mu mu_;
+  Mutex mu_;
   bool is_shutdown_ = false;
   // An array of handshakers added via grpc_handshake_manager_add().
   absl::InlinedVector<RefCountedPtr<Handshaker>, HANDSHAKERS_INIT_SIZE>
@@ -161,10 +148,6 @@
   grpc_closure on_handshake_done_;
   // Handshaker args.
   HandshakerArgs args_;
-  // Links to the previous and next managers in a list of all pending handshakes
-  // Used at server side only.
-  HandshakeManager* prev_ = nullptr;
-  HandshakeManager* next_ = nullptr;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/lib/channel/status_util.cc b/grpc/src/core/lib/channel/status_util.cc
index 39f310a..0c60030 100644
--- a/grpc/src/core/lib/channel/status_util.cc
+++ b/grpc/src/core/lib/channel/status_util.cc
@@ -75,8 +75,6 @@
       return "ALREADY_EXISTS";
     case GRPC_STATUS_PERMISSION_DENIED:
       return "PERMISSION_DENIED";
-    case GRPC_STATUS_UNAUTHENTICATED:
-      return "UNAUTHENTICATED";
     case GRPC_STATUS_RESOURCE_EXHAUSTED:
       return "RESOURCE_EXHAUSTED";
     case GRPC_STATUS_FAILED_PRECONDITION:
@@ -93,7 +91,19 @@
       return "UNAVAILABLE";
     case GRPC_STATUS_DATA_LOSS:
       return "DATA_LOSS";
+    case GRPC_STATUS_UNAUTHENTICATED:
+      return "UNAUTHENTICATED";
     default:
       return "UNKNOWN";
   }
 }
+
+bool grpc_status_code_from_int(int status_int, grpc_status_code* status) {
+  // The range of status code enum is [0, 16], 0 is OK, 16 is UNAUTHENTICATED.
+  if (status_int < GRPC_STATUS_OK || status_int > GRPC_STATUS_UNAUTHENTICATED) {
+    *status = GRPC_STATUS_UNKNOWN;
+    return false;
+  }
+  *status = static_cast<grpc_status_code>(status_int);
+  return true;
+}
diff --git a/grpc/src/core/lib/channel/status_util.h b/grpc/src/core/lib/channel/status_util.h
index 5409de6..969033a 100644
--- a/grpc/src/core/lib/channel/status_util.h
+++ b/grpc/src/core/lib/channel/status_util.h
@@ -34,6 +34,11 @@
 /// Returns the string form of \a status, or "UNKNOWN" if invalid.
 const char* grpc_status_code_to_string(grpc_status_code status);
 
+// Converts an int to grpc_status_code. If the int is not a valid status code,
+// sets the code to GRPC_STATUS_UNKNOWN and returns false. Otherwise, returns
+// true.
+bool grpc_status_code_from_int(int status_int, grpc_status_code* status);
+
 namespace grpc_core {
 namespace internal {
 
diff --git a/grpc/src/core/lib/event_engine/slice_allocator.cc b/grpc/src/core/lib/event_engine/slice_allocator.cc
new file mode 100644
index 0000000..3ea615a
--- /dev/null
+++ b/grpc/src/core/lib/event_engine/slice_allocator.cc
@@ -0,0 +1,59 @@
+// Copyright 2021 The 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>
+
+#include "grpc/event_engine/slice_allocator.h"
+
+#include <functional>
+
+#include "absl/status/status.h"
+
+#include "src/core/lib/iomgr/resource_quota.h"
+
+namespace grpc_event_engine {
+namespace experimental {
+
+SliceAllocator::SliceAllocator(grpc_resource_user* user)
+    : resource_user_(user) {
+  grpc_resource_user_ref(resource_user_);
+};
+
+SliceAllocator::~SliceAllocator() { grpc_resource_user_unref(resource_user_); };
+
+absl::Status SliceAllocator::Allocate(size_t size, SliceBuffer* dest,
+                                      SliceAllocator::AllocateCallback cb) {
+  // TODO(hork): implement
+  (void)size;
+  (void)dest;
+  (void)cb;
+  return absl::OkStatus();
+};
+
+SliceAllocatorFactory::SliceAllocatorFactory(grpc_resource_quota* quota)
+    : resource_quota_(quota) {
+  grpc_resource_quota_ref_internal(resource_quota_);
+};
+
+SliceAllocatorFactory::~SliceAllocatorFactory() {
+  grpc_resource_quota_unref_internal(resource_quota_);
+}
+
+SliceAllocator SliceAllocatorFactory::CreateSliceAllocator(
+    absl::string_view peer_name) {
+  return SliceAllocator(
+      grpc_resource_user_create(resource_quota_, peer_name.data()));
+}
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
diff --git a/grpc/src/core/lib/event_engine/sockaddr.cc b/grpc/src/core/lib/event_engine/sockaddr.cc
new file mode 100644
index 0000000..811d351
--- /dev/null
+++ b/grpc/src/core/lib/event_engine/sockaddr.cc
@@ -0,0 +1,38 @@
+// Copyright 2021 The 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>
+
+#include <string.h>
+
+#include "grpc/event_engine/event_engine.h"
+#include "grpc/event_engine/port.h"
+#include "grpc/support/log.h"
+
+namespace grpc_event_engine {
+namespace experimental {
+
+EventEngine::ResolvedAddress::ResolvedAddress(const sockaddr* address,
+                                              socklen_t size) {
+  GPR_ASSERT(size <= sizeof(address_));
+  memcpy(&address_, address, size);
+}
+
+const struct sockaddr* EventEngine::ResolvedAddress::address() const {
+  return reinterpret_cast<const struct sockaddr*>(address_);
+}
+
+socklen_t EventEngine::ResolvedAddress::size() const { return size_; }
+
+}  // namespace experimental
+}  // namespace grpc_event_engine
diff --git a/grpc/src/core/lib/gpr/log.cc b/grpc/src/core/lib/gpr/log.cc
index 9a5a54f..9400f7c 100644
--- a/grpc/src/core/lib/gpr/log.cc
+++ b/grpc/src/core/lib/gpr/log.cc
@@ -28,7 +28,12 @@
 #include <stdio.h>
 #include <string.h>
 
-GPR_GLOBAL_CONFIG_DEFINE_STRING(grpc_verbosity, "ERROR",
+#ifndef GPR_DEFAULT_LOG_VERBOSITY_STRING
+#define GPR_DEFAULT_LOG_VERBOSITY_STRING "ERROR"
+#endif  // !GPR_DEFAULT_LOG_VERBOSITY_STRING
+
+GPR_GLOBAL_CONFIG_DEFINE_STRING(grpc_verbosity,
+                                GPR_DEFAULT_LOG_VERBOSITY_STRING,
                                 "Default gRPC logging verbosity")
 GPR_GLOBAL_CONFIG_DEFINE_STRING(grpc_stacktrace_minloglevel, "",
                                 "Messages logged at the same or higher level "
diff --git a/grpc/src/core/lib/gpr/sync_abseil.cc b/grpc/src/core/lib/gpr/sync_abseil.cc
index 56b1cc7..0da9caa 100644
--- a/grpc/src/core/lib/gpr/sync_abseil.cc
+++ b/grpc/src/core/lib/gpr/sync_abseil.cc
@@ -62,8 +62,7 @@
 
 int gpr_mu_trylock(gpr_mu* mu) {
   GPR_TIMER_SCOPE("gpr_mu_trylock", 0);
-  int ret = reinterpret_cast<absl::Mutex*>(mu)->TryLock() == true;
-  return ret;
+  return reinterpret_cast<absl::Mutex*>(mu)->TryLock();
 }
 
 /*----------------------------------------*/
@@ -89,10 +88,8 @@
   abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
   timespec ts = {static_cast<decltype(ts.tv_sec)>(abs_deadline.tv_sec),
                  static_cast<decltype(ts.tv_nsec)>(abs_deadline.tv_nsec)};
-  int ret = reinterpret_cast<absl::CondVar*>(cv)->WaitWithDeadline(
-                reinterpret_cast<absl::Mutex*>(mu),
-                absl::TimeFromTimespec(ts)) == true;
-  return ret;
+  return reinterpret_cast<absl::CondVar*>(cv)->WaitWithDeadline(
+      reinterpret_cast<absl::Mutex*>(mu), absl::TimeFromTimespec(ts));
 }
 
 void gpr_cv_signal(gpr_cv* cv) {
diff --git a/grpc/src/core/lib/gpr/sync_windows.cc b/grpc/src/core/lib/gpr/sync_windows.cc
index 64eec7c..a6173c7 100644
--- a/grpc/src/core/lib/gpr/sync_windows.cc
+++ b/grpc/src/core/lib/gpr/sync_windows.cc
@@ -100,7 +100,7 @@
 
 /*----------------------------------------*/
 
-static void* dummy;
+static void* phony;
 struct run_once_func_arg {
   void (*init_function)(void);
 };
@@ -113,7 +113,7 @@
 void gpr_once_init(gpr_once* once, void (*init_function)(void)) {
   struct run_once_func_arg arg;
   arg.init_function = init_function;
-  InitOnceExecuteOnce(once, run_once_func, &arg, &dummy);
+  InitOnceExecuteOnce(once, run_once_func, &arg, &phony);
 }
 
 #endif /* defined(GPR_WINDOWS) && !defined(GPR_ABSEIL_SYNC) && \
diff --git a/grpc/src/core/lib/gprpp/atomic.h b/grpc/src/core/lib/gprpp/atomic.h
index 4a53d2c..dd99d9e 100644
--- a/grpc/src/core/lib/gprpp/atomic.h
+++ b/grpc/src/core/lib/gprpp/atomic.h
@@ -81,8 +81,8 @@
 
   // Atomically increment a counter only if the counter value is not zero.
   // Returns true if increment took place; false if counter is zero.
-  bool IncrementIfNonzero(MemoryOrder load_order = MemoryOrder::ACQUIRE) {
-    T count = storage_.load(static_cast<std::memory_order>(load_order));
+  bool IncrementIfNonzero() {
+    T count = storage_.load(std::memory_order_acquire);
     do {
       // If zero, we are done (without an increment). If not, we must do a CAS
       // to maintain the contract: do not increment the counter if it is already
@@ -91,7 +91,7 @@
         return false;
       }
     } while (!CompareExchangeWeak(&count, count + 1, MemoryOrder::ACQ_REL,
-                                  load_order));
+                                  MemoryOrder::ACQUIRE));
     return true;
   }
 
diff --git a/grpc/src/core/lib/gprpp/dual_ref_counted.h b/grpc/src/core/lib/gprpp/dual_ref_counted.h
index 91469ea..5217bfa 100644
--- a/grpc/src/core/lib/gprpp/dual_ref_counted.h
+++ b/grpc/src/core/lib/gprpp/dual_ref_counted.h
@@ -170,8 +170,8 @@
 #endif
     const uint64_t prev_ref_pair =
         refs_.FetchSub(MakeRefPair(0, 1), MemoryOrder::ACQ_REL);
-    const uint32_t weak_refs = GetWeakRefs(prev_ref_pair);
 #ifndef NDEBUG
+    const uint32_t weak_refs = GetWeakRefs(prev_ref_pair);
     const uint32_t strong_refs = GetStrongRefs(prev_ref_pair);
     if (trace != nullptr) {
       gpr_log(GPR_INFO, "%s:%p weak_unref %d -> %d (refs=%d)", trace, this,
@@ -192,10 +192,10 @@
 #endif
     const uint64_t prev_ref_pair =
         refs_.FetchSub(MakeRefPair(0, 1), MemoryOrder::ACQ_REL);
-    const uint32_t weak_refs = GetWeakRefs(prev_ref_pair);
 #ifndef NDEBUG
+    const uint32_t weak_refs = GetWeakRefs(prev_ref_pair);
     const uint32_t strong_refs = GetStrongRefs(prev_ref_pair);
-    if (trace_ != nullptr) {
+    if (trace != nullptr) {
       gpr_log(GPR_INFO, "%s:%p %s:%d weak_unref %d -> %d (refs=%d) %s", trace,
               this, location.file(), location.line(), weak_refs, weak_refs - 1,
               strong_refs, reason);
diff --git a/grpc/src/core/lib/gprpp/mpscq.cc b/grpc/src/core/lib/gprpp/mpscq.cc
index 2bf9981..373ec09 100644
--- a/grpc/src/core/lib/gprpp/mpscq.cc
+++ b/grpc/src/core/lib/gprpp/mpscq.cc
@@ -86,9 +86,9 @@
 
 LockedMultiProducerSingleConsumerQueue::Node*
 LockedMultiProducerSingleConsumerQueue::TryPop() {
-  if (gpr_mu_trylock(mu_.get())) {
+  if (mu_.TryLock()) {
     Node* node = queue_.Pop();
-    gpr_mu_unlock(mu_.get());
+    mu_.Unlock();
     return node;
   }
   return nullptr;
diff --git a/grpc/src/core/lib/gprpp/ref_counted.h b/grpc/src/core/lib/gprpp/ref_counted.h
index 64f3f8f..a8def8c 100644
--- a/grpc/src/core/lib/gprpp/ref_counted.h
+++ b/grpc/src/core/lib/gprpp/ref_counted.h
@@ -215,31 +215,45 @@
   ~NonPolymorphicRefCount() = default;
 };
 
+// Behavior of RefCounted<> upon ref count reaching 0.
+enum UnrefBehavior {
+  // Default behavior: Delete the object.
+  kUnrefDelete,
+  // Do not delete the object upon unref.  This is useful in cases where all
+  // existing objects must be tracked in a registry but the object's entry in
+  // the registry cannot be removed from the object's dtor due to
+  // synchronization issues.  In this case, the registry can be cleaned up
+  // later by identifying entries for which RefIfNonZero() returns null.
+  kUnrefNoDelete,
+  // Call the object's dtor but do not delete it.  This is useful for cases
+  // where the object is stored in memory allocated elsewhere (e.g., the call
+  // arena).
+  kUnrefCallDtor,
+};
+
 namespace internal {
-template <typename T, bool DoDelete>
+template <typename T, UnrefBehavior UnrefBehaviorArg>
 class Delete;
 template <typename T>
-class Delete<T, true> {
+class Delete<T, kUnrefDelete> {
  public:
   explicit Delete(T* t) { delete t; }
 };
 template <typename T>
-class Delete<T, false> {
+class Delete<T, kUnrefNoDelete> {
  public:
-  explicit Delete(T* t) {}
+  explicit Delete(T* /*t*/) {}
+};
+template <typename T>
+class Delete<T, kUnrefCallDtor> {
+ public:
+  explicit Delete(T* t) { t->~T(); }
 };
 }  // namespace internal
 
 // A base class for reference-counted objects.
 // New objects should be created via new and start with a refcount of 1.
-// When the refcount reaches 0, the object will be deleted via delete.
-//
-// If DeleteUponUnref is false, deletion will not occur when the ref
-// count reaches 0.  This is useful in cases where all existing objects
-// must be tracked in a registry but the object's entry in the registry
-// cannot be removed from the object's dtor due to synchronization issues.
-// In this case, the registry can be cleaned up later by identifying
-// entries for which RefIfNonZero() returns null.
+// When the refcount reaches 0, executes the specified UnrefBehavior.
 //
 // This will commonly be used by CRTP (curiously-recurring template pattern)
 // e.g., class MyClass : public RefCounted<MyClass>
@@ -264,7 +278,7 @@
 //    ch->Unref();
 //
 template <typename Child, typename Impl = PolymorphicRefCount,
-          bool DeleteUponUnref = true>
+          UnrefBehavior UnrefBehaviorArg = kUnrefDelete>
 class RefCounted : public Impl {
  public:
   // Note: Depending on the Impl used, this dtor can be implicitly virtual.
@@ -287,12 +301,12 @@
   // friend of this class.
   void Unref() {
     if (GPR_UNLIKELY(refs_.Unref())) {
-      internal::Delete<Child, DeleteUponUnref>(static_cast<Child*>(this));
+      internal::Delete<Child, UnrefBehaviorArg>(static_cast<Child*>(this));
     }
   }
   void Unref(const DebugLocation& location, const char* reason) {
     if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
-      internal::Delete<Child, DeleteUponUnref>(static_cast<Child*>(this));
+      internal::Delete<Child, UnrefBehaviorArg>(static_cast<Child*>(this));
     }
   }
 
diff --git a/grpc/src/core/lib/gprpp/ref_counted_ptr.h b/grpc/src/core/lib/gprpp/ref_counted_ptr.h
index fd3bfbd..4ee1b95 100644
--- a/grpc/src/core/lib/gprpp/ref_counted_ptr.h
+++ b/grpc/src/core/lib/gprpp/ref_counted_ptr.h
@@ -83,6 +83,7 @@
   }
 
   // Copy assignment.
+  // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
   RefCountedPtr& operator=(const RefCountedPtr& other) {
     // Note: Order of reffing and unreffing is important here in case value_
     // and other.value_ are the same object.
@@ -235,6 +236,7 @@
   }
 
   // Copy assignment.
+  // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
   WeakRefCountedPtr& operator=(const WeakRefCountedPtr& other) {
     // Note: Order of reffing and unreffing is important here in case value_
     // and other.value_ are the same object.
diff --git a/grpc/src/core/lib/gprpp/status_helper.cc b/grpc/src/core/lib/gprpp/status_helper.cc
new file mode 100644
index 0000000..8266e16
--- /dev/null
+++ b/grpc/src/core/lib/gprpp/status_helper.cc
@@ -0,0 +1,407 @@
+//
+//
+// Copyright 2021 the 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>
+
+#include "src/core/lib/gprpp/status_helper.h"
+#include "src/core/lib/gprpp/time_util.h"
+
+#include <grpc/support/log.h>
+
+#include "absl/strings/cord.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+#include "absl/time/clock.h"
+
+#include "google/protobuf/any.upb.h"
+#include "google/rpc/status.upb.h"
+#include "upb/upb.hpp"
+
+namespace grpc_core {
+
+namespace {
+
+#define TYPE_URL_PREFIX "type.googleapis.com/grpc.status."
+#define TYPE_INT_TAG "int."
+#define TYPE_STR_TAG "str."
+#define TYPE_TIME_TAG "time."
+#define TYPE_CHILDREN_TAG "children"
+#define TYPE_URL(name) (TYPE_URL_PREFIX name)
+const absl::string_view kTypeUrlPrefix = TYPE_URL_PREFIX;
+const absl::string_view kTypeIntTag = TYPE_INT_TAG;
+const absl::string_view kTypeStrTag = TYPE_STR_TAG;
+const absl::string_view kTypeTimeTag = TYPE_TIME_TAG;
+const absl::string_view kTypeChildrenTag = TYPE_CHILDREN_TAG;
+const absl::string_view kChildrenPropertyUrl = TYPE_URL(TYPE_CHILDREN_TAG);
+
+const char* GetStatusIntPropertyUrl(StatusIntProperty key) {
+  switch (key) {
+    case StatusIntProperty::kErrorNo:
+      return TYPE_URL(TYPE_INT_TAG "errno");
+    case StatusIntProperty::kFileLine:
+      return TYPE_URL(TYPE_INT_TAG "file_line");
+    case StatusIntProperty::kStreamId:
+      return TYPE_URL(TYPE_INT_TAG "stream_id");
+    case StatusIntProperty::kRpcStatus:
+      return TYPE_URL(TYPE_INT_TAG "grpc_status");
+    case StatusIntProperty::kOffset:
+      return TYPE_URL(TYPE_INT_TAG "offset");
+    case StatusIntProperty::kIndex:
+      return TYPE_URL(TYPE_INT_TAG "index");
+    case StatusIntProperty::kSize:
+      return TYPE_URL(TYPE_INT_TAG "size");
+    case StatusIntProperty::kHttp2Error:
+      return TYPE_URL(TYPE_INT_TAG "http2_error");
+    case StatusIntProperty::kTsiCode:
+      return TYPE_URL(TYPE_INT_TAG "tsi_code");
+    case StatusIntProperty::kWsaError:
+      return TYPE_URL(TYPE_INT_TAG "wsa_error");
+    case StatusIntProperty::kFd:
+      return TYPE_URL(TYPE_INT_TAG "fd");
+    case StatusIntProperty::kHttpStatus:
+      return TYPE_URL(TYPE_INT_TAG "http_status");
+    case StatusIntProperty::kOccurredDuringWrite:
+      return TYPE_URL(TYPE_INT_TAG "occurred_during_write");
+    case StatusIntProperty::ChannelConnectivityState:
+      return TYPE_URL(TYPE_INT_TAG "channel_connectivity_state");
+    case StatusIntProperty::kLbPolicyDrop:
+      return TYPE_URL(TYPE_INT_TAG "lb_policy_drop");
+  }
+  GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+const char* GetStatusStrPropertyUrl(StatusStrProperty key) {
+  switch (key) {
+    case StatusStrProperty::kDescription:
+      return TYPE_URL(TYPE_STR_TAG "description");
+    case StatusStrProperty::kFile:
+      return TYPE_URL(TYPE_STR_TAG "file");
+    case StatusStrProperty::kOsError:
+      return TYPE_URL(TYPE_STR_TAG "os_error");
+    case StatusStrProperty::kSyscall:
+      return TYPE_URL(TYPE_STR_TAG "syscall");
+    case StatusStrProperty::kTargetAddress:
+      return TYPE_URL(TYPE_STR_TAG "target_address");
+    case StatusStrProperty::kGrpcMessage:
+      return TYPE_URL(TYPE_STR_TAG "grpc_message");
+    case StatusStrProperty::kRawBytes:
+      return TYPE_URL(TYPE_STR_TAG "raw_bytes");
+    case StatusStrProperty::kTsiError:
+      return TYPE_URL(TYPE_STR_TAG "tsi_error");
+    case StatusStrProperty::kFilename:
+      return TYPE_URL(TYPE_STR_TAG "filename");
+    case StatusStrProperty::kKey:
+      return TYPE_URL(TYPE_STR_TAG "key");
+    case StatusStrProperty::kValue:
+      return TYPE_URL(TYPE_STR_TAG "value");
+  }
+  GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+const char* GetStatusTimePropertyUrl(StatusTimeProperty key) {
+  switch (key) {
+    case StatusTimeProperty::kCreated:
+      return TYPE_URL(TYPE_TIME_TAG "created_time");
+  }
+  GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+void EncodeUInt32ToBytes(uint32_t v, char* buf) {
+  buf[0] = v & 0xFF;
+  buf[1] = (v >> 8) & 0xFF;
+  buf[2] = (v >> 16) & 0xFF;
+  buf[3] = (v >> 24) & 0xFF;
+}
+
+uint32_t DecodeUInt32FromBytes(const char* buf) {
+  return buf[0] | (uint32_t(buf[1]) << 8) | (uint32_t(buf[2]) << 16) |
+         (uint32_t(buf[3]) << 24);
+}
+
+std::vector<absl::Status> ParseChildren(absl::Cord children) {
+  std::vector<absl::Status> result;
+  upb::Arena arena;
+  // Cord is flattened to iterate the buffer easily at the cost of memory copy.
+  // TODO(veblush): Optimize this once CordReader is introduced.
+  absl::string_view buf = children.Flatten();
+  size_t cur = 0;
+  while (buf.size() - cur >= sizeof(uint32_t)) {
+    size_t msg_size = DecodeUInt32FromBytes(buf.data() + cur);
+    cur += sizeof(uint32_t);
+    GPR_ASSERT(buf.size() - cur >= msg_size);
+    google_rpc_Status* msg =
+        google_rpc_Status_parse(buf.data() + cur, msg_size, arena.ptr());
+    cur += msg_size;
+    result.push_back(internal::StatusFromProto(msg));
+  }
+  return result;
+}
+
+}  // namespace
+
+absl::Status StatusCreate(absl::StatusCode code, absl::string_view msg,
+                          const DebugLocation& location,
+                          std::initializer_list<absl::Status> children) {
+  absl::Status s(code, msg);
+  if (location.file() != nullptr) {
+    StatusSetStr(&s, StatusStrProperty::kFile, location.file());
+  }
+  if (location.line() != -1) {
+    StatusSetInt(&s, StatusIntProperty::kFileLine, location.line());
+  }
+  StatusSetTime(&s, StatusTimeProperty::kCreated, absl::Now());
+  for (const absl::Status& child : children) {
+    if (!child.ok()) {
+      StatusAddChild(&s, child);
+    }
+  }
+  return s;
+}
+
+void StatusSetInt(absl::Status* status, StatusIntProperty key, intptr_t value) {
+  status->SetPayload(GetStatusIntPropertyUrl(key),
+                     absl::Cord(std::to_string(value)));
+}
+
+absl::optional<intptr_t> StatusGetInt(const absl::Status& status,
+                                      StatusIntProperty key) {
+  absl::optional<absl::Cord> p =
+      status.GetPayload(GetStatusIntPropertyUrl(key));
+  if (p.has_value()) {
+    absl::optional<absl::string_view> sv = p->TryFlat();
+    intptr_t value;
+    if (sv.has_value()) {
+      if (absl::SimpleAtoi(*sv, &value)) {
+        return value;
+      }
+    } else {
+      if (absl::SimpleAtoi(std::string(*p), &value)) {
+        return value;
+      }
+    }
+  }
+  return {};
+}
+
+void StatusSetStr(absl::Status* status, StatusStrProperty key,
+                  absl::string_view value) {
+  status->SetPayload(GetStatusStrPropertyUrl(key), absl::Cord(value));
+}
+
+absl::optional<std::string> StatusGetStr(const absl::Status& status,
+                                         StatusStrProperty key) {
+  absl::optional<absl::Cord> p =
+      status.GetPayload(GetStatusStrPropertyUrl(key));
+  if (p.has_value()) {
+    return std::string(*p);
+  }
+  return {};
+}
+
+void StatusSetTime(absl::Status* status, StatusTimeProperty key,
+                   absl::Time time) {
+  status->SetPayload(GetStatusTimePropertyUrl(key),
+                     absl::Cord(absl::string_view(
+                         reinterpret_cast<const char*>(&time), sizeof(time))));
+}
+
+absl::optional<absl::Time> StatusGetTime(const absl::Status& status,
+                                         StatusTimeProperty key) {
+  absl::optional<absl::Cord> p =
+      status.GetPayload(GetStatusTimePropertyUrl(key));
+  if (p.has_value()) {
+    absl::optional<absl::string_view> sv = p->TryFlat();
+    if (sv.has_value()) {
+      return *reinterpret_cast<const absl::Time*>(sv->data());
+    } else {
+      std::string s = std::string(*p);
+      return *reinterpret_cast<const absl::Time*>(s.c_str());
+    }
+  }
+  return {};
+}
+
+void StatusAddChild(absl::Status* status, absl::Status child) {
+  upb::Arena arena;
+  // Serialize msg to buf
+  google_rpc_Status* msg = internal::StatusToProto(child, arena.ptr());
+  size_t buf_len = 0;
+  char* buf = google_rpc_Status_serialize(msg, arena.ptr(), &buf_len);
+  // Append (msg-length and msg) to children payload
+  absl::optional<absl::Cord> old_children =
+      status->GetPayload(kChildrenPropertyUrl);
+  absl::Cord children;
+  if (old_children.has_value()) {
+    children = *old_children;
+  }
+  char head_buf[sizeof(uint32_t)];
+  EncodeUInt32ToBytes(buf_len, head_buf);
+  children.Append(absl::string_view(head_buf, sizeof(uint32_t)));
+  children.Append(absl::string_view(buf, buf_len));
+  status->SetPayload(kChildrenPropertyUrl, std::move(children));
+}
+
+std::vector<absl::Status> StatusGetChildren(absl::Status status) {
+  absl::optional<absl::Cord> children = status.GetPayload(kChildrenPropertyUrl);
+  return children.has_value() ? ParseChildren(*children)
+                              : std::vector<absl::Status>();
+}
+
+std::string StatusToString(const absl::Status& status) {
+  if (status.ok()) {
+    return "OK";
+  }
+  std::string head;
+  absl::StrAppend(&head, absl::StatusCodeToString(status.code()));
+  if (!status.message().empty()) {
+    absl::StrAppend(&head, ":", status.message());
+  }
+  std::vector<std::string> kvs;
+  absl::optional<absl::Cord> children;
+  status.ForEachPayload([&](absl::string_view type_url,
+                            const absl::Cord& payload) {
+    if (absl::StartsWith(type_url, kTypeUrlPrefix)) {
+      type_url.remove_prefix(kTypeUrlPrefix.size());
+      if (type_url == kTypeChildrenTag) {
+        children = payload;
+        return;
+      }
+      absl::string_view payload_view;
+      std::string payload_storage;
+      if (payload.TryFlat().has_value()) {
+        payload_view = payload.TryFlat().value();
+      } else {
+        payload_storage = std::string(payload);
+        payload_view = payload_storage;
+      }
+      if (absl::StartsWith(type_url, kTypeIntTag)) {
+        type_url.remove_prefix(kTypeIntTag.size());
+        kvs.push_back(absl::StrCat(type_url, ":", payload_view));
+      } else if (absl::StartsWith(type_url, kTypeStrTag)) {
+        type_url.remove_prefix(kTypeStrTag.size());
+        kvs.push_back(absl::StrCat(type_url, ":\"",
+                                   absl::CHexEscape(payload_view), "\""));
+      } else if (absl::StartsWith(type_url, kTypeTimeTag)) {
+        type_url.remove_prefix(kTypeTimeTag.size());
+        absl::Time t =
+            *reinterpret_cast<const absl::Time*>(payload_view.data());
+        kvs.push_back(absl::StrCat(type_url, ":\"", absl::FormatTime(t), "\""));
+      } else {
+        kvs.push_back(absl::StrCat(type_url, ":\"",
+                                   absl::CHexEscape(payload_view), "\""));
+      }
+    } else {
+      absl::optional<absl::string_view> payload_view = payload.TryFlat();
+      std::string payload_str = absl::CHexEscape(
+          payload_view.has_value() ? *payload_view : std::string(payload));
+      kvs.push_back(absl::StrCat(type_url, ":\"", payload_str, "\""));
+    }
+  });
+  if (children.has_value()) {
+    std::vector<absl::Status> children_status = ParseChildren(*children);
+    std::vector<std::string> children_text;
+    children_text.reserve(children_status.size());
+    for (const absl::Status& child_status : children_status) {
+      children_text.push_back(StatusToString(child_status));
+    }
+    kvs.push_back(
+        absl::StrCat("children:[", absl::StrJoin(children_text, ", "), "]"));
+  }
+  return kvs.empty() ? head
+                     : absl::StrCat(head, " {", absl::StrJoin(kvs, ", "), "}");
+}
+
+namespace internal {
+
+google_rpc_Status* StatusToProto(absl::Status status, upb_arena* arena) {
+  google_rpc_Status* msg = google_rpc_Status_new(arena);
+  google_rpc_Status_set_code(msg, int32_t(status.code()));
+  google_rpc_Status_set_message(
+      msg, upb_strview_make(status.message().data(), status.message().size()));
+  status.ForEachPayload([&](absl::string_view type_url,
+                            const absl::Cord& payload) {
+    google_protobuf_Any* any = google_rpc_Status_add_details(msg, arena);
+    char* type_url_buf =
+        reinterpret_cast<char*>(upb_arena_malloc(arena, type_url.size()));
+    memcpy(type_url_buf, type_url.data(), type_url.size());
+    google_protobuf_Any_set_type_url(
+        any, upb_strview_make(type_url_buf, type_url.size()));
+    absl::optional<absl::string_view> v_view = payload.TryFlat();
+    if (v_view.has_value()) {
+      google_protobuf_Any_set_value(
+          any, upb_strview_make(v_view->data(), v_view->size()));
+    } else {
+      char* buf =
+          reinterpret_cast<char*>(upb_arena_malloc(arena, payload.size()));
+      char* cur = buf;
+      for (absl::string_view chunk : payload.Chunks()) {
+        memcpy(cur, chunk.data(), chunk.size());
+        cur += chunk.size();
+      }
+      google_protobuf_Any_set_value(any, upb_strview_make(buf, payload.size()));
+    }
+  });
+  return msg;
+}
+
+absl::Status StatusFromProto(google_rpc_Status* msg) {
+  int32_t code = google_rpc_Status_code(msg);
+  upb_strview message = google_rpc_Status_message(msg);
+  absl::Status status(static_cast<absl::StatusCode>(code),
+                      absl::string_view(message.data, message.size));
+  size_t detail_len;
+  const google_protobuf_Any* const* details =
+      google_rpc_Status_details(msg, &detail_len);
+  for (size_t i = 0; i < detail_len; i++) {
+    upb_strview type_url = google_protobuf_Any_type_url(details[i]);
+    upb_strview value = google_protobuf_Any_value(details[i]);
+    status.SetPayload(absl::string_view(type_url.data, type_url.size),
+                      absl::Cord(absl::string_view(value.data, value.size)));
+  }
+  return status;
+}
+
+uintptr_t StatusAllocPtr(absl::Status s) {
+  // This relies the fact that absl::Status has only one member, StatusRep*
+  // so the sizeof(absl::Status) has the same size of intptr_t and StatusRep*
+  // can be stolen using placement allocation.
+  static_assert(sizeof(intptr_t) == sizeof(absl::Status),
+                "absl::Status should be as big as intptr_t");
+  // This does two things;
+  // 1. Copies StatusRep* of absl::Status to ptr
+  // 2. Increases the counter of StatusRep if it's not inlined
+  uintptr_t ptr;
+  new (&ptr) absl::Status(s);
+  return ptr;
+}
+
+void StatusFreePtr(uintptr_t ptr) {
+  // Decreases the counter of StatusRep if it's not inlined.
+  reinterpret_cast<absl::Status*>(&ptr)->~Status();
+}
+
+absl::Status StatusGetFromPtr(uintptr_t ptr) {
+  // Constructs Status from ptr having the address of StatusRep.
+  return *reinterpret_cast<absl::Status*>(&ptr);
+}
+
+}  // namespace internal
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/lib/gprpp/status_helper.h b/grpc/src/core/lib/gprpp/status_helper.h
new file mode 100644
index 0000000..50bcdff
--- /dev/null
+++ b/grpc/src/core/lib/gprpp/status_helper.h
@@ -0,0 +1,180 @@
+//
+//
+// Copyright 2021 the 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_LIB_GPRPP_STATUS_HELPER_H
+#define GRPC_CORE_LIB_GPRPP_STATUS_HELPER_H
+
+#include <grpc/support/port_platform.h>
+
+#include "absl/status/status.h"
+#include "absl/time/time.h"
+
+#include "src/core/lib/gprpp/debug_location.h"
+
+extern "C" {
+struct google_rpc_Status;
+struct upb_arena;
+}
+
+namespace grpc_core {
+
+/// This enum should have the same value of grpc_error_ints
+// TODO(veblush): Use camel-case names once migration to absl::Status is done.
+enum class StatusIntProperty {
+  /// 'errno' from the operating system
+  kErrorNo,
+  /// __LINE__ from the call site creating the error
+  kFileLine,
+  /// stream identifier: for errors that are associated with an individual
+  /// wire stream
+  kStreamId,
+  /// grpc status code representing this error
+  // TODO(veblush): Remove this after grpc_error is replaced with absl::Status
+  kRpcStatus,
+  /// offset into some binary blob (usually represented by
+  /// RAW_BYTES) where the error occurred
+  kOffset,
+  /// context sensitive index associated with the error
+  kIndex,
+  /// context sensitive size associated with the error
+  kSize,
+  /// http2 error code associated with the error (see the HTTP2 RFC)
+  kHttp2Error,
+  /// TSI status code associated with the error
+  kTsiCode,
+  /// WSAGetLastError() reported when this error occurred
+  kWsaError,
+  /// File descriptor associated with this error
+  kFd,
+  /// HTTP status (i.e. 404)
+  kHttpStatus,
+  /// chttp2: did the error occur while a write was in progress
+  kOccurredDuringWrite,
+  /// channel connectivity state associated with the error
+  ChannelConnectivityState,
+  /// LB policy drop
+  kLbPolicyDrop,
+};
+
+/// This enum should have the same value of grpc_error_strs
+// TODO(veblush): Use camel-case names once migration to absl::Status is done.
+enum class StatusStrProperty {
+  /// top-level textual description of this error
+  kDescription,
+  /// source file in which this error occurred
+  kFile,
+  /// operating system description of this error
+  kOsError,
+  /// syscall that generated this error
+  kSyscall,
+  /// peer that we were trying to communicate when this error occurred
+  kTargetAddress,
+  /// grpc status message associated with this error
+  kGrpcMessage,
+  /// hex dump (or similar) with the data that generated this error
+  kRawBytes,
+  /// tsi error string associated with this error
+  kTsiError,
+  /// filename that we were trying to read/write when this error occurred
+  kFilename,
+  /// key associated with the error
+  kKey,
+  /// value associated with the error
+  kValue,
+};
+
+/// This enum should have the same value of grpc_error_times
+enum class StatusTimeProperty {
+  /// timestamp of error creation
+  kCreated,
+};
+
+/// Creates a status with given additional information
+absl::Status StatusCreate(
+    absl::StatusCode code, absl::string_view msg, const DebugLocation& location,
+    std::initializer_list<absl::Status> children) GRPC_MUST_USE_RESULT;
+
+/// Sets the int property to the status
+void StatusSetInt(absl::Status* status, StatusIntProperty key, intptr_t value);
+
+/// Gets the int property from the status
+absl::optional<intptr_t> StatusGetInt(
+    const absl::Status& status, StatusIntProperty key) GRPC_MUST_USE_RESULT;
+
+/// Sets the str property to the status
+void StatusSetStr(absl::Status* status, StatusStrProperty key,
+                  absl::string_view value);
+
+/// Gets the str property from the status
+absl::optional<std::string> StatusGetStr(
+    const absl::Status& status, StatusStrProperty key) GRPC_MUST_USE_RESULT;
+
+/// Sets the time property to the status
+void StatusSetTime(absl::Status* status, StatusTimeProperty key,
+                   absl::Time time);
+
+/// Gets the time property from the status
+absl::optional<absl::Time> StatusGetTime(
+    const absl::Status& status, StatusTimeProperty key) GRPC_MUST_USE_RESULT;
+
+/// Adds a child status to status
+void StatusAddChild(absl::Status* status, absl::Status child);
+
+/// Returns all children status from a status
+std::vector<absl::Status> StatusGetChildren(absl::Status status)
+    GRPC_MUST_USE_RESULT;
+
+/// Returns a string representation from status
+/// Error status will be like
+///   STATUS[:MESSAGE] [{PAYLOADS[, children:[CHILDREN-STATUS-LISTS]]}]
+/// e.g.
+///   CANCELLATION:SampleMessage {errno:'2021', line:'54', children:[ABORTED]}
+std::string StatusToString(const absl::Status& status) GRPC_MUST_USE_RESULT;
+
+namespace internal {
+
+/// Builds a upb message, google_rpc_Status from a status
+/// This is for internal implementation & test only
+google_rpc_Status* StatusToProto(absl::Status status,
+                                 upb_arena* arena) GRPC_MUST_USE_RESULT;
+
+/// Builds a status from a upb message, google_rpc_Status
+/// This is for internal implementation & test only
+absl::Status StatusFromProto(google_rpc_Status* msg) GRPC_MUST_USE_RESULT;
+
+/// The same value of grpc_core::internal::StatusAllocPtr(absl::OkStatus())
+static constexpr uintptr_t kOkStatusPtr = 0;
+
+/// Returns ptr where the given status is copied into.
+/// This ptr can be used to get Status later and should be freed by
+/// StatusFreePtr. This shouldn't be used except migration purpose.
+uintptr_t StatusAllocPtr(absl::Status s);
+
+/// Frees the allocated status at ptr.
+/// This shouldn't be used except migration purpose.
+void StatusFreePtr(uintptr_t ptr);
+
+/// Get the status from ptr.
+/// This shouldn't be used except migration purpose.
+absl::Status StatusGetFromPtr(uintptr_t ptr);
+
+}  // namespace internal
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_LIB_GPRPP_STATUS_HELPER_H
diff --git a/grpc/src/core/lib/gprpp/sync.h b/grpc/src/core/lib/gprpp/sync.h
index 0a911b1..f385883 100644
--- a/grpc/src/core/lib/gprpp/sync.h
+++ b/grpc/src/core/lib/gprpp/sync.h
@@ -26,6 +26,9 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "absl/synchronization/mutex.h"
+#include "src/core/lib/gprpp/time_util.h"
+
 // The core library is not accessible in C++ codegen headers, and vice versa.
 // Thus, we need to have duplicate headers with similar functionality.
 // Make sure any change to this file is also reflected in
@@ -37,7 +40,23 @@
 
 namespace grpc_core {
 
-class Mutex {
+#ifdef GPR_ABSEIL_SYNC
+
+using Mutex = absl::Mutex;
+using MutexLock = absl::MutexLock;
+using ReleasableMutexLock = absl::ReleasableMutexLock;
+using CondVar = absl::CondVar;
+
+// Returns the underlying gpr_mu from Mutex. This should be used only when
+// it has to like passing the C++ mutex to C-core API.
+// TODO(veblush): Remove this after C-core no longer uses gpr_mu.
+inline gpr_mu* GetUnderlyingGprMu(Mutex* mutex) {
+  return reinterpret_cast<gpr_mu*>(mutex);
+}
+
+#else
+
+class ABSL_LOCKABLE Mutex {
  public:
   Mutex() { gpr_mu_init(&mu_); }
   ~Mutex() { gpr_mu_destroy(&mu_); }
@@ -45,52 +64,59 @@
   Mutex(const Mutex&) = delete;
   Mutex& operator=(const Mutex&) = delete;
 
-  gpr_mu* get() { return &mu_; }
-  const gpr_mu* get() const { return &mu_; }
+  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { gpr_mu_lock(&mu_); }
+  void Unlock() ABSL_UNLOCK_FUNCTION() { gpr_mu_unlock(&mu_); }
+  bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+    return gpr_mu_trylock(&mu_) != 0;
+  }
 
  private:
   gpr_mu mu_;
+
+  friend class CondVar;
+  friend gpr_mu* GetUnderlyingGprMu(Mutex* mutex);
 };
 
-// MutexLock is a std::
-class MutexLock {
+// Returns the underlying gpr_mu from Mutex. This should be used only when
+// it has to like passing the C++ mutex to C-core API.
+// TODO(veblush): Remove this after C-core no longer uses gpr_mu.
+inline gpr_mu* GetUnderlyingGprMu(Mutex* mutex) { return &mutex->mu_; }
+
+class ABSL_SCOPED_LOCKABLE MutexLock {
  public:
-  explicit MutexLock(Mutex* mu) : mu_(mu->get()) { gpr_mu_lock(mu_); }
-  explicit MutexLock(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu_); }
-  ~MutexLock() { gpr_mu_unlock(mu_); }
+  explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
+    mu_->Lock();
+  }
+  ~MutexLock() ABSL_UNLOCK_FUNCTION() { mu_->Unlock(); }
 
   MutexLock(const MutexLock&) = delete;
   MutexLock& operator=(const MutexLock&) = delete;
 
  private:
-  gpr_mu* const mu_;
+  Mutex* const mu_;
 };
 
-class ReleasableMutexLock {
+class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
  public:
-  explicit ReleasableMutexLock(Mutex* mu) : mu_(mu->get()) { gpr_mu_lock(mu_); }
-  explicit ReleasableMutexLock(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu_); }
-  ~ReleasableMutexLock() {
-    if (!released_) gpr_mu_unlock(mu_);
+  explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu_->Lock();
+  }
+  ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
+    if (!released_) mu_->Unlock();
   }
 
   ReleasableMutexLock(const ReleasableMutexLock&) = delete;
   ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
 
-  void Lock() {
-    GPR_DEBUG_ASSERT(released_);
-    gpr_mu_lock(mu_);
-    released_ = false;
-  }
-
-  void Unlock() {
+  void Release() ABSL_UNLOCK_FUNCTION() {
     GPR_DEBUG_ASSERT(!released_);
     released_ = true;
-    gpr_mu_unlock(mu_);
+    mu_->Unlock();
   }
 
  private:
-  gpr_mu* const mu_;
+  Mutex* const mu_;
   bool released_ = false;
 };
 
@@ -103,33 +129,96 @@
   CondVar& operator=(const CondVar&) = delete;
 
   void Signal() { gpr_cv_signal(&cv_); }
-  void Broadcast() { gpr_cv_broadcast(&cv_); }
+  void SignalAll() { gpr_cv_broadcast(&cv_); }
 
-  int Wait(Mutex* mu) { return Wait(mu, gpr_inf_future(GPR_CLOCK_REALTIME)); }
-  int Wait(Mutex* mu, const gpr_timespec& deadline) {
-    return gpr_cv_wait(&cv_, mu->get(), deadline);
+  void Wait(Mutex* mu) { WaitWithDeadline(mu, absl::InfiniteFuture()); }
+  bool WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
+    return gpr_cv_wait(&cv_, &mu->mu_, ToGprTimeSpec(timeout)) != 0;
   }
-
-  template <typename Predicate>
-  void WaitUntil(Mutex* mu, Predicate pred) {
-    while (!pred()) {
-      Wait(mu, gpr_inf_future(GPR_CLOCK_REALTIME));
-    }
-  }
-
-  // Returns true iff we timed-out
-  template <typename Predicate>
-  bool WaitUntil(Mutex* mu, Predicate pred, const gpr_timespec& deadline) {
-    while (!pred()) {
-      if (Wait(mu, deadline)) return true;
-    }
-    return false;
+  bool WaitWithDeadline(Mutex* mu, absl::Time deadline) {
+    return gpr_cv_wait(&cv_, &mu->mu_, ToGprTimeSpec(deadline)) != 0;
   }
 
  private:
   gpr_cv cv_;
 };
 
+#endif  // GPR_ABSEIL_SYNC
+
+template <typename Predicate>
+static void WaitUntil(CondVar* cv, Mutex* mu, Predicate pred) {
+  while (!pred()) {
+    cv->Wait(mu);
+  }
+}
+
+// Returns true iff we timed-out
+template <typename Predicate>
+static bool WaitUntilWithTimeout(CondVar* cv, Mutex* mu, Predicate pred,
+                                 absl::Duration timeout) {
+  while (!pred()) {
+    if (cv->WaitWithTimeout(mu, timeout)) return true;
+  }
+  return false;
+}
+
+// Returns true iff we timed-out
+template <typename Predicate>
+static bool WaitUntilWithDeadline(CondVar* cv, Mutex* mu, Predicate pred,
+                                  absl::Time deadline) {
+  while (!pred()) {
+    if (cv->WaitWithDeadline(mu, deadline)) return true;
+  }
+  return false;
+}
+
+// Deprecated. Prefer MutexLock
+class MutexLockForGprMu {
+ public:
+  explicit MutexLockForGprMu(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu_); }
+  ~MutexLockForGprMu() { gpr_mu_unlock(mu_); }
+
+  MutexLockForGprMu(const MutexLock&) = delete;
+  MutexLockForGprMu& operator=(const MutexLock&) = delete;
+
+ private:
+  gpr_mu* const mu_;
+};
+
+// Deprecated. Prefer MutexLock or ReleasableMutexLock
+class ABSL_SCOPED_LOCKABLE LockableAndReleasableMutexLock {
+ public:
+  explicit LockableAndReleasableMutexLock(Mutex* mu)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu_->Lock();
+  }
+  ~LockableAndReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
+    if (!released_) mu_->Unlock();
+  }
+
+  LockableAndReleasableMutexLock(const LockableAndReleasableMutexLock&) =
+      delete;
+  LockableAndReleasableMutexLock& operator=(
+      const LockableAndReleasableMutexLock&) = delete;
+
+  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
+    GPR_DEBUG_ASSERT(released_);
+    mu_->Lock();
+    released_ = false;
+  }
+
+  void Release() ABSL_UNLOCK_FUNCTION() {
+    GPR_DEBUG_ASSERT(!released_);
+    released_ = true;
+    mu_->Unlock();
+  }
+
+ private:
+  Mutex* const mu_;
+  bool released_ = false;
+};
+
 }  // namespace grpc_core
 
 #endif /* GRPC_CORE_LIB_GPRPP_SYNC_H */
diff --git a/grpc/src/core/lib/gprpp/thd.h b/grpc/src/core/lib/gprpp/thd.h
index 2e7135e..c4ce04c 100644
--- a/grpc/src/core/lib/gprpp/thd.h
+++ b/grpc/src/core/lib/gprpp/thd.h
@@ -157,7 +157,7 @@
   Thread& operator=(const Thread&) = delete;
 
   /// The thread states are as follows:
-  /// FAKE -- just a dummy placeholder Thread created by the default constructor
+  /// FAKE -- just a phony placeholder Thread created by the default constructor
   /// ALIVE -- an actual thread of control exists associated with this thread
   /// STARTED -- the thread of control has been started
   /// DONE -- the thread of control has completed and been joined
diff --git a/grpc/src/core/lib/gprpp/time_util.cc b/grpc/src/core/lib/gprpp/time_util.cc
new file mode 100644
index 0000000..d3aa25a
--- /dev/null
+++ b/grpc/src/core/lib/gprpp/time_util.cc
@@ -0,0 +1,77 @@
+//
+// Copyright 2021 the 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>
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gprpp/time_util.h"
+
+namespace grpc_core {
+
+gpr_timespec ToGprTimeSpec(absl::Duration duration) {
+  if (duration == absl::InfiniteDuration()) {
+    return gpr_inf_future(GPR_TIMESPAN);
+  } else if (duration == -absl::InfiniteDuration()) {
+    return gpr_inf_past(GPR_TIMESPAN);
+  } else {
+    int64_t s = absl::IDivDuration(duration, absl::Seconds(1), &duration);
+    int64_t n = absl::IDivDuration(duration, absl::Nanoseconds(1), &duration);
+    return gpr_time_add(gpr_time_from_seconds(s, GPR_TIMESPAN),
+                        gpr_time_from_nanos(n, GPR_TIMESPAN));
+  }
+}
+
+gpr_timespec ToGprTimeSpec(absl::Time time) {
+  if (time == absl::InfiniteFuture()) {
+    return gpr_inf_future(GPR_CLOCK_REALTIME);
+  } else if (time == absl::InfinitePast()) {
+    return gpr_inf_past(GPR_CLOCK_REALTIME);
+  } else {
+    timespec ts = absl::ToTimespec(time);
+    gpr_timespec out;
+    out.tv_sec = static_cast<decltype(out.tv_sec)>(ts.tv_sec);
+    out.tv_nsec = static_cast<decltype(out.tv_nsec)>(ts.tv_nsec);
+    out.clock_type = GPR_CLOCK_REALTIME;
+    return out;
+  }
+}
+
+absl::Duration ToAbslDuration(gpr_timespec ts) {
+  GPR_ASSERT(ts.clock_type == GPR_TIMESPAN);
+  if (gpr_time_cmp(ts, gpr_inf_future(GPR_TIMESPAN)) == 0) {
+    return absl::InfiniteDuration();
+  } else if (gpr_time_cmp(ts, gpr_inf_past(GPR_TIMESPAN)) == 0) {
+    return -absl::InfiniteDuration();
+  } else {
+    return absl::Seconds(ts.tv_sec) + absl::Nanoseconds(ts.tv_nsec);
+  }
+}
+
+absl::Time ToAbslTime(gpr_timespec ts) {
+  GPR_ASSERT(ts.clock_type != GPR_TIMESPAN);
+  gpr_timespec rts = gpr_convert_clock_type(ts, GPR_CLOCK_REALTIME);
+  if (gpr_time_cmp(rts, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) {
+    return absl::InfiniteFuture();
+  } else if (gpr_time_cmp(rts, gpr_inf_past(GPR_CLOCK_REALTIME)) == 0) {
+    return absl::InfinitePast();
+  } else {
+    return absl::UnixEpoch() + absl::Seconds(rts.tv_sec) +
+           absl::Nanoseconds(rts.tv_nsec);
+  }
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/lib/gprpp/time_util.h b/grpc/src/core/lib/gprpp/time_util.h
new file mode 100644
index 0000000..4ae4a40
--- /dev/null
+++ b/grpc/src/core/lib/gprpp/time_util.h
@@ -0,0 +1,42 @@
+//
+// Copyright 2021 the 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_LIB_GPRPP_TIME_UTIL_H
+#define GRPC_CORE_LIB_GPRPP_TIME_UTIL_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/time.h>
+
+#include "absl/time/time.h"
+
+namespace grpc_core {
+
+// Converts absl::Duration to gpr_timespec(GPR_TIMESPAN)
+gpr_timespec ToGprTimeSpec(absl::Duration duration);
+
+// Converts absl::Time to gpr_timespec(GPR_CLOCK_REALTIME)
+gpr_timespec ToGprTimeSpec(absl::Time time);
+
+// Converts gpr_timespec(GPR_TIMESPAN) to absl::Duration
+absl::Duration ToAbslDuration(gpr_timespec ts);
+
+// Converts gpr_timespec(GPR_CLOCK_[MONOTONIC|REALTIME|PRECISE]) to absl::Time
+absl::Time ToAbslTime(gpr_timespec ts);
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_LIB_GPRPP_TIME_UTIL_H
diff --git a/grpc/src/core/lib/http/httpcli.cc b/grpc/src/core/lib/http/httpcli.cc
index 8d024dd..e3d2fbe 100644
--- a/grpc/src/core/lib/http/httpcli.cc
+++ b/grpc/src/core/lib/http/httpcli.cc
@@ -30,6 +30,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
@@ -38,7 +39,6 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/slice/slice_internal.h"
 
@@ -62,7 +62,7 @@
   grpc_closure on_read;
   grpc_closure done_write;
   grpc_closure connected;
-  grpc_error* overall_error;
+  grpc_error_handle overall_error;
   grpc_resource_quota* resource_quota;
 };
 static grpc_httpcli_get_override g_get_override = nullptr;
@@ -86,9 +86,9 @@
   grpc_pollset_set_destroy(context->pollset_set);
 }
 
-static void next_address(internal_request* req, grpc_error* due_to_error);
+static void next_address(internal_request* req, grpc_error_handle due_to_error);
 
-static void finish(internal_request* req, grpc_error* error) {
+static void finish(internal_request* req, grpc_error_handle error) {
   grpc_polling_entity_del_from_pollset_set(req->pollent,
                                            req->context->pollset_set);
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, req->on_done, error);
@@ -110,7 +110,7 @@
   gpr_free(req);
 }
 
-static void append_error(internal_request* req, grpc_error* error) {
+static void append_error(internal_request* req, grpc_error_handle error) {
   if (req->overall_error == GRPC_ERROR_NONE) {
     req->overall_error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request");
@@ -127,14 +127,14 @@
   grpc_endpoint_read(req->ep, &req->incoming, &req->on_read, /*urgent=*/true);
 }
 
-static void on_read(void* user_data, grpc_error* error) {
+static void on_read(void* user_data, grpc_error_handle error) {
   internal_request* req = static_cast<internal_request*>(user_data);
   size_t i;
 
   for (i = 0; i < req->incoming.count; i++) {
     if (GRPC_SLICE_LENGTH(req->incoming.slices[i])) {
       req->have_read_byte = 1;
-      grpc_error* err = grpc_http_parser_parse(
+      grpc_error_handle err = grpc_http_parser_parse(
           &req->parser, req->incoming.slices[i], nullptr);
       if (err != GRPC_ERROR_NONE) {
         finish(req, err);
@@ -154,7 +154,7 @@
 
 static void on_written(internal_request* req) { do_read(req); }
 
-static void done_write(void* arg, grpc_error* error) {
+static void done_write(void* arg, grpc_error_handle error) {
   internal_request* req = static_cast<internal_request*>(arg);
   if (error == GRPC_ERROR_NONE) {
     on_written(req);
@@ -182,7 +182,7 @@
   start_write(req);
 }
 
-static void on_connected(void* arg, grpc_error* error) {
+static void on_connected(void* arg, grpc_error_handle error) {
   internal_request* req = static_cast<internal_request*>(arg);
 
   if (!req->ep) {
@@ -194,7 +194,7 @@
       req->deadline, on_handshake_done);
 }
 
-static void next_address(internal_request* req, grpc_error* error) {
+static void next_address(internal_request* req, grpc_error_handle error) {
   grpc_resolved_address* addr;
   if (error != GRPC_ERROR_NONE) {
     append_error(req, error);
@@ -216,7 +216,7 @@
                           &args, addr, req->deadline);
 }
 
-static void on_resolved(void* arg, grpc_error* error) {
+static void on_resolved(void* arg, grpc_error_handle error) {
   internal_request* req = static_cast<internal_request*>(arg);
   if (error != GRPC_ERROR_NONE) {
     finish(req, GRPC_ERROR_REF(error));
diff --git a/grpc/src/core/lib/http/httpcli_security_connector.cc b/grpc/src/core/lib/http/httpcli_security_connector.cc
index 15aea33..e26f99b 100644
--- a/grpc/src/core/lib/http/httpcli_security_connector.cc
+++ b/grpc/src/core/lib/http/httpcli_security_connector.cc
@@ -91,7 +91,7 @@
   void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
                   grpc_core::RefCountedPtr<grpc_auth_context>* /*auth_context*/,
                   grpc_closure* on_peer_checked) override {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
 
     /* Check the peer name. */
     if (secure_peer_name_ != nullptr &&
@@ -105,6 +105,11 @@
     tsi_peer_destruct(&peer);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override {
     auto* other =
         reinterpret_cast<const grpc_httpcli_ssl_channel_security_connector*>(
@@ -115,13 +120,13 @@
   bool check_call_host(absl::string_view /*host*/,
                        grpc_auth_context* /*auth_context*/,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** error) override {
+                       grpc_error_handle* error) override {
     *error = GRPC_ERROR_NONE;
     return true;
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -160,13 +165,12 @@
   void* arg;
   grpc_core::RefCountedPtr<grpc_core::HandshakeManager> handshake_mgr;
 };
-static void on_handshake_done(void* arg, grpc_error* error) {
+static void on_handshake_done(void* arg, grpc_error_handle error) {
   auto* args = static_cast<grpc_core::HandshakerArgs*>(arg);
   on_done_closure* c = static_cast<on_done_closure*>(args->user_data);
   if (error != GRPC_ERROR_NONE) {
-    const char* msg = grpc_error_string(error);
-    gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg);
-
+    gpr_log(GPR_ERROR, "Secure transport setup failed: %s",
+            grpc_error_std_string(error).c_str());
     c->func(c->arg, nullptr);
   } else {
     grpc_channel_args_destroy(args->args);
@@ -203,8 +207,8 @@
   grpc_channel_args args = {1, &channel_arg};
   c->handshake_mgr = grpc_core::MakeRefCounted<grpc_core::HandshakeManager>();
   grpc_core::HandshakerRegistry::AddHandshakers(
-      grpc_core::HANDSHAKER_CLIENT, &args, /*interested_parties=*/nullptr,
-      c->handshake_mgr.get());
+      grpc_core::HANDSHAKER_CLIENT, &args,
+      /*interested_parties=*/nullptr, c->handshake_mgr.get());
   c->handshake_mgr->DoHandshake(tcp, /*channel_args=*/nullptr, deadline,
                                 /*acceptor=*/nullptr, on_handshake_done,
                                 /*user_data=*/c);
diff --git a/grpc/src/core/lib/http/parser.cc b/grpc/src/core/lib/http/parser.cc
index 3a0b2be..c47a017 100644
--- a/grpc/src/core/lib/http/parser.cc
+++ b/grpc/src/core/lib/http/parser.cc
@@ -37,7 +37,7 @@
   return out;
 }
 
-static grpc_error* handle_response_line(grpc_http_parser* parser) {
+static grpc_error_handle handle_response_line(grpc_http_parser* parser) {
   uint8_t* beg = parser->cur_line;
   uint8_t* cur = beg;
   uint8_t* end = beg + parser->cur_line_length;
@@ -90,7 +90,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* handle_request_line(grpc_http_parser* parser) {
+static grpc_error_handle handle_request_line(grpc_http_parser* parser) {
   uint8_t* beg = parser->cur_line;
   uint8_t* cur = beg;
   uint8_t* end = beg + parser->cur_line_length;
@@ -161,7 +161,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* handle_first_line(grpc_http_parser* parser) {
+static grpc_error_handle handle_first_line(grpc_http_parser* parser) {
   switch (parser->type) {
     case GRPC_HTTP_REQUEST:
       return handle_request_line(parser);
@@ -172,14 +172,14 @@
       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
 }
 
-static grpc_error* add_header(grpc_http_parser* parser) {
+static grpc_error_handle add_header(grpc_http_parser* parser) {
   uint8_t* beg = parser->cur_line;
   uint8_t* cur = beg;
   uint8_t* end = beg + parser->cur_line_length;
   size_t* hdr_count = nullptr;
   grpc_http_header** hdrs = nullptr;
   grpc_http_header hdr = {nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   GPR_ASSERT(cur != end);
 
@@ -235,9 +235,9 @@
   return error;
 }
 
-static grpc_error* finish_line(grpc_http_parser* parser,
-                               bool* found_body_start) {
-  grpc_error* err;
+static grpc_error_handle finish_line(grpc_http_parser* parser,
+                                     bool* found_body_start) {
+  grpc_error_handle err;
   switch (parser->state) {
     case GRPC_HTTP_FIRST_LINE:
       err = handle_first_line(parser);
@@ -264,7 +264,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* addbyte_body(grpc_http_parser* parser, uint8_t byte) {
+static grpc_error_handle addbyte_body(grpc_http_parser* parser, uint8_t byte) {
   size_t* body_length = nullptr;
   char** body = nullptr;
 
@@ -313,8 +313,8 @@
   return false;
 }
 
-static grpc_error* addbyte(grpc_http_parser* parser, uint8_t byte,
-                           bool* found_body_start) {
+static grpc_error_handle addbyte(grpc_http_parser* parser, uint8_t byte,
+                                 bool* found_body_start) {
   switch (parser->state) {
     case GRPC_HTTP_FIRST_LINE:
     case GRPC_HTTP_HEADERS:
@@ -371,12 +371,12 @@
   gpr_free(response->hdrs);
 }
 
-grpc_error* grpc_http_parser_parse(grpc_http_parser* parser,
-                                   const grpc_slice& slice,
-                                   size_t* start_of_body) {
+grpc_error_handle grpc_http_parser_parse(grpc_http_parser* parser,
+                                         const grpc_slice& slice,
+                                         size_t* start_of_body) {
   for (size_t i = 0; i < GRPC_SLICE_LENGTH(slice); i++) {
     bool found_body_start = false;
-    grpc_error* err =
+    grpc_error_handle err =
         addbyte(parser, GRPC_SLICE_START_PTR(slice)[i], &found_body_start);
     if (err != GRPC_ERROR_NONE) return err;
     if (found_body_start && start_of_body != nullptr) *start_of_body = i + 1;
@@ -384,7 +384,7 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_http_parser_eof(grpc_http_parser* parser) {
+grpc_error_handle grpc_http_parser_eof(grpc_http_parser* parser) {
   if (parser->state != GRPC_HTTP_BODY) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Did not finish headers");
   }
diff --git a/grpc/src/core/lib/http/parser.h b/grpc/src/core/lib/http/parser.h
index 2da2190..613b972 100644
--- a/grpc/src/core/lib/http/parser.h
+++ b/grpc/src/core/lib/http/parser.h
@@ -100,10 +100,10 @@
 void grpc_http_parser_destroy(grpc_http_parser* parser);
 
 /* Sets \a start_of_body to the offset in \a slice of the start of the body. */
-grpc_error* grpc_http_parser_parse(grpc_http_parser* parser,
-                                   const grpc_slice& slice,
-                                   size_t* start_of_body);
-grpc_error* grpc_http_parser_eof(grpc_http_parser* parser);
+grpc_error_handle grpc_http_parser_parse(grpc_http_parser* parser,
+                                         const grpc_slice& slice,
+                                         size_t* start_of_body);
+grpc_error_handle grpc_http_parser_eof(grpc_http_parser* parser);
 
 void grpc_http_request_destroy(grpc_http_request* request);
 void grpc_http_response_destroy(grpc_http_response* response);
diff --git a/grpc/src/core/lib/iomgr/buffer_list.cc b/grpc/src/core/lib/iomgr/buffer_list.cc
index e1b87da..f92fc9b 100644
--- a/grpc/src/core/lib/iomgr/buffer_list.cc
+++ b/grpc/src/core/lib/iomgr/buffer_list.cc
@@ -40,14 +40,14 @@
 }
 
 void default_timestamps_callback(void* /*arg*/, grpc_core::Timestamps* /*ts*/,
-                                 grpc_error* /*shudown_err*/) {
+                                 grpc_error_handle /*shudown_err*/) {
   gpr_log(GPR_DEBUG, "Timestamps callback has not been registered");
 }
 
 /** The saved callback function that will be invoked when we get all the
  * timestamps that we are going to get for a TracedBuffer. */
 void (*timestamps_callback)(void*, grpc_core::Timestamps*,
-                            grpc_error* shutdown_err) =
+                            grpc_error_handle shutdown_err) =
     default_timestamps_callback;
 
 /* Used to extract individual opt stats from cmsg, so as to avoid troubles with
@@ -268,7 +268,7 @@
 }
 
 void TracedBuffer::Shutdown(TracedBuffer** head, void* remaining,
-                            grpc_error* shutdown_err) {
+                            grpc_error_handle shutdown_err) {
   GPR_DEBUG_ASSERT(head != nullptr);
   TracedBuffer* elem = *head;
   while (elem != nullptr) {
@@ -284,9 +284,8 @@
   GRPC_ERROR_UNREF(shutdown_err);
 }
 
-void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*,
-                                                       grpc_core::Timestamps*,
-                                                       grpc_error* error)) {
+void grpc_tcp_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error)) {
   timestamps_callback = fn;
 }
 } /* namespace grpc_core */
@@ -294,9 +293,8 @@
 #else /* GRPC_LINUX_ERRQUEUE */
 
 namespace grpc_core {
-void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*,
-                                                       grpc_core::Timestamps*,
-                                                       grpc_error* error)) {
+void grpc_tcp_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error)) {
   // Cast value of fn to void to avoid unused parameter warning.
   // Can't comment out the name because some compilers and formatters don't
   // like the sequence */* , which would arise from */*fn*/.
diff --git a/grpc/src/core/lib/iomgr/buffer_list.h b/grpc/src/core/lib/iomgr/buffer_list.h
index f804f02..982c4c6 100644
--- a/grpc/src/core/lib/iomgr/buffer_list.h
+++ b/grpc/src/core/lib/iomgr/buffer_list.h
@@ -135,7 +135,7 @@
   /** Cleans the list by calling the callback for each traced buffer in the list
    * with timestamps that it has. */
   static void Shutdown(grpc_core::TracedBuffer** head, void* remaining,
-                       grpc_error* shutdown_err);
+                       grpc_error_handle shutdown_err);
 
  private:
   uint32_t seq_no_; /* The sequence number for the last byte in the buffer */
@@ -146,9 +146,9 @@
 #else  /* GRPC_LINUX_ERRQUEUE */
 class TracedBuffer {
  public:
-  /* Dummy shutdown function */
+  /* Phony shutdown function */
   static void Shutdown(grpc_core::TracedBuffer** /*head*/, void* /*remaining*/,
-                       grpc_error* shutdown_err) {
+                       grpc_error_handle shutdown_err) {
     GRPC_ERROR_UNREF(shutdown_err);
   }
 };
@@ -156,9 +156,8 @@
 
 /** Sets the callback function to call when timestamps for a write are
  *  collected. The callback does not own a reference to error. */
-void grpc_tcp_set_write_timestamps_callback(void (*fn)(void*,
-                                                       grpc_core::Timestamps*,
-                                                       grpc_error* error));
+void grpc_tcp_set_write_timestamps_callback(
+    void (*fn)(void*, grpc_core::Timestamps*, grpc_error_handle error));
 
 } /* namespace grpc_core */
 
diff --git a/grpc/src/core/lib/iomgr/call_combiner.cc b/grpc/src/core/lib/iomgr/call_combiner.cc
index 043b3bb..44ffb12 100644
--- a/grpc/src/core/lib/iomgr/call_combiner.cc
+++ b/grpc/src/core/lib/iomgr/call_combiner.cc
@@ -32,15 +32,15 @@
 
 namespace {
 
-grpc_error* DecodeCancelStateError(gpr_atm cancel_state) {
+grpc_error_handle DecodeCancelStateError(gpr_atm cancel_state) {
   if (cancel_state & 1) {
-    return reinterpret_cast<grpc_error*>(cancel_state &
-                                         ~static_cast<gpr_atm>(1));
+    return reinterpret_cast<grpc_error_handle>(cancel_state &
+                                               ~static_cast<gpr_atm>(1));
   }
   return GRPC_ERROR_NONE;
 }
 
-gpr_atm EncodeCancelStateError(grpc_error* error) {
+gpr_atm EncodeCancelStateError(grpc_error_handle error) {
   return static_cast<gpr_atm>(1) | reinterpret_cast<gpr_atm>(error);
 }
 
@@ -60,7 +60,7 @@
 }
 
 #ifdef GRPC_TSAN_ENABLED
-void CallCombiner::TsanClosure(void* arg, grpc_error* error) {
+void CallCombiner::TsanClosure(void* arg, grpc_error_handle error) {
   CallCombiner* self = static_cast<CallCombiner*>(arg);
   // We ref-count the lock, and check if it's already taken.
   // If it was taken, we should do nothing. Otherwise, we will mark it as
@@ -91,7 +91,8 @@
 }
 #endif
 
-void CallCombiner::ScheduleClosure(grpc_closure* closure, grpc_error* error) {
+void CallCombiner::ScheduleClosure(grpc_closure* closure,
+                                   grpc_error_handle error) {
 #ifdef GRPC_TSAN_ENABLED
   original_closure_ = closure;
   ExecCtx::Run(DEBUG_LOCATION, &tsan_closure_, error);
@@ -110,14 +111,15 @@
 #define DEBUG_FMT_ARGS
 #endif
 
-void CallCombiner::Start(grpc_closure* closure, grpc_error* error,
+void CallCombiner::Start(grpc_closure* closure, grpc_error_handle error,
                          DEBUG_ARGS const char* reason) {
   GPR_TIMER_SCOPE("CallCombiner::Start", 0);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) {
     gpr_log(GPR_INFO,
             "==> CallCombiner::Start() [%p] closure=%p [" DEBUG_FMT_STR
             "%s] error=%s",
-            this, closure DEBUG_FMT_ARGS, reason, grpc_error_string(error));
+            this, closure DEBUG_FMT_ARGS, reason,
+            grpc_error_std_string(error).c_str());
   }
   size_t prev_size =
       static_cast<size_t>(gpr_atm_full_fetch_add(&size_, (gpr_atm)1));
@@ -176,7 +178,8 @@
       }
       if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) {
         gpr_log(GPR_INFO, "  EXECUTING FROM QUEUE: closure=%p error=%s",
-                closure, grpc_error_string(closure->error_data.error));
+                closure,
+                grpc_error_std_string(closure->error_data.error).c_str());
       }
       ScheduleClosure(closure, closure->error_data.error);
       break;
@@ -191,7 +194,7 @@
   while (true) {
     // Decode original state.
     gpr_atm original_state = gpr_atm_acq_load(&cancel_state_);
-    grpc_error* original_error = DecodeCancelStateError(original_state);
+    grpc_error_handle original_error = DecodeCancelStateError(original_state);
     // If error is set, invoke the cancellation closure immediately.
     // Otherwise, store the new closure.
     if (original_error != GRPC_ERROR_NONE) {
@@ -229,11 +232,11 @@
   }
 }
 
-void CallCombiner::Cancel(grpc_error* error) {
+void CallCombiner::Cancel(grpc_error_handle error) {
   GRPC_STATS_INC_CALL_COMBINER_CANCELLED();
   while (true) {
     gpr_atm original_state = gpr_atm_acq_load(&cancel_state_);
-    grpc_error* original_error = DecodeCancelStateError(original_state);
+    grpc_error_handle original_error = DecodeCancelStateError(original_state);
     if (original_error != GRPC_ERROR_NONE) {
       GRPC_ERROR_UNREF(error);
       break;
diff --git a/grpc/src/core/lib/iomgr/call_combiner.h b/grpc/src/core/lib/iomgr/call_combiner.h
index 44acd9f..e5429cc 100644
--- a/grpc/src/core/lib/iomgr/call_combiner.h
+++ b/grpc/src/core/lib/iomgr/call_combiner.h
@@ -58,7 +58,7 @@
 #define GRPC_CALL_COMBINER_STOP(call_combiner, reason) \
   (call_combiner)->Stop(__FILE__, __LINE__, (reason))
   /// Starts processing \a closure.
-  void Start(grpc_closure* closure, grpc_error* error, const char* file,
+  void Start(grpc_closure* closure, grpc_error_handle error, const char* file,
              int line, const char* reason);
   /// Yields the call combiner to the next closure in the queue, if any.
   void Stop(const char* file, int line, const char* reason);
@@ -68,7 +68,8 @@
 #define GRPC_CALL_COMBINER_STOP(call_combiner, reason) \
   (call_combiner)->Stop((reason))
   /// Starts processing \a closure.
-  void Start(grpc_closure* closure, grpc_error* error, const char* reason);
+  void Start(grpc_closure* closure, grpc_error_handle error,
+             const char* reason);
   /// Yields the call combiner to the next closure in the queue, if any.
   void Stop(const char* reason);
 #endif
@@ -94,26 +95,22 @@
   /// cancellation; this effectively unregisters the previously set closure.
   /// However, most filters will not need to explicitly unregister their
   /// callbacks, as this is done automatically when the call is destroyed.
-  /// Filters that schedule the cancellation closure on ExecCtx do not need
-  /// to take a ref on the call stack to guarantee closure liveness. This is
-  /// done by explicitly flushing ExecCtx after the unregistration during
-  /// call destruction.
   void SetNotifyOnCancel(grpc_closure* closure);
 
   /// Indicates that the call has been cancelled.
-  void Cancel(grpc_error* error);
+  void Cancel(grpc_error_handle error);
 
  private:
-  void ScheduleClosure(grpc_closure* closure, grpc_error* error);
+  void ScheduleClosure(grpc_closure* closure, grpc_error_handle error);
 #ifdef GRPC_TSAN_ENABLED
-  static void TsanClosure(void* arg, grpc_error* error);
+  static void TsanClosure(void* arg, grpc_error_handle error);
 #endif
 
   gpr_atm size_ = 0;  // size_t, num closures in queue or currently executing
   MultiProducerSingleConsumerQueue queue_;
   // Either 0 (if not cancelled and no cancellation closure set),
   // a grpc_closure* (if the lowest bit is 0),
-  // or a grpc_error* (if the lowest bit is 1).
+  // or a grpc_error_handle (if the lowest bit is 1).
   gpr_atm cancel_state_ = 0;
 #ifdef GRPC_TSAN_ENABLED
   // A fake ref-counted lock that is kept alive after the destruction of
@@ -150,7 +147,7 @@
 
   // Adds a closure to the list.  The closure must eventually result in
   // the call combiner being yielded.
-  void Add(grpc_closure* closure, grpc_error* error, const char* reason) {
+  void Add(grpc_closure* closure, grpc_error_handle error, const char* reason) {
     closures_.emplace_back(closure, error, reason);
   }
 
@@ -176,7 +173,8 @@
               "CallCombinerClosureList executing closure while already "
               "holding call_combiner %p: closure=%p error=%s reason=%s",
               call_combiner, closures_[0].closure,
-              grpc_error_string(closures_[0].error), closures_[0].reason);
+              grpc_error_std_string(closures_[0].error).c_str(),
+              closures_[0].reason);
     }
     // This will release the call combiner.
     ExecCtx::Run(DEBUG_LOCATION, closures_[0].closure, closures_[0].error);
@@ -199,10 +197,10 @@
  private:
   struct CallCombinerClosure {
     grpc_closure* closure;
-    grpc_error* error;
+    grpc_error_handle error;
     const char* reason;
 
-    CallCombinerClosure(grpc_closure* closure, grpc_error* error,
+    CallCombinerClosure(grpc_closure* closure, grpc_error_handle error,
                         const char* reason)
         : closure(closure), error(error), reason(reason) {}
   };
diff --git a/grpc/src/core/lib/iomgr/cfstream_handle.cc b/grpc/src/core/lib/iomgr/cfstream_handle.cc
index 46914e5..fb11231 100644
--- a/grpc/src/core/lib/iomgr/cfstream_handle.cc
+++ b/grpc/src/core/lib/iomgr/cfstream_handle.cc
@@ -62,7 +62,7 @@
                                   void* client_callback_info) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  grpc_error* error;
+  grpc_error_handle error;
   CFErrorRef stream_error;
   CFStreamHandle* handle = static_cast<CFStreamHandle*>(client_callback_info);
   if (grpc_tcp_trace.enabled()) {
@@ -97,7 +97,7 @@
                                    void* clientCallBackInfo) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
-  grpc_error* error;
+  grpc_error_handle error;
   CFErrorRef stream_error;
   CFStreamHandle* handle = static_cast<CFStreamHandle*>(clientCallBackInfo);
   if (grpc_tcp_trace.enabled()) {
@@ -171,7 +171,7 @@
   write_event_.NotifyOn(closure);
 }
 
-void CFStreamHandle::Shutdown(grpc_error* error) {
+void CFStreamHandle::Shutdown(grpc_error_handle error) {
   open_event_.SetShutdown(GRPC_ERROR_REF(error));
   read_event_.SetShutdown(GRPC_ERROR_REF(error));
   write_event_.SetShutdown(GRPC_ERROR_REF(error));
@@ -202,9 +202,9 @@
 
 #else
 
-/* Creating a dummy function so that the grpc_cfstream library will be
+/* Creating a phony function so that the grpc_cfstream library will be
  * non-empty.
  */
-void CFStreamDummy() {}
+void CFStreamPhony() {}
 
 #endif
diff --git a/grpc/src/core/lib/iomgr/cfstream_handle.h b/grpc/src/core/lib/iomgr/cfstream_handle.h
index b0f0664..2358758 100644
--- a/grpc/src/core/lib/iomgr/cfstream_handle.h
+++ b/grpc/src/core/lib/iomgr/cfstream_handle.h
@@ -53,7 +53,7 @@
   void NotifyOnOpen(grpc_closure* closure);
   void NotifyOnRead(grpc_closure* closure);
   void NotifyOnWrite(grpc_closure* closure);
-  void Shutdown(grpc_error* error);
+  void Shutdown(grpc_error_handle error);
 
   void Ref(const char* file = "", int line = 0, const char* reason = nullptr);
   void Unref(const char* file = "", int line = 0, const char* reason = nullptr);
diff --git a/grpc/src/core/lib/iomgr/closure.h b/grpc/src/core/lib/iomgr/closure.h
index 6bb6534..b429c9e 100644
--- a/grpc/src/core/lib/iomgr/closure.h
+++ b/grpc/src/core/lib/iomgr/closure.h
@@ -50,7 +50,7 @@
  *              describing what went wrong.
  *              Error contract: it is not the cb's job to unref this error;
  *              the closure scheduler will do that after the cb returns */
-typedef void (*grpc_iomgr_cb_func)(void* arg, grpc_error* error);
+typedef void (*grpc_iomgr_cb_func)(void* arg, grpc_error_handle error);
 
 /** A closure over a grpc_iomgr_cb_func. */
 struct grpc_closure {
@@ -72,7 +72,7 @@
 
   /** Once queued, the result of the closure. Before then: scratch space */
   union {
-    grpc_error* error;
+    grpc_error_handle error;
     uintptr_t scratch;
   } error_data;
 
@@ -126,7 +126,7 @@
   void* cb_arg;
   grpc_closure wrapper;
 };
-inline void closure_wrapper(void* arg, grpc_error* error) {
+inline void closure_wrapper(void* arg, grpc_error_handle error) {
   wrapped_closure* wc = static_cast<wrapped_closure*>(arg);
   grpc_iomgr_cb_func cb = wc->cb;
   void* cb_arg = wc->cb_arg;
@@ -175,7 +175,8 @@
     and set \a closure's result to \a error
     Returns true if \a list becomes non-empty */
 inline bool grpc_closure_list_append(grpc_closure_list* closure_list,
-                                     grpc_closure* closure, grpc_error* error) {
+                                     grpc_closure* closure,
+                                     grpc_error_handle error) {
   if (closure == nullptr) {
     GRPC_ERROR_UNREF(error);
     return false;
@@ -194,7 +195,7 @@
 
 /** force all success bits in \a list to false */
 inline void grpc_closure_list_fail_all(grpc_closure_list* list,
-                                       grpc_error* forced_failure) {
+                                       grpc_error_handle forced_failure) {
   for (grpc_closure* c = list->head; c != nullptr; c = c->next_data.next) {
     if (c->error_data.error == GRPC_ERROR_NONE) {
       c->error_data.error = GRPC_ERROR_REF(forced_failure);
@@ -227,7 +228,7 @@
 class Closure {
  public:
   static void Run(const DebugLocation& location, grpc_closure* closure,
-                  grpc_error* error) {
+                  grpc_error_handle error) {
     (void)location;
     if (closure == nullptr) {
       GRPC_ERROR_UNREF(error);
diff --git a/grpc/src/core/lib/iomgr/combiner.cc b/grpc/src/core/lib/iomgr/combiner.cc
index aa5a2ea..48237e5 100644
--- a/grpc/src/core/lib/iomgr/combiner.cc
+++ b/grpc/src/core/lib/iomgr/combiner.cc
@@ -46,11 +46,12 @@
 #define STATE_ELEM_COUNT_LOW_BIT 2
 
 static void combiner_exec(grpc_core::Combiner* lock, grpc_closure* closure,
-                          grpc_error* error);
+                          grpc_error_handle error);
 static void combiner_finally_exec(grpc_core::Combiner* lock,
-                                  grpc_closure* closure, grpc_error* error);
+                                  grpc_closure* closure,
+                                  grpc_error_handle error);
 
-static void offload(void* arg, grpc_error* error);
+static void offload(void* arg, grpc_error_handle error);
 
 grpc_core::Combiner* grpc_combiner_create(void) {
   grpc_core::Combiner* lock = new grpc_core::Combiner();
@@ -126,7 +127,7 @@
 }
 
 static void combiner_exec(grpc_core::Combiner* lock, grpc_closure* cl,
-                          grpc_error* error) {
+                          grpc_error_handle error) {
   GPR_TIMER_SCOPE("combiner.execute", 0);
   GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_ITEMS();
   gpr_atm last = gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT);
@@ -167,7 +168,7 @@
   }
 }
 
-static void offload(void* arg, grpc_error* /*error*/) {
+static void offload(void* arg, grpc_error_handle /*error*/) {
   grpc_core::Combiner* lock = static_cast<grpc_core::Combiner*>(arg);
   push_last_on_exec_ctx(lock);
 }
@@ -230,7 +231,7 @@
     }
     GPR_TIMER_SCOPE("combiner.exec1", 0);
     grpc_closure* cl = reinterpret_cast<grpc_closure*>(n);
-    grpc_error* cl_err = cl->error_data.error;
+    grpc_error_handle cl_err = cl->error_data.error;
 #ifndef NDEBUG
     cl->scheduled = false;
 #endif
@@ -246,7 +247,7 @@
       GRPC_COMBINER_TRACE(
           gpr_log(GPR_INFO, "C:%p execute_final[%d] c=%p", lock, loops, c));
       grpc_closure* next = c->next_data.next;
-      grpc_error* error = c->error_data.error;
+      grpc_error_handle error = c->error_data.error;
 #ifndef NDEBUG
       c->scheduled = false;
 #endif
@@ -297,10 +298,11 @@
   return true;
 }
 
-static void enqueue_finally(void* closure, grpc_error* error);
+static void enqueue_finally(void* closure, grpc_error_handle error);
 
 static void combiner_finally_exec(grpc_core::Combiner* lock,
-                                  grpc_closure* closure, grpc_error* error) {
+                                  grpc_closure* closure,
+                                  grpc_error_handle error) {
   GPR_ASSERT(lock != nullptr);
   GPR_TIMER_SCOPE("combiner.execute_finally", 0);
   GRPC_STATS_INC_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS();
@@ -322,7 +324,7 @@
   grpc_closure_list_append(&lock->final_list, closure, error);
 }
 
-static void enqueue_finally(void* closure, grpc_error* error) {
+static void enqueue_finally(void* closure, grpc_error_handle error) {
   grpc_closure* cl = static_cast<grpc_closure*>(closure);
   combiner_finally_exec(
       reinterpret_cast<grpc_core::Combiner*>(cl->error_data.scratch), cl,
@@ -330,11 +332,11 @@
 }
 
 namespace grpc_core {
-void Combiner::Run(grpc_closure* closure, grpc_error* error) {
+void Combiner::Run(grpc_closure* closure, grpc_error_handle error) {
   combiner_exec(this, closure, error);
 }
 
-void Combiner::FinallyRun(grpc_closure* closure, grpc_error* error) {
+void Combiner::FinallyRun(grpc_closure* closure, grpc_error_handle error) {
   combiner_finally_exec(this, closure, error);
 }
 }  // namespace grpc_core
diff --git a/grpc/src/core/lib/iomgr/combiner.h b/grpc/src/core/lib/iomgr/combiner.h
index 3271206..efa2bce 100644
--- a/grpc/src/core/lib/iomgr/combiner.h
+++ b/grpc/src/core/lib/iomgr/combiner.h
@@ -32,9 +32,9 @@
 // use ExecCtx
 class Combiner {
  public:
-  void Run(grpc_closure* closure, grpc_error* error);
+  void Run(grpc_closure* closure, grpc_error_handle error);
   // TODO(yashkt) : Remove this method
-  void FinallyRun(grpc_closure* closure, grpc_error* error);
+  void FinallyRun(grpc_closure* closure, grpc_error_handle error);
   Combiner* next_combiner_on_this_exec_ctx = nullptr;
   MultiProducerSingleConsumerQueue queue;
   // either:
diff --git a/grpc/src/core/lib/iomgr/endpoint.cc b/grpc/src/core/lib/iomgr/endpoint.cc
index 8954f9d..4c84501 100644
--- a/grpc/src/core/lib/iomgr/endpoint.cc
+++ b/grpc/src/core/lib/iomgr/endpoint.cc
@@ -46,7 +46,7 @@
   ep->vtable->delete_from_pollset_set(ep, pollset_set);
 }
 
-void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) {
+void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   ep->vtable->shutdown(ep, why);
 }
 
diff --git a/grpc/src/core/lib/iomgr/endpoint.h b/grpc/src/core/lib/iomgr/endpoint.h
index b6e6086..4db5e3d 100644
--- a/grpc/src/core/lib/iomgr/endpoint.h
+++ b/grpc/src/core/lib/iomgr/endpoint.h
@@ -44,7 +44,7 @@
   void (*add_to_pollset)(grpc_endpoint* ep, grpc_pollset* pollset);
   void (*add_to_pollset_set)(grpc_endpoint* ep, grpc_pollset_set* pollset);
   void (*delete_from_pollset_set)(grpc_endpoint* ep, grpc_pollset_set* pollset);
-  void (*shutdown)(grpc_endpoint* ep, grpc_error* why);
+  void (*shutdown)(grpc_endpoint* ep, grpc_error_handle why);
   void (*destroy)(grpc_endpoint* ep);
   grpc_resource_user* (*get_resource_user)(grpc_endpoint* ep);
   absl::string_view (*get_peer)(grpc_endpoint* ep);
@@ -86,7 +86,7 @@
 
 /* Causes any pending and future read/write callbacks to run immediately with
    success==0 */
-void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error* why);
+void grpc_endpoint_shutdown(grpc_endpoint* ep, grpc_error_handle why);
 void grpc_endpoint_destroy(grpc_endpoint* ep);
 
 /* Add an endpoint to a pollset or pollset_set, so that when the pollset is
diff --git a/grpc/src/core/lib/iomgr/endpoint_cfstream.cc b/grpc/src/core/lib/iomgr/endpoint_cfstream.cc
index 75cd0f0..6394506 100644
--- a/grpc/src/core/lib/iomgr/endpoint_cfstream.cc
+++ b/grpc/src/core/lib/iomgr/endpoint_cfstream.cc
@@ -29,13 +29,13 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/cfstream_handle.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/error_cfstream.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 
@@ -106,8 +106,8 @@
 static void CFStreamRef(CFStreamEndpoint* ep) { gpr_ref(&ep->refcount); }
 #endif
 
-static grpc_error* CFStreamAnnotateError(grpc_error* src_error,
-                                         CFStreamEndpoint* ep) {
+static grpc_error_handle CFStreamAnnotateError(grpc_error_handle src_error,
+                                               CFStreamEndpoint* ep) {
   return grpc_error_set_str(
       grpc_error_set_int(src_error, GRPC_ERROR_INT_GRPC_STATUS,
                          GRPC_STATUS_UNAVAILABLE),
@@ -115,13 +115,12 @@
       grpc_slice_from_copied_string(ep->peer_string.c_str()));
 }
 
-static void CallReadCb(CFStreamEndpoint* ep, grpc_error* error) {
+static void CallReadCb(CFStreamEndpoint* ep, grpc_error_handle error) {
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CFStream endpoint:%p call_read_cb %p %p:%p", ep,
             ep->read_cb, ep->read_cb->cb, ep->read_cb->cb_arg);
     size_t i;
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "read: error=%s", str);
+    gpr_log(GPR_DEBUG, "read: error=%s", grpc_error_std_string(error).c_str());
 
     for (i = 0; i < ep->read_slices->count; i++) {
       char* dump = grpc_dump_slice(ep->read_slices->slices[i],
@@ -137,12 +136,11 @@
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
 }
 
-static void CallWriteCb(CFStreamEndpoint* ep, grpc_error* error) {
+static void CallWriteCb(CFStreamEndpoint* ep, grpc_error_handle error) {
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CFStream endpoint:%p call_write_cb %p %p:%p", ep,
             ep->write_cb, ep->write_cb->cb, ep->write_cb->cb_arg);
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "write: error=%s", str);
+    gpr_log(GPR_DEBUG, "write: error=%s", grpc_error_std_string(error).c_str());
   }
   grpc_closure* cb = ep->write_cb;
   ep->write_cb = nullptr;
@@ -150,7 +148,7 @@
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
 }
 
-static void ReadAction(void* arg, grpc_error* error) {
+static void ReadAction(void* arg, grpc_error_handle error) {
   CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg);
   GPR_ASSERT(ep->read_cb != nullptr);
   if (error) {
@@ -192,7 +190,7 @@
   }
 }
 
-static void WriteAction(void* arg, grpc_error* error) {
+static void WriteAction(void* arg, grpc_error_handle error) {
   CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg);
   GPR_ASSERT(ep->write_cb != nullptr);
   if (error) {
@@ -242,7 +240,7 @@
   grpc_slice_unref_internal(slice);
 }
 
-static void CFStreamReadAllocationDone(void* arg, grpc_error* error) {
+static void CFStreamReadAllocationDone(void* arg, grpc_error_handle error) {
   CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg);
   if (error == GRPC_ERROR_NONE) {
     ep->stream_sync->NotifyOnRead(&ep->read_action);
@@ -286,7 +284,7 @@
   ep_impl->stream_sync->NotifyOnWrite(&ep_impl->write_action);
 }
 
-void CFStreamShutdown(grpc_endpoint* ep, grpc_error* why) {
+void CFStreamShutdown(grpc_endpoint* ep, grpc_error_handle why) {
   CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CFStream endpoint:%p shutdown (%p)", ep_impl, why);
diff --git a/grpc/src/core/lib/iomgr/endpoint_pair_windows.cc b/grpc/src/core/lib/iomgr/endpoint_pair_windows.cc
index 9962809..c1113e1 100644
--- a/grpc/src/core/lib/iomgr/endpoint_pair_windows.cc
+++ b/grpc/src/core/lib/iomgr/endpoint_pair_windows.cc
@@ -21,9 +21,9 @@
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 #include <errno.h>
 #include <fcntl.h>
diff --git a/grpc/src/core/lib/iomgr/error.cc b/grpc/src/core/lib/iomgr/error.cc
index 0910145..378bdf7 100644
--- a/grpc/src/core/lib/iomgr/error.cc
+++ b/grpc/src/core/lib/iomgr/error.cc
@@ -41,6 +41,114 @@
                                                         "error_refcount");
 grpc_core::DebugOnlyTraceFlag grpc_trace_closure(false, "closure");
 
+static gpr_atm g_error_creation_allowed = true;
+
+void grpc_disable_error_creation() {
+  gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
+}
+
+void grpc_enable_error_creation() {
+  gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
+}
+
+#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
+
+absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
+                                const grpc_core::DebugLocation& location,
+                                size_t children_count, absl::Status* children) {
+  absl::Status s = StatusCreate(code, msg, location, {});
+  for (size_t i = 0; i < children_count; ++i) {
+    if (!children[i].ok()) {
+      StatusAddChild(&s, children[i]);
+    }
+  }
+  return s;
+}
+
+std::string grpc_error_std_string(const absl::Status& error) {
+  return grpc_core::StatusToString(error);
+}
+
+absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
+                           const char* call_name) {
+  absl::Status s =
+      StatusCreate(absl::StatusCode::kUnknown, "OS Error", location, {});
+  grpc_core::StatusSetInt(&s, grpc_core::StatusIntProperty::ERRNO, err);
+  grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::OS_ERROR,
+                          strerror(err));
+  grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::SYSCALL, call_name);
+  return s;
+}
+
+#ifdef GPR_WINDOWS
+absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
+                            const char* call_name) {
+  char* utf8_message = gpr_format_message(err);
+  absl::Status s =
+      StatusCreate(absl::StatusCode::kUnknown, "WSA Error", location, {});
+  StatusSetInt(&s, StatusIntProperty::WSA_ERROR, err);
+  StatusSetStr(&s, StatusStrProperty::OS_ERROR, utf8_message);
+  StatusSetStr(&s, StatusStrProperty::SYSCALL, call_name);
+}
+#endif
+
+grpc_error_handle grpc_error_set_int(grpc_error_handle src,
+                                     grpc_error_ints which, intptr_t value) {
+  grpc_core::StatusSetInt(
+      &src, static_cast<grpc_core::StatusIntProperty>(which), value);
+  return src;
+}
+
+bool grpc_error_get_int(grpc_error_handle error, grpc_error_ints which,
+                        intptr_t* p) {
+  absl::optional<intptr_t> value = grpc_core::StatusGetInt(
+      error, static_cast<grpc_core::StatusIntProperty>(which));
+  if (value.has_value()) {
+    *p = *value;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+grpc_error_handle grpc_error_set_str(grpc_error_handle src,
+                                     grpc_error_strs which,
+                                     const grpc_slice& str) {
+  grpc_core::StatusSetStr(
+      &src, static_cast<grpc_core::StatusStrProperty>(which),
+      std::string(reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(str)),
+                  GRPC_SLICE_LENGTH(str)));
+  return src;
+}
+
+bool grpc_error_get_str(grpc_error_handle error, grpc_error_strs which,
+                        grpc_slice* s) {
+  absl::optional<std::string> value = grpc_core::StatusGetStr(
+      error, static_cast<grpc_core::StatusStrProperty>(which));
+  if (value.has_value()) {
+    *s = grpc_slice_from_copied_buffer(value->c_str(), value->size());
+    return true;
+  } else {
+    return false;
+  }
+}
+
+grpc_error_handle grpc_error_add_child(grpc_error_handle src,
+                                       grpc_error_handle child) {
+  grpc_core::StatusAddChild(&src, child);
+  return src;
+}
+
+bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
+                    int line) {
+  GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
+  gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what,
+          grpc_core::StatusToString(error).c_str());
+  return false;
+}
+
+#else  // GRPC_ERROR_IS_ABSEIL_STATUS
+
 static const char* error_int_name(grpc_error_ints key) {
   switch (key) {
     case GRPC_ERROR_INT_ERRNO:
@@ -61,20 +169,18 @@
       return "http2_error";
     case GRPC_ERROR_INT_TSI_CODE:
       return "tsi_code";
-    case GRPC_ERROR_INT_SECURITY_STATUS:
-      return "security_status";
     case GRPC_ERROR_INT_FD:
       return "fd";
     case GRPC_ERROR_INT_WSA_ERROR:
       return "wsa_error";
     case GRPC_ERROR_INT_HTTP_STATUS:
       return "http_status";
-    case GRPC_ERROR_INT_LIMIT:
-      return "limit";
     case GRPC_ERROR_INT_OCCURRED_DURING_WRITE:
       return "occurred_during_write";
     case GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE:
       return "channel_connectivity_state";
+    case GRPC_ERROR_INT_LB_POLICY_DROP:
+      return "lb_policy_drop";
     case GRPC_ERROR_INT_MAX:
       GPR_UNREACHABLE_CODE(return "unknown");
   }
@@ -105,8 +211,6 @@
       return "tsi_error";
     case GRPC_ERROR_STR_FILENAME:
       return "filename";
-    case GRPC_ERROR_STR_QUEUED_BUFFERS:
-      return "queued_buffers";
     case GRPC_ERROR_STR_MAX:
       GPR_UNREACHABLE_CODE(return "unknown");
   }
@@ -124,7 +228,8 @@
 }
 
 #ifndef NDEBUG
-grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line) {
+grpc_error_handle grpc_error_do_ref(grpc_error_handle err, const char* file,
+                                    int line) {
   if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
             gpr_atm_no_barrier_load(&err->atomics.refs.count),
@@ -134,13 +239,13 @@
   return err;
 }
 #else
-grpc_error* grpc_error_do_ref(grpc_error* err) {
+grpc_error_handle grpc_error_do_ref(grpc_error_handle err) {
   gpr_ref(&err->atomics.refs);
   return err;
 }
 #endif
 
-static void unref_errs(grpc_error* err) {
+static void unref_errs(grpc_error_handle err) {
   uint8_t slot = err->first_err;
   while (slot != UINT8_MAX) {
     grpc_linked_error* lerr =
@@ -152,7 +257,7 @@
   }
 }
 
-static void unref_strs(grpc_error* err) {
+static void unref_strs(grpc_error_handle err) {
   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
     uint8_t slot = err->strs[which];
     if (slot != UINT8_MAX) {
@@ -162,7 +267,7 @@
   }
 }
 
-static void error_destroy(grpc_error* err) {
+static void error_destroy(grpc_error_handle err) {
   GPR_ASSERT(!grpc_error_is_special(err));
   unref_errs(err);
   unref_strs(err);
@@ -172,7 +277,7 @@
 }
 
 #ifndef NDEBUG
-void grpc_error_do_unref(grpc_error* err, const char* file, int line) {
+void grpc_error_do_unref(grpc_error_handle err, const char* file, int line) {
   if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
             gpr_atm_no_barrier_load(&err->atomics.refs.count),
@@ -183,14 +288,14 @@
   }
 }
 #else
-void grpc_error_do_unref(grpc_error* err) {
+void grpc_error_do_unref(grpc_error_handle err) {
   if (gpr_unref(&err->atomics.refs)) {
     error_destroy(err);
   }
 }
 #endif
 
-static uint8_t get_placement(grpc_error** err, size_t size) {
+static uint8_t get_placement(grpc_error_handle* err, size_t size) {
   GPR_ASSERT(*err);
   uint8_t slots = static_cast<uint8_t>(size / sizeof(intptr_t));
   if ((*err)->arena_size + slots > (*err)->arena_capacity) {
@@ -200,9 +305,9 @@
       return UINT8_MAX;
     }
 #ifndef NDEBUG
-    grpc_error* orig = *err;
+    grpc_error_handle orig = *err;
 #endif
-    *err = static_cast<grpc_error*>(gpr_realloc(
+    *err = static_cast<grpc_error_handle>(gpr_realloc(
         *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t)));
 #ifndef NDEBUG
     if (grpc_trace_error_refcount.enabled()) {
@@ -217,7 +322,7 @@
   return placement;
 }
 
-static void internal_set_int(grpc_error** err, grpc_error_ints which,
+static void internal_set_int(grpc_error_handle* err, grpc_error_ints which,
                              intptr_t value) {
   uint8_t slot = (*err)->ints[which];
   if (slot == UINT8_MAX) {
@@ -232,7 +337,7 @@
   (*err)->arena[slot] = value;
 }
 
-static void internal_set_str(grpc_error** err, grpc_error_strs which,
+static void internal_set_str(grpc_error_handle* err, grpc_error_strs which,
                              const grpc_slice& value) {
   uint8_t slot = (*err)->strs[which];
   if (slot == UINT8_MAX) {
@@ -253,7 +358,7 @@
 }
 
 static char* fmt_time(gpr_timespec tm);
-static void internal_set_time(grpc_error** err, grpc_error_times which,
+static void internal_set_time(grpc_error_handle* err, grpc_error_times which,
                               gpr_timespec value) {
   uint8_t slot = (*err)->times[which];
   if (slot == UINT8_MAX) {
@@ -270,7 +375,8 @@
   memcpy((*err)->arena + slot, &value, sizeof(value));
 }
 
-static void internal_add_error(grpc_error** err, grpc_error* new_err) {
+static void internal_add_error(grpc_error_handle* err,
+                               grpc_error_handle new_err) {
   grpc_linked_error new_last = {new_err, UINT8_MAX};
   uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
   if (slot == UINT8_MAX) {
@@ -306,25 +412,16 @@
 // It is very common to include and extra int and string in an error
 #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
 
-static gpr_atm g_error_creation_allowed = true;
-
-void grpc_disable_error_creation() {
-  gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
-}
-
-void grpc_enable_error_creation() {
-  gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
-}
-
-grpc_error* grpc_error_create(const char* file, int line,
-                              const grpc_slice& desc, grpc_error** referencing,
-                              size_t num_referencing) {
+grpc_error_handle grpc_error_create(const char* file, int line,
+                                    const grpc_slice& desc,
+                                    grpc_error_handle* referencing,
+                                    size_t num_referencing) {
   GPR_TIMER_SCOPE("grpc_error_create", 0);
   uint8_t initial_arena_capacity = static_cast<uint8_t>(
       DEFAULT_ERROR_CAPACITY +
       static_cast<uint8_t>(num_referencing * SLOTS_PER_LINKED_ERROR) +
       SURPLUS_CAPACITY);
-  grpc_error* err = static_cast<grpc_error*>(
+  grpc_error_handle err = static_cast<grpc_error_handle>(
       gpr_malloc(sizeof(*err) + initial_arena_capacity * sizeof(intptr_t)));
   if (err == nullptr) {  // TODO(ctiller): make gpr_malloc return NULL
     return GRPC_ERROR_OOM;
@@ -370,7 +467,7 @@
   return err;
 }
 
-static void ref_strs(grpc_error* err) {
+static void ref_strs(grpc_error_handle err) {
   for (size_t i = 0; i < GRPC_ERROR_STR_MAX; ++i) {
     uint8_t slot = err->strs[i];
     if (slot != UINT8_MAX) {
@@ -380,7 +477,7 @@
   }
 }
 
-static void ref_errs(grpc_error* err) {
+static void ref_errs(grpc_error_handle err) {
   uint8_t slot = err->first_err;
   while (slot != UINT8_MAX) {
     grpc_linked_error* lerr =
@@ -390,9 +487,9 @@
   }
 }
 
-static grpc_error* copy_error_and_unref(grpc_error* in) {
+static grpc_error_handle copy_error_and_unref(grpc_error_handle in) {
   GPR_TIMER_SCOPE("copy_error_and_unref", 0);
-  grpc_error* out;
+  grpc_error_handle out;
   if (grpc_error_is_special(in)) {
     out = GRPC_ERROR_CREATE_FROM_STATIC_STRING("unknown");
     if (in == GRPC_ERROR_NONE) {
@@ -417,7 +514,7 @@
         static_cast<uint8_t> SLOTS_PER_STR) {
       new_arena_capacity = static_cast<uint8_t>(3 * new_arena_capacity / 2);
     }
-    out = static_cast<grpc_error*>(
+    out = static_cast<grpc_error_handle>(
         gpr_malloc(sizeof(*in) + new_arena_capacity * sizeof(intptr_t)));
 #ifndef NDEBUG
     if (grpc_trace_error_refcount.enabled()) {
@@ -441,10 +538,10 @@
   return out;
 }
 
-grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
-                               intptr_t value) {
+grpc_error_handle grpc_error_set_int(grpc_error_handle src,
+                                     grpc_error_ints which, intptr_t value) {
   GPR_TIMER_SCOPE("grpc_error_set_int", 0);
-  grpc_error* new_err = copy_error_and_unref(src);
+  grpc_error_handle new_err = copy_error_and_unref(src);
   internal_set_int(&new_err, which, value);
   return new_err;
 }
@@ -464,7 +561,8 @@
      strlen("Cancelled")},  // GRPC_ERROR_CANCELLED
 };
 
-bool grpc_error_get_int(grpc_error* err, grpc_error_ints which, intptr_t* p) {
+bool grpc_error_get_int(grpc_error_handle err, grpc_error_ints which,
+                        intptr_t* p) {
   GPR_TIMER_SCOPE("grpc_error_get_int", 0);
   if (grpc_error_is_special(err)) {
     if (which != GRPC_ERROR_INT_GRPC_STATUS) return false;
@@ -479,15 +577,16 @@
   return false;
 }
 
-grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
-                               const grpc_slice& str) {
+grpc_error_handle grpc_error_set_str(grpc_error_handle src,
+                                     grpc_error_strs which,
+                                     const grpc_slice& str) {
   GPR_TIMER_SCOPE("grpc_error_set_str", 0);
-  grpc_error* new_err = copy_error_and_unref(src);
+  grpc_error_handle new_err = copy_error_and_unref(src);
   internal_set_str(&new_err, which, str);
   return new_err;
 }
 
-bool grpc_error_get_str(grpc_error* err, grpc_error_strs which,
+bool grpc_error_get_str(grpc_error_handle err, grpc_error_strs which,
                         grpc_slice* str) {
   if (grpc_error_is_special(err)) {
     if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false;
@@ -508,14 +607,15 @@
   }
 }
 
-grpc_error* grpc_error_add_child(grpc_error* src, grpc_error* child) {
+grpc_error_handle grpc_error_add_child(grpc_error_handle src,
+                                       grpc_error_handle child) {
   GPR_TIMER_SCOPE("grpc_error_add_child", 0);
   if (src != GRPC_ERROR_NONE) {
     if (child == GRPC_ERROR_NONE) {
       /* \a child is empty. Simply return the ref to \a src */
       return src;
     } else if (child != src) {
-      grpc_error* new_err = copy_error_and_unref(src);
+      grpc_error_handle new_err = copy_error_and_unref(src);
       internal_add_error(&new_err, child);
       return new_err;
     } else {
@@ -616,7 +716,7 @@
   return s;
 }
 
-static void collect_ints_kvs(grpc_error* err, kv_pairs* kvs) {
+static void collect_ints_kvs(grpc_error_handle err, kv_pairs* kvs) {
   for (size_t which = 0; which < GRPC_ERROR_INT_MAX; ++which) {
     uint8_t slot = err->ints[which];
     if (slot != UINT8_MAX) {
@@ -640,7 +740,7 @@
   return s;
 }
 
-static void collect_strs_kvs(grpc_error* err, kv_pairs* kvs) {
+static void collect_strs_kvs(grpc_error_handle err, kv_pairs* kvs) {
   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
     uint8_t slot = err->strs[which];
     if (slot != UINT8_MAX) {
@@ -675,7 +775,7 @@
   return out;
 }
 
-static void collect_times_kvs(grpc_error* err, kv_pairs* kvs) {
+static void collect_times_kvs(grpc_error_handle err, kv_pairs* kvs) {
   for (size_t which = 0; which < GRPC_ERROR_TIME_MAX; ++which) {
     uint8_t slot = err->times[which];
     if (slot != UINT8_MAX) {
@@ -685,7 +785,7 @@
   }
 }
 
-static void add_errs(grpc_error* err, char** s, size_t* sz, size_t* cap) {
+static void add_errs(grpc_error_handle err, char** s, size_t* sz, size_t* cap) {
   uint8_t slot = err->first_err;
   bool first = true;
   while (slot != UINT8_MAX) {
@@ -701,7 +801,7 @@
   }
 }
 
-static char* errs_string(grpc_error* err) {
+static char* errs_string(grpc_error_handle err) {
   char* s = nullptr;
   size_t sz = 0;
   size_t cap = 0;
@@ -740,7 +840,7 @@
   return s;
 }
 
-const char* grpc_error_string(grpc_error* err) {
+const char* grpc_error_string(grpc_error_handle err) {
   GPR_TIMER_SCOPE("grpc_error_string", 0);
   if (err == GRPC_ERROR_NONE) return no_error_string;
   if (err == GRPC_ERROR_OOM) return oom_error_string;
@@ -775,8 +875,12 @@
   return out;
 }
 
-grpc_error* grpc_os_error(const char* file, int line, int err,
-                          const char* call_name) {
+std::string grpc_error_std_string(grpc_error_handle error) {
+  return std::string(grpc_error_string(error));
+}
+
+grpc_error_handle grpc_os_error(const char* file, int line, int err,
+                                const char* call_name) {
   return grpc_error_set_str(
       grpc_error_set_str(
           grpc_error_set_int(
@@ -790,10 +894,10 @@
 }
 
 #ifdef GPR_WINDOWS
-grpc_error* grpc_wsa_error(const char* file, int line, int err,
-                           const char* call_name) {
+grpc_error_handle grpc_wsa_error(const char* file, int line, int err,
+                                 const char* call_name) {
   char* utf8_message = gpr_format_message(err);
-  grpc_error* error = grpc_error_set_str(
+  grpc_error_handle error = grpc_error_set_str(
       grpc_error_set_str(
           grpc_error_set_int(
               grpc_error_create(file, line,
@@ -807,7 +911,7 @@
 }
 #endif
 
-bool grpc_log_error(const char* what, grpc_error* error, const char* file,
+bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
                     int line) {
   GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
   const char* msg = grpc_error_string(error);
@@ -815,3 +919,5 @@
   GRPC_ERROR_UNREF(error);
   return false;
 }
+
+#endif  // GRPC_ERROR_IS_ABSEIL_STATUS
diff --git a/grpc/src/core/lib/iomgr/error.h b/grpc/src/core/lib/iomgr/error.h
index ac3ff87..aecd1e9 100644
--- a/grpc/src/core/lib/iomgr/error.h
+++ b/grpc/src/core/lib/iomgr/error.h
@@ -30,50 +30,70 @@
 #include <grpc/support/time.h>
 
 #include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gprpp/status_helper.h"
+
+#include "absl/status/status.h"
 
 /// Opaque representation of an error.
 /// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a
 /// full write up of this object.
 
-typedef struct grpc_error grpc_error;
+#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
 
-extern grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount;
+typedef absl::Status grpc_error_handle;
+
+#else  // GRPC_ERROR_IS_ABSEIL_STATUS
+
+typedef struct grpc_error grpc_error;
+typedef grpc_error* grpc_error_handle;
+
+#endif  // GRPC_ERROR_IS_ABSEIL_STATUS
 
 typedef enum {
   /// 'errno' from the operating system
-  GRPC_ERROR_INT_ERRNO,
+  GRPC_ERROR_INT_ERRNO =
+      static_cast<int>(grpc_core::StatusIntProperty::kErrorNo),
   /// __LINE__ from the call site creating the error
-  GRPC_ERROR_INT_FILE_LINE,
+  GRPC_ERROR_INT_FILE_LINE =
+      static_cast<int>(grpc_core::StatusIntProperty::kFileLine),
   /// stream identifier: for errors that are associated with an individual
   /// wire stream
-  GRPC_ERROR_INT_STREAM_ID,
+  GRPC_ERROR_INT_STREAM_ID =
+      static_cast<int>(grpc_core::StatusIntProperty::kStreamId),
   /// grpc status code representing this error
-  GRPC_ERROR_INT_GRPC_STATUS,
+  GRPC_ERROR_INT_GRPC_STATUS =
+      static_cast<int>(grpc_core::StatusIntProperty::kRpcStatus),
   /// offset into some binary blob (usually represented by
   /// GRPC_ERROR_STR_RAW_BYTES) where the error occurred
-  GRPC_ERROR_INT_OFFSET,
+  GRPC_ERROR_INT_OFFSET =
+      static_cast<int>(grpc_core::StatusIntProperty::kOffset),
   /// context sensitive index associated with the error
-  GRPC_ERROR_INT_INDEX,
+  GRPC_ERROR_INT_INDEX = static_cast<int>(grpc_core::StatusIntProperty::kIndex),
   /// context sensitive size associated with the error
-  GRPC_ERROR_INT_SIZE,
+  GRPC_ERROR_INT_SIZE = static_cast<int>(grpc_core::StatusIntProperty::kSize),
   /// http2 error code associated with the error (see the HTTP2 RFC)
-  GRPC_ERROR_INT_HTTP2_ERROR,
+  GRPC_ERROR_INT_HTTP2_ERROR =
+      static_cast<int>(grpc_core::StatusIntProperty::kHttp2Error),
   /// TSI status code associated with the error
-  GRPC_ERROR_INT_TSI_CODE,
-  /// grpc_security_status associated with the error
-  GRPC_ERROR_INT_SECURITY_STATUS,
+  GRPC_ERROR_INT_TSI_CODE =
+      static_cast<int>(grpc_core::StatusIntProperty::kTsiCode),
   /// WSAGetLastError() reported when this error occurred
-  GRPC_ERROR_INT_WSA_ERROR,
+  GRPC_ERROR_INT_WSA_ERROR =
+      static_cast<int>(grpc_core::StatusIntProperty::kWsaError),
   /// File descriptor associated with this error
-  GRPC_ERROR_INT_FD,
+  GRPC_ERROR_INT_FD = static_cast<int>(grpc_core::StatusIntProperty::kFd),
   /// HTTP status (i.e. 404)
-  GRPC_ERROR_INT_HTTP_STATUS,
-  /// context sensitive limit associated with the error
-  GRPC_ERROR_INT_LIMIT,
+  GRPC_ERROR_INT_HTTP_STATUS =
+      static_cast<int>(grpc_core::StatusIntProperty::kHttpStatus),
   /// chttp2: did the error occur while a write was in progress
-  GRPC_ERROR_INT_OCCURRED_DURING_WRITE,
+  GRPC_ERROR_INT_OCCURRED_DURING_WRITE =
+      static_cast<int>(grpc_core::StatusIntProperty::kOccurredDuringWrite),
   /// channel connectivity state associated with the error
-  GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE,
+  GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE =
+      static_cast<int>(grpc_core::StatusIntProperty::ChannelConnectivityState),
+  /// LB policy drop
+  GRPC_ERROR_INT_LB_POLICY_DROP =
+      static_cast<int>(grpc_core::StatusIntProperty::kLbPolicyDrop),
 
   /// Must always be last
   GRPC_ERROR_INT_MAX,
@@ -81,29 +101,35 @@
 
 typedef enum {
   /// top-level textual description of this error
-  GRPC_ERROR_STR_DESCRIPTION,
+  GRPC_ERROR_STR_DESCRIPTION =
+      static_cast<int>(grpc_core::StatusStrProperty::kDescription),
   /// source file in which this error occurred
-  GRPC_ERROR_STR_FILE,
+  GRPC_ERROR_STR_FILE = static_cast<int>(grpc_core::StatusStrProperty::kFile),
   /// operating system description of this error
-  GRPC_ERROR_STR_OS_ERROR,
+  GRPC_ERROR_STR_OS_ERROR =
+      static_cast<int>(grpc_core::StatusStrProperty::kOsError),
   /// syscall that generated this error
-  GRPC_ERROR_STR_SYSCALL,
+  GRPC_ERROR_STR_SYSCALL =
+      static_cast<int>(grpc_core::StatusStrProperty::kSyscall),
   /// peer that we were trying to communicate when this error occurred
-  GRPC_ERROR_STR_TARGET_ADDRESS,
+  GRPC_ERROR_STR_TARGET_ADDRESS =
+      static_cast<int>(grpc_core::StatusStrProperty::kTargetAddress),
   /// grpc status message associated with this error
-  GRPC_ERROR_STR_GRPC_MESSAGE,
+  GRPC_ERROR_STR_GRPC_MESSAGE =
+      static_cast<int>(grpc_core::StatusStrProperty::kGrpcMessage),
   /// hex dump (or similar) with the data that generated this error
-  GRPC_ERROR_STR_RAW_BYTES,
+  GRPC_ERROR_STR_RAW_BYTES =
+      static_cast<int>(grpc_core::StatusStrProperty::kRawBytes),
   /// tsi error string associated with this error
-  GRPC_ERROR_STR_TSI_ERROR,
+  GRPC_ERROR_STR_TSI_ERROR =
+      static_cast<int>(grpc_core::StatusStrProperty::kTsiError),
   /// filename that we were trying to read/write when this error occurred
-  GRPC_ERROR_STR_FILENAME,
-  /// which data was queued for writing when the error occurred
-  GRPC_ERROR_STR_QUEUED_BUFFERS,
+  GRPC_ERROR_STR_FILENAME =
+      static_cast<int>(grpc_core::StatusStrProperty::kFilename),
   /// key associated with the error
-  GRPC_ERROR_STR_KEY,
+  GRPC_ERROR_STR_KEY = static_cast<int>(grpc_core::StatusStrProperty::kKey),
   /// value associated with the error
-  GRPC_ERROR_STR_VALUE,
+  GRPC_ERROR_STR_VALUE = static_cast<int>(grpc_core::StatusStrProperty::kValue),
 
   /// Must always be last
   GRPC_ERROR_STR_MAX,
@@ -117,32 +143,135 @@
   GRPC_ERROR_TIME_MAX,
 } grpc_error_times;
 
-/// The following "special" errors can be propagated without allocating memory.
-/// They are always even so that other code (particularly combiner locks,
-/// polling engines) can safely use the lower bit for themselves.
-
-#define GRPC_ERROR_NONE ((grpc_error*)NULL)
-#define GRPC_ERROR_RESERVED_1 ((grpc_error*)1)
-#define GRPC_ERROR_OOM ((grpc_error*)2)
-#define GRPC_ERROR_RESERVED_2 ((grpc_error*)3)
-#define GRPC_ERROR_CANCELLED ((grpc_error*)4)
-#define GRPC_ERROR_SPECIAL_MAX GRPC_ERROR_CANCELLED
-
-inline bool grpc_error_is_special(struct grpc_error* err) {
-  return err <= GRPC_ERROR_SPECIAL_MAX;
-}
+// DEPRECATED: Use grpc_error_std_string instead
+const char* grpc_error_string(grpc_error_handle error);
+std::string grpc_error_std_string(grpc_error_handle error);
 
 // debug only toggles that allow for a sanity to check that ensures we will
 // never create any errors in the per-RPC hotpath.
 void grpc_disable_error_creation();
 void grpc_enable_error_creation();
 
-const char* grpc_error_string(grpc_error* error);
+#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
+
+#define GRPC_ERROR_NONE absl::OkStatus()
+#define GRPC_ERROR_OOM absl::Status(absl::ResourceExhaustedError)
+#define GRPC_ERROR_CANCELLED absl::CancelledError()
+
+#define GRPC_ERROR_REF(err) (err)
+#define GRPC_ERROR_UNREF(err)
+
+#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc) \
+  StatusCreate(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
+#define GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc) \
+  StatusCreate(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
+#define GRPC_ERROR_CREATE_FROM_STRING_VIEW(desc) \
+  StatusCreate(ababsl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
+
+absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
+                                const grpc_core::DebugLocation& location,
+                                size_t children_count,
+                                absl::Status* children) GRPC_MUST_USE_RESULT;
+
+// Create an error that references some other errors. This function adds a
+// reference to each error in errs - it does not consume an existing reference
+#define GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(desc, errs, count)   \
+  grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, count, \
+                     errs)
+#define GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(desc, errs, count)   \
+  grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, count, \
+                     errs)
+
+// Consumes all the errors in the vector and forms a referencing error from
+// them. If the vector is empty, return GRPC_ERROR_NONE.
+template <typename VectorType>
+static absl::Status grpc_status_create_from_vector(
+    const grpc_core::DebugLocation& location, const char* desc,
+    VectorType* error_list) {
+  absl::Status error = GRPC_ERROR_NONE;
+  if (error_list->size() != 0) {
+    error = grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION,
+                               error_list->size(), error_list->data());
+    error_list->clear();
+  }
+  return error;
+}
+
+#define GRPC_ERROR_CREATE_FROM_VECTOR(desc, error_list) \
+  grpc_status_create_from_vector(DEBUG_LOCATION, desc, error_list)
+
+absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
+                           const char* call_name) GRPC_MUST_USE_RESULT;
+
+inline absl::Status grpc_assert_never_ok(absl::Status error) {
+  GPR_ASSERT(error != GRPC_ERROR_NONE);
+  return error;
+}
+
+/// create an error associated with errno!=0 (an 'operating system' error)
+#define GRPC_OS_ERROR(err, call_name) \
+  grpc_assert_never_ok(grpc_os_error(DEBUG_LOCATION, err, call_name))
+
+absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
+                            const char* call_name) GRPC_MUST_USE_RESULT;
+
+/// windows only: create an error associated with WSAGetLastError()!=0
+#define GRPC_WSA_ERROR(err, call_name) \
+  grpc_wsa_error(DEBUG_LOCATION, err, call_name)
+
+#else  // GRPC_ERROR_IS_ABSEIL_STATUS
+
+/// The following "special" errors can be propagated without allocating memory.
+/// They are always even so that other code (particularly combiner locks,
+/// polling engines) can safely use the lower bit for themselves.
+
+#define GRPC_ERROR_NONE ((grpc_error_handle)NULL)
+#define GRPC_ERROR_RESERVED_1 ((grpc_error_handle)1)
+#define GRPC_ERROR_OOM ((grpc_error_handle)2)
+#define GRPC_ERROR_RESERVED_2 ((grpc_error_handle)3)
+#define GRPC_ERROR_CANCELLED ((grpc_error_handle)4)
+#define GRPC_ERROR_SPECIAL_MAX GRPC_ERROR_CANCELLED
+
+inline bool grpc_error_is_special(grpc_error_handle err) {
+  return err <= GRPC_ERROR_SPECIAL_MAX;
+}
+
+#ifndef NDEBUG
+grpc_error_handle grpc_error_do_ref(grpc_error_handle err, const char* file,
+                                    int line);
+void grpc_error_do_unref(grpc_error_handle err, const char* file, int line);
+inline grpc_error_handle grpc_error_ref(grpc_error_handle err, const char* file,
+                                        int line) {
+  if (grpc_error_is_special(err)) return err;
+  return grpc_error_do_ref(err, file, line);
+}
+inline void grpc_error_unref(grpc_error_handle err, const char* file,
+                             int line) {
+  if (grpc_error_is_special(err)) return;
+  grpc_error_do_unref(err, file, line);
+}
+#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
+#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
+#else
+grpc_error_handle grpc_error_do_ref(grpc_error_handle err);
+void grpc_error_do_unref(grpc_error_handle err);
+inline grpc_error_handle grpc_error_ref(grpc_error_handle err) {
+  if (grpc_error_is_special(err)) return err;
+  return grpc_error_do_ref(err);
+}
+inline void grpc_error_unref(grpc_error_handle err) {
+  if (grpc_error_is_special(err)) return;
+  grpc_error_do_unref(err);
+}
+#define GRPC_ERROR_REF(err) grpc_error_ref(err)
+#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
+#endif
 
 /// Create an error - but use GRPC_ERROR_CREATE instead
-grpc_error* grpc_error_create(const char* file, int line,
-                              const grpc_slice& desc, grpc_error** referencing,
-                              size_t num_referencing);
+grpc_error_handle grpc_error_create(const char* file, int line,
+                                    const grpc_slice& desc,
+                                    grpc_error_handle* referencing,
+                                    size_t num_referencing);
 /// Create an error (this is the preferred way of generating an error that is
 ///   not due to a system call - for system calls, use GRPC_OS_ERROR or
 ///   GRPC_WSA_ERROR as appropriate)
@@ -157,6 +286,10 @@
 #define GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc)                           \
   grpc_error_create(__FILE__, __LINE__, grpc_slice_from_copied_string(desc), \
                     NULL, 0)
+#define GRPC_ERROR_CREATE_FROM_STRING_VIEW(desc) \
+  grpc_error_create(                             \
+      __FILE__, __LINE__,                        \
+      grpc_slice_from_copied_buffer((desc).data(), (desc).size()), NULL, 0)
 
 // Create an error that references some other errors. This function adds a
 // reference to each error in errs - it does not consume an existing reference
@@ -170,41 +303,14 @@
 #define GRPC_ERROR_CREATE_FROM_VECTOR(desc, error_list) \
   grpc_error_create_from_vector(__FILE__, __LINE__, desc, error_list)
 
-#ifndef NDEBUG
-grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line);
-void grpc_error_do_unref(grpc_error* err, const char* file, int line);
-inline grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
-  if (grpc_error_is_special(err)) return err;
-  return grpc_error_do_ref(err, file, line);
-}
-inline void grpc_error_unref(grpc_error* err, const char* file, int line) {
-  if (grpc_error_is_special(err)) return;
-  grpc_error_do_unref(err, file, line);
-}
-#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
-#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
-#else
-grpc_error* grpc_error_do_ref(grpc_error* err);
-void grpc_error_do_unref(grpc_error* err);
-inline grpc_error* grpc_error_ref(grpc_error* err) {
-  if (grpc_error_is_special(err)) return err;
-  return grpc_error_do_ref(err);
-}
-inline void grpc_error_unref(grpc_error* err) {
-  if (grpc_error_is_special(err)) return;
-  grpc_error_do_unref(err);
-}
-#define GRPC_ERROR_REF(err) grpc_error_ref(err)
-#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
-#endif
-
 // Consumes all the errors in the vector and forms a referencing error from
 // them. If the vector is empty, return GRPC_ERROR_NONE.
 template <typename VectorType>
-static grpc_error* grpc_error_create_from_vector(const char* file, int line,
-                                                 const char* desc,
-                                                 VectorType* error_list) {
-  grpc_error* error = GRPC_ERROR_NONE;
+static grpc_error_handle grpc_error_create_from_vector(const char* file,
+                                                       int line,
+                                                       const char* desc,
+                                                       VectorType* error_list) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (error_list->size() != 0) {
     error = grpc_error_create(file, line, grpc_slice_from_static_string(desc),
                               error_list->data(), error_list->size());
@@ -217,18 +323,40 @@
   return error;
 }
 
-grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
-                               intptr_t value) GRPC_MUST_USE_RESULT;
-/// It is an error to pass nullptr as `p`. Caller should allocate a dummy
+grpc_error_handle grpc_os_error(const char* file, int line, int err,
+                                const char* call_name) GRPC_MUST_USE_RESULT;
+
+inline grpc_error_handle grpc_assert_never_ok(grpc_error_handle error) {
+  GPR_ASSERT(error != GRPC_ERROR_NONE);
+  return error;
+}
+
+/// create an error associated with errno!=0 (an 'operating system' error)
+#define GRPC_OS_ERROR(err, call_name) \
+  grpc_assert_never_ok(grpc_os_error(__FILE__, __LINE__, err, call_name))
+grpc_error_handle grpc_wsa_error(const char* file, int line, int err,
+                                 const char* call_name) GRPC_MUST_USE_RESULT;
+/// windows only: create an error associated with WSAGetLastError()!=0
+#define GRPC_WSA_ERROR(err, call_name) \
+  grpc_wsa_error(__FILE__, __LINE__, err, call_name)
+
+#endif  // GRPC_ERROR_IS_ABSEIL_STATUS
+
+grpc_error_handle grpc_error_set_int(grpc_error_handle src,
+                                     grpc_error_ints which,
+                                     intptr_t value) GRPC_MUST_USE_RESULT;
+/// It is an error to pass nullptr as `p`. Caller should allocate a phony
 /// intptr_t for `p`, even if the value of `p` is not used.
-bool grpc_error_get_int(grpc_error* error, grpc_error_ints which, intptr_t* p);
+bool grpc_error_get_int(grpc_error_handle error, grpc_error_ints which,
+                        intptr_t* p);
 /// This call takes ownership of the slice; the error is responsible for
 /// eventually unref-ing it.
-grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
-                               const grpc_slice& str) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_error_set_str(
+    grpc_error_handle src, grpc_error_strs which,
+    const grpc_slice& str) GRPC_MUST_USE_RESULT;
 /// Returns false if the specified string is not set.
 /// Caller does NOT own the slice.
-bool grpc_error_get_str(grpc_error* error, grpc_error_strs which,
+bool grpc_error_get_str(grpc_error_handle error, grpc_error_strs which,
                         grpc_slice* s);
 
 /// Add a child error: an error that is believed to have contributed to this
@@ -242,29 +370,12 @@
 /// returns GRPC_ERROR_NONE. 3) If \a src and \a child point to the same error,
 /// returns a single reference. (Note that, 2 references should have been
 /// received to the error in this case.)
-grpc_error* grpc_error_add_child(grpc_error* src,
-                                 grpc_error* child) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_error_add_child(
+    grpc_error_handle src, grpc_error_handle child) GRPC_MUST_USE_RESULT;
 
-grpc_error* grpc_os_error(const char* file, int line, int err,
-                          const char* call_name) GRPC_MUST_USE_RESULT;
-
-inline grpc_error* grpc_assert_never_ok(grpc_error* error) {
-  GPR_ASSERT(error != GRPC_ERROR_NONE);
-  return error;
-}
-
-/// create an error associated with errno!=0 (an 'operating system' error)
-#define GRPC_OS_ERROR(err, call_name) \
-  grpc_assert_never_ok(grpc_os_error(__FILE__, __LINE__, err, call_name))
-grpc_error* grpc_wsa_error(const char* file, int line, int err,
-                           const char* call_name) GRPC_MUST_USE_RESULT;
-/// windows only: create an error associated with WSAGetLastError()!=0
-#define GRPC_WSA_ERROR(err, call_name) \
-  grpc_wsa_error(__FILE__, __LINE__, err, call_name)
-
-bool grpc_log_error(const char* what, grpc_error* error, const char* file,
+bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
                     int line);
-inline bool grpc_log_if_error(const char* what, grpc_error* error,
+inline bool grpc_log_if_error(const char* what, grpc_error_handle error,
                               const char* file, int line) {
   return error == GRPC_ERROR_NONE ? true
                                   : grpc_log_error(what, error, file, line);
diff --git a/grpc/src/core/lib/iomgr/error_cfstream.cc b/grpc/src/core/lib/iomgr/error_cfstream.cc
index 7bf2865..114b3f2 100644
--- a/grpc/src/core/lib/iomgr/error_cfstream.cc
+++ b/grpc/src/core/lib/iomgr/error_cfstream.cc
@@ -31,8 +31,9 @@
 
 #define MAX_ERROR_DESCRIPTION 256
 
-grpc_error* grpc_error_create_from_cferror(const char* file, int line,
-                                           void* arg, const char* custom_desc) {
+grpc_error_handle grpc_error_create_from_cferror(const char* file, int line,
+                                                 void* arg,
+                                                 const char* custom_desc) {
   CFErrorRef error = static_cast<CFErrorRef>(arg);
   char buf_domain[MAX_ERROR_DESCRIPTION];
   char buf_desc[MAX_ERROR_DESCRIPTION];
diff --git a/grpc/src/core/lib/iomgr/error_cfstream.h b/grpc/src/core/lib/iomgr/error_cfstream.h
index 06ab751..2d5b744 100644
--- a/grpc/src/core/lib/iomgr/error_cfstream.h
+++ b/grpc/src/core/lib/iomgr/error_cfstream.h
@@ -24,8 +24,8 @@
 #define GRPC_ERROR_CREATE_FROM_CFERROR(error, desc)  \
   grpc_error_create_from_cferror(__FILE__, __LINE__, \
                                  static_cast<void*>((error)), (desc))
-grpc_error* grpc_error_create_from_cferror(const char* file, int line,
-                                           void* arg, const char* desc);
+grpc_error_handle grpc_error_create_from_cferror(const char* file, int line,
+                                                 void* arg, const char* desc);
 #endif /* GRPC_CFSTREAM */
 
 #endif /* GRPC_CORE_LIB_IOMGR_ERROR_CFSTREAM_H */
diff --git a/grpc/src/core/lib/iomgr/error_internal.h b/grpc/src/core/lib/iomgr/error_internal.h
index 33c233b..50c1dde 100644
--- a/grpc/src/core/lib/iomgr/error_internal.h
+++ b/grpc/src/core/lib/iomgr/error_internal.h
@@ -27,10 +27,12 @@
 #include <grpc/support/sync.h>
 #include "src/core/lib/iomgr/error.h"
 
+#ifndef GRPC_ERROR_IS_ABSEIL_STATUS
+
 typedef struct grpc_linked_error grpc_linked_error;
 
 struct grpc_linked_error {
-  grpc_error* err;
+  grpc_error_handle err;
   uint8_t next;
 };
 
@@ -58,4 +60,6 @@
   intptr_t arena[0];
 };
 
+#endif  // GRPC_ERROR_IS_ABSEIL_STATUS
+
 #endif /* GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H */
diff --git a/grpc/src/core/lib/iomgr/ev_apple.cc b/grpc/src/core/lib/iomgr/ev_apple.cc
index d152582..2580582 100644
--- a/grpc/src/core/lib/iomgr/ev_apple.cc
+++ b/grpc/src/core/lib/iomgr/ev_apple.cc
@@ -20,7 +20,7 @@
 /// is enabled (see iomgr_posix_cfstream.cc), a global thread is started to
 /// handle and trigger all the CFStream events. The CFStream streams register
 /// themselves with the run loop with functions grpc_apple_register_read_stream
-/// and grpc_apple_register_read_stream. Pollsets are dummy and block on a
+/// and grpc_apple_register_read_stream. Pollsets are phony and block on a
 /// condition variable in pollset_work().
 
 #include <grpc/support/port_platform.h>
@@ -33,7 +33,10 @@
 
 #include <list>
 
+#include "absl/time/time.h"
+
 #include "src/core/lib/gprpp/thd.h"
+#include "src/core/lib/gprpp/time_util.h"
 #include "src/core/lib/iomgr/ev_apple.h"
 
 grpc_core::DebugOnlyTraceFlag grpc_apple_polling_trace(false, "apple_polling");
@@ -161,7 +164,7 @@
 /// Drive the run loop in a global singleton thread until the global run loop is
 /// shutdown.
 static void GlobalRunLoopFunc(void* arg) {
-  grpc_core::ReleasableMutexLock lock(&gGlobalRunLoopContext->mu);
+  grpc_core::LockableAndReleasableMutexLock lock(&gGlobalRunLoopContext->mu);
   gGlobalRunLoopContext->run_loop = CFRunLoopGetCurrent();
   gGlobalRunLoopContext->init_cv.Signal();
 
@@ -173,11 +176,11 @@
       gGlobalRunLoopContext->input_source_cv.Wait(&gGlobalRunLoopContext->mu);
     }
     gGlobalRunLoopContext->input_source_registered = false;
-    lock.Unlock();
+    lock.Release();
     CFRunLoopRun();
     lock.Lock();
   }
-  lock.Unlock();
+  lock.Release();
 }
 
 // pollset implementation
@@ -216,9 +219,9 @@
 /// The Apple pollset simply waits on a condition variable until it is kicked.
 /// The network events are handled in the global run loop thread. Processing of
 /// these events will eventually trigger the kick.
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker,
+                                      grpc_millis deadline) {
   GRPC_POLLING_TRACE("pollset work: %p, worker: %p, deadline: %" PRIu64,
                      pollset, worker, deadline);
   GrpcApplePollset* apple_pollset =
@@ -237,9 +240,9 @@
     auto it = apple_pollset->workers.begin();
 
     while (!actual_worker.kicked && !apple_pollset->is_shutdown) {
-      if (actual_worker.cv.Wait(
-              &apple_pollset->mu,
-              grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME))) {
+      if (actual_worker.cv.WaitWithDeadline(
+              &apple_pollset->mu, grpc_core::ToAbslTime(grpc_millis_to_timespec(
+                                      deadline, GPR_CLOCK_REALTIME)))) {
         // timed out
         break;
       }
@@ -269,8 +272,8 @@
 /// The caller must acquire the lock GrpcApplePollset.mu before calling this
 /// function. The kick action simply signals the condition variable of the
 /// worker.
-static grpc_error* pollset_kick(grpc_pollset* pollset,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* pollset,
+                                      grpc_pollset_worker* specific_worker) {
   GrpcApplePollset* apple_pollset =
       reinterpret_cast<GrpcApplePollset*>(pollset);
 
@@ -299,7 +302,7 @@
 static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
   GRPC_POLLING_TRACE("pollset init: %p", pollset);
   GrpcApplePollset* apple_pollset = new (pollset) GrpcApplePollset();
-  *mu = apple_pollset->mu.get();
+  *mu = grpc_core::GetUnderlyingGprMu(&apple_pollset->mu);
 }
 
 /// The caller must acquire the lock GrpcApplePollset.mu before calling this
diff --git a/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc b/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc
index 8a1013d..f09cd78 100644
--- a/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc
+++ b/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc
@@ -241,7 +241,7 @@
  * Common helpers
  */
 
-static bool append_error(grpc_error** composite, grpc_error* error,
+static bool append_error(grpc_error_handle* composite, grpc_error_handle error,
                          const char* desc) {
   if (error == GRPC_ERROR_NONE) return true;
   if (*composite == GRPC_ERROR_NONE) {
@@ -382,15 +382,15 @@
 /* if 'releasing_fd' is true, it means that we are going to detach the internal
  * fd from grpc_fd structure (i.e which means we should not be calling
  * shutdown() syscall on that fd) */
-static void fd_shutdown_internal(grpc_fd* fd, grpc_error* why,
+static void fd_shutdown_internal(grpc_fd* fd, grpc_error_handle why,
                                  bool releasing_fd) {
   if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
     if (!releasing_fd) {
       shutdown(fd->fd, SHUT_RDWR);
     } else {
-      /* we need a dummy event for earlier linux versions. */
-      epoll_event dummy_event;
-      if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_DEL, fd->fd, &dummy_event) !=
+      /* we need a phony event for earlier linux versions. */
+      epoll_event phony_event;
+      if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_DEL, fd->fd, &phony_event) !=
           0) {
         gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
       }
@@ -402,13 +402,13 @@
 }
 
 /* Might be called multiple times */
-static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
+static void fd_shutdown(grpc_fd* fd, grpc_error_handle why) {
   fd_shutdown_internal(fd, why, false);
 }
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
                       const char* reason) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   bool is_release_fd = (release_fd != nullptr);
 
   if (!fd->read_closure->IsShutdown()) {
@@ -514,12 +514,12 @@
   return static_cast<size_t>(gpr_cpu_current_cpu()) % g_num_neighborhoods;
 }
 
-static grpc_error* pollset_global_init(void) {
+static grpc_error_handle pollset_global_init(void) {
   gpr_tls_init(&g_current_thread_pollset);
   gpr_tls_init(&g_current_thread_worker);
   gpr_atm_no_barrier_store(&g_active_poller, 0);
   global_wakeup_fd.read_fd = -1;
-  grpc_error* err = grpc_wakeup_fd_init(&global_wakeup_fd);
+  grpc_error_handle err = grpc_wakeup_fd_init(&global_wakeup_fd);
   if (err != GRPC_ERROR_NONE) return err;
   struct epoll_event ev;
   ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLET);
@@ -589,9 +589,9 @@
   gpr_mu_destroy(&pollset->mu);
 }
 
-static grpc_error* pollset_kick_all(grpc_pollset* pollset) {
+static grpc_error_handle pollset_kick_all(grpc_pollset* pollset) {
   GPR_TIMER_SCOPE("pollset_kick_all", 0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (pollset->root_worker != nullptr) {
     grpc_pollset_worker* worker = pollset->root_worker;
     do {
@@ -663,11 +663,11 @@
    NOTE ON SYNCRHONIZATION: Similar to do_epoll_wait(), this function is only
    called by g_active_poller thread. So there is no need for synchronization
    when accessing fields in g_epoll_set */
-static grpc_error* process_epoll_events(grpc_pollset* /*pollset*/) {
+static grpc_error_handle process_epoll_events(grpc_pollset* /*pollset*/) {
   GPR_TIMER_SCOPE("process_epoll_events", 0);
 
   static const char* err_desc = "process_events";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   long num_events = gpr_atm_acq_load(&g_epoll_set.num_events);
   long cursor = gpr_atm_acq_load(&g_epoll_set.cursor);
   for (int idx = 0;
@@ -715,7 +715,7 @@
    NOTE ON SYNCHRONIZATION: At any point of time, only the g_active_poller
    (i.e the designated poller thread) will be calling this function. So there is
    no need for any synchronization when accesing fields in g_epoll_set */
-static grpc_error* do_epoll_wait(grpc_pollset* ps, grpc_millis deadline) {
+static grpc_error_handle do_epoll_wait(grpc_pollset* ps, grpc_millis deadline) {
   GPR_TIMER_SCOPE("do_epoll_wait", 0);
 
   int r;
@@ -1014,12 +1014,12 @@
    The function pollset_work() may temporarily release the lock (pollset->po.mu)
    during the course of its execution but it will always re-acquire the lock and
    ensure that it is held by the time the function returns */
-static grpc_error* pollset_work(grpc_pollset* ps,
-                                grpc_pollset_worker** worker_hdl,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* ps,
+                                      grpc_pollset_worker** worker_hdl,
+                                      grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollset_work", 0);
   grpc_pollset_worker worker;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollset_work";
   if (ps->kicked_without_poller) {
     ps->kicked_without_poller = false;
@@ -1065,11 +1065,11 @@
   return error;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* pollset,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* pollset,
+                                      grpc_pollset_worker* specific_worker) {
   GPR_TIMER_SCOPE("pollset_kick", 0);
   GRPC_STATS_INC_POLLSET_KICK();
-  grpc_error* ret_err = GRPC_ERROR_NONE;
+  grpc_error_handle ret_err = GRPC_ERROR_NONE;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     std::vector<std::string> log;
     log.push_back(absl::StrFormat(
@@ -1260,7 +1260,7 @@
 static void shutdown_background_closure(void) {}
 
 static bool add_closure_to_background_poller(grpc_closure* /*closure*/,
-                                             grpc_error* /*error*/) {
+                                             grpc_error_handle /*error*/) {
   return false;
 }
 
diff --git a/grpc/src/core/lib/iomgr/ev_epollex_linux.cc b/grpc/src/core/lib/iomgr/ev_epollex_linux.cc
index acd095a..72d7da7 100644
--- a/grpc/src/core/lib/iomgr/ev_epollex_linux.cc
+++ b/grpc/src/core/lib/iomgr/ev_epollex_linux.cc
@@ -134,7 +134,7 @@
 /// added
 static pollable* g_empty_pollable;
 
-static grpc_error* pollable_create(pollable_type type, pollable** p);
+static grpc_error_handle pollable_create(pollable_type type, pollable** p);
 static pollable* pollable_ref(pollable* p,
                               const grpc_core::DebugLocation& dbg_loc,
                               const char* reason) {
@@ -314,7 +314,7 @@
  * Common helpers
  */
 
-static bool append_error(grpc_error** composite, grpc_error* error,
+static bool append_error(grpc_error_handle* composite, grpc_error_handle error,
                          const char* desc) {
   if (error == GRPC_ERROR_NONE) return true;
   if (*composite == GRPC_ERROR_NONE) {
@@ -372,7 +372,7 @@
 }
 
 /* Uninitialize and add to the freelist */
-static void fd_destroy(void* arg, grpc_error* /*error*/) {
+static void fd_destroy(void* arg, grpc_error_handle /*error*/) {
   grpc_fd* fd = static_cast<grpc_fd*>(arg);
   fd->destroy();
 
@@ -509,7 +509,7 @@
 }
 
 /* Might be called multiple times */
-static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
+static void fd_shutdown(grpc_fd* fd, grpc_error_handle why) {
   if (fd->read_closure.SetShutdown(GRPC_ERROR_REF(why))) {
     if (shutdown(fd->fd, SHUT_RDWR)) {
       if (errno != ENOTCONN) {
@@ -537,7 +537,7 @@
 
 static bool fd_has_pollset(grpc_fd* fd, grpc_pollset* pollset) {
   const int epfd = pollset->active_pollable->epfd;
-  grpc_core::MutexLock lock(&fd->pollable_mu);
+  grpc_core::MutexLockForGprMu lock(&fd->pollable_mu);
   for (size_t i = 0; i < fd->pollset_fds.size(); ++i) {
     if (fd->pollset_fds[i] == epfd) {
       return true;
@@ -548,7 +548,7 @@
 
 static void fd_add_pollset(grpc_fd* fd, grpc_pollset* pollset) {
   const int epfd = pollset->active_pollable->epfd;
-  grpc_core::MutexLock lock(&fd->pollable_mu);
+  grpc_core::MutexLockForGprMu lock(&fd->pollable_mu);
   fd->pollset_fds.push_back(epfd);
 }
 
@@ -556,7 +556,7 @@
  * Pollable Definitions
  */
 
-static grpc_error* pollable_create(pollable_type type, pollable** p) {
+static grpc_error_handle pollable_create(pollable_type type, pollable** p) {
   *p = nullptr;
 
   int epfd = epoll_create1(EPOLL_CLOEXEC);
@@ -565,7 +565,7 @@
   }
   GRPC_FD_TRACE("Pollable_create: created epfd: %d (type: %d)", epfd, type);
   *p = static_cast<pollable*>(gpr_malloc(sizeof(**p)));
-  grpc_error* err = grpc_wakeup_fd_init(&(*p)->wakeup);
+  grpc_error_handle err = grpc_wakeup_fd_init(&(*p)->wakeup);
   if (err != GRPC_ERROR_NONE) {
     GRPC_FD_TRACE(
         "Pollable_create: closed epfd: %d (type: %d). wakeupfd_init error",
@@ -609,8 +609,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) {
-  grpc_error* error = GRPC_ERROR_NONE;
+static grpc_error_handle pollable_add_fd(pollable* p, grpc_fd* fd) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollable_add_fd";
   const int epfd = p->epfd;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
@@ -647,7 +647,7 @@
 GPR_TLS_DECL(g_current_thread_worker);
 
 /* Global state management */
-static grpc_error* pollset_global_init(void) {
+static grpc_error_handle pollset_global_init(void) {
   gpr_tls_init(&g_current_thread_pollset);
   gpr_tls_init(&g_current_thread_worker);
   return pollable_create(PO_EMPTY, &g_empty_pollable);
@@ -681,10 +681,10 @@
 /* pollset->mu must be held before calling this function,
  * pollset->active_pollable->mu & specific_worker->pollable_obj->mu must not be
  * held */
-static grpc_error* kick_one_worker(grpc_pollset_worker* specific_worker) {
+static grpc_error_handle kick_one_worker(grpc_pollset_worker* specific_worker) {
   GPR_TIMER_SCOPE("kick_one_worker", 0);
   pollable* p = specific_worker->pollable_obj;
-  grpc_core::MutexLock lock(&p->mu);
+  grpc_core::MutexLockForGprMu lock(&p->mu);
   GPR_ASSERT(specific_worker != nullptr);
   if (specific_worker->kicked) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
@@ -708,7 +708,7 @@
       gpr_log(GPR_INFO, "PS:%p kicked_specific_via_wakeup_fd", p);
     }
     specific_worker->kicked = true;
-    grpc_error* error = grpc_wakeup_fd_wakeup(&p->wakeup);
+    grpc_error_handle error = grpc_wakeup_fd_wakeup(&p->wakeup);
     return error;
   }
   if (specific_worker->initialized_cv) {
@@ -725,8 +725,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* pollset,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* pollset,
+                                      grpc_pollset_worker* specific_worker) {
   GPR_TIMER_SCOPE("pollset_kick", 0);
   GRPC_STATS_INC_POLLSET_KICK();
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
@@ -777,9 +777,9 @@
   }
 }
 
-static grpc_error* pollset_kick_all(grpc_pollset* pollset) {
+static grpc_error_handle pollset_kick_all(grpc_pollset* pollset) {
   GPR_TIMER_SCOPE("pollset_kick_all", 0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   const char* err_desc = "pollset_kick_all";
   grpc_pollset_worker* w = pollset->root_worker;
   if (w != nullptr) {
@@ -828,9 +828,9 @@
  *
  * Note that if a pollable object is already attached to the fd, it may be of
  * either PO_FD or PO_MULTI type */
-static grpc_error* get_fd_pollable(grpc_fd* fd, pollable** p) {
+static grpc_error_handle get_fd_pollable(grpc_fd* fd, pollable** p) {
   gpr_mu_lock(&fd->pollable_mu);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "get_fd_pollable";
   if (fd->pollable_obj == nullptr) {
     if (append_error(&error, pollable_create(PO_FD, &fd->pollable_obj),
@@ -863,8 +863,9 @@
   pollset_maybe_finish_shutdown(pollset);
 }
 
-static grpc_error* pollable_process_events(grpc_pollset* pollset,
-                                           pollable* pollable_obj, bool drain) {
+static grpc_error_handle pollable_process_events(grpc_pollset* pollset,
+                                                 pollable* pollable_obj,
+                                                 bool drain) {
   GPR_TIMER_SCOPE("pollable_process_events", 0);
   static const char* err_desc = "pollset_process_events";
   // Use a simple heuristic to determine how many fd events to process
@@ -877,7 +878,7 @@
   if (handle_count == 0) {
     handle_count = 1;
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   for (int i = 0; (drain || i < handle_count) &&
                   pollable_obj->event_cursor != pollable_obj->event_count;
        i++) {
@@ -932,7 +933,7 @@
   gpr_mu_destroy(&pollset->mu);
 }
 
-static grpc_error* pollable_epoll(pollable* p, grpc_millis deadline) {
+static grpc_error_handle pollable_epoll(pollable* p, grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollable_epoll", 0);
   int timeout = poll_deadline_to_millis_timeout(deadline);
 
@@ -1103,9 +1104,9 @@
    The function pollset_work() may temporarily release the lock (pollset->po.mu)
    during the course of its execution but it will always re-acquire the lock and
    ensure that it is held by the time the function returns */
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker_hdl,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker_hdl,
+                                      grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollset_work", 0);
 #ifdef GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP
   grpc_pollset_worker* worker =
@@ -1126,7 +1127,7 @@
             deadline, pollset->kicked_without_poller, pollset->active_pollable);
   }
   static const char* err_desc = "pollset_work";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (pollset->kicked_without_poller) {
     pollset->kicked_without_poller = false;
   } else {
@@ -1155,10 +1156,10 @@
   return error;
 }
 
-static grpc_error* pollset_transition_pollable_from_empty_to_fd_locked(
+static grpc_error_handle pollset_transition_pollable_from_empty_to_fd_locked(
     grpc_pollset* pollset, grpc_fd* fd) {
   static const char* err_desc = "pollset_transition_pollable_from_empty_to_fd";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(GPR_INFO,
             "PS:%p add fd %p (%d); transition pollable from empty to fd",
@@ -1171,10 +1172,10 @@
   return error;
 }
 
-static grpc_error* pollset_transition_pollable_from_fd_to_multi_locked(
+static grpc_error_handle pollset_transition_pollable_from_fd_to_multi_locked(
     grpc_pollset* pollset, grpc_fd* and_add_fd) {
   static const char* err_desc = "pollset_transition_pollable_from_fd_to_multi";
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(
         GPR_INFO,
@@ -1200,8 +1201,9 @@
 }
 
 /* expects pollsets locked, flag whether fd is locked or not */
-static grpc_error* pollset_add_fd_locked(grpc_pollset* pollset, grpc_fd* fd) {
-  grpc_error* error = GRPC_ERROR_NONE;
+static grpc_error_handle pollset_add_fd_locked(grpc_pollset* pollset,
+                                               grpc_fd* fd) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   pollable* po_at_start =
       POLLABLE_REF(pollset->active_pollable, "pollset_add_fd");
   switch (pollset->active_pollable->type) {
@@ -1236,9 +1238,9 @@
   return error;
 }
 
-static grpc_error* pollset_as_multipollable_locked(grpc_pollset* pollset,
-                                                   pollable** pollable_obj) {
-  grpc_error* error = GRPC_ERROR_NONE;
+static grpc_error_handle pollset_as_multipollable_locked(
+    grpc_pollset* pollset, pollable** pollable_obj) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
   pollable* po_at_start =
       POLLABLE_REF(pollset->active_pollable, "pollset_as_multipollable");
   switch (pollset->active_pollable->type) {
@@ -1296,8 +1298,8 @@
     return;
   }
 
-  grpc_core::MutexLock lock(&pollset->mu);
-  grpc_error* error = pollset_add_fd_locked(pollset, fd);
+  grpc_core::MutexLockForGprMu lock(&pollset->mu);
+  grpc_error_handle error = pollset_add_fd_locked(pollset, fd);
 
   // If we are in PO_MULTI mode, we should update the pollsets of the FD.
   if (gpr_atm_no_barrier_load(&pollset->active_pollable_type) == PO_MULTI) {
@@ -1354,7 +1356,7 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(GPR_INFO, "PSS:%p: add fd %p (%d)", pss, fd, fd->fd);
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollset_set_add_fd";
   pss = pss_lock_adam(pss);
   for (size_t i = 0; i < pss->pollset_count; i++) {
@@ -1421,13 +1423,14 @@
 
 // add all fds to pollables, and output a new array of unorphaned out_fds
 // assumes pollsets are multipollable
-static grpc_error* add_fds_to_pollsets(grpc_fd** fds, size_t fd_count,
-                                       grpc_pollset** pollsets,
-                                       size_t pollset_count,
-                                       const char* err_desc, grpc_fd** out_fds,
-                                       size_t* out_fd_count) {
+static grpc_error_handle add_fds_to_pollsets(grpc_fd** fds, size_t fd_count,
+                                             grpc_pollset** pollsets,
+                                             size_t pollset_count,
+                                             const char* err_desc,
+                                             grpc_fd** out_fds,
+                                             size_t* out_fd_count) {
   GPR_TIMER_SCOPE("add_fds_to_pollsets", 0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   for (size_t i = 0; i < fd_count; i++) {
     gpr_mu_lock(&fds[i]->orphan_mu);
     if ((gpr_atm_no_barrier_load(&fds[i]->refst) & 1) == 0) {
@@ -1451,7 +1454,7 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(GPR_INFO, "PSS:%p: add pollset %p", pss, ps);
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollset_set_add_pollset";
   pollable* pollable_obj = nullptr;
   gpr_mu_lock(&ps->mu);
@@ -1488,7 +1491,7 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
     gpr_log(GPR_INFO, "PSS: merge (%p, %p)", a, b);
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   static const char* err_desc = "pollset_set_add_fd";
   for (;;) {
     if (a == b) {
@@ -1573,7 +1576,7 @@
 static void shutdown_background_closure(void) {}
 
 static bool add_closure_to_background_poller(grpc_closure* /*closure*/,
-                                             grpc_error* /*error*/) {
+                                             grpc_error_handle /*error*/) {
   return false;
 }
 
diff --git a/grpc/src/core/lib/iomgr/ev_poll_posix.cc b/grpc/src/core/lib/iomgr/ev_poll_posix.cc
index e58d1d3..fa4242f 100644
--- a/grpc/src/core/lib/iomgr/ev_poll_posix.cc
+++ b/grpc/src/core/lib/iomgr/ev_poll_posix.cc
@@ -89,7 +89,7 @@
   int closed;
   int released;
   gpr_atm pollhup;
-  grpc_error* shutdown_error;
+  grpc_error_handle shutdown_error;
 
   /* The watcher list.
 
@@ -230,9 +230,9 @@
 #define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
 /* As per pollset_kick, with an extended set of flags (defined above)
    -- mostly for fd_posix's use. */
-static grpc_error* pollset_kick_ext(grpc_pollset* p,
-                                    grpc_pollset_worker* specific_worker,
-                                    uint32_t flags) GRPC_MUST_USE_RESULT;
+static grpc_error_handle pollset_kick_ext(grpc_pollset* p,
+                                          grpc_pollset_worker* specific_worker,
+                                          uint32_t flags) GRPC_MUST_USE_RESULT;
 
 /* Return 1 if the pollset has active threads in pollset_work (pollset must
  * be locked) */
@@ -394,11 +394,12 @@
   return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
 }
 
-static grpc_error* pollset_kick_locked(grpc_fd_watcher* watcher) {
+static grpc_error_handle pollset_kick_locked(grpc_fd_watcher* watcher) {
   gpr_mu_lock(&watcher->pollset->mu);
   GPR_ASSERT(watcher->worker);
-  grpc_error* err = pollset_kick_ext(watcher->pollset, watcher->worker,
-                                     GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
+  grpc_error_handle err =
+      pollset_kick_ext(watcher->pollset, watcher->worker,
+                       GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
   gpr_mu_unlock(&watcher->pollset->mu);
   return err;
 }
@@ -484,7 +485,7 @@
 static void fd_unref(grpc_fd* fd) { unref_by(fd, 2); }
 #endif
 
-static grpc_error* fd_shutdown_error(grpc_fd* fd) {
+static grpc_error_handle fd_shutdown_error(grpc_fd* fd) {
   if (!fd->shutdown) {
     return GRPC_ERROR_NONE;
   } else {
@@ -537,7 +538,7 @@
   }
 }
 
-static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
+static void fd_shutdown(grpc_fd* fd, grpc_error_handle why) {
   gpr_mu_lock(&fd->mu);
   /* only shutdown once */
   if (!fd->shutdown) {
@@ -747,7 +748,8 @@
   worker->prev->next = worker->next->prev = worker;
 }
 
-static void kick_append_error(grpc_error** composite, grpc_error* error) {
+static void kick_append_error(grpc_error_handle* composite,
+                              grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) return;
   if (*composite == GRPC_ERROR_NONE) {
     *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Kick Failure");
@@ -755,11 +757,11 @@
   *composite = grpc_error_add_child(*composite, error);
 }
 
-static grpc_error* pollset_kick_ext(grpc_pollset* p,
-                                    grpc_pollset_worker* specific_worker,
-                                    uint32_t flags) {
+static grpc_error_handle pollset_kick_ext(grpc_pollset* p,
+                                          grpc_pollset_worker* specific_worker,
+                                          uint32_t flags) {
   GPR_TIMER_SCOPE("pollset_kick_ext", 0);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   GRPC_STATS_INC_POLLSET_KICK();
 
   /* pollset->mu already held */
@@ -826,14 +828,14 @@
   return error;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* p,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* p,
+                                      grpc_pollset_worker* specific_worker) {
   return pollset_kick_ext(p, specific_worker, 0);
 }
 
 /* global state management */
 
-static grpc_error* pollset_global_init(void) {
+static grpc_error_handle pollset_global_init(void) {
   gpr_tls_init(&g_current_thread_poller);
   gpr_tls_init(&g_current_thread_worker);
   return GRPC_ERROR_NONE;
@@ -904,7 +906,8 @@
                           GRPC_ERROR_NONE);
 }
 
-static void work_combine_error(grpc_error** composite, grpc_error* error) {
+static void work_combine_error(grpc_error_handle* composite,
+                               grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) return;
   if (*composite == GRPC_ERROR_NONE) {
     *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("pollset_work");
@@ -912,13 +915,13 @@
   *composite = grpc_error_add_child(*composite, error);
 }
 
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker_hdl,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker_hdl,
+                                      grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollset_work", 0);
   grpc_pollset_worker worker;
   if (worker_hdl) *worker_hdl = &worker;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   /* Avoid malloc for small number of elements. */
   enum { inline_elements = 96 };
@@ -1336,7 +1339,7 @@
 static void shutdown_background_closure(void) {}
 
 static bool add_closure_to_background_poller(grpc_closure* /*closure*/,
-                                             grpc_error* /*error*/) {
+                                             grpc_error_handle /*error*/) {
   return false;
 }
 
diff --git a/grpc/src/core/lib/iomgr/ev_posix.cc b/grpc/src/core/lib/iomgr/ev_posix.cc
index 3d32359..dfb250f 100644
--- a/grpc/src/core/lib/iomgr/ev_posix.cc
+++ b/grpc/src/core/lib/iomgr/ev_posix.cc
@@ -89,7 +89,7 @@
 
 grpc_poll_function_type real_poll_function;
 
-int dummy_poll(struct pollfd fds[], nfds_t nfds, int timeout) {
+int phony_poll(struct pollfd fds[], nfds_t nfds, int timeout) {
   if (timeout == 0) {
     return real_poll_function(fds, nfds, 0);
   } else {
@@ -103,10 +103,10 @@
   if (!explicit_request) {
     return nullptr;
   }
-  // return the simplest engine as a dummy but also override the poller
+  // return the simplest engine as a phony but also override the poller
   auto ret = grpc_init_poll_posix(explicit_request);
   real_poll_function = grpc_poll_function;
-  grpc_poll_function = dummy_poll;
+  grpc_poll_function = phony_poll;
 
   return ret;
 }
@@ -270,7 +270,7 @@
   g_event_engine->fd_orphan(fd, on_done, release_fd, reason);
 }
 
-void grpc_fd_shutdown(grpc_fd* fd, grpc_error* why) {
+void grpc_fd_shutdown(grpc_fd* fd, grpc_error_handle why) {
   GRPC_POLLING_API_TRACE("fd_shutdown(%d)", grpc_fd_wrapped_fd(fd));
   GRPC_FD_TRACE("fd_shutdown(%d)", grpc_fd_wrapped_fd(fd));
   g_event_engine->fd_shutdown(fd, why);
@@ -315,19 +315,20 @@
   g_event_engine->pollset_destroy(pollset);
 }
 
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker,
+                                      grpc_millis deadline) {
   GRPC_POLLING_API_TRACE("pollset_work(%p, %" PRId64 ") begin", pollset,
                          deadline);
-  grpc_error* err = g_event_engine->pollset_work(pollset, worker, deadline);
+  grpc_error_handle err =
+      g_event_engine->pollset_work(pollset, worker, deadline);
   GRPC_POLLING_API_TRACE("pollset_work(%p, %" PRId64 ") end", pollset,
                          deadline);
   return err;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* pollset,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* pollset,
+                                      grpc_pollset_worker* specific_worker) {
   GRPC_POLLING_API_TRACE("pollset_kick(%p, %p)", pollset, specific_worker);
   return g_event_engine->pollset_kick(pollset, specific_worker);
 }
@@ -406,7 +407,7 @@
 }
 
 bool grpc_add_closure_to_background_poller(grpc_closure* closure,
-                                           grpc_error* error) {
+                                           grpc_error_handle error) {
   return g_event_engine->add_closure_to_background_poller(closure, error);
 }
 
diff --git a/grpc/src/core/lib/iomgr/ev_posix.h b/grpc/src/core/lib/iomgr/ev_posix.h
index 84edabc..479921a 100644
--- a/grpc/src/core/lib/iomgr/ev_posix.h
+++ b/grpc/src/core/lib/iomgr/ev_posix.h
@@ -52,7 +52,7 @@
   int (*fd_wrapped_fd)(grpc_fd* fd);
   void (*fd_orphan)(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
                     const char* reason);
-  void (*fd_shutdown)(grpc_fd* fd, grpc_error* why);
+  void (*fd_shutdown)(grpc_fd* fd, grpc_error_handle why);
   void (*fd_notify_on_read)(grpc_fd* fd, grpc_closure* closure);
   void (*fd_notify_on_write)(grpc_fd* fd, grpc_closure* closure);
   void (*fd_notify_on_error)(grpc_fd* fd, grpc_closure* closure);
@@ -64,11 +64,11 @@
   void (*pollset_init)(grpc_pollset* pollset, gpr_mu** mu);
   void (*pollset_shutdown)(grpc_pollset* pollset, grpc_closure* closure);
   void (*pollset_destroy)(grpc_pollset* pollset);
-  grpc_error* (*pollset_work)(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker,
-                              grpc_millis deadline);
-  grpc_error* (*pollset_kick)(grpc_pollset* pollset,
-                              grpc_pollset_worker* specific_worker);
+  grpc_error_handle (*pollset_work)(grpc_pollset* pollset,
+                                    grpc_pollset_worker** worker,
+                                    grpc_millis deadline);
+  grpc_error_handle (*pollset_kick)(grpc_pollset* pollset,
+                                    grpc_pollset_worker* specific_worker);
   void (*pollset_add_fd)(grpc_pollset* pollset, struct grpc_fd* fd);
 
   grpc_pollset_set* (*pollset_set_create)(void);
@@ -88,7 +88,7 @@
   void (*shutdown_background_closure)(void);
   void (*shutdown_engine)(void);
   bool (*add_closure_to_background_poller)(grpc_closure* closure,
-                                           grpc_error* error);
+                                           grpc_error_handle error);
 } grpc_event_engine_vtable;
 
 /* register a new event engine factory */
@@ -139,7 +139,7 @@
 bool grpc_fd_is_shutdown(grpc_fd* fd);
 
 /* Cause any current and future callbacks to fail. */
-void grpc_fd_shutdown(grpc_fd* fd, grpc_error* why);
+void grpc_fd_shutdown(grpc_fd* fd, grpc_error_handle why);
 
 /* Register read interest, causing read_cb to be called once when fd becomes
    readable, on deadline specified by deadline, or on shutdown triggered by
@@ -195,7 +195,7 @@
  * that the closure may or may not run yet when this function returns, and the
  * closure should not be blocking or long-running. */
 bool grpc_add_closure_to_background_poller(grpc_closure* closure,
-                                           grpc_error* error);
+                                           grpc_error_handle error);
 
 /* Shut down all the closures registered in the background poller. */
 void grpc_shutdown_background_closure();
diff --git a/grpc/src/core/lib/iomgr/exec_ctx.cc b/grpc/src/core/lib/iomgr/exec_ctx.cc
index 18d0aae..54ab9fd 100644
--- a/grpc/src/core/lib/iomgr/exec_ctx.cc
+++ b/grpc/src/core/lib/iomgr/exec_ctx.cc
@@ -27,7 +27,7 @@
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/profiling/timers.h"
 
-static void exec_ctx_run(grpc_closure* closure, grpc_error* error) {
+static void exec_ctx_run(grpc_closure* closure, grpc_error_handle error) {
 #ifndef NDEBUG
   closure->scheduled = false;
   if (grpc_trace_closure.enabled()) {
@@ -46,7 +46,7 @@
   GRPC_ERROR_UNREF(error);
 }
 
-static void exec_ctx_sched(grpc_closure* closure, grpc_error* error) {
+static void exec_ctx_sched(grpc_closure* closure, grpc_error_handle error) {
   grpc_closure_list_append(grpc_core::ExecCtx::Get()->closure_list(), closure,
                            error);
 }
@@ -58,7 +58,9 @@
   double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) +
              static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS;
   if (x < 0) return 0;
-  if (x > GRPC_MILLIS_INF_FUTURE) return GRPC_MILLIS_INF_FUTURE;
+  if (x > static_cast<double>(GRPC_MILLIS_INF_FUTURE)) {
+    return GRPC_MILLIS_INF_FUTURE;
+  }
   return static_cast<grpc_millis>(x);
 }
 
@@ -72,7 +74,9 @@
              static_cast<double>(GPR_NS_PER_SEC - 1) /
                  static_cast<double>(GPR_NS_PER_SEC);
   if (x < 0) return 0;
-  if (x > GRPC_MILLIS_INF_FUTURE) return GRPC_MILLIS_INF_FUTURE;
+  if (x > static_cast<double>(GRPC_MILLIS_INF_FUTURE)) {
+    return GRPC_MILLIS_INF_FUTURE;
+  }
   return static_cast<grpc_millis>(x);
 }
 
@@ -148,7 +152,7 @@
       closure_list_.head = closure_list_.tail = nullptr;
       while (c != nullptr) {
         grpc_closure* next = c->next_data.next;
-        grpc_error* error = c->error_data.error;
+        grpc_error_handle error = c->error_data.error;
         did_something = true;
         exec_ctx_run(c, error);
         c = next;
@@ -170,7 +174,7 @@
 }
 
 void ExecCtx::Run(const DebugLocation& location, grpc_closure* closure,
-                  grpc_error* error) {
+                  grpc_error_handle error) {
   (void)location;
   if (closure == nullptr) {
     GRPC_ERROR_UNREF(error);
diff --git a/grpc/src/core/lib/iomgr/exec_ctx.h b/grpc/src/core/lib/iomgr/exec_ctx.h
index c993133..9cb5257 100644
--- a/grpc/src/core/lib/iomgr/exec_ctx.h
+++ b/grpc/src/core/lib/iomgr/exec_ctx.h
@@ -228,7 +228,7 @@
   }
 
   static void Run(const DebugLocation& location, grpc_closure* closure,
-                  grpc_error* error);
+                  grpc_error_handle error);
 
   static void RunList(const DebugLocation& location, grpc_closure_list* list);
 
diff --git a/grpc/src/core/lib/iomgr/executor.cc b/grpc/src/core/lib/iomgr/executor.cc
index b1d21bc..3d8d757 100644
--- a/grpc/src/core/lib/iomgr/executor.cc
+++ b/grpc/src/core/lib/iomgr/executor.cc
@@ -57,27 +57,27 @@
 
 Executor* executors[static_cast<size_t>(ExecutorType::NUM_EXECUTORS)];
 
-void default_enqueue_short(grpc_closure* closure, grpc_error* error) {
+void default_enqueue_short(grpc_closure* closure, grpc_error_handle error) {
   executors[static_cast<size_t>(ExecutorType::DEFAULT)]->Enqueue(
       closure, error, true /* is_short */);
 }
 
-void default_enqueue_long(grpc_closure* closure, grpc_error* error) {
+void default_enqueue_long(grpc_closure* closure, grpc_error_handle error) {
   executors[static_cast<size_t>(ExecutorType::DEFAULT)]->Enqueue(
       closure, error, false /* is_short */);
 }
 
-void resolver_enqueue_short(grpc_closure* closure, grpc_error* error) {
+void resolver_enqueue_short(grpc_closure* closure, grpc_error_handle error) {
   executors[static_cast<size_t>(ExecutorType::RESOLVER)]->Enqueue(
       closure, error, true /* is_short */);
 }
 
-void resolver_enqueue_long(grpc_closure* closure, grpc_error* error) {
+void resolver_enqueue_long(grpc_closure* closure, grpc_error_handle error) {
   executors[static_cast<size_t>(ExecutorType::RESOLVER)]->Enqueue(
       closure, error, false /* is_short */);
 }
 
-using EnqueueFunc = void (*)(grpc_closure* closure, grpc_error* error);
+using EnqueueFunc = void (*)(grpc_closure* closure, grpc_error_handle error);
 
 const EnqueueFunc
     executor_enqueue_fns_[static_cast<size_t>(ExecutorType::NUM_EXECUTORS)]
@@ -115,7 +115,7 @@
   grpc_closure* c = list.head;
   while (c != nullptr) {
     grpc_closure* next = c->next_data.next;
-    grpc_error* error = c->error_data.error;
+    grpc_error_handle error = c->error_data.error;
 #ifndef NDEBUG
     EXECUTOR_TRACE("(%s) run %p [created by %s:%d]", executor_name, c,
                    c->file_created, c->line_created);
@@ -251,7 +251,7 @@
   gpr_tls_set(&g_this_thread_state, reinterpret_cast<intptr_t>(nullptr));
 }
 
-void Executor::Enqueue(grpc_closure* closure, grpc_error* error,
+void Executor::Enqueue(grpc_closure* closure, grpc_error_handle error,
                        bool is_short) {
   bool retry_push;
   if (is_short) {
@@ -404,7 +404,7 @@
   EXECUTOR_TRACE0("Executor::InitAll() done");
 }
 
-void Executor::Run(grpc_closure* closure, grpc_error* error,
+void Executor::Run(grpc_closure* closure, grpc_error_handle error,
                    ExecutorType executor_type, ExecutorJobType job_type) {
   executor_enqueue_fns_[static_cast<size_t>(executor_type)]
                        [static_cast<size_t>(job_type)](closure, error);
diff --git a/grpc/src/core/lib/iomgr/executor.h b/grpc/src/core/lib/iomgr/executor.h
index 7a5d16b..37e5c1e 100644
--- a/grpc/src/core/lib/iomgr/executor.h
+++ b/grpc/src/core/lib/iomgr/executor.h
@@ -70,7 +70,7 @@
 
   /** Enqueue the closure onto the executor. is_short is true if the closure is
    * a short job (i.e expected to not block and complete quickly) */
-  void Enqueue(grpc_closure* closure, grpc_error* error, bool is_short);
+  void Enqueue(grpc_closure* closure, grpc_error_handle error, bool is_short);
 
   // TODO(sreek): Currently we have two executors (available globally): The
   // default executor and the resolver executor.
@@ -83,7 +83,7 @@
   // Initialize ALL the executors
   static void InitAll();
 
-  static void Run(grpc_closure* closure, grpc_error* error,
+  static void Run(grpc_closure* closure, grpc_error_handle error,
                   ExecutorType executor_type = ExecutorType::DEFAULT,
                   ExecutorJobType job_type = ExecutorJobType::SHORT);
 
diff --git a/grpc/src/core/lib/iomgr/iomgr.cc b/grpc/src/core/lib/iomgr/iomgr.cc
index 02646db..1210bd7 100644
--- a/grpc/src/core/lib/iomgr/iomgr.cc
+++ b/grpc/src/core/lib/iomgr/iomgr.cc
@@ -169,7 +169,7 @@
 }
 
 bool grpc_iomgr_add_closure_to_background_poller(grpc_closure* closure,
-                                                 grpc_error* error) {
+                                                 grpc_error_handle error) {
   return grpc_iomgr_platform_add_closure_to_background_poller(closure, error);
 }
 
diff --git a/grpc/src/core/lib/iomgr/iomgr.h b/grpc/src/core/lib/iomgr/iomgr.h
index e02f15e..9af0557 100644
--- a/grpc/src/core/lib/iomgr/iomgr.h
+++ b/grpc/src/core/lib/iomgr/iomgr.h
@@ -52,7 +52,7 @@
  * that the closure may or may not run yet when this function returns, and the
  * closure should not be blocking or long-running. */
 bool grpc_iomgr_add_closure_to_background_poller(grpc_closure* closure,
-                                                 grpc_error* error);
+                                                 grpc_error_handle error);
 
 /* Exposed only for testing */
 size_t grpc_iomgr_count_objects_for_testing();
diff --git a/grpc/src/core/lib/iomgr/iomgr_custom.cc b/grpc/src/core/lib/iomgr/iomgr_custom.cc
index 684044a..9a9f06a 100644
--- a/grpc/src/core/lib/iomgr/iomgr_custom.cc
+++ b/grpc/src/core/lib/iomgr/iomgr_custom.cc
@@ -45,7 +45,7 @@
   return false;
 }
 static bool iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* /*closure*/, grpc_error* /*error*/) {
+    grpc_closure* /*closure*/, grpc_error_handle /*error*/) {
   return false;
 }
 
diff --git a/grpc/src/core/lib/iomgr/iomgr_internal.cc b/grpc/src/core/lib/iomgr/iomgr_internal.cc
index 896d9fc..e5ce8ab 100644
--- a/grpc/src/core/lib/iomgr/iomgr_internal.cc
+++ b/grpc/src/core/lib/iomgr/iomgr_internal.cc
@@ -50,8 +50,8 @@
   return iomgr_platform_vtable->is_any_background_poller_thread();
 }
 
-bool grpc_iomgr_platform_add_closure_to_background_poller(grpc_closure* closure,
-                                                          grpc_error* error) {
+bool grpc_iomgr_platform_add_closure_to_background_poller(
+    grpc_closure* closure, grpc_error_handle error) {
   return iomgr_platform_vtable->add_closure_to_background_poller(closure,
                                                                  error);
 }
diff --git a/grpc/src/core/lib/iomgr/iomgr_internal.h b/grpc/src/core/lib/iomgr/iomgr_internal.h
index 17607f9..01cd248 100644
--- a/grpc/src/core/lib/iomgr/iomgr_internal.h
+++ b/grpc/src/core/lib/iomgr/iomgr_internal.h
@@ -38,7 +38,7 @@
   void (*shutdown_background_closure)(void);
   bool (*is_any_background_poller_thread)(void);
   bool (*add_closure_to_background_poller)(grpc_closure* closure,
-                                           grpc_error* error);
+                                           grpc_error_handle error);
 } grpc_iomgr_platform_vtable;
 
 void grpc_iomgr_register_object(grpc_iomgr_object* obj, const char* name);
@@ -65,8 +65,8 @@
 /** Return true if the closure is registered into the background poller. Note
  * that the closure may or may not run yet when this function returns, and the
  * closure should not be blocking or long-running. */
-bool grpc_iomgr_platform_add_closure_to_background_poller(grpc_closure* closure,
-                                                          grpc_error* error);
+bool grpc_iomgr_platform_add_closure_to_background_poller(
+    grpc_closure* closure, grpc_error_handle error);
 
 bool grpc_iomgr_abort_on_leaks(void);
 
diff --git a/grpc/src/core/lib/iomgr/iomgr_posix.cc b/grpc/src/core/lib/iomgr/iomgr_posix.cc
index de22d20..0407e30 100644
--- a/grpc/src/core/lib/iomgr/iomgr_posix.cc
+++ b/grpc/src/core/lib/iomgr/iomgr_posix.cc
@@ -25,7 +25,6 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/iomgr_posix.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_posix.h"
@@ -60,7 +59,7 @@
 }
 
 static bool iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* closure, grpc_error* error) {
+    grpc_closure* closure, grpc_error_handle error) {
   return grpc_add_closure_to_background_poller(closure, error);
 }
 
diff --git a/grpc/src/core/lib/iomgr/iomgr_posix.h b/grpc/src/core/lib/iomgr/iomgr_posix.h
deleted file mode 100644
index 54ec46e..0000000
--- a/grpc/src/core/lib/iomgr/iomgr_posix.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *
- * Copyright 2015 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_LIB_IOMGR_IOMGR_POSIX_H
-#define GRPC_CORE_LIB_IOMGR_IOMGR_POSIX_H
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/iomgr/iomgr_internal.h"
-
-#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_POSIX_H */
diff --git a/grpc/src/core/lib/iomgr/iomgr_posix_cfstream.cc b/grpc/src/core/lib/iomgr/iomgr_posix_cfstream.cc
index 30c44ed..78b2985 100644
--- a/grpc/src/core/lib/iomgr/iomgr_posix_cfstream.cc
+++ b/grpc/src/core/lib/iomgr/iomgr_posix_cfstream.cc
@@ -40,7 +40,6 @@
 #include "src/core/lib/iomgr/ev_apple.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/iomgr_posix.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_posix.h"
@@ -73,7 +72,7 @@
 }
 
 static bool apple_iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* closure, grpc_error* error) {
+    grpc_closure* closure, grpc_error_handle error) {
   return false;
 }
 
@@ -106,7 +105,7 @@
 }
 
 static bool iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* closure, grpc_error* error) {
+    grpc_closure* closure, grpc_error_handle error) {
   return grpc_add_closure_to_background_poller(closure, error);
 }
 
diff --git a/grpc/src/core/lib/iomgr/iomgr_windows.cc b/grpc/src/core/lib/iomgr/iomgr_windows.cc
index 728d404..df1207a 100644
--- a/grpc/src/core/lib/iomgr/iomgr_windows.cc
+++ b/grpc/src/core/lib/iomgr/iomgr_windows.cc
@@ -79,7 +79,7 @@
 }
 
 static bool iomgr_platform_add_closure_to_background_poller(
-    grpc_closure* closure, grpc_error* error) {
+    grpc_closure* closure, grpc_error_handle error) {
   return false;
 }
 
diff --git a/grpc/src/core/lib/iomgr/load_file.cc b/grpc/src/core/lib/iomgr/load_file.cc
index 4bed627..a187822 100644
--- a/grpc/src/core/lib/iomgr/load_file.cc
+++ b/grpc/src/core/lib/iomgr/load_file.cc
@@ -30,14 +30,14 @@
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 
-grpc_error* grpc_load_file(const char* filename, int add_null_terminator,
-                           grpc_slice* output) {
+grpc_error_handle grpc_load_file(const char* filename, int add_null_terminator,
+                                 grpc_slice* output) {
   unsigned char* contents = nullptr;
   size_t contents_size = 0;
   grpc_slice result = grpc_empty_slice();
   FILE* file;
   size_t bytes_read = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   GRPC_SCHEDULING_START_BLOCKING_REGION;
   file = fopen(filename, "rb");
@@ -67,7 +67,7 @@
   *output = result;
   if (file != nullptr) fclose(file);
   if (error != GRPC_ERROR_NONE) {
-    grpc_error* error_out =
+    grpc_error_handle error_out =
         grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                                "Failed to load file", &error, 1),
                            GRPC_ERROR_STR_FILENAME,
diff --git a/grpc/src/core/lib/iomgr/load_file.h b/grpc/src/core/lib/iomgr/load_file.h
index d7f8175..a0206e2 100644
--- a/grpc/src/core/lib/iomgr/load_file.h
+++ b/grpc/src/core/lib/iomgr/load_file.h
@@ -29,7 +29,7 @@
 
 /* Loads the content of a file into a slice. add_null_terminator will add
    a NULL terminator if non-zero. */
-grpc_error* grpc_load_file(const char* filename, int add_null_terminator,
-                           grpc_slice* output);
+grpc_error_handle grpc_load_file(const char* filename, int add_null_terminator,
+                                 grpc_slice* output);
 
 #endif /* GRPC_CORE_LIB_IOMGR_LOAD_FILE_H */
diff --git a/grpc/src/core/lib/iomgr/lockfree_event.cc b/grpc/src/core/lib/iomgr/lockfree_event.cc
index b3fd8e0..fa21406 100644
--- a/grpc/src/core/lib/iomgr/lockfree_event.cc
+++ b/grpc/src/core/lib/iomgr/lockfree_event.cc
@@ -77,7 +77,7 @@
   do {
     curr = gpr_atm_no_barrier_load(&state_);
     if (curr & kShutdownBit) {
-      GRPC_ERROR_UNREF((grpc_error*)(curr & ~kShutdownBit));
+      GRPC_ERROR_UNREF((grpc_error_handle)(curr & ~kShutdownBit));
     } else {
       GPR_ASSERT(curr == kClosureNotReady || curr == kClosureReady);
     }
@@ -139,8 +139,8 @@
            contains a pointer to the shutdown-error). If the fd is shutdown,
            schedule the closure with the shutdown error */
         if ((curr & kShutdownBit) > 0) {
-          grpc_error* shutdown_err =
-              reinterpret_cast<grpc_error*>(curr & ~kShutdownBit);
+          grpc_error_handle shutdown_err =
+              reinterpret_cast<grpc_error_handle>(curr & ~kShutdownBit);
           ExecCtx::Run(DEBUG_LOCATION, closure,
                        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                            "FD Shutdown", &shutdown_err, 1));
@@ -159,7 +159,7 @@
   GPR_UNREACHABLE_CODE(return );
 }
 
-bool LockfreeEvent::SetShutdown(grpc_error* shutdown_error) {
+bool LockfreeEvent::SetShutdown(grpc_error_handle shutdown_error) {
   gpr_atm new_state = reinterpret_cast<gpr_atm>(shutdown_error) | kShutdownBit;
 
   while (true) {
@@ -167,7 +167,7 @@
     if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
       gpr_log(GPR_DEBUG,
               "LockfreeEvent::SetShutdown: %p curr=%" PRIxPTR " err=%s",
-              &state_, curr, grpc_error_string(shutdown_error));
+              &state_, curr, grpc_error_std_string(shutdown_error).c_str());
     }
     switch (curr) {
       case kClosureReady:
diff --git a/grpc/src/core/lib/iomgr/lockfree_event.h b/grpc/src/core/lib/iomgr/lockfree_event.h
index f7e8554..944f364 100644
--- a/grpc/src/core/lib/iomgr/lockfree_event.h
+++ b/grpc/src/core/lib/iomgr/lockfree_event.h
@@ -56,7 +56,7 @@
 
   // Sets the shutdown state. If a closure had been provided by NotifyOn and has
   // not yet been scheduled, it will be scheduled with \a shutdown_error.
-  bool SetShutdown(grpc_error* shutdown_error);
+  bool SetShutdown(grpc_error_handle shutdown_error);
 
   // Signals that the event has been received.
   void SetReady();
diff --git a/grpc/src/core/lib/iomgr/poller/eventmanager_interface.h b/grpc/src/core/lib/iomgr/poller/eventmanager_interface.h
deleted file mode 100644
index b4fbaeb..0000000
--- a/grpc/src/core/lib/iomgr/poller/eventmanager_interface.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * Copyright 2019 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_LIB_IOMGR_POLLER_EVENTMANAGER_INTERFACE_H
-#define GRPC_CORE_LIB_IOMGR_POLLER_EVENTMANAGER_INTERFACE_H
-
-namespace grpc {
-namespace experimental {
-
-class BaseEventManagerInterface {
- public:
-  virtual ~BaseEventManagerInterface() {}
-};
-
-class EpollEventManagerInterface : public BaseEventManagerInterface {};
-
-}  // namespace experimental
-}  // namespace grpc
-
-#endif /* GRPC_CORE_LIB_IOMGR_POLLER_EVENTMANAGER_INTERFACE_H */
diff --git a/grpc/src/core/lib/iomgr/poller/eventmanager_libuv.cc b/grpc/src/core/lib/iomgr/poller/eventmanager_libuv.cc
deleted file mode 100644
index c34430a..0000000
--- a/grpc/src/core/lib/iomgr/poller/eventmanager_libuv.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- *
- * Copyright 2019 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>
-
-#include "src/core/lib/iomgr/poller/eventmanager_libuv.h"
-
-#include <grpc/support/time.h>
-
-grpc::experimental::LibuvEventManager::Options::Options() : num_workers_(-1) {}
-grpc::experimental::LibuvEventManager::Options::Options(int num_workers)
-    : num_workers_(num_workers) {}
-
-grpc::experimental::LibuvEventManager::LibuvEventManager(const Options& options)
-    : options_(options) {
-  int num_workers = options_.num_workers();
-  // Number of workers can't be 0 if we do not accept thread donation.
-  // TODO(guantaol): replaces the hard-coded number with a flag.
-  if (num_workers <= 0) num_workers = 32;
-
-  for (int i = 0; i < num_workers; i++) {
-    workers_.emplace_back(
-        options_.thread_name_prefix().c_str(),
-        [](void* em) { static_cast<LibuvEventManager*>(em)->RunWorkerLoop(); },
-        this);
-    workers_.back().Start();
-  }
-}
-
-grpc::experimental::LibuvEventManager::~LibuvEventManager() {
-  Shutdown();
-  for (auto& th : workers_) {
-    th.Join();
-  }
-}
-
-void grpc::experimental::LibuvEventManager::RunWorkerLoop() {
-  while (true) {
-    // TODO(guantaol): extend the worker loop with real work.
-    if (ShouldStop()) return;
-    gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                                 gpr_time_from_micros(10, GPR_TIMESPAN)));
-  }
-}
-
-bool grpc::experimental::LibuvEventManager::ShouldStop() {
-  return should_stop_.Load(grpc_core::MemoryOrder::ACQUIRE) != 0;
-}
-
-void grpc::experimental::LibuvEventManager::Shutdown() {
-  if (should_stop_.Load(grpc_core::MemoryOrder::ACQUIRE)) {
-    return;  // Already shut down.
-  }
-
-  {
-    grpc_core::MutexLock lock(&shutdown_mu_);
-    while (shutdown_refcount_.Load(grpc_core::MemoryOrder::ACQUIRE) > 0) {
-      shutdown_cv_.Wait(&shutdown_mu_);
-    }
-  }
-  should_stop_.Store(true, grpc_core::MemoryOrder::RELEASE);
-}
-
-void grpc::experimental::LibuvEventManager::ShutdownRef() {
-  shutdown_refcount_.FetchAdd(1, grpc_core::MemoryOrder::RELAXED);
-}
-
-void grpc::experimental::LibuvEventManager::ShutdownUnref() {
-  if (shutdown_refcount_.FetchSub(1, grpc_core::MemoryOrder::ACQ_REL) == 1) {
-    grpc_core::MutexLock lock(&shutdown_mu_);
-    shutdown_cv_.Signal();
-  }
-}
diff --git a/grpc/src/core/lib/iomgr/poller/eventmanager_libuv.h b/grpc/src/core/lib/iomgr/poller/eventmanager_libuv.h
deleted file mode 100644
index 0bd0ecc..0000000
--- a/grpc/src/core/lib/iomgr/poller/eventmanager_libuv.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- *
- * Copyright 2019 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_LIB_IOMGR_POLLER_EVENTMANAGER_LIBUV_H
-#define GRPC_CORE_LIB_IOMGR_POLLER_EVENTMANAGER_LIBUV_H
-
-#include <grpc/support/port_platform.h>
-
-#include <string>
-#include <vector>
-
-#include "src/core/lib/gprpp/atomic.h"
-#include "src/core/lib/gprpp/sync.h"
-#include "src/core/lib/gprpp/thd.h"
-
-namespace grpc {
-namespace experimental {
-
-class LibuvEventManager {
- public:
-  class Options {
-   public:
-    Options();
-    explicit Options(int num_workers);
-
-    int num_workers() const { return num_workers_; }
-    void set_num_workers(int num) { num_workers_ = num; }
-
-    const std::string& thread_name_prefix() const {
-      return thread_name_prefix_;
-    }
-    void set_thread_name_prefix(const std::string& name) {
-      thread_name_prefix_ = name;
-    }
-
-   private:
-    // Number of worker threads to create at startup. If less than 0, uses the
-    // default value of 32.
-    int num_workers_;
-    // Name prefix used for worker.
-    std::string thread_name_prefix_;
-  };
-
-  explicit LibuvEventManager(const Options& options);
-  virtual ~LibuvEventManager();
-
-  void Shutdown();
-  void ShutdownRef();
-  void ShutdownUnref();
-
- private:
-  // Function run by the worker threads.
-  void RunWorkerLoop();
-
-  // Whether the EventManager has been shut down.
-  bool ShouldStop();
-
-  const Options options_;
-  // Whether the EventManager workers should be stopped.
-  grpc_core::Atomic<bool> should_stop_{false};
-  // A refcount preventing the EventManager from shutdown.
-  grpc_core::Atomic<int> shutdown_refcount_{0};
-  // Worker threads of the EventManager.
-  std::vector<grpc_core::Thread> workers_;
-  // Mutex and condition variable used for shutdown.
-  grpc_core::Mutex shutdown_mu_;
-  grpc_core::CondVar shutdown_cv_;
-};
-
-}  // namespace experimental
-}  // namespace grpc
-
-#endif /* GRPC_CORE_LIB_IOMGR_POLLER_EVENTMANAGER_LIBUV_H */
diff --git a/grpc/src/core/lib/iomgr/pollset.cc b/grpc/src/core/lib/iomgr/pollset.cc
index ebfef1d..ba2a58d 100644
--- a/grpc/src/core/lib/iomgr/pollset.cc
+++ b/grpc/src/core/lib/iomgr/pollset.cc
@@ -42,14 +42,14 @@
   grpc_pollset_impl->destroy(pollset);
 }
 
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker,
-                              grpc_millis deadline) {
+grpc_error_handle grpc_pollset_work(grpc_pollset* pollset,
+                                    grpc_pollset_worker** worker,
+                                    grpc_millis deadline) {
   return grpc_pollset_impl->work(pollset, worker, deadline);
 }
 
-grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
-                              grpc_pollset_worker* specific_worker) {
+grpc_error_handle grpc_pollset_kick(grpc_pollset* pollset,
+                                    grpc_pollset_worker* specific_worker) {
   return grpc_pollset_impl->kick(pollset, specific_worker);
 }
 
diff --git a/grpc/src/core/lib/iomgr/pollset.h b/grpc/src/core/lib/iomgr/pollset.h
index 28472b3..7c87a82 100644
--- a/grpc/src/core/lib/iomgr/pollset.h
+++ b/grpc/src/core/lib/iomgr/pollset.h
@@ -44,10 +44,10 @@
   void (*init)(grpc_pollset* pollset, gpr_mu** mu);
   void (*shutdown)(grpc_pollset* pollset, grpc_closure* closure);
   void (*destroy)(grpc_pollset* pollset);
-  grpc_error* (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
-                      grpc_millis deadline);
-  grpc_error* (*kick)(grpc_pollset* pollset,
-                      grpc_pollset_worker* specific_worker);
+  grpc_error_handle (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
+                            grpc_millis deadline);
+  grpc_error_handle (*kick)(grpc_pollset* pollset,
+                            grpc_pollset_worker* specific_worker);
   size_t (*pollset_size)(void);
 } grpc_pollset_vtable;
 
@@ -86,14 +86,14 @@
    May call grpc_closure_list_run on grpc_closure_list, without holding the
    pollset
    lock */
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker,
-                              grpc_millis deadline) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_pollset_work(grpc_pollset* pollset,
+                                    grpc_pollset_worker** worker,
+                                    grpc_millis deadline) GRPC_MUST_USE_RESULT;
 
 /* Break one polling thread out of polling work for this pollset.
    If specific_worker is non-NULL, then kick that worker. */
-grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
-                              grpc_pollset_worker* specific_worker)
+grpc_error_handle grpc_pollset_kick(grpc_pollset* pollset,
+                                    grpc_pollset_worker* specific_worker)
     GRPC_MUST_USE_RESULT;
 
 #endif /* GRPC_CORE_LIB_IOMGR_POLLSET_H */
diff --git a/grpc/src/core/lib/iomgr/pollset_custom.cc b/grpc/src/core/lib/iomgr/pollset_custom.cc
index 98c8e64..62c4b39 100644
--- a/grpc/src/core/lib/iomgr/pollset_custom.cc
+++ b/grpc/src/core/lib/iomgr/pollset_custom.cc
@@ -63,9 +63,9 @@
   gpr_mu_destroy(&pollset->mu);
 }
 
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** /*worker_hdl*/,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** /*worker_hdl*/,
+                                      grpc_millis deadline) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   gpr_mu_unlock(&pollset->mu);
   grpc_millis now = grpc_core::ExecCtx::Get()->Now();
@@ -87,8 +87,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* /*pollset*/,
-                                grpc_pollset_worker* /*specific_worker*/) {
+static grpc_error_handle pollset_kick(
+    grpc_pollset* /*pollset*/, grpc_pollset_worker* /*specific_worker*/) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   poller_vtable->kick();
   return GRPC_ERROR_NONE;
diff --git a/grpc/src/core/lib/iomgr/pollset_windows.cc b/grpc/src/core/lib/iomgr/pollset_windows.cc
index 184c330..f8758a3 100644
--- a/grpc/src/core/lib/iomgr/pollset_windows.cc
+++ b/grpc/src/core/lib/iomgr/pollset_windows.cc
@@ -106,9 +106,9 @@
 
 static void pollset_destroy(grpc_pollset* pollset) {}
 
-static grpc_error* pollset_work(grpc_pollset* pollset,
-                                grpc_pollset_worker** worker_hdl,
-                                grpc_millis deadline) {
+static grpc_error_handle pollset_work(grpc_pollset* pollset,
+                                      grpc_pollset_worker** worker_hdl,
+                                      grpc_millis deadline) {
   grpc_pollset_worker worker;
   if (worker_hdl) *worker_hdl = &worker;
 
@@ -183,8 +183,8 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pollset_kick(grpc_pollset* p,
-                                grpc_pollset_worker* specific_worker) {
+static grpc_error_handle pollset_kick(grpc_pollset* p,
+                                      grpc_pollset_worker* specific_worker) {
   bool should_kick_global = false;
   if (specific_worker != NULL) {
     if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
diff --git a/grpc/src/core/lib/iomgr/port.h b/grpc/src/core/lib/iomgr/port.h
index 2a8d67b..8d3cd98 100644
--- a/grpc/src/core/lib/iomgr/port.h
+++ b/grpc/src/core/lib/iomgr/port.h
@@ -192,7 +192,7 @@
         defined(GRPC_CUSTOM_SOCKET) + defined(GRPC_CFSTREAM) != \
     1
 #error \
-    "Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GRPC_CUSTOM_SOCKET"
+    "Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GRPC_CUSTOM_SOCKET, GRPC_CFSTREAM"
 #endif
 
 #ifdef GRPC_POSIX_SOCKET
diff --git a/grpc/src/core/lib/iomgr/python_util.h b/grpc/src/core/lib/iomgr/python_util.h
index 05d72a5..10c335b 100644
--- a/grpc/src/core/lib/iomgr/python_util.h
+++ b/grpc/src/core/lib/iomgr/python_util.h
@@ -29,7 +29,7 @@
 // They are easier to define here (rather than in Cython)
 // because Cython doesn't handle #defines well.
 
-inline grpc_error* grpc_socket_error(char* error) {
+inline grpc_error_handle grpc_socket_error(char* error) {
   return grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error),
                             GRPC_ERROR_INT_GRPC_STATUS,
                             GRPC_STATUS_UNAVAILABLE);
diff --git a/grpc/src/core/lib/iomgr/resolve_address.cc b/grpc/src/core/lib/iomgr/resolve_address.cc
index 7479836..83c6aac 100644
--- a/grpc/src/core/lib/iomgr/resolve_address.cc
+++ b/grpc/src/core/lib/iomgr/resolve_address.cc
@@ -42,9 +42,9 @@
   gpr_free(addresses);
 }
 
-grpc_error* grpc_blocking_resolve_address(const char* name,
-                                          const char* default_port,
-                                          grpc_resolved_addresses** addresses) {
+grpc_error_handle grpc_blocking_resolve_address(
+    const char* name, const char* default_port,
+    grpc_resolved_addresses** addresses) {
   return grpc_resolve_address_impl->blocking_resolve_address(name, default_port,
                                                              addresses);
 }
diff --git a/grpc/src/core/lib/iomgr/resolve_address.h b/grpc/src/core/lib/iomgr/resolve_address.h
index 025a141..112d0ac 100644
--- a/grpc/src/core/lib/iomgr/resolve_address.h
+++ b/grpc/src/core/lib/iomgr/resolve_address.h
@@ -54,9 +54,9 @@
                           grpc_pollset_set* interested_parties,
                           grpc_closure* on_done,
                           grpc_resolved_addresses** addresses);
-  grpc_error* (*blocking_resolve_address)(const char* name,
-                                          const char* default_port,
-                                          grpc_resolved_addresses** addresses);
+  grpc_error_handle (*blocking_resolve_address)(
+      const char* name, const char* default_port,
+      grpc_resolved_addresses** addresses);
 } grpc_address_resolver_vtable;
 
 void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable);
@@ -74,8 +74,8 @@
 
 /* Resolve addr in a blocking fashion. On success,
    result must be freed with grpc_resolved_addresses_destroy. */
-grpc_error* grpc_blocking_resolve_address(const char* name,
-                                          const char* default_port,
-                                          grpc_resolved_addresses** addresses);
+grpc_error_handle grpc_blocking_resolve_address(
+    const char* name, const char* default_port,
+    grpc_resolved_addresses** addresses);
 
 #endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/grpc/src/core/lib/iomgr/resolve_address_custom.cc b/grpc/src/core/lib/iomgr/resolve_address_custom.cc
index 5ddd452..f89eab0 100644
--- a/grpc/src/core/lib/iomgr/resolve_address_custom.cc
+++ b/grpc/src/core/lib/iomgr/resolve_address_custom.cc
@@ -29,12 +29,12 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/iomgr_custom.h"
 #include "src/core/lib/iomgr/port.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 struct grpc_custom_resolver {
   grpc_closure* on_done = nullptr;
@@ -53,7 +53,7 @@
     if (r->port == svc[i][0]) {
       r->port = svc[i][1];
       if (res) {
-        grpc_error* error = resolve_address_vtable->resolve(
+        grpc_error_handle error = resolve_address_vtable->resolve(
             r->host.c_str(), r->port.c_str(), res);
         if (error != GRPC_ERROR_NONE) {
           GRPC_ERROR_UNREF(error);
@@ -71,7 +71,7 @@
 
 void grpc_custom_resolve_callback(grpc_custom_resolver* r,
                                   grpc_resolved_addresses* result,
-                                  grpc_error* error) {
+                                  grpc_error_handle error) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
@@ -86,9 +86,10 @@
   delete r;
 }
 
-static grpc_error* try_split_host_port(const char* name,
-                                       const char* default_port,
-                                       std::string* host, std::string* port) {
+static grpc_error_handle try_split_host_port(const char* name,
+                                             const char* default_port,
+                                             std::string* host,
+                                             std::string* port) {
   /* parse name, splitting it into host and port parts */
   grpc_core::SplitHostPort(name, host, port);
   if (host->empty()) {
@@ -106,13 +107,13 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* blocking_resolve_address_impl(
+static grpc_error_handle blocking_resolve_address_impl(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
 
   grpc_custom_resolver resolver;
-  grpc_error* err =
+  grpc_error_handle err =
       try_split_host_port(name, default_port, &resolver.host, &resolver.port);
   if (err != GRPC_ERROR_NONE) {
     return err;
@@ -144,7 +145,7 @@
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   std::string host;
   std::string port;
-  grpc_error* err = try_split_host_port(name, default_port, &host, &port);
+  grpc_error_handle err = try_split_host_port(name, default_port, &host, &port);
   if (err != GRPC_ERROR_NONE) {
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, err);
     return;
diff --git a/grpc/src/core/lib/iomgr/resolve_address_custom.h b/grpc/src/core/lib/iomgr/resolve_address_custom.h
index f5f68ca..5f674dd 100644
--- a/grpc/src/core/lib/iomgr/resolve_address_custom.h
+++ b/grpc/src/core/lib/iomgr/resolve_address_custom.h
@@ -29,15 +29,15 @@
 typedef struct grpc_custom_resolver grpc_custom_resolver;
 
 typedef struct grpc_custom_resolver_vtable {
-  grpc_error* (*resolve)(const char* host, const char* port,
-                         grpc_resolved_addresses** res);
+  grpc_error_handle (*resolve)(const char* host, const char* port,
+                               grpc_resolved_addresses** res);
   void (*resolve_async)(grpc_custom_resolver* resolver, const char* host,
                         const char* port);
 } grpc_custom_resolver_vtable;
 
 void grpc_custom_resolve_callback(grpc_custom_resolver* resolver,
                                   grpc_resolved_addresses* result,
-                                  grpc_error* error);
+                                  grpc_error_handle error);
 
 /* Internal APIs */
 void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl);
diff --git a/grpc/src/core/lib/iomgr/resolve_address_posix.cc b/grpc/src/core/lib/iomgr/resolve_address_posix.cc
index 122dbe6..d0d1e0c 100644
--- a/grpc/src/core/lib/iomgr/resolve_address_posix.cc
+++ b/grpc/src/core/lib/iomgr/resolve_address_posix.cc
@@ -42,7 +42,7 @@
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
-static grpc_error* posix_blocking_resolve_address(
+static grpc_error_handle posix_blocking_resolve_address(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   grpc_core::ExecCtx exec_ctx;
@@ -50,7 +50,7 @@
   struct addrinfo *result = nullptr, *resp;
   int s;
   size_t i;
-  grpc_error* err;
+  grpc_error_handle err;
 
   std::string host;
   std::string port;
@@ -145,7 +145,7 @@
 };
 /* Callback to be passed to grpc Executor to asynch-ify
  * grpc_blocking_resolve_address */
-static void do_request_thread(void* rp, grpc_error* /*error*/) {
+static void do_request_thread(void* rp, grpc_error_handle /*error*/) {
   request* r = static_cast<request*>(rp);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION, r->on_done,
diff --git a/grpc/src/core/lib/iomgr/resolve_address_windows.cc b/grpc/src/core/lib/iomgr/resolve_address_windows.cc
index 5d2d365..926237b 100644
--- a/grpc/src/core/lib/iomgr/resolve_address_windows.cc
+++ b/grpc/src/core/lib/iomgr/resolve_address_windows.cc
@@ -39,13 +39,13 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 struct request {
   char* name;
@@ -54,7 +54,7 @@
   grpc_closure* on_done;
   grpc_resolved_addresses** addresses;
 };
-static grpc_error* windows_blocking_resolve_address(
+static grpc_error_handle windows_blocking_resolve_address(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   grpc_core::ExecCtx exec_ctx;
@@ -62,7 +62,7 @@
   struct addrinfo *result = NULL, *resp;
   int s;
   size_t i;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   /* parse name, splitting it into host and port parts */
   std::string host;
@@ -121,7 +121,7 @@
 
 /* Callback to be passed to grpc_executor to asynch-ify
  * grpc_blocking_resolve_address */
-static void do_request_thread(void* rp, grpc_error* error) {
+static void do_request_thread(void* rp, grpc_error_handle error) {
   request* r = (request*)rp;
   if (error == GRPC_ERROR_NONE) {
     error =
diff --git a/grpc/src/core/lib/iomgr/resource_quota.cc b/grpc/src/core/lib/iomgr/resource_quota.cc
index 464cccd..a4f4107 100644
--- a/grpc/src/core/lib/iomgr/resource_quota.cc
+++ b/grpc/src/core/lib/iomgr/resource_quota.cc
@@ -132,7 +132,7 @@
      scaled to the range [0..RESOURCE_USAGE_ESTIMATION_MAX] */
   gpr_atm memory_usage_estimation;
 
-  /* Master combiner lock: all activity on a quota executes under this combiner
+  /* Main combiner lock: all activity on a quota executes under this combiner
    * (so no mutex is needed for this data structure) */
   grpc_core::Combiner* combiner;
   /* Size of the resource quota */
@@ -276,7 +276,7 @@
     grpc_resource_quota* resource_quota);
 static bool rq_reclaim(grpc_resource_quota* resource_quota, bool destructive);
 
-static void rq_step(void* rq, grpc_error* /*error*/) {
+static void rq_step(void* rq, grpc_error_handle /*error*/) {
   grpc_resource_quota* resource_quota = static_cast<grpc_resource_quota*>(rq);
   resource_quota->step_scheduled = false;
   do {
@@ -484,7 +484,7 @@
  * the combiner
  */
 
-static void ru_allocate(void* ru, grpc_error* /*error*/) {
+static void ru_allocate(void* ru, grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (rulist_empty(resource_user->resource_quota,
                    GRPC_RULIST_AWAITING_ALLOCATION)) {
@@ -493,7 +493,7 @@
   rulist_add_tail(resource_user, GRPC_RULIST_AWAITING_ALLOCATION);
 }
 
-static void ru_add_to_free_pool(void* ru, grpc_error* /*error*/) {
+static void ru_add_to_free_pool(void* ru, grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!rulist_empty(resource_user->resource_quota,
                     GRPC_RULIST_AWAITING_ALLOCATION) &&
@@ -518,7 +518,7 @@
   return true;
 }
 
-static void ru_post_benign_reclaimer(void* ru, grpc_error* /*error*/) {
+static void ru_post_benign_reclaimer(void* ru, grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!ru_post_reclaimer(resource_user, false)) return;
   if (!rulist_empty(resource_user->resource_quota,
@@ -532,7 +532,8 @@
   rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_BENIGN);
 }
 
-static void ru_post_destructive_reclaimer(void* ru, grpc_error* /*error*/) {
+static void ru_post_destructive_reclaimer(void* ru,
+                                          grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!ru_post_reclaimer(resource_user, true)) return;
   if (!rulist_empty(resource_user->resource_quota,
@@ -548,7 +549,7 @@
   rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
 }
 
-static void ru_shutdown(void* ru, grpc_error* /*error*/) {
+static void ru_shutdown(void* ru, grpc_error_handle /*error*/) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) {
     gpr_log(GPR_INFO, "RU shutdown %p", ru);
   }
@@ -568,7 +569,7 @@
   gpr_mu_unlock(&resource_user->mu);
 }
 
-static void ru_destroy(void* ru, grpc_error* /*error*/) {
+static void ru_destroy(void* ru, grpc_error_handle /*error*/) {
   grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->refs) == 0);
   // Free all the remaining thread quota
@@ -601,7 +602,7 @@
   }
 }
 
-static void ru_allocated_slices(void* arg, grpc_error* error) {
+static void ru_allocated_slices(void* arg, grpc_error_handle error) {
   grpc_resource_user_slice_allocator* slice_allocator =
       static_cast<grpc_resource_user_slice_allocator*>(arg);
   if (error == GRPC_ERROR_NONE) ru_alloc_slices(slice_allocator);
@@ -619,7 +620,7 @@
   grpc_resource_quota* resource_quota;
   grpc_closure closure;
 };
-static void rq_resize(void* args, grpc_error* /*error*/) {
+static void rq_resize(void* args, grpc_error_handle /*error*/) {
   rq_resize_args* a = static_cast<rq_resize_args*>(args);
   int64_t delta = a->size - a->resource_quota->size;
   a->resource_quota->size += delta;
@@ -630,7 +631,7 @@
   gpr_free(a);
 }
 
-static void rq_reclamation_done(void* rq, grpc_error* /*error*/) {
+static void rq_reclamation_done(void* rq, grpc_error_handle /*error*/) {
   grpc_resource_quota* resource_quota = static_cast<grpc_resource_quota*>(rq);
   resource_quota->reclaiming = false;
   rq_step_sched(resource_quota);
diff --git a/grpc/src/core/lib/iomgr/socket_utils_common_posix.cc b/grpc/src/core/lib/iomgr/socket_utils_common_posix.cc
index fa7f893..e8c9ee1 100644
--- a/grpc/src/core/lib/iomgr/socket_utils_common_posix.cc
+++ b/grpc/src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -47,13 +47,13 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 /* set a socket to use zerocopy */
-grpc_error* grpc_set_socket_zerocopy(int fd) {
+grpc_error_handle grpc_set_socket_zerocopy(int fd) {
 #ifdef GRPC_LINUX_ERRQUEUE
   const int enable = 1;
   auto err = setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &enable, sizeof(enable));
@@ -62,12 +62,13 @@
   }
   return GRPC_ERROR_NONE;
 #else
+  (void)fd;
   return GRPC_OS_ERROR(ENOSYS, "setsockopt(SO_ZEROCOPY)");
 #endif
 }
 
 /* set a socket to non blocking mode */
-grpc_error* grpc_set_socket_nonblocking(int fd, int non_blocking) {
+grpc_error_handle grpc_set_socket_nonblocking(int fd, int non_blocking) {
   int oldflags = fcntl(fd, F_GETFL, 0);
   if (oldflags < 0) {
     return GRPC_OS_ERROR(errno, "fcntl");
@@ -86,7 +87,7 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_set_socket_no_sigpipe_if_possible(int fd) {
+grpc_error_handle grpc_set_socket_no_sigpipe_if_possible(int fd) {
 #ifdef GRPC_HAVE_SO_NOSIGPIPE
   int val = 1;
   int newval;
@@ -107,7 +108,7 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_set_socket_ip_pktinfo_if_possible(int fd) {
+grpc_error_handle grpc_set_socket_ip_pktinfo_if_possible(int fd) {
   // Use conditionally-important parameter to avoid warning
   (void)fd;
 #ifdef GRPC_HAVE_IP_PKTINFO
@@ -120,7 +121,7 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
+grpc_error_handle grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
   // Use conditionally-important parameter to avoid warning
   (void)fd;
 #ifdef GRPC_HAVE_IPV6_RECVPKTINFO
@@ -133,14 +134,14 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_set_socket_sndbuf(int fd, int buffer_size_bytes) {
+grpc_error_handle grpc_set_socket_sndbuf(int fd, int buffer_size_bytes) {
   return 0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size_bytes,
                          sizeof(buffer_size_bytes))
              ? GRPC_ERROR_NONE
              : GRPC_OS_ERROR(errno, "setsockopt(SO_SNDBUF)");
 }
 
-grpc_error* grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
+grpc_error_handle grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
   return 0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size_bytes,
                          sizeof(buffer_size_bytes))
              ? GRPC_ERROR_NONE
@@ -148,7 +149,7 @@
 }
 
 /* set a socket to close on exec */
-grpc_error* grpc_set_socket_cloexec(int fd, int close_on_exec) {
+grpc_error_handle grpc_set_socket_cloexec(int fd, int close_on_exec) {
   int oldflags = fcntl(fd, F_GETFD, 0);
   if (oldflags < 0) {
     return GRPC_OS_ERROR(errno, "fcntl");
@@ -168,7 +169,7 @@
 }
 
 /* set a socket to reuse old addresses */
-grpc_error* grpc_set_socket_reuse_addr(int fd, int reuse) {
+grpc_error_handle grpc_set_socket_reuse_addr(int fd, int reuse) {
   int val = (reuse != 0);
   int newval;
   socklen_t intlen = sizeof(newval);
@@ -186,7 +187,7 @@
 }
 
 /* set a socket to reuse old addresses */
-grpc_error* grpc_set_socket_reuse_port(int fd, int reuse) {
+grpc_error_handle grpc_set_socket_reuse_port(int fd, int reuse) {
 #ifndef SO_REUSEPORT
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "SO_REUSEPORT unavailable on compiling system");
@@ -231,7 +232,7 @@
 }
 
 /* disable nagle */
-grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) {
+grpc_error_handle grpc_set_socket_low_latency(int fd, int low_latency) {
   int val = (low_latency != 0);
   int newval;
   socklen_t intlen = sizeof(newval);
@@ -296,7 +297,7 @@
 }
 
 /* Set TCP_USER_TIMEOUT */
-grpc_error* grpc_set_socket_tcp_user_timeout(
+grpc_error_handle grpc_set_socket_tcp_user_timeout(
     int fd, const grpc_channel_args* channel_args, bool is_client) {
   // Use conditionally-important parameter to avoid warning
   (void)fd;
@@ -387,7 +388,8 @@
 }
 
 /* set a socket using a grpc_socket_mutator */
-grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
+grpc_error_handle grpc_set_socket_with_mutator(int fd,
+                                               grpc_socket_mutator* mutator) {
   GPR_ASSERT(mutator);
   if (!grpc_socket_mutator_mutate_fd(mutator, fd)) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("grpc_socket_mutator failed.");
@@ -395,8 +397,8 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_apply_socket_mutator_in_args(int fd,
-                                              const grpc_channel_args* args) {
+grpc_error_handle grpc_apply_socket_mutator_in_args(
+    int fd, const grpc_channel_args* args) {
   const grpc_arg* socket_mutator_arg =
       grpc_channel_args_find(args, GRPC_ARG_SOCKET_MUTATOR);
   if (socket_mutator_arg == nullptr) {
@@ -436,16 +438,17 @@
   return g_ipv6_loopback_available;
 }
 
-static grpc_error* error_for_fd(int fd, const grpc_resolved_address* addr) {
+static grpc_error_handle error_for_fd(int fd,
+                                      const grpc_resolved_address* addr) {
   if (fd >= 0) return GRPC_ERROR_NONE;
   std::string addr_str = grpc_sockaddr_to_string(addr, false);
-  grpc_error* err = grpc_error_set_str(
+  grpc_error_handle err = grpc_error_set_str(
       GRPC_OS_ERROR(errno, "socket"), GRPC_ERROR_STR_TARGET_ADDRESS,
       grpc_slice_from_copied_string(addr_str.c_str()));
   return err;
 }
 
-grpc_error* grpc_create_dualstack_socket(
+grpc_error_handle grpc_create_dualstack_socket(
     const grpc_resolved_address* resolved_addr, int type, int protocol,
     grpc_dualstack_mode* dsmode, int* newfd) {
   return grpc_create_dualstack_socket_using_factory(
@@ -459,7 +462,7 @@
              : socket(domain, type, protocol);
 }
 
-grpc_error* grpc_create_dualstack_socket_using_factory(
+grpc_error_handle grpc_create_dualstack_socket_using_factory(
     grpc_socket_factory* factory, const grpc_resolved_address* resolved_addr,
     int type, int protocol, grpc_dualstack_mode* dsmode, int* newfd) {
   const grpc_sockaddr* addr =
diff --git a/grpc/src/core/lib/iomgr/socket_utils_posix.h b/grpc/src/core/lib/iomgr/socket_utils_posix.h
index b4dc909..13c22bc 100644
--- a/grpc/src/core/lib/iomgr/socket_utils_posix.h
+++ b/grpc/src/core/lib/iomgr/socket_utils_posix.h
@@ -45,31 +45,31 @@
                  int cloexec);
 
 /* set a socket to use zerocopy */
-grpc_error* grpc_set_socket_zerocopy(int fd);
+grpc_error_handle grpc_set_socket_zerocopy(int fd);
 
 /* set a socket to non blocking mode */
-grpc_error* grpc_set_socket_nonblocking(int fd, int non_blocking);
+grpc_error_handle grpc_set_socket_nonblocking(int fd, int non_blocking);
 
 /* set a socket to close on exec */
-grpc_error* grpc_set_socket_cloexec(int fd, int close_on_exec);
+grpc_error_handle grpc_set_socket_cloexec(int fd, int close_on_exec);
 
 /* set a socket to reuse old addresses */
-grpc_error* grpc_set_socket_reuse_addr(int fd, int reuse);
+grpc_error_handle grpc_set_socket_reuse_addr(int fd, int reuse);
 
 /* return true if SO_REUSEPORT is supported */
 bool grpc_is_socket_reuse_port_supported();
 
 /* disable nagle */
-grpc_error* grpc_set_socket_low_latency(int fd, int low_latency);
+grpc_error_handle grpc_set_socket_low_latency(int fd, int low_latency);
 
 /* set SO_REUSEPORT */
-grpc_error* grpc_set_socket_reuse_port(int fd, int reuse);
+grpc_error_handle grpc_set_socket_reuse_port(int fd, int reuse);
 
 /* Configure the default values for TCP_USER_TIMEOUT */
 void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client);
 
 /* Set TCP_USER_TIMEOUT */
-grpc_error* grpc_set_socket_tcp_user_timeout(
+grpc_error_handle grpc_set_socket_tcp_user_timeout(
     int fd, const grpc_channel_args* channel_args, bool is_client);
 
 /* Returns true if this system can create AF_INET6 sockets bound to ::1.
@@ -84,28 +84,29 @@
 
 /* Tries to set SO_NOSIGPIPE if available on this platform.
    If SO_NO_SIGPIPE is not available, returns 1. */
-grpc_error* grpc_set_socket_no_sigpipe_if_possible(int fd);
+grpc_error_handle grpc_set_socket_no_sigpipe_if_possible(int fd);
 
 /* Tries to set IP_PKTINFO if available on this platform.
    If IP_PKTINFO is not available, returns 1. */
-grpc_error* grpc_set_socket_ip_pktinfo_if_possible(int fd);
+grpc_error_handle grpc_set_socket_ip_pktinfo_if_possible(int fd);
 
 /* Tries to set IPV6_RECVPKTINFO if available on this platform.
    If IPV6_RECVPKTINFO is not available, returns 1. */
-grpc_error* grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd);
+grpc_error_handle grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd);
 
 /* Tries to set the socket's send buffer to given size. */
-grpc_error* grpc_set_socket_sndbuf(int fd, int buffer_size_bytes);
+grpc_error_handle grpc_set_socket_sndbuf(int fd, int buffer_size_bytes);
 
 /* Tries to set the socket's receive buffer to given size. */
-grpc_error* grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes);
+grpc_error_handle grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes);
 
 /* Tries to set the socket using a grpc_socket_mutator */
-grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator);
+grpc_error_handle grpc_set_socket_with_mutator(int fd,
+                                               grpc_socket_mutator* mutator);
 
 /* Extracts the first socket mutator from args if any and applies on the fd. */
-grpc_error* grpc_apply_socket_mutator_in_args(int fd,
-                                              const grpc_channel_args* args);
+grpc_error_handle grpc_apply_socket_mutator_in_args(
+    int fd, const grpc_channel_args* args);
 
 /* An enum to keep track of IPv4/IPv6 socket modes.
 
@@ -149,14 +150,13 @@
      IPv4, so that bind() or connect() see the correct family.
    Also, it's important to distinguish between DUALSTACK and IPV6 when
    listening on the [::] wildcard address. */
-grpc_error* grpc_create_dualstack_socket(const grpc_resolved_address* addr,
-                                         int type, int protocol,
-                                         grpc_dualstack_mode* dsmode,
-                                         int* newfd);
+grpc_error_handle grpc_create_dualstack_socket(
+    const grpc_resolved_address* addr, int type, int protocol,
+    grpc_dualstack_mode* dsmode, int* newfd);
 
 /* Same as grpc_create_dualstack_socket(), but use the given socket factory (if
    non-null) to create the socket, rather than calling socket() directly. */
-grpc_error* grpc_create_dualstack_socket_using_factory(
+grpc_error_handle grpc_create_dualstack_socket_using_factory(
     grpc_socket_factory* factory, const grpc_resolved_address* addr, int type,
     int protocol, grpc_dualstack_mode* dsmode, int* newfd);
 
diff --git a/grpc/src/core/lib/iomgr/tcp_client_cfstream.cc b/grpc/src/core/lib/iomgr/tcp_client_cfstream.cc
index d0be97a..5c0a95e 100644
--- a/grpc/src/core/lib/iomgr/tcp_client_cfstream.cc
+++ b/grpc/src/core/lib/iomgr/tcp_client_cfstream.cc
@@ -33,6 +33,7 @@
 
 #include <netinet/in.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/iomgr/cfstream_handle.h"
@@ -40,7 +41,6 @@
 #include "src/core/lib/iomgr/endpoint_cfstream.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/error_cfstream.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/timer.h"
 
@@ -78,7 +78,7 @@
   delete connect;
 }
 
-static void OnAlarm(void* arg, grpc_error* error) {
+static void OnAlarm(void* arg, grpc_error_handle error) {
   CFStreamConnect* connect = static_cast<CFStreamConnect*>(arg);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT :%p OnAlarm, error:%p", connect, error);
@@ -93,13 +93,13 @@
   if (done) {
     CFStreamConnectCleanup(connect);
   } else {
-    grpc_error* error =
+    grpc_error_handle error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("connect() timed out");
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, closure, error);
   }
 }
 
-static void OnOpen(void* arg, grpc_error* error) {
+static void OnOpen(void* arg, grpc_error_handle error) {
   CFStreamConnect* connect = static_cast<CFStreamConnect*>(arg);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT :%p OnOpen, error:%p", connect, error);
diff --git a/grpc/src/core/lib/iomgr/tcp_client_custom.cc b/grpc/src/core/lib/iomgr/tcp_client_custom.cc
index 046380c..d54a5f0 100644
--- a/grpc/src/core/lib/iomgr/tcp_client_custom.cc
+++ b/grpc/src/core/lib/iomgr/tcp_client_custom.cc
@@ -25,9 +25,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/iomgr_custom.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_custom.h"
 #include "src/core/lib/iomgr/timer.h"
@@ -59,14 +59,13 @@
 
 static void custom_close_callback(grpc_custom_socket* /*socket*/) {}
 
-static void on_alarm(void* acp, grpc_error* error) {
+static void on_alarm(void* acp, grpc_error_handle error) {
   int done;
   grpc_custom_socket* socket = static_cast<grpc_custom_socket*>(acp);
   grpc_custom_tcp_connect* connect = socket->connector;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
     gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_alarm: error=%s",
-            connect->addr_name.c_str(), str);
+            connect->addr_name.c_str(), grpc_error_std_string(error).c_str());
   }
   if (error == GRPC_ERROR_NONE) {
     /* error == NONE implies that the timer ran out, and wasn't cancelled. If
@@ -81,7 +80,7 @@
 }
 
 static void custom_connect_callback_internal(grpc_custom_socket* socket,
-                                             grpc_error* error) {
+                                             grpc_error_handle error) {
   grpc_custom_tcp_connect* connect = socket->connector;
   int done;
   grpc_closure* closure = connect->closure;
@@ -99,7 +98,7 @@
 }
 
 static void custom_connect_callback(grpc_custom_socket* socket,
-                                    grpc_error* error) {
+                                    grpc_error_handle error) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   if (grpc_core::ExecCtx::Get() == nullptr) {
     /* If we are being run on a thread which does not have an exec_ctx created
diff --git a/grpc/src/core/lib/iomgr/tcp_client_posix.cc b/grpc/src/core/lib/iomgr/tcp_client_posix.cc
index fb4149b..741cc6a 100644
--- a/grpc/src/core/lib/iomgr/tcp_client_posix.cc
+++ b/grpc/src/core/lib/iomgr/tcp_client_posix.cc
@@ -35,12 +35,12 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/ev_posix.h"
-#include "src/core/lib/iomgr/iomgr_posix.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/iomgr/tcp_posix.h"
@@ -64,9 +64,10 @@
   grpc_channel_args* channel_args;
 };
 
-static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
-                                  const grpc_channel_args* channel_args) {
-  grpc_error* err = GRPC_ERROR_NONE;
+static grpc_error_handle prepare_socket(const grpc_resolved_address* addr,
+                                        int fd,
+                                        const grpc_channel_args* channel_args) {
+  grpc_error_handle err = GRPC_ERROR_NONE;
 
   GPR_ASSERT(fd >= 0);
 
@@ -99,13 +100,12 @@
   return err;
 }
 
-static void tc_on_alarm(void* acp, grpc_error* error) {
+static void tc_on_alarm(void* acp, grpc_error_handle error) {
   int done;
   async_connect* ac = static_cast<async_connect*>(acp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
     gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_alarm: error=%s",
-            ac->addr_str.c_str(), str);
+            ac->addr_str.c_str(), grpc_error_std_string(error).c_str());
   }
   gpr_mu_lock(&ac->mu);
   if (ac->fd != nullptr) {
@@ -126,7 +126,7 @@
   return grpc_tcp_create(fd, channel_args, addr_str);
 }
 
-static void on_writable(void* acp, grpc_error* error) {
+static void on_writable(void* acp, grpc_error_handle error) {
   async_connect* ac = static_cast<async_connect*>(acp);
   int so_error = 0;
   socklen_t so_error_size;
@@ -139,9 +139,8 @@
   GRPC_ERROR_REF(error);
 
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
     gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_writable: error=%s",
-            ac->addr_str.c_str(), str);
+            ac->addr_str.c_str(), grpc_error_std_string(error).c_str());
   }
 
   gpr_mu_lock(&ac->mu);
@@ -242,12 +241,11 @@
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, closure, error);
 }
 
-grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
-                                       const grpc_resolved_address* addr,
-                                       grpc_resolved_address* mapped_addr,
-                                       int* fd) {
+grpc_error_handle grpc_tcp_client_prepare_fd(
+    const grpc_channel_args* channel_args, const grpc_resolved_address* addr,
+    grpc_resolved_address* mapped_addr, int* fd) {
   grpc_dualstack_mode dsmode;
-  grpc_error* error;
+  grpc_error_handle error;
   *fd = -1;
   /* Use dualstack sockets where available. Set mapped to v6 or v4 mapped to
      v6. */
@@ -293,7 +291,7 @@
     return;
   }
   if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
-    grpc_error* error = GRPC_OS_ERROR(errno, "connect");
+    grpc_error_handle error = GRPC_OS_ERROR(errno, "connect");
     error = grpc_error_set_str(
         error, GRPC_ERROR_STR_TARGET_ADDRESS,
         grpc_slice_from_cpp_string(grpc_sockaddr_to_uri(addr)));
@@ -335,7 +333,7 @@
                         grpc_millis deadline) {
   grpc_resolved_address mapped_addr;
   int fd = -1;
-  grpc_error* error;
+  grpc_error_handle error;
   *ep = nullptr;
   if ((error = grpc_tcp_client_prepare_fd(channel_args, addr, &mapped_addr,
                                           &fd)) != GRPC_ERROR_NONE) {
diff --git a/grpc/src/core/lib/iomgr/tcp_client_posix.h b/grpc/src/core/lib/iomgr/tcp_client_posix.h
index 6f61866..2467f37 100644
--- a/grpc/src/core/lib/iomgr/tcp_client_posix.h
+++ b/grpc/src/core/lib/iomgr/tcp_client_posix.h
@@ -45,10 +45,9 @@
    fd: out parameter. The new FD
    Returns: error, if any. Out parameters are not set on error
 */
-grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
-                                       const grpc_resolved_address* addr,
-                                       grpc_resolved_address* mapped_addr,
-                                       int* fd);
+grpc_error_handle grpc_tcp_client_prepare_fd(
+    const grpc_channel_args* channel_args, const grpc_resolved_address* addr,
+    grpc_resolved_address* mapped_addr, int* fd);
 
 /* Connect a configured TCP client fd.
 
diff --git a/grpc/src/core/lib/iomgr/tcp_client_windows.cc b/grpc/src/core/lib/iomgr/tcp_client_windows.cc
index 061e703..ef260ca 100644
--- a/grpc/src/core/lib/iomgr/tcp_client_windows.cc
+++ b/grpc/src/core/lib/iomgr/tcp_client_windows.cc
@@ -31,10 +31,10 @@
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_windows.h"
@@ -66,7 +66,7 @@
   if (socket != NULL) grpc_winsocket_destroy(socket);
 }
 
-static void on_alarm(void* acp, grpc_error* error) {
+static void on_alarm(void* acp, grpc_error_handle error) {
   async_connect* ac = (async_connect*)acp;
   gpr_mu_lock(&ac->mu);
   grpc_winsocket* socket = ac->socket;
@@ -77,7 +77,7 @@
   async_connect_unlock_and_cleanup(ac, socket);
 }
 
-static void on_connect(void* acp, grpc_error* error) {
+static void on_connect(void* acp, grpc_error_handle error) {
   async_connect* ac = (async_connect*)acp;
   grpc_endpoint** ep = ac->endpoint;
   GPR_ASSERT(*ep == NULL);
@@ -137,7 +137,7 @@
   GUID guid = WSAID_CONNECTEX;
   DWORD ioctl_num_bytes;
   grpc_winsocket_callback_info* info;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   async_connect* ac = NULL;
 
   *endpoint = NULL;
@@ -213,7 +213,7 @@
 failure:
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   std::string target_uri = grpc_sockaddr_to_uri(addr);
-  grpc_error* final_error =
+  grpc_error_handle final_error =
       grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                              "Failed to connect", &error, 1),
                          GRPC_ERROR_STR_TARGET_ADDRESS,
diff --git a/grpc/src/core/lib/iomgr/tcp_custom.cc b/grpc/src/core/lib/iomgr/tcp_custom.cc
index 0f45c75..c526a95 100644
--- a/grpc/src/core/lib/iomgr/tcp_custom.cc
+++ b/grpc/src/core/lib/iomgr/tcp_custom.cc
@@ -29,10 +29,10 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/iomgr_custom.h"
 #include "src/core/lib/iomgr/resource_quota.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_custom.h"
 #include "src/core/lib/iomgr/tcp_server.h"
@@ -122,15 +122,13 @@
 static void tcp_ref(custom_tcp_endpoint* tcp) { gpr_ref(&tcp->refcount); }
 #endif
 
-static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error* error) {
+static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error_handle error) {
   grpc_closure* cb = tcp->read_cb;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "TCP:%p call_cb %p %p:%p", tcp->socket, cb, cb->cb,
             cb->cb_arg);
     size_t i;
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_INFO, "read: error=%s", str);
-
+    gpr_log(GPR_INFO, "read: error=%s", grpc_error_std_string(error).c_str());
     for (i = 0; i < tcp->read_slices->count; i++) {
       char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
                                    GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -146,7 +144,7 @@
 }
 
 static void custom_read_callback(grpc_custom_socket* socket, size_t nread,
-                                 grpc_error* error) {
+                                 grpc_error_handle error) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   grpc_slice_buffer garbage;
@@ -171,11 +169,11 @@
   call_read_cb(tcp, error);
 }
 
-static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
+static void tcp_read_allocation_done(void* tcpp, grpc_error_handle error) {
   custom_tcp_endpoint* tcp = static_cast<custom_tcp_endpoint*>(tcpp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "TCP:%p read_allocation_done: %s", tcp->socket,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   if (error == GRPC_ERROR_NONE) {
     /* Before calling read, we allocate a buffer with exactly one slice
@@ -191,8 +189,8 @@
     call_read_cb(tcp, GRPC_ERROR_REF(error));
   }
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_INFO, "Initiating read on %p: error=%s", tcp->socket, str);
+    gpr_log(GPR_INFO, "Initiating read on %p: error=%s", tcp->socket,
+            grpc_error_std_string(error).c_str());
   }
 }
 
@@ -213,7 +211,7 @@
 }
 
 static void custom_write_callback(grpc_custom_socket* socket,
-                                  grpc_error* error) {
+                                  grpc_error_handle error) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   custom_tcp_endpoint* tcp =
@@ -221,8 +219,8 @@
   grpc_closure* cb = tcp->write_cb;
   tcp->write_cb = nullptr;
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_INFO, "write complete on %p: error=%s", tcp->socket, str);
+    gpr_log(GPR_INFO, "write complete on %p: error=%s", tcp->socket,
+            grpc_error_std_string(error).c_str());
   }
   TCP_UNREF(tcp, "write");
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
@@ -287,12 +285,12 @@
   (void)pollset;
 }
 
-static void endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void endpoint_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   custom_tcp_endpoint* tcp = reinterpret_cast<custom_tcp_endpoint*>(ep);
   if (!tcp->shutting_down) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-      const char* str = grpc_error_string(why);
-      gpr_log(GPR_INFO, "TCP %p shutdown why=%s", tcp->socket, str);
+      gpr_log(GPR_INFO, "TCP %p shutdown why=%s", tcp->socket,
+              grpc_error_std_string(why).c_str());
     }
     tcp->shutting_down = true;
     // grpc_core::ExecCtx::Run(DEBUG_LOCATION,tcp->read_cb,
diff --git a/grpc/src/core/lib/iomgr/tcp_custom.h b/grpc/src/core/lib/iomgr/tcp_custom.h
index d32ed2b..b342efb 100644
--- a/grpc/src/core/lib/iomgr/tcp_custom.h
+++ b/grpc/src/core/lib/iomgr/tcp_custom.h
@@ -40,18 +40,19 @@
 } grpc_custom_socket;
 
 typedef void (*grpc_custom_connect_callback)(grpc_custom_socket* socket,
-                                             grpc_error* error);
+                                             grpc_error_handle error);
 typedef void (*grpc_custom_write_callback)(grpc_custom_socket* socket,
-                                           grpc_error* error);
+                                           grpc_error_handle error);
 typedef void (*grpc_custom_read_callback)(grpc_custom_socket* socket,
-                                          size_t nread, grpc_error* error);
+                                          size_t nread,
+                                          grpc_error_handle error);
 typedef void (*grpc_custom_accept_callback)(grpc_custom_socket* socket,
                                             grpc_custom_socket* client,
-                                            grpc_error* error);
+                                            grpc_error_handle error);
 typedef void (*grpc_custom_close_callback)(grpc_custom_socket* socket);
 
 typedef struct grpc_socket_vtable {
-  grpc_error* (*init)(grpc_custom_socket* socket, int domain);
+  grpc_error_handle (*init)(grpc_custom_socket* socket, int domain);
   void (*connect)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
                   size_t len, grpc_custom_connect_callback cb);
   void (*destroy)(grpc_custom_socket* socket);
@@ -61,13 +62,13 @@
                 grpc_custom_write_callback cb);
   void (*read)(grpc_custom_socket* socket, char* buffer, size_t length,
                grpc_custom_read_callback cb);
-  grpc_error* (*getpeername)(grpc_custom_socket* socket,
-                             const grpc_sockaddr* addr, int* len);
-  grpc_error* (*getsockname)(grpc_custom_socket* socket,
-                             const grpc_sockaddr* addr, int* len);
-  grpc_error* (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
-                      size_t len, int flags);
-  grpc_error* (*listen)(grpc_custom_socket* socket);
+  grpc_error_handle (*getpeername)(grpc_custom_socket* socket,
+                                   const grpc_sockaddr* addr, int* len);
+  grpc_error_handle (*getsockname)(grpc_custom_socket* socket,
+                                   const grpc_sockaddr* addr, int* len);
+  grpc_error_handle (*bind)(grpc_custom_socket* socket,
+                            const grpc_sockaddr* addr, size_t len, int flags);
+  grpc_error_handle (*listen)(grpc_custom_socket* socket);
   void (*accept)(grpc_custom_socket* socket, grpc_custom_socket* client,
                  grpc_custom_accept_callback cb);
 } grpc_socket_vtable;
diff --git a/grpc/src/core/lib/iomgr/tcp_posix.cc b/grpc/src/core/lib/iomgr/tcp_posix.cc
index 7813e04..1f28b77 100644
--- a/grpc/src/core/lib/iomgr/tcp_posix.cc
+++ b/grpc/src/core/lib/iomgr/tcp_posix.cc
@@ -45,6 +45,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/debug/trace.h"
@@ -54,7 +55,6 @@
 #include "src/core/lib/iomgr/buffer_list.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/executor.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -435,12 +435,12 @@
 static gpr_atm g_uncovered_notifications_pending;
 static gpr_atm g_backup_poller; /* backup_poller* */
 
-static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error);
-static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error);
+static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error_handle error);
+static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error_handle error);
 static void tcp_drop_uncovered_then_handle_write(void* arg /* grpc_tcp */,
-                                                 grpc_error* error);
+                                                 grpc_error_handle error);
 
-static void done_poller(void* bp, grpc_error* /*error_ignored*/) {
+static void done_poller(void* bp, grpc_error_handle /*error_ignored*/) {
   backup_poller* p = static_cast<backup_poller*>(bp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "BACKUP_POLLER:%p destroy", p);
@@ -449,7 +449,7 @@
   gpr_free(p);
 }
 
-static void run_poller(void* bp, grpc_error* /*error_ignored*/) {
+static void run_poller(void* bp, grpc_error_handle /*error_ignored*/) {
   backup_poller* p = static_cast<backup_poller*>(bp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "BACKUP_POLLER:%p run", p);
@@ -560,9 +560,11 @@
   grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_done_closure);
 }
 
-static void tcp_drop_uncovered_then_handle_write(void* arg, grpc_error* error) {
+static void tcp_drop_uncovered_then_handle_write(void* arg,
+                                                 grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    gpr_log(GPR_INFO, "TCP:%p got_write: %s", arg, grpc_error_string(error));
+    gpr_log(GPR_INFO, "TCP:%p got_write: %s", arg,
+            grpc_error_std_string(error).c_str());
   }
   drop_uncovered(static_cast<grpc_tcp*>(arg));
   tcp_handle_write(arg, error);
@@ -604,7 +606,8 @@
   return sz;
 }
 
-static grpc_error* tcp_annotate_error(grpc_error* src_error, grpc_tcp* tcp) {
+static grpc_error_handle tcp_annotate_error(grpc_error_handle src_error,
+                                            grpc_tcp* tcp) {
   return grpc_error_set_str(
       grpc_error_set_int(
           grpc_error_set_int(src_error, GRPC_ERROR_INT_FD, tcp->fd),
@@ -615,10 +618,10 @@
       grpc_slice_from_copied_string(tcp->peer_string.c_str()));
 }
 
-static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error);
-static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error);
+static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error_handle error);
+static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error_handle error);
 
-static void tcp_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void tcp_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   ZerocopyDisableAndWaitForRemaining(tcp);
   grpc_fd_shutdown(tcp->em_fd, why);
@@ -678,16 +681,14 @@
   TCP_UNREF(tcp, "destroy");
 }
 
-static void call_read_cb(grpc_tcp* tcp, grpc_error* error) {
+static void call_read_cb(grpc_tcp* tcp, grpc_error_handle error) {
   grpc_closure* cb = tcp->read_cb;
 
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "TCP:%p call_cb %p %p:%p", tcp, cb, cb->cb, cb->cb_arg);
     size_t i;
-    const char* str = grpc_error_string(error);
     gpr_log(GPR_INFO, "READ %p (peer=%s) error=%s", tcp,
-            tcp->peer_string.c_str(), str);
-
+            tcp->peer_string.c_str(), grpc_error_std_string(error).c_str());
     if (gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
       for (i = 0; i < tcp->incoming_buffer->count; i++) {
         char* dump = grpc_dump_slice(tcp->incoming_buffer->slices[i],
@@ -850,11 +851,11 @@
   TCP_UNREF(tcp, "read");
 }
 
-static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
+static void tcp_read_allocation_done(void* tcpp, grpc_error_handle error) {
   grpc_tcp* tcp = static_cast<grpc_tcp*>(tcpp);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "TCP:%p read_allocation_done: %s", tcp,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
     grpc_slice_buffer_reset_and_unref_internal(tcp->incoming_buffer);
@@ -887,10 +888,11 @@
   tcp_do_read(tcp);
 }
 
-static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error) {
+static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error_handle error) {
   grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    gpr_log(GPR_INFO, "TCP:%p got_read: %s", tcp, grpc_error_string(error));
+    gpr_log(GPR_INFO, "TCP:%p got_read: %s", tcp,
+            grpc_error_std_string(error).c_str());
   }
 
   if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
@@ -958,7 +960,7 @@
                                       int additional_flags = 0);
 
 /** The callback function to be invoked when we get an error on the socket. */
-static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error);
+static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error_handle error);
 
 static TcpZerocopySendRecord* tcp_get_send_zerocopy_record(
     grpc_tcp* tcp, grpc_slice_buffer* buf);
@@ -1213,10 +1215,12 @@
   }
 }
 
-static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) {
+static void tcp_handle_error(void* arg /* grpc_tcp */,
+                             grpc_error_handle error) {
   grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-    gpr_log(GPR_INFO, "TCP:%p got_error: %s", tcp, grpc_error_string(error));
+    gpr_log(GPR_INFO, "TCP:%p got_error: %s", tcp,
+            grpc_error_std_string(error).c_str());
   }
 
   if (error != GRPC_ERROR_NONE ||
@@ -1241,11 +1245,11 @@
 
 #else  /* GRPC_LINUX_ERRQUEUE */
 static TcpZerocopySendRecord* tcp_get_send_zerocopy_record(
-    grpc_tcp* tcp, grpc_slice_buffer* buf) {
+    grpc_tcp* /*tcp*/, grpc_slice_buffer* /*buf*/) {
   return nullptr;
 }
 
-static void ZerocopyDisableAndWaitForRemaining(grpc_tcp* tcp) {}
+static void ZerocopyDisableAndWaitForRemaining(grpc_tcp* /*tcp*/) {}
 
 static bool tcp_write_with_timestamps(grpc_tcp* /*tcp*/, struct msghdr* /*msg*/,
                                       size_t /*sending_length*/,
@@ -1257,7 +1261,7 @@
 }
 
 static void tcp_handle_error(void* /*arg*/ /* grpc_tcp */,
-                             grpc_error* /*error*/) {
+                             grpc_error_handle /*error*/) {
   gpr_log(GPR_ERROR, "Error handling is not supported for this platform");
   GPR_ASSERT(0);
 }
@@ -1323,7 +1327,7 @@
 
 // returns true if done, false if pending; if returning true, *error is set
 static bool do_tcp_flush_zerocopy(grpc_tcp* tcp, TcpZerocopySendRecord* record,
-                                  grpc_error** error) {
+                                  grpc_error_handle* error) {
   struct msghdr msg;
   struct iovec iov[MAX_WRITE_IOVEC];
   msg_iovlen_type iov_size;
@@ -1391,15 +1395,15 @@
 
 static void UnrefMaybePutZerocopySendRecord(grpc_tcp* tcp,
                                             TcpZerocopySendRecord* record,
-                                            uint32_t seq,
-                                            const char* /* tag */) {
+                                            uint32_t /*seq*/,
+                                            const char* /*tag*/) {
   if (record->Unref()) {
     tcp->tcp_zerocopy_send_ctx.PutSendRecord(record);
   }
 }
 
 static bool tcp_flush_zerocopy(grpc_tcp* tcp, TcpZerocopySendRecord* record,
-                               grpc_error** error) {
+                               grpc_error_handle* error) {
   bool done = do_tcp_flush_zerocopy(tcp, record, error);
   if (done) {
     // Either we encountered an error, or we successfully sent all the bytes.
@@ -1409,7 +1413,7 @@
   return done;
 }
 
-static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
+static bool tcp_flush(grpc_tcp* tcp, grpc_error_handle* error) {
   struct msghdr msg;
   struct iovec iov[MAX_WRITE_IOVEC];
   msg_iovlen_type iov_size;
@@ -1516,7 +1520,8 @@
   }
 }
 
-static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error) {
+static void tcp_handle_write(void* arg /* grpc_tcp */,
+                             grpc_error_handle error) {
   grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
   grpc_closure* cb;
 
@@ -1549,8 +1554,7 @@
     tcp->write_cb = nullptr;
     tcp->current_zerocopy_send = nullptr;
     if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-      const char* str = grpc_error_string(error);
-      gpr_log(GPR_INFO, "write: %s", str);
+      gpr_log(GPR_INFO, "write: %s", grpc_error_std_string(error).c_str());
     }
     // No need to take a ref on error since tcp_flush provides a ref.
     grpc_core::Closure::Run(DEBUG_LOCATION, cb, error);
@@ -1562,7 +1566,7 @@
                       grpc_closure* cb, void* arg) {
   GPR_TIMER_SCOPE("tcp_write", 0);
   grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   TcpZerocopySendRecord* zerocopy_send_record = nullptr;
 
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
@@ -1618,8 +1622,7 @@
     notify_on_write(tcp);
   } else {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
-      const char* str = grpc_error_string(error);
-      gpr_log(GPR_INFO, "write: %s", str);
+      gpr_log(GPR_INFO, "write: %s", grpc_error_std_string(error).c_str());
     }
     grpc_core::Closure::Run(DEBUG_LOCATION, cb, error);
   }
@@ -1639,7 +1642,6 @@
 static void tcp_delete_from_pollset_set(grpc_endpoint* ep,
                                         grpc_pollset_set* pollset_set) {
   grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
-  ZerocopyDisableAndWaitForRemaining(tcp);
   grpc_pollset_set_del_fd(pollset_set, tcp->em_fd);
 }
 
@@ -1673,10 +1675,7 @@
   if (getsockname(tcp->fd, &addr, &len) < 0) {
     return false;
   }
-  if (addr.sa_family == AF_INET || addr.sa_family == AF_INET6) {
-    return true;
-  }
-  return false;
+  return addr.sa_family == AF_INET || addr.sa_family == AF_INET6;
 }
 
 static const grpc_endpoint_vtable vtable = {tcp_read,
diff --git a/grpc/src/core/lib/iomgr/tcp_server.cc b/grpc/src/core/lib/iomgr/tcp_server.cc
index 046fd49..8d6fefb 100644
--- a/grpc/src/core/lib/iomgr/tcp_server.cc
+++ b/grpc/src/core/lib/iomgr/tcp_server.cc
@@ -22,9 +22,9 @@
 
 grpc_tcp_server_vtable* grpc_tcp_server_impl;
 
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
-                                   const grpc_channel_args* args,
-                                   grpc_tcp_server** server) {
+grpc_error_handle grpc_tcp_server_create(grpc_closure* shutdown_complete,
+                                         const grpc_channel_args* args,
+                                         grpc_tcp_server** server) {
   return grpc_tcp_server_impl->create(shutdown_complete, args, server);
 }
 
@@ -34,9 +34,9 @@
   grpc_tcp_server_impl->start(server, pollsets, on_accept_cb, cb_arg);
 }
 
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     int* out_port) {
+grpc_error_handle grpc_tcp_server_add_port(grpc_tcp_server* s,
+                                           const grpc_resolved_address* addr,
+                                           int* out_port) {
   return grpc_tcp_server_impl->add_port(s, addr, out_port);
 }
 
diff --git a/grpc/src/core/lib/iomgr/tcp_server.h b/grpc/src/core/lib/iomgr/tcp_server.h
index 6ba3513..50ac4e7 100644
--- a/grpc/src/core/lib/iomgr/tcp_server.h
+++ b/grpc/src/core/lib/iomgr/tcp_server.h
@@ -63,14 +63,15 @@
 }  // namespace grpc_core
 
 typedef struct grpc_tcp_server_vtable {
-  grpc_error* (*create)(grpc_closure* shutdown_complete,
-                        const grpc_channel_args* args,
-                        grpc_tcp_server** server);
+  grpc_error_handle (*create)(grpc_closure* shutdown_complete,
+                              const grpc_channel_args* args,
+                              grpc_tcp_server** server);
   void (*start)(grpc_tcp_server* server,
                 const std::vector<grpc_pollset*>* pollsets,
                 grpc_tcp_server_cb on_accept_cb, void* cb_arg);
-  grpc_error* (*add_port)(grpc_tcp_server* s, const grpc_resolved_address* addr,
-                          int* out_port);
+  grpc_error_handle (*add_port)(grpc_tcp_server* s,
+                                const grpc_resolved_address* addr,
+                                int* out_port);
   grpc_core::TcpServerFdHandler* (*create_fd_handler)(grpc_tcp_server* s);
   unsigned (*port_fd_count)(grpc_tcp_server* s, unsigned port_index);
   int (*port_fd)(grpc_tcp_server* s, unsigned port_index, unsigned fd_index);
@@ -84,9 +85,9 @@
 /* Create a server, initially not bound to any ports. The caller owns one ref.
    If shutdown_complete is not NULL, it will be used by
    grpc_tcp_server_unref() when the ref count reaches zero. */
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
-                                   const grpc_channel_args* args,
-                                   grpc_tcp_server** server);
+grpc_error_handle grpc_tcp_server_create(grpc_closure* shutdown_complete,
+                                         const grpc_channel_args* args,
+                                         grpc_tcp_server** server);
 
 /* Start listening to bound ports */
 void grpc_tcp_server_start(grpc_tcp_server* server,
@@ -102,9 +103,9 @@
    but not dualstack sockets. */
 /* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
                   all of the multiple socket port matching logic in one place */
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     int* out_port);
+grpc_error_handle grpc_tcp_server_add_port(grpc_tcp_server* s,
+                                           const grpc_resolved_address* addr,
+                                           int* out_port);
 
 /* Create and return a TcpServerFdHandler so that it can be used by upper layer
    to hand over an externally connected fd to the grpc server. */
diff --git a/grpc/src/core/lib/iomgr/tcp_server_custom.cc b/grpc/src/core/lib/iomgr/tcp_server_custom.cc
index 18d7494..fff7545 100644
--- a/grpc/src/core/lib/iomgr/tcp_server_custom.cc
+++ b/grpc/src/core/lib/iomgr/tcp_server_custom.cc
@@ -28,12 +28,12 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr_custom.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_custom.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 
@@ -80,9 +80,9 @@
   grpc_resource_quota* resource_quota;
 };
 
-static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
-                                     const grpc_channel_args* args,
-                                     grpc_tcp_server** server) {
+static grpc_error_handle tcp_server_create(grpc_closure* shutdown_complete,
+                                           const grpc_channel_args* args,
+                                           grpc_tcp_server** server) {
   grpc_tcp_server* s =
       static_cast<grpc_tcp_server*>(gpr_malloc(sizeof(grpc_tcp_server)));
   // Let the implementation decide if so_reuseport can be enabled or not.
@@ -218,7 +218,7 @@
   grpc_endpoint* ep = nullptr;
   grpc_resolved_address peer_name;
   std::string peer_name_string;
-  grpc_error* err;
+  grpc_error_handle err;
 
   memset(&peer_name, 0, sizeof(grpc_resolved_address));
   peer_name.len = GRPC_MAX_SOCKADDR_SIZE;
@@ -246,17 +246,18 @@
 
 static void custom_accept_callback(grpc_custom_socket* socket,
                                    grpc_custom_socket* client,
-                                   grpc_error* error);
+                                   grpc_error_handle error);
 
 static void custom_accept_callback(grpc_custom_socket* socket,
                                    grpc_custom_socket* client,
-                                   grpc_error* error) {
+                                   grpc_error_handle error) {
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   grpc_tcp_listener* sp = socket->listener;
   if (error != GRPC_ERROR_NONE) {
     if (!sp->closed) {
-      gpr_log(GPR_ERROR, "Accept failed: %s", grpc_error_string(error));
+      gpr_log(GPR_ERROR, "Accept failed: %s",
+              grpc_error_std_string(error).c_str());
     }
     gpr_free(client);
     GRPC_ERROR_UNREF(error);
@@ -275,14 +276,14 @@
   }
 }
 
-static grpc_error* add_socket_to_server(grpc_tcp_server* s,
-                                        grpc_custom_socket* socket,
-                                        const grpc_resolved_address* addr,
-                                        unsigned port_index,
-                                        grpc_tcp_listener** listener) {
+static grpc_error_handle add_socket_to_server(grpc_tcp_server* s,
+                                              grpc_custom_socket* socket,
+                                              const grpc_resolved_address* addr,
+                                              unsigned port_index,
+                                              grpc_tcp_listener** listener) {
   grpc_tcp_listener* sp = nullptr;
   int port = -1;
-  grpc_error* error;
+  grpc_error_handle error;
   grpc_resolved_address sockname_temp;
 
   // NOTE(lidiz) The last argument is "flags" which is unused by other
@@ -335,9 +336,9 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
-                                       const grpc_resolved_address* addr,
-                                       int* port) {
+static grpc_error_handle tcp_server_add_port(grpc_tcp_server* s,
+                                             const grpc_resolved_address* addr,
+                                             int* port) {
   // This function is mostly copied from tcp_server_windows.c
   grpc_tcp_listener* sp = nullptr;
   grpc_custom_socket* socket;
@@ -346,7 +347,7 @@
   grpc_resolved_address* allocated_addr = nullptr;
   grpc_resolved_address sockname_temp;
   unsigned port_index = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   int family;
 
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
@@ -392,7 +393,7 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
     gpr_log(GPR_INFO, "SERVER %p add_port %s error=%s", s,
             grpc_sockaddr_to_string(addr, false).c_str(),
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
 
   family = grpc_sockaddr_get_family(addr);
@@ -410,8 +411,9 @@
   gpr_free(allocated_addr);
 
   if (error != GRPC_ERROR_NONE) {
-    grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-        "Failed to add port to server", &error, 1);
+    grpc_error_handle error_out =
+        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+            "Failed to add port to server", &error, 1);
     GRPC_ERROR_UNREF(error);
     error = error_out;
     *port = -1;
diff --git a/grpc/src/core/lib/iomgr/tcp_server_posix.cc b/grpc/src/core/lib/iomgr/tcp_server_posix.cc
index d6e13e8..5662aec 100644
--- a/grpc/src/core/lib/iomgr/tcp_server_posix.cc
+++ b/grpc/src/core/lib/iomgr/tcp_server_posix.cc
@@ -47,22 +47,22 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/iomgr/tcp_posix.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/iomgr/tcp_server_utils_posix.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
-static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
-                                     const grpc_channel_args* args,
-                                     grpc_tcp_server** server) {
+static grpc_error_handle tcp_server_create(grpc_closure* shutdown_complete,
+                                           const grpc_channel_args* args,
+                                           grpc_tcp_server** server) {
   grpc_tcp_server* s =
       static_cast<grpc_tcp_server*>(gpr_zalloc(sizeof(grpc_tcp_server)));
   s->so_reuseport = grpc_is_socket_reuse_port_supported();
@@ -129,7 +129,7 @@
   gpr_free(s);
 }
 
-static void destroyed_port(void* server, grpc_error* /*error*/) {
+static void destroyed_port(void* server, grpc_error_handle /*error*/) {
   grpc_tcp_server* s = static_cast<grpc_tcp_server*>(server);
   gpr_mu_lock(&s->mu);
   s->destroyed_ports++;
@@ -188,7 +188,7 @@
 }
 
 /* event manager callback when reads are ready */
-static void on_read(void* arg, grpc_error* err) {
+static void on_read(void* arg, grpc_error_handle err) {
   grpc_tcp_listener* sp = static_cast<grpc_tcp_listener*>(arg);
   grpc_pollset* read_notifier_pollset;
   if (err != GRPC_ERROR_NONE) {
@@ -281,18 +281,18 @@
 }
 
 /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
-static grpc_error* add_wildcard_addrs_to_server(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                int* out_port) {
+static grpc_error_handle add_wildcard_addrs_to_server(grpc_tcp_server* s,
+                                                      unsigned port_index,
+                                                      int requested_port,
+                                                      int* out_port) {
   grpc_resolved_address wild4;
   grpc_resolved_address wild6;
   unsigned fd_index = 0;
   grpc_dualstack_mode dsmode;
   grpc_tcp_listener* sp = nullptr;
   grpc_tcp_listener* sp2 = nullptr;
-  grpc_error* v6_err = GRPC_ERROR_NONE;
-  grpc_error* v4_err = GRPC_ERROR_NONE;
+  grpc_error_handle v6_err = GRPC_ERROR_NONE;
+  grpc_error_handle v4_err = GRPC_ERROR_NONE;
   *out_port = -1;
 
   if (grpc_tcp_server_have_ifaddrs() && s->expand_wildcard_addrs) {
@@ -325,19 +325,19 @@
       gpr_log(GPR_INFO,
               "Failed to add :: listener, "
               "the environment may not support IPv6: %s",
-              grpc_error_string(v6_err));
+              grpc_error_std_string(v6_err).c_str());
       GRPC_ERROR_UNREF(v6_err);
     }
     if (v4_err != GRPC_ERROR_NONE) {
       gpr_log(GPR_INFO,
               "Failed to add 0.0.0.0 listener, "
               "the environment may not support IPv4: %s",
-              grpc_error_string(v4_err));
+              grpc_error_std_string(v4_err).c_str());
       GRPC_ERROR_UNREF(v4_err);
     }
     return GRPC_ERROR_NONE;
   } else {
-    grpc_error* root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+    grpc_error_handle root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Failed to add any wildcard listeners");
     GPR_ASSERT(v6_err != GRPC_ERROR_NONE && v4_err != GRPC_ERROR_NONE);
     root_err = grpc_error_add_child(root_err, v6_err);
@@ -346,10 +346,11 @@
   }
 }
 
-static grpc_error* clone_port(grpc_tcp_listener* listener, unsigned count) {
+static grpc_error_handle clone_port(grpc_tcp_listener* listener,
+                                    unsigned count) {
   grpc_tcp_listener* sp = nullptr;
   std::string addr_str;
-  grpc_error* err;
+  grpc_error_handle err;
 
   for (grpc_tcp_listener* l = listener->next; l && l->is_sibling; l = l->next) {
     l->fd_index += count;
@@ -395,16 +396,16 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
-                                       const grpc_resolved_address* addr,
-                                       int* out_port) {
+static grpc_error_handle tcp_server_add_port(grpc_tcp_server* s,
+                                             const grpc_resolved_address* addr,
+                                             int* out_port) {
   grpc_tcp_listener* sp;
   grpc_resolved_address sockname_temp;
   grpc_resolved_address addr6_v4mapped;
   int requested_port = grpc_sockaddr_get_port(addr);
   unsigned port_index = 0;
   grpc_dualstack_mode dsmode;
-  grpc_error* err;
+  grpc_error_handle err;
   *out_port = -1;
   if (s->tail != nullptr) {
     port_index = s->tail->port_index + 1;
diff --git a/grpc/src/core/lib/iomgr/tcp_server_utils_posix.h b/grpc/src/core/lib/iomgr/tcp_server_utils_posix.h
index 6b8a5f9..ed4587a 100644
--- a/grpc/src/core/lib/iomgr/tcp_server_utils_posix.h
+++ b/grpc/src/core/lib/iomgr/tcp_server_utils_posix.h
@@ -98,26 +98,27 @@
 
 /* If successful, add a listener to \a s for \a addr, set \a dsmode for the
    socket, and return the \a listener. */
-grpc_error* grpc_tcp_server_add_addr(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     unsigned port_index, unsigned fd_index,
-                                     grpc_dualstack_mode* dsmode,
-                                     grpc_tcp_listener** listener);
+grpc_error_handle grpc_tcp_server_add_addr(grpc_tcp_server* s,
+                                           const grpc_resolved_address* addr,
+                                           unsigned port_index,
+                                           unsigned fd_index,
+                                           grpc_dualstack_mode* dsmode,
+                                           grpc_tcp_listener** listener);
 
 /* Get all addresses assigned to network interfaces on the machine and create a
    listener for each. requested_port is the port to use for every listener, or 0
    to select one random port that will be used for every listener. Set *out_port
    to the port selected. Return GRPC_ERROR_NONE only if all listeners were
    added. */
-grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                int* out_port);
+grpc_error_handle grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
+                                                      unsigned port_index,
+                                                      int requested_port,
+                                                      int* out_port);
 
 /* Prepare a recently-created socket for listening. */
-grpc_error* grpc_tcp_server_prepare_socket(grpc_tcp_server*, int fd,
-                                           const grpc_resolved_address* addr,
-                                           bool so_reuseport, int* port);
+grpc_error_handle grpc_tcp_server_prepare_socket(
+    grpc_tcp_server*, int fd, const grpc_resolved_address* addr,
+    bool so_reuseport, int* port);
 /* Ruturn true if the platform supports ifaddrs */
 bool grpc_tcp_server_have_ifaddrs(void);
 
diff --git a/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.cc b/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
index bd7ff9b..6fdf070 100644
--- a/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
+++ b/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
@@ -37,9 +37,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
 #define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
@@ -80,14 +80,15 @@
   return s_max_accept_queue_size;
 }
 
-static grpc_error* add_socket_to_server(grpc_tcp_server* s, int fd,
-                                        const grpc_resolved_address* addr,
-                                        unsigned port_index, unsigned fd_index,
-                                        grpc_tcp_listener** listener) {
+static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, int fd,
+                                              const grpc_resolved_address* addr,
+                                              unsigned port_index,
+                                              unsigned fd_index,
+                                              grpc_tcp_listener** listener) {
   grpc_tcp_listener* sp = nullptr;
   int port = -1;
 
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_tcp_server_prepare_socket(s, fd, addr, s->so_reuseport, &port);
   if (err == GRPC_ERROR_NONE) {
     GPR_ASSERT(port > 0);
@@ -123,14 +124,15 @@
 
 /* If successful, add a listener to s for addr, set *dsmode for the socket, and
    return the *listener. */
-grpc_error* grpc_tcp_server_add_addr(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     unsigned port_index, unsigned fd_index,
-                                     grpc_dualstack_mode* dsmode,
-                                     grpc_tcp_listener** listener) {
+grpc_error_handle grpc_tcp_server_add_addr(grpc_tcp_server* s,
+                                           const grpc_resolved_address* addr,
+                                           unsigned port_index,
+                                           unsigned fd_index,
+                                           grpc_dualstack_mode* dsmode,
+                                           grpc_tcp_listener** listener) {
   grpc_resolved_address addr4_copy;
   int fd;
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd);
   if (err != GRPC_ERROR_NONE) {
     return err;
@@ -143,11 +145,11 @@
 }
 
 /* Prepare a recently-created socket for listening. */
-grpc_error* grpc_tcp_server_prepare_socket(grpc_tcp_server* s, int fd,
-                                           const grpc_resolved_address* addr,
-                                           bool so_reuseport, int* port) {
+grpc_error_handle grpc_tcp_server_prepare_socket(
+    grpc_tcp_server* s, int fd, const grpc_resolved_address* addr,
+    bool so_reuseport, int* port) {
   grpc_resolved_address sockname_temp;
-  grpc_error* err = GRPC_ERROR_NONE;
+  grpc_error_handle err = GRPC_ERROR_NONE;
 
   GPR_ASSERT(fd >= 0);
 
@@ -210,7 +212,7 @@
   if (fd >= 0) {
     close(fd);
   }
-  grpc_error* ret =
+  grpc_error_handle ret =
       grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                              "Unable to configure socket", &err, 1),
                          GRPC_ERROR_INT_FD, fd);
diff --git a/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc b/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
index d591f78..a7e8f84 100644
--- a/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
+++ b/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
@@ -36,9 +36,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 /* Return the listener in s with address addr or NULL. */
 static grpc_tcp_listener* find_listener_with_addr(grpc_tcp_server* s,
@@ -58,12 +58,12 @@
 }
 
 /* Bind to "::" to get a port number not used by any address. */
-static grpc_error* get_unused_port(int* port) {
+static grpc_error_handle get_unused_port(int* port) {
   grpc_resolved_address wild;
   grpc_sockaddr_make_wildcard6(0, &wild);
   grpc_dualstack_mode dsmode;
   int fd;
-  grpc_error* err =
+  grpc_error_handle err =
       grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
   if (err != GRPC_ERROR_NONE) {
     return err;
@@ -89,15 +89,15 @@
                     : GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                int* out_port) {
+grpc_error_handle grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
+                                                      unsigned port_index,
+                                                      int requested_port,
+                                                      int* out_port) {
   struct ifaddrs* ifa = nullptr;
   struct ifaddrs* ifa_it;
   unsigned fd_index = 0;
   grpc_tcp_listener* sp = nullptr;
-  grpc_error* err = GRPC_ERROR_NONE;
+  grpc_error_handle err = GRPC_ERROR_NONE;
   if (requested_port == 0) {
     /* Note: There could be a race where some local addrs can listen on the
        selected port and some can't. The sane way to handle this would be to
@@ -146,7 +146,7 @@
     }
     if ((err = grpc_tcp_server_add_addr(s, &addr, port_index, fd_index, &dsmode,
                                         &new_sp)) != GRPC_ERROR_NONE) {
-      grpc_error* root_err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
+      grpc_error_handle root_err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
           absl::StrCat("Failed to add listener: ", addr_str).c_str());
       err = grpc_error_add_child(root_err, err);
       break;
diff --git a/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc b/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
index 86ee14f..a9354b0 100644
--- a/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
+++ b/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
@@ -24,10 +24,10 @@
 
 #include "src/core/lib/iomgr/tcp_server_utils_posix.h"
 
-grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                int* out_port) {
+grpc_error_handle grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
+                                                      unsigned port_index,
+                                                      int requested_port,
+                                                      int* out_port) {
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING("no ifaddrs available");
 }
 
diff --git a/grpc/src/core/lib/iomgr/tcp_server_windows.cc b/grpc/src/core/lib/iomgr/tcp_server_windows.cc
index c44c3a5..614ea35 100644
--- a/grpc/src/core/lib/iomgr/tcp_server_windows.cc
+++ b/grpc/src/core/lib/iomgr/tcp_server_windows.cc
@@ -38,11 +38,11 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/pollset_windows.h"
 #include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/iomgr/tcp_windows.h"
@@ -101,9 +101,9 @@
 
 /* Public function. Allocates the proper data structures to hold a
    grpc_tcp_server. */
-static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
-                                     const grpc_channel_args* args,
-                                     grpc_tcp_server** server) {
+static grpc_error_handle tcp_server_create(grpc_closure* shutdown_complete,
+                                           const grpc_channel_args* args,
+                                           grpc_tcp_server** server) {
   grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server));
   s->channel_args = grpc_channel_args_copy(args);
   gpr_ref_init(&s->refs, 1);
@@ -120,7 +120,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static void destroy_server(void* arg, grpc_error* error) {
+static void destroy_server(void* arg, grpc_error_handle error) {
   grpc_tcp_server* s = (grpc_tcp_server*)arg;
 
   /* Now that the accepts have been aborted, we can destroy the sockets.
@@ -191,11 +191,11 @@
 }
 
 /* Prepare (bind) a recently-created socket for listening. */
-static grpc_error* prepare_socket(SOCKET sock,
-                                  const grpc_resolved_address* addr,
-                                  int* port) {
+static grpc_error_handle prepare_socket(SOCKET sock,
+                                        const grpc_resolved_address* addr,
+                                        int* port) {
   grpc_resolved_address sockname_temp;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   int sockname_temp_len;
 
   error = grpc_tcp_prepare_socket(sock);
@@ -249,12 +249,12 @@
 
 /* In order to do an async accept, we need to create a socket first which
    will be the one assigned to the new incoming connection. */
-static grpc_error* start_accept_locked(grpc_tcp_listener* port) {
+static grpc_error_handle start_accept_locked(grpc_tcp_listener* port) {
   SOCKET sock = INVALID_SOCKET;
   BOOL success;
   DWORD addrlen = sizeof(grpc_sockaddr_in6) + 16;
   DWORD bytes_received = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   if (port->shutting_down) {
     return GRPC_ERROR_NONE;
@@ -299,7 +299,7 @@
 }
 
 /* Event manager callback when reads are ready. */
-static void on_accept(void* arg, grpc_error* error) {
+static void on_accept(void* arg, grpc_error_handle error) {
   grpc_tcp_listener* sp = (grpc_tcp_listener*)arg;
   SOCKET sock = sp->new_socket;
   grpc_winsocket_callback_info* info = &sp->socket->read_info;
@@ -318,8 +318,8 @@
      this is necessary in the read/write case, it's useless for the accept
      case. We only need to adjust the pending callback count */
   if (error != GRPC_ERROR_NONE) {
-    const char* msg = grpc_error_string(error);
-    gpr_log(GPR_INFO, "Skipping on_accept due to error: %s", msg);
+    gpr_log(GPR_INFO, "Skipping on_accept due to error: %s",
+            grpc_error_std_string(error).c_str());
 
     gpr_mu_unlock(&sp->server->mu);
     return;
@@ -388,17 +388,17 @@
   gpr_mu_unlock(&sp->server->mu);
 }
 
-static grpc_error* add_socket_to_server(grpc_tcp_server* s, SOCKET sock,
-                                        const grpc_resolved_address* addr,
-                                        unsigned port_index,
-                                        grpc_tcp_listener** listener) {
+static grpc_error_handle add_socket_to_server(grpc_tcp_server* s, SOCKET sock,
+                                              const grpc_resolved_address* addr,
+                                              unsigned port_index,
+                                              grpc_tcp_listener** listener) {
   grpc_tcp_listener* sp = NULL;
   int port = -1;
   int status;
   GUID guid = WSAID_ACCEPTEX;
   DWORD ioctl_num_bytes;
   LPFN_ACCEPTEX AcceptEx;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   /* We need to grab the AcceptEx pointer for that port, as it may be
      interface-dependent. We'll cache it to avoid doing that again. */
@@ -446,9 +446,9 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
-                                       const grpc_resolved_address* addr,
-                                       int* port) {
+static grpc_error_handle tcp_server_add_port(grpc_tcp_server* s,
+                                             const grpc_resolved_address* addr,
+                                             int* port) {
   grpc_tcp_listener* sp = NULL;
   SOCKET sock;
   grpc_resolved_address addr6_v4mapped;
@@ -456,7 +456,7 @@
   grpc_resolved_address* allocated_addr = NULL;
   grpc_resolved_address sockname_temp;
   unsigned port_index = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   if (s->tail != NULL) {
     port_index = s->tail->port_index + 1;
@@ -508,8 +508,9 @@
   gpr_free(allocated_addr);
 
   if (error != GRPC_ERROR_NONE) {
-    grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-        "Failed to add port to server", &error, 1);
+    grpc_error_handle error_out =
+        GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+            "Failed to add port to server", &error, 1);
     GRPC_ERROR_UNREF(error);
     error = error_out;
     *port = -1;
diff --git a/grpc/src/core/lib/iomgr/tcp_uv.cc b/grpc/src/core/lib/iomgr/tcp_uv.cc
index 942b7d6..8f64d22 100644
--- a/grpc/src/core/lib/iomgr/tcp_uv.cc
+++ b/grpc/src/core/lib/iomgr/tcp_uv.cc
@@ -55,7 +55,7 @@
 
   int pending_connections;
   grpc_custom_socket* accept_socket;
-  grpc_error* accept_error;
+  grpc_error_handle accept_error;
 
   grpc_custom_connect_callback connect_cb;
   grpc_custom_write_callback write_cb;
@@ -65,11 +65,11 @@
 
 } uv_socket_t;
 
-static grpc_error* tcp_error_create(const char* desc, int status) {
+static grpc_error_handle tcp_error_create(const char* desc, int status) {
   if (status == 0) {
     return GRPC_ERROR_NONE;
   }
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc);
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc);
   /* All tcp errors are marked with UNAVAILABLE so that application may
    * choose to retry. */
   error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
@@ -95,7 +95,7 @@
 
 static void uv_read_callback(uv_stream_t* stream, ssize_t nread,
                              const uv_buf_t* buf) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (nread == 0) {
     // Nothing happened. Wait for the next callback
     return;
@@ -126,7 +126,7 @@
                            size_t length, grpc_custom_read_callback read_cb) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int status;
-  grpc_error* error;
+  grpc_error_handle error;
   uv_socket->read_cb = read_cb;
   uv_socket->read_buf = buffer;
   uv_socket->read_len = length;
@@ -184,7 +184,8 @@
   uv_close((uv_handle_t*)uv_socket->handle, uv_close_callback);
 }
 
-static grpc_error* uv_socket_init_helper(uv_socket_t* uv_socket, int domain) {
+static grpc_error_handle uv_socket_init_helper(uv_socket_t* uv_socket,
+                                               int domain) {
   uv_tcp_t* tcp = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
   uv_socket->handle = tcp;
   int status = uv_tcp_init_ex(uv_default_loop(), tcp, (unsigned int)domain);
@@ -212,9 +213,10 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* uv_socket_init(grpc_custom_socket* socket, int domain) {
+static grpc_error_handle uv_socket_init(grpc_custom_socket* socket,
+                                        int domain) {
   uv_socket_t* uv_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t));
-  grpc_error* error = uv_socket_init_helper(uv_socket, domain);
+  grpc_error_handle error = uv_socket_init_helper(uv_socket, domain);
   if (error != GRPC_ERROR_NONE) {
     return error;
   }
@@ -223,18 +225,18 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* uv_socket_getpeername(grpc_custom_socket* socket,
-                                         const grpc_sockaddr* addr,
-                                         int* addr_len) {
+static grpc_error_handle uv_socket_getpeername(grpc_custom_socket* socket,
+                                               const grpc_sockaddr* addr,
+                                               int* addr_len) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int err = uv_tcp_getpeername(uv_socket->handle,
                                (struct sockaddr*)IGNORE_CONST(addr), addr_len);
   return tcp_error_create("getpeername failed", err);
 }
 
-static grpc_error* uv_socket_getsockname(grpc_custom_socket* socket,
-                                         const grpc_sockaddr* addr,
-                                         int* addr_len) {
+static grpc_error_handle uv_socket_getsockname(grpc_custom_socket* socket,
+                                               const grpc_sockaddr* addr,
+                                               int* addr_len) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int err = uv_tcp_getsockname(uv_socket->handle,
                                (struct sockaddr*)IGNORE_CONST(addr), addr_len);
@@ -247,13 +249,13 @@
     return;
   }
   grpc_custom_socket* new_socket = uv_socket->accept_socket;
-  grpc_error* error = uv_socket->accept_error;
+  grpc_error_handle error = uv_socket->accept_error;
   uv_socket->accept_socket = nullptr;
   uv_socket->accept_error = GRPC_ERROR_NONE;
   uv_socket->pending_connections -= 1;
   if (uv_socket->accept_error != GRPC_ERROR_NONE) {
-    uv_stream_t dummy_handle;
-    uv_accept((uv_stream_t*)uv_socket->handle, &dummy_handle);
+    uv_stream_t phony_handle;
+    uv_accept((uv_stream_t*)uv_socket->handle, &phony_handle);
     uv_socket->accept_cb(socket, new_socket, error);
   } else {
     uv_socket_t* uv_new_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t));
@@ -293,16 +295,16 @@
   accept_new_connection(socket);
 }
 
-static grpc_error* uv_socket_bind(grpc_custom_socket* socket,
-                                  const grpc_sockaddr* addr, size_t len,
-                                  int flags) {
+static grpc_error_handle uv_socket_bind(grpc_custom_socket* socket,
+                                        const grpc_sockaddr* addr, size_t len,
+                                        int flags) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int status =
       uv_tcp_bind((uv_tcp_t*)uv_socket->handle, (struct sockaddr*)addr, 0);
   return tcp_error_create("Failed to bind to port", status);
 }
 
-static grpc_error* uv_socket_listen(grpc_custom_socket* socket) {
+static grpc_error_handle uv_socket_listen(grpc_custom_socket* socket) {
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int status =
       uv_listen((uv_stream_t*)uv_socket->handle, SOMAXCONN, uv_on_connect);
@@ -312,7 +314,7 @@
 static void uv_tc_on_connect(uv_connect_t* req, int status) {
   grpc_custom_socket* socket = (grpc_custom_socket*)req->data;
   uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
-  grpc_error* error;
+  grpc_error_handle error;
   if (status == UV_ECANCELED) {
     // This should only happen if the handle is already closed
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timeout occurred");
@@ -370,8 +372,8 @@
                                tcp_error_create("getaddrinfo failed", status));
 }
 
-static grpc_error* uv_resolve(const char* host, const char* port,
-                              grpc_resolved_addresses** result) {
+static grpc_error_handle uv_resolve(const char* host, const char* port,
+                                    grpc_resolved_addresses** result) {
   int status;
   uv_getaddrinfo_t req;
   struct addrinfo hints;
@@ -403,7 +405,7 @@
                           port, &hints);
   if (status != 0) {
     gpr_free(req);
-    grpc_error* error = tcp_error_create("getaddrinfo failed", status);
+    grpc_error_handle error = tcp_error_create("getaddrinfo failed", status);
     grpc_custom_resolve_callback(r, NULL, error);
   }
 }
diff --git a/grpc/src/core/lib/iomgr/tcp_windows.cc b/grpc/src/core/lib/iomgr/tcp_windows.cc
index d28a54c..aa693cc 100644
--- a/grpc/src/core/lib/iomgr/tcp_windows.cc
+++ b/grpc/src/core/lib/iomgr/tcp_windows.cc
@@ -32,10 +32,10 @@
 #include <grpc/support/log_windows.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_windows.h"
@@ -53,7 +53,7 @@
 
 extern grpc_core::TraceFlag grpc_tcp_trace;
 
-grpc_error* grpc_tcp_set_non_block(SOCKET sock) {
+grpc_error_handle grpc_tcp_set_non_block(SOCKET sock) {
   int status;
   uint32_t param = 1;
   DWORD ret;
@@ -64,7 +64,7 @@
              : GRPC_WSA_ERROR(WSAGetLastError(), "WSAIoctl(GRPC_FIONBIO)");
 }
 
-static grpc_error* set_dualstack(SOCKET sock) {
+static grpc_error_handle set_dualstack(SOCKET sock) {
   int status;
   unsigned long param = 0;
   status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&param,
@@ -74,7 +74,7 @@
              : GRPC_WSA_ERROR(WSAGetLastError(), "setsockopt(IPV6_V6ONLY)");
 }
 
-static grpc_error* enable_socket_low_latency(SOCKET sock) {
+static grpc_error_handle enable_socket_low_latency(SOCKET sock) {
   int status;
   BOOL param = TRUE;
   status = ::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
@@ -86,8 +86,8 @@
                      : GRPC_WSA_ERROR(status, "setsockopt(TCP_NODELAY)");
 }
 
-grpc_error* grpc_tcp_prepare_socket(SOCKET sock) {
-  grpc_error* err;
+grpc_error_handle grpc_tcp_prepare_socket(SOCKET sock) {
+  grpc_error_handle err;
   err = grpc_tcp_set_non_block(sock);
   if (err != GRPC_ERROR_NONE) return err;
   err = set_dualstack(sock);
@@ -123,7 +123,7 @@
      to protect ourselves when requesting a shutdown. */
   gpr_mu mu;
   int shutting_down;
-  grpc_error* shutdown_error;
+  grpc_error_handle shutdown_error;
 
   std::string peer_string;
   std::string local_address;
@@ -177,7 +177,7 @@
 #endif
 
 /* Asynchronous callback from the IOCP, or the background thread. */
-static void on_read(void* tcpp, grpc_error* error) {
+static void on_read(void* tcpp, grpc_error_handle error) {
   grpc_tcp* tcp = (grpc_tcp*)tcpp;
   grpc_closure* cb = tcp->read_cb;
   grpc_winsocket* socket = tcp->socket;
@@ -313,7 +313,7 @@
 }
 
 /* Asynchronous callback from the IOCP, or the background thread. */
-static void on_write(void* tcpp, grpc_error* error) {
+static void on_write(void* tcpp, grpc_error_handle error) {
   grpc_tcp* tcp = (grpc_tcp*)tcpp;
   grpc_winsocket* handle = tcp->socket;
   grpc_winsocket_callback_info* info = &handle->write_info;
@@ -399,9 +399,9 @@
      connection that has its send queue filled up. But if we don't, then we can
      avoid doing an async write operation at all. */
   if (info->wsa_error != WSAEWOULDBLOCK) {
-    grpc_error* error = status == 0
-                            ? GRPC_ERROR_NONE
-                            : GRPC_WSA_ERROR(info->wsa_error, "WSASend");
+    grpc_error_handle error = status == 0
+                                  ? GRPC_ERROR_NONE
+                                  : GRPC_WSA_ERROR(info->wsa_error, "WSASend");
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
     if (allocated) gpr_free(allocated);
     return;
@@ -454,7 +454,7 @@
    we're not going to protect against these. However the IO Completion Port
    callback will happen from another thread, so we need to protect against
    concurrent access of the data structure in that regard. */
-static void win_shutdown(grpc_endpoint* ep, grpc_error* why) {
+static void win_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
   grpc_tcp* tcp = (grpc_tcp*)ep;
   gpr_mu_lock(&tcp->mu);
   /* At that point, what may happen is that we're already inside the IOCP
diff --git a/grpc/src/core/lib/iomgr/tcp_windows.h b/grpc/src/core/lib/iomgr/tcp_windows.h
index 04ef810..de3dc55 100644
--- a/grpc/src/core/lib/iomgr/tcp_windows.h
+++ b/grpc/src/core/lib/iomgr/tcp_windows.h
@@ -44,9 +44,9 @@
                                grpc_channel_args* channel_args,
                                const char* peer_string);
 
-grpc_error* grpc_tcp_prepare_socket(SOCKET sock);
+grpc_error_handle grpc_tcp_prepare_socket(SOCKET sock);
 
-grpc_error* grpc_tcp_set_non_block(SOCKET sock);
+grpc_error_handle grpc_tcp_set_non_block(SOCKET sock);
 
 #endif
 
diff --git a/grpc/src/core/lib/iomgr/timer_custom.cc b/grpc/src/core/lib/iomgr/timer_custom.cc
index 867359a..cb01b7c 100644
--- a/grpc/src/core/lib/iomgr/timer_custom.cc
+++ b/grpc/src/core/lib/iomgr/timer_custom.cc
@@ -30,7 +30,8 @@
 
 static grpc_custom_timer_vtable* custom_timer_impl;
 
-void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* /*error*/) {
+void grpc_custom_timer_callback(grpc_custom_timer* t,
+                                grpc_error_handle /*error*/) {
   GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
   grpc_core::ExecCtx exec_ctx;
diff --git a/grpc/src/core/lib/iomgr/timer_custom.h b/grpc/src/core/lib/iomgr/timer_custom.h
index bfea8ba..83c3e8d 100644
--- a/grpc/src/core/lib/iomgr/timer_custom.h
+++ b/grpc/src/core/lib/iomgr/timer_custom.h
@@ -38,6 +38,6 @@
 
 void grpc_custom_timer_init(grpc_custom_timer_vtable* impl);
 
-void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error);
+void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error_handle error);
 
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H */
diff --git a/grpc/src/core/lib/iomgr/timer_generic.cc b/grpc/src/core/lib/iomgr/timer_generic.cc
index 153fb1d..3d2fc00 100644
--- a/grpc/src/core/lib/iomgr/timer_generic.cc
+++ b/grpc/src/core/lib/iomgr/timer_generic.cc
@@ -247,7 +247,7 @@
 
 static grpc_timer_check_result run_some_expired_timers(grpc_millis now,
                                                        grpc_millis* next,
-                                                       grpc_error* error);
+                                                       grpc_error_handle error);
 
 static grpc_millis compute_min_deadline(timer_shard* shard) {
   return grpc_timer_heap_is_empty(&shard->heap)
@@ -409,7 +409,7 @@
   }
   gpr_mu_unlock(&shard->mu);
 
-  /* Deadline may have decreased, we need to adjust the master queue.  Note
+  /* Deadline may have decreased, we need to adjust the main queue.  Note
      that there is a potential racy unlocked region here.  There could be a
      reordering of multiple grpc_timer_init calls, at this point, but the < test
      below should ensure that we err on the side of caution.  There could
@@ -561,7 +561,8 @@
 
 /* REQUIRES: shard->mu unlocked */
 static size_t pop_timers(timer_shard* shard, grpc_millis now,
-                         grpc_millis* new_min_deadline, grpc_error* error) {
+                         grpc_millis* new_min_deadline,
+                         grpc_error_handle error) {
   size_t n = 0;
   grpc_timer* timer;
   gpr_mu_lock(&shard->mu);
@@ -580,9 +581,8 @@
   return n;
 }
 
-static grpc_timer_check_result run_some_expired_timers(grpc_millis now,
-                                                       grpc_millis* next,
-                                                       grpc_error* error) {
+static grpc_timer_check_result run_some_expired_timers(
+    grpc_millis now, grpc_millis* next, grpc_error_handle error) {
   grpc_timer_check_result result = GRPC_TIMERS_NOT_CHECKED;
 
 #if GPR_ARCH_64
@@ -639,7 +639,7 @@
 
       /* An grpc_timer_init() on the shard could intervene here, adding a new
          timer that is earlier than new_min_deadline.  However,
-         grpc_timer_init() will block on the master_lock before it can call
+         grpc_timer_init() will block on the mutex before it can call
          set_min_deadline, so this one will complete first and then the Addtimer
          will reduce the min_deadline (perhaps unnecessarily). */
       g_shard_queue[0]->min_deadline = new_min_deadline;
@@ -702,7 +702,7 @@
     return GRPC_TIMERS_CHECKED_AND_EMPTY;
   }
 
-  grpc_error* shutdown_error =
+  grpc_error_handle shutdown_error =
       now != GRPC_MILLIS_INF_FUTURE
           ? GRPC_ERROR_NONE
           : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system");
diff --git a/grpc/src/core/lib/iomgr/timer_manager.cc b/grpc/src/core/lib/iomgr/timer_manager.cc
index e234727..bf467cb 100644
--- a/grpc/src/core/lib/iomgr/timer_manager.cc
+++ b/grpc/src/core/lib/iomgr/timer_manager.cc
@@ -133,7 +133,7 @@
   }
   grpc_core::ExecCtx::Get()->Flush();
   gpr_mu_lock(&g_mu);
-  // garbage collect any threads hanging out that are dead
+  // garbage collect any threads that are dead
   gc_completed_threads();
   // get ready to wait again
   ++g_waiter_count;
diff --git a/grpc/src/core/lib/iomgr/udp_server.cc b/grpc/src/core/lib/iomgr/udp_server.cc
index c2eacc5..4efaf23 100644
--- a/grpc/src/core/lib/iomgr/udp_server.cc
+++ b/grpc/src/core/lib/iomgr/udp_server.cc
@@ -56,6 +56,8 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
+
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
@@ -64,7 +66,6 @@
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_factory_posix.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
@@ -83,11 +84,11 @@
 
   /* Called when data is available to read from the socket.
    * Return true if there is more data to read from fd. */
-  void OnRead(grpc_error* error, void* do_read_arg);
+  void OnRead(grpc_error_handle error, void* do_read_arg);
 
   /* Called when the socket is writeable. The given closure should be scheduled
    * when the socket becomes blocked next time. */
-  void OnCanWrite(grpc_error* error, void* do_write_arg);
+  void OnCanWrite(grpc_error_handle error, void* do_write_arg);
 
   /* Called when the grpc_fd is about to be orphaned (and the FD closed). */
   void OnFdAboutToOrphan();
@@ -107,16 +108,16 @@
 
  private:
   /* event manager callback when reads are ready */
-  static void on_read(void* arg, grpc_error* error);
-  static void on_write(void* arg, grpc_error* error);
+  static void on_read(void* arg, grpc_error_handle error);
+  static void on_write(void* arg, grpc_error_handle error);
 
-  static void do_read(void* arg, grpc_error* error);
-  static void do_write(void* arg, grpc_error* error);
+  static void do_read(void* arg, grpc_error_handle error);
+  static void do_write(void* arg, grpc_error_handle error);
   // Wrapper of grpc_fd_notify_on_write() with a grpc_closure callback
   // interface.
-  static void fd_notify_on_write_wrapper(void* arg, grpc_error* error);
+  static void fd_notify_on_write_wrapper(void* arg, grpc_error_handle error);
 
-  static void shutdown_fd(void* args, grpc_error* error);
+  static void shutdown_fd(void* args, grpc_error_handle error);
 
   int fd_;
   grpc_fd* emfd_;
@@ -222,7 +223,7 @@
 }
 
 // static
-void GrpcUdpListener::shutdown_fd(void* args, grpc_error* error) {
+void GrpcUdpListener::shutdown_fd(void* args, grpc_error_handle error) {
   if (args == nullptr) {
     // No-op if shutdown args are null.
     return;
@@ -261,7 +262,7 @@
   delete s;
 }
 
-static void destroyed_port(void* server, grpc_error* /*error*/) {
+static void destroyed_port(void* server, grpc_error_handle /*error*/) {
   grpc_udp_server* s = static_cast<grpc_udp_server*>(server);
   gpr_mu_lock(&s->mu);
   s->destroyed_ports++;
@@ -436,7 +437,7 @@
 }
 
 // static
-void GrpcUdpListener::do_read(void* arg, grpc_error* error) {
+void GrpcUdpListener::do_read(void* arg, grpc_error_handle error) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   /* TODO: the reason we hold server->mu here is merely to prevent fd
@@ -460,12 +461,12 @@
 }
 
 // static
-void GrpcUdpListener::on_read(void* arg, grpc_error* error) {
+void GrpcUdpListener::on_read(void* arg, grpc_error_handle error) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   sp->OnRead(error, arg);
 }
 
-void GrpcUdpListener::OnRead(grpc_error* error, void* do_read_arg) {
+void GrpcUdpListener::OnRead(grpc_error_handle error, void* do_read_arg) {
   if (error != GRPC_ERROR_NONE) {
     gpr_mu_lock(&server_->mu);
     if (0 == --server_->active_ports && server_->shutdown) {
@@ -497,7 +498,7 @@
 // static
 // Wrapper of grpc_fd_notify_on_write() with a grpc_closure callback interface.
 void GrpcUdpListener::fd_notify_on_write_wrapper(void* arg,
-                                                 grpc_error* /*error*/) {
+                                                 grpc_error_handle /*error*/) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   gpr_mu_lock(sp->mutex());
   if (!sp->notify_on_write_armed_) {
@@ -508,7 +509,7 @@
 }
 
 // static
-void GrpcUdpListener::do_write(void* arg, grpc_error* error) {
+void GrpcUdpListener::do_write(void* arg, grpc_error_handle error) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   gpr_mu_lock(sp->mutex());
   if (sp->already_shutdown_) {
@@ -527,12 +528,12 @@
 }
 
 // static
-void GrpcUdpListener::on_write(void* arg, grpc_error* error) {
+void GrpcUdpListener::on_write(void* arg, grpc_error_handle error) {
   GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
   sp->OnCanWrite(error, arg);
 }
 
-void GrpcUdpListener::OnCanWrite(grpc_error* error, void* do_write_arg) {
+void GrpcUdpListener::OnCanWrite(grpc_error_handle error, void* do_write_arg) {
   if (error != GRPC_ERROR_NONE) {
     gpr_mu_lock(&server_->mu);
     if (0 == --server_->active_ports && server_->shutdown) {
@@ -630,7 +631,7 @@
 
       /* Try listening on IPv6 first. */
       addr = &wild6;
-      // TODO(rjshade): Test and propagate the returned grpc_error*:
+      // TODO(rjshade): Test and propagate the returned grpc_error_handle:
       GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
           s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
       allocated_port1 =
@@ -666,7 +667,7 @@
       addr = &wild4;
     }
 
-    // TODO(rjshade): Test and propagate the returned grpc_error*:
+    // TODO(rjshade): Test and propagate the returned grpc_error_handle:
     GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
         s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
     if (fd < 0) {
diff --git a/grpc/src/core/lib/iomgr/unix_sockets_posix.cc b/grpc/src/core/lib/iomgr/unix_sockets_posix.cc
index 034aa91..2b077a3 100644
--- a/grpc/src/core/lib/iomgr/unix_sockets_posix.cc
+++ b/grpc/src/core/lib/iomgr/unix_sockets_posix.cc
@@ -30,7 +30,7 @@
 
 #include "absl/strings/str_cat.h"
 
-#include "src/core/lib/iomgr/parse_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
 #include <grpc/support/alloc.h>
@@ -42,7 +42,7 @@
   GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
 }
 
-grpc_error* grpc_resolve_unix_domain_address(
+grpc_error_handle grpc_resolve_unix_domain_address(
     const char* name, grpc_resolved_addresses** addresses) {
   *addresses = static_cast<grpc_resolved_addresses*>(
       gpr_malloc(sizeof(grpc_resolved_addresses)));
@@ -52,7 +52,7 @@
   return grpc_core::UnixSockaddrPopulate(name, (*addresses)->addrs);
 }
 
-grpc_error* grpc_resolve_unix_abstract_domain_address(
+grpc_error_handle grpc_resolve_unix_abstract_domain_address(
     const absl::string_view name, grpc_resolved_addresses** addresses) {
   *addresses = static_cast<grpc_resolved_addresses*>(
       gpr_malloc(sizeof(grpc_resolved_addresses)));
diff --git a/grpc/src/core/lib/iomgr/unix_sockets_posix.h b/grpc/src/core/lib/iomgr/unix_sockets_posix.h
index 302ac17..c35423b 100644
--- a/grpc/src/core/lib/iomgr/unix_sockets_posix.h
+++ b/grpc/src/core/lib/iomgr/unix_sockets_posix.h
@@ -33,10 +33,10 @@
 
 void grpc_create_socketpair_if_unix(int sv[2]);
 
-grpc_error* grpc_resolve_unix_domain_address(
+grpc_error_handle grpc_resolve_unix_domain_address(
     const char* name, grpc_resolved_addresses** addresses);
 
-grpc_error* grpc_resolve_unix_abstract_domain_address(
+grpc_error_handle grpc_resolve_unix_abstract_domain_address(
     absl::string_view name, grpc_resolved_addresses** addresses);
 
 int grpc_is_unix_socket(const grpc_resolved_address* resolved_addr);
diff --git a/grpc/src/core/lib/iomgr/unix_sockets_posix_noop.cc b/grpc/src/core/lib/iomgr/unix_sockets_posix_noop.cc
index 7205797..c265922 100644
--- a/grpc/src/core/lib/iomgr/unix_sockets_posix_noop.cc
+++ b/grpc/src/core/lib/iomgr/unix_sockets_posix_noop.cc
@@ -26,33 +26,36 @@
 
 #include <grpc/support/log.h>
 
-void grpc_create_socketpair_if_unix(int sv[2]) {
+void grpc_create_socketpair_if_unix(int /* sv */[2]) {
   // TODO: Either implement this for the non-Unix socket case or make
   // sure that it is never called in any such case. Until then, leave an
   // assertion to notify if this gets called inadvertently
   GPR_ASSERT(0);
 }
 
-grpc_error* grpc_resolve_unix_domain_address(
-    const char* name, grpc_resolved_addresses** addresses) {
+grpc_error_handle grpc_resolve_unix_domain_address(
+    const char* /* name */, grpc_resolved_addresses** addresses) {
   *addresses = NULL;
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Unix domain sockets are not supported on Windows");
 }
 
-grpc_error* grpc_resolve_unix_abstract_domain_address(
+grpc_error_handle grpc_resolve_unix_abstract_domain_address(
     absl::string_view, grpc_resolved_addresses** addresses) {
   *addresses = NULL;
   return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Unix domain sockets are not supported on Windows");
 }
 
-int grpc_is_unix_socket(const grpc_resolved_address* addr) { return false; }
+int grpc_is_unix_socket(const grpc_resolved_address* /* addr */) {
+  return false;
+}
 
-void grpc_unlink_if_unix_domain_socket(const grpc_resolved_address* addr) {}
+void grpc_unlink_if_unix_domain_socket(
+    const grpc_resolved_address* /* addr */) {}
 
 std::string grpc_sockaddr_to_uri_unix_if_possible(
-    const grpc_resolved_address* addr) {
+    const grpc_resolved_address* /* addr */) {
   return "";
 }
 
diff --git a/grpc/src/core/lib/iomgr/wakeup_fd_eventfd.cc b/grpc/src/core/lib/iomgr/wakeup_fd_eventfd.cc
index d68c9ad..3951fe6 100644
--- a/grpc/src/core/lib/iomgr/wakeup_fd_eventfd.cc
+++ b/grpc/src/core/lib/iomgr/wakeup_fd_eventfd.cc
@@ -31,7 +31,7 @@
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/profiling/timers.h"
 
-static grpc_error* eventfd_create(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle eventfd_create(grpc_wakeup_fd* fd_info) {
   fd_info->read_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
   fd_info->write_fd = -1;
   if (fd_info->read_fd < 0) {
@@ -40,7 +40,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* eventfd_consume(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle eventfd_consume(grpc_wakeup_fd* fd_info) {
   eventfd_t value;
   int err;
   do {
@@ -52,7 +52,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* eventfd_wakeup(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle eventfd_wakeup(grpc_wakeup_fd* fd_info) {
   GPR_TIMER_SCOPE("eventfd_wakeup", 0);
   int err;
   do {
diff --git a/grpc/src/core/lib/iomgr/wakeup_fd_nospecial.cc b/grpc/src/core/lib/iomgr/wakeup_fd_nospecial.cc
index 6477892..b156575 100644
--- a/grpc/src/core/lib/iomgr/wakeup_fd_nospecial.cc
+++ b/grpc/src/core/lib/iomgr/wakeup_fd_nospecial.cc
@@ -17,7 +17,7 @@
  */
 
 /*
- * This is a dummy file to provide an invalid specialized_wakeup_fd_vtable on
+ * This is a phony file to provide an invalid specialized_wakeup_fd_vtable on
  * systems without anything better than pipe.
  */
 
diff --git a/grpc/src/core/lib/iomgr/wakeup_fd_pipe.cc b/grpc/src/core/lib/iomgr/wakeup_fd_pipe.cc
index 797cd44..943d9d5 100644
--- a/grpc/src/core/lib/iomgr/wakeup_fd_pipe.cc
+++ b/grpc/src/core/lib/iomgr/wakeup_fd_pipe.cc
@@ -33,14 +33,14 @@
 
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 
-static grpc_error* pipe_init(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle pipe_init(grpc_wakeup_fd* fd_info) {
   int pipefd[2];
   int r = pipe(pipefd);
   if (0 != r) {
     gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno));
     return GRPC_OS_ERROR(errno, "pipe");
   }
-  grpc_error* err;
+  grpc_error_handle err;
   err = grpc_set_socket_nonblocking(pipefd[0], 1);
   if (err != GRPC_ERROR_NONE) return err;
   err = grpc_set_socket_nonblocking(pipefd[1], 1);
@@ -50,7 +50,7 @@
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error* pipe_consume(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle pipe_consume(grpc_wakeup_fd* fd_info) {
   char buf[128];
   ssize_t r;
 
@@ -69,7 +69,7 @@
   }
 }
 
-static grpc_error* pipe_wakeup(grpc_wakeup_fd* fd_info) {
+static grpc_error_handle pipe_wakeup(grpc_wakeup_fd* fd_info) {
   char c = 0;
   while (write(fd_info->write_fd, &c, 1) != 1 && errno == EINTR) {
   }
diff --git a/grpc/src/core/lib/iomgr/wakeup_fd_posix.cc b/grpc/src/core/lib/iomgr/wakeup_fd_posix.cc
index 3b66d6f..36b497b 100644
--- a/grpc/src/core/lib/iomgr/wakeup_fd_posix.cc
+++ b/grpc/src/core/lib/iomgr/wakeup_fd_posix.cc
@@ -50,15 +50,15 @@
 
 int grpc_has_wakeup_fd(void) { return has_real_wakeup_fd; }
 
-grpc_error* grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info) {
+grpc_error_handle grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info) {
   return wakeup_fd_vtable->init(fd_info);
 }
 
-grpc_error* grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info) {
+grpc_error_handle grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info) {
   return wakeup_fd_vtable->consume(fd_info);
 }
 
-grpc_error* grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info) {
+grpc_error_handle grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info) {
   return wakeup_fd_vtable->wakeup(fd_info);
 }
 
diff --git a/grpc/src/core/lib/iomgr/wakeup_fd_posix.h b/grpc/src/core/lib/iomgr/wakeup_fd_posix.h
index 670c319..1079ce6 100644
--- a/grpc/src/core/lib/iomgr/wakeup_fd_posix.h
+++ b/grpc/src/core/lib/iomgr/wakeup_fd_posix.h
@@ -65,9 +65,9 @@
 typedef struct grpc_wakeup_fd grpc_wakeup_fd;
 
 typedef struct grpc_wakeup_fd_vtable {
-  grpc_error* (*init)(grpc_wakeup_fd* fd_info);
-  grpc_error* (*consume)(grpc_wakeup_fd* fd_info);
-  grpc_error* (*wakeup)(grpc_wakeup_fd* fd_info);
+  grpc_error_handle (*init)(grpc_wakeup_fd* fd_info);
+  grpc_error_handle (*consume)(grpc_wakeup_fd* fd_info);
+  grpc_error_handle (*wakeup)(grpc_wakeup_fd* fd_info);
   void (*destroy)(grpc_wakeup_fd* fd_info);
   /* Must be called before calling any other functions */
   int (*check_availability)(void);
@@ -83,10 +83,12 @@
 
 #define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd)
 
-grpc_error* grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info) GRPC_MUST_USE_RESULT;
-grpc_error* grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info)
+grpc_error_handle grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info)
     GRPC_MUST_USE_RESULT;
-grpc_error* grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info) GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info)
+    GRPC_MUST_USE_RESULT;
+grpc_error_handle grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info)
+    GRPC_MUST_USE_RESULT;
 void grpc_wakeup_fd_destroy(grpc_wakeup_fd* fd_info);
 
 /* Defined in some specialized implementation's .c file, or by
diff --git a/grpc/src/core/lib/iomgr/work_serializer.h b/grpc/src/core/lib/iomgr/work_serializer.h
index 169562d..547b80c 100644
--- a/grpc/src/core/lib/iomgr/work_serializer.h
+++ b/grpc/src/core/lib/iomgr/work_serializer.h
@@ -20,6 +20,8 @@
 
 #include <functional>
 
+#include "absl/synchronization/mutex.h"
+
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/atomic.h"
 #include "src/core/lib/gprpp/debug_location.h"
@@ -43,12 +45,26 @@
 // other callbacks from other threads might also be executed before Run()
 // returns. Since an arbitrary set of callbacks might be executed when Run() is
 // called, generally no locks should be held while calling Run().
-class WorkSerializer {
+class ABSL_LOCKABLE WorkSerializer {
  public:
   WorkSerializer();
 
   ~WorkSerializer();
 
+  // Runs a given callback.
+  //
+  // If you want to use clang thread annotation to make sure that callback is
+  // called by WorkSerializer only, you need to add the annotation to both the
+  // lambda function given to Run and the actual callback function like;
+  //
+  //   void run_callback() {
+  //     work_serializer.Run(
+  //         []() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer) {
+  //            callback();
+  //         }, DEBUG_LOCATION);
+  //   }
+  //   void callback() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer) { ... }
+  //
   // TODO(yashkt): Replace grpc_core::DebugLocation with absl::SourceLocation
   // once we can start using it directly.
   void Run(std::function<void()> callback,
diff --git a/grpc/src/core/lib/json/json.h b/grpc/src/core/lib/json/json.h
index 9b3e0be..fc09d3a 100644
--- a/grpc/src/core/lib/json/json.h
+++ b/grpc/src/core/lib/json/json.h
@@ -56,7 +56,7 @@
   using Array = std::vector<Json>;
 
   // Parses JSON string from json_str.  On error, sets *error.
-  static Json Parse(absl::string_view json_str, grpc_error** error);
+  static Json Parse(absl::string_view json_str, grpc_error_handle* error);
 
   Json() = default;
 
diff --git a/grpc/src/core/lib/json/json_reader.cc b/grpc/src/core/lib/json/json_reader.cc
index d23112e..2daeadf 100644
--- a/grpc/src/core/lib/json/json_reader.cc
+++ b/grpc/src/core/lib/json/json_reader.cc
@@ -38,7 +38,7 @@
 
 class JsonReader {
  public:
-  static grpc_error* Parse(absl::string_view input, Json* output);
+  static grpc_error_handle Parse(absl::string_view input, Json* output);
 
  private:
   enum class Status {
@@ -117,7 +117,7 @@
   bool container_just_begun_ = false;
   uint16_t unicode_char_ = 0;
   uint16_t unicode_high_surrogate_ = 0;
-  std::vector<grpc_error*> errors_;
+  std::vector<grpc_error_handle> errors_;
   bool truncated_errors_ = false;
 
   Json root_value_;
@@ -821,7 +821,7 @@
   GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
 }
 
-grpc_error* JsonReader::Parse(absl::string_view input, Json* output) {
+grpc_error_handle JsonReader::Parse(absl::string_view input, Json* output) {
   JsonReader reader(input);
   Status status = reader.Run();
   if (reader.truncated_errors_) {
@@ -849,7 +849,7 @@
 
 }  // namespace
 
-Json Json::Parse(absl::string_view json_str, grpc_error** error) {
+Json Json::Parse(absl::string_view json_str, grpc_error_handle* error) {
   Json value;
   *error = JsonReader::Parse(json_str, &value);
   return value;
diff --git a/grpc/src/core/lib/matchers/matchers.cc b/grpc/src/core/lib/matchers/matchers.cc
new file mode 100644
index 0000000..489a480
--- /dev/null
+++ b/grpc/src/core/lib/matchers/matchers.cc
@@ -0,0 +1,339 @@
+// Copyright 2021 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>
+
+#include "src/core/lib/matchers/matchers.h"
+
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/str_split.h"
+
+namespace grpc_core {
+
+//
+// StringMatcher
+//
+
+absl::StatusOr<StringMatcher> StringMatcher::Create(Type type,
+                                                    absl::string_view matcher,
+                                                    bool case_sensitive) {
+  if (type == Type::kSafeRegex) {
+    RE2::Options options;
+    options.set_case_sensitive(case_sensitive);
+    auto regex_matcher = absl::make_unique<RE2>(std::string(matcher), options);
+    if (!regex_matcher->ok()) {
+      return absl::InvalidArgumentError(
+          "Invalid regex string specified in matcher.");
+    }
+    return StringMatcher(std::move(regex_matcher), case_sensitive);
+  } else {
+    return StringMatcher(type, matcher, case_sensitive);
+  }
+}
+
+StringMatcher::StringMatcher(Type type, absl::string_view matcher,
+                             bool case_sensitive)
+    : type_(type), string_matcher_(matcher), case_sensitive_(case_sensitive) {}
+
+StringMatcher::StringMatcher(std::unique_ptr<RE2> regex_matcher,
+                             bool case_sensitive)
+    : type_(Type::kSafeRegex),
+      regex_matcher_(std::move(regex_matcher)),
+      case_sensitive_(case_sensitive) {}
+
+StringMatcher::StringMatcher(const StringMatcher& other)
+    : type_(other.type_), case_sensitive_(other.case_sensitive_) {
+  if (type_ == Type::kSafeRegex) {
+    RE2::Options options;
+    options.set_case_sensitive(other.case_sensitive_);
+    regex_matcher_ =
+        absl::make_unique<RE2>(other.regex_matcher_->pattern(), options);
+  } else {
+    string_matcher_ = other.string_matcher_;
+  }
+}
+
+StringMatcher& StringMatcher::operator=(const StringMatcher& other) {
+  type_ = other.type_;
+  if (type_ == Type::kSafeRegex) {
+    RE2::Options options;
+    options.set_case_sensitive(other.case_sensitive_);
+    regex_matcher_ =
+        absl::make_unique<RE2>(other.regex_matcher_->pattern(), options);
+  } else {
+    string_matcher_ = other.string_matcher_;
+  }
+  case_sensitive_ = other.case_sensitive_;
+  return *this;
+}
+
+StringMatcher::StringMatcher(StringMatcher&& other) noexcept
+    : type_(other.type_), case_sensitive_(other.case_sensitive_) {
+  if (type_ == Type::kSafeRegex) {
+    regex_matcher_ = std::move(other.regex_matcher_);
+  } else {
+    string_matcher_ = std::move(other.string_matcher_);
+  }
+}
+
+StringMatcher& StringMatcher::operator=(StringMatcher&& other) noexcept {
+  type_ = other.type_;
+  if (type_ == Type::kSafeRegex) {
+    regex_matcher_ = std::move(other.regex_matcher_);
+  } else {
+    string_matcher_ = std::move(other.string_matcher_);
+  }
+  case_sensitive_ = other.case_sensitive_;
+  return *this;
+}
+
+bool StringMatcher::operator==(const StringMatcher& other) const {
+  if (type_ != other.type_ || case_sensitive_ != other.case_sensitive_) {
+    return false;
+  }
+  if (type_ == Type::kSafeRegex) {
+    return regex_matcher_->pattern() == other.regex_matcher_->pattern();
+  } else {
+    return string_matcher_ == other.string_matcher_;
+  }
+}
+
+bool StringMatcher::Match(absl::string_view value) const {
+  switch (type_) {
+    case Type::kExact:
+      return case_sensitive_ ? value == string_matcher_
+                             : absl::EqualsIgnoreCase(value, string_matcher_);
+    case StringMatcher::Type::kPrefix:
+      return case_sensitive_
+                 ? absl::StartsWith(value, string_matcher_)
+                 : absl::StartsWithIgnoreCase(value, string_matcher_);
+    case StringMatcher::Type::kSuffix:
+      return case_sensitive_ ? absl::EndsWith(value, string_matcher_)
+                             : absl::EndsWithIgnoreCase(value, string_matcher_);
+    case StringMatcher::Type::kContains:
+      return case_sensitive_
+                 ? absl::StrContains(value, string_matcher_)
+                 : absl::StrContains(absl::AsciiStrToLower(value),
+                                     absl::AsciiStrToLower(string_matcher_));
+    case StringMatcher::Type::kSafeRegex:
+      return RE2::FullMatch(std::string(value), *regex_matcher_);
+    default:
+      return false;
+  }
+}
+
+std::string StringMatcher::ToString() const {
+  switch (type_) {
+    case Type::kExact:
+      return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_,
+                             case_sensitive_ ? "" : ", case_sensitive=false");
+    case Type::kPrefix:
+      return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_,
+                             case_sensitive_ ? "" : ", case_sensitive=false");
+    case Type::kSuffix:
+      return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_,
+                             case_sensitive_ ? "" : ", case_sensitive=false");
+    case Type::kContains:
+      return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_,
+                             case_sensitive_ ? "" : ", case_sensitive=false");
+    case Type::kSafeRegex:
+      return absl::StrFormat("StringMatcher{safe_regex=%s%s}",
+                             regex_matcher_->pattern(),
+                             case_sensitive_ ? "" : ", case_sensitive=false");
+    default:
+      return "";
+  }
+}
+
+//
+// HeaderMatcher
+//
+
+absl::StatusOr<HeaderMatcher> HeaderMatcher::Create(
+    absl::string_view name, Type type, absl::string_view matcher,
+    int64_t range_start, int64_t range_end, bool present_match,
+    bool invert_match) {
+  if (static_cast<int>(type) < 5) {
+    // Only for EXACT, PREFIX, SUFFIX, SAFE_REGEX and CONTAINS.
+    absl::StatusOr<StringMatcher> string_matcher =
+        StringMatcher::Create(static_cast<StringMatcher::Type>(type), matcher,
+                              /*case_sensitive=*/true);
+    if (!string_matcher.ok()) {
+      return string_matcher.status();
+    }
+    return HeaderMatcher(name, type, std::move(string_matcher.value()),
+                         invert_match);
+  } else if (type == Type::kRange) {
+    if (range_start > range_end) {
+      return absl::InvalidArgumentError(
+          "Invalid range specifier specified: end cannot be smaller than "
+          "start.");
+    }
+    return HeaderMatcher(name, range_start, range_end, invert_match);
+  } else {
+    return HeaderMatcher(name, present_match, invert_match);
+  }
+}
+
+HeaderMatcher::HeaderMatcher(absl::string_view name, Type type,
+                             StringMatcher string_matcher, bool invert_match)
+    : name_(name),
+      type_(type),
+      matcher_(std::move(string_matcher)),
+      invert_match_(invert_match) {}
+
+HeaderMatcher::HeaderMatcher(absl::string_view name, int64_t range_start,
+                             int64_t range_end, bool invert_match)
+    : name_(name),
+      type_(Type::kRange),
+      range_start_(range_start),
+      range_end_(range_end),
+      invert_match_(invert_match) {}
+
+HeaderMatcher::HeaderMatcher(absl::string_view name, bool present_match,
+                             bool invert_match)
+    : name_(name),
+      type_(Type::kPresent),
+      present_match_(present_match),
+      invert_match_(invert_match) {}
+
+HeaderMatcher::HeaderMatcher(const HeaderMatcher& other)
+    : name_(other.name_),
+      type_(other.type_),
+      invert_match_(other.invert_match_) {
+  switch (type_) {
+    case Type::kRange:
+      range_start_ = other.range_start_;
+      range_end_ = other.range_end_;
+      break;
+    case Type::kPresent:
+      present_match_ = other.present_match_;
+      break;
+    default:
+      matcher_ = other.matcher_;
+  }
+}
+
+HeaderMatcher& HeaderMatcher::operator=(const HeaderMatcher& other) {
+  name_ = other.name_;
+  type_ = other.type_;
+  invert_match_ = other.invert_match_;
+  switch (type_) {
+    case Type::kRange:
+      range_start_ = other.range_start_;
+      range_end_ = other.range_end_;
+      break;
+    case Type::kPresent:
+      present_match_ = other.present_match_;
+      break;
+    default:
+      matcher_ = other.matcher_;
+  }
+  return *this;
+}
+
+HeaderMatcher::HeaderMatcher(HeaderMatcher&& other) noexcept
+    : name_(std::move(other.name_)),
+      type_(other.type_),
+      invert_match_(other.invert_match_) {
+  switch (type_) {
+    case Type::kRange:
+      range_start_ = other.range_start_;
+      range_end_ = other.range_end_;
+      break;
+    case Type::kPresent:
+      present_match_ = other.present_match_;
+      break;
+    default:
+      matcher_ = std::move(other.matcher_);
+  }
+}
+
+HeaderMatcher& HeaderMatcher::operator=(HeaderMatcher&& other) noexcept {
+  name_ = std::move(other.name_);
+  type_ = other.type_;
+  invert_match_ = other.invert_match_;
+  switch (type_) {
+    case Type::kRange:
+      range_start_ = other.range_start_;
+      range_end_ = other.range_end_;
+      break;
+    case Type::kPresent:
+      present_match_ = other.present_match_;
+      break;
+    default:
+      matcher_ = std::move(other.matcher_);
+  }
+  return *this;
+}
+
+bool HeaderMatcher::operator==(const HeaderMatcher& other) const {
+  if (name_ != other.name_) return false;
+  if (type_ != other.type_) return false;
+  if (invert_match_ != other.invert_match_) return false;
+  switch (type_) {
+    case Type::kRange:
+      return range_start_ == other.range_start_ &&
+             range_end_ == other.range_end_;
+    case Type::kPresent:
+      return present_match_ == other.present_match_;
+    default:
+      return matcher_ == other.matcher_;
+  }
+}
+
+bool HeaderMatcher::Match(
+    const absl::optional<absl::string_view>& value) const {
+  bool match;
+  if (type_ == Type::kPresent) {
+    match = value.has_value() == present_match_;
+  } else if (!value.has_value()) {
+    // All other types fail to match if field is not present.
+    match = false;
+  } else if (type_ == Type::kRange) {
+    int64_t int_value;
+    match = absl::SimpleAtoi(value.value(), &int_value) &&
+            int_value >= range_start_ && int_value < range_end_;
+  } else {
+    match = matcher_.Match(value.value());
+  }
+  return match != invert_match_;
+}
+
+std::string HeaderMatcher::ToString() const {
+  switch (type_) {
+    case Type::kRange:
+      return absl::StrFormat("HeaderMatcher{%s %srange=[%d, %d]}", name_,
+                             invert_match_ ? "not " : "", range_start_,
+                             range_end_);
+    case Type::kPresent:
+      return absl::StrFormat("HeaderMatcher{%s %spresent=%s}", name_,
+                             invert_match_ ? "not " : "",
+                             present_match_ ? "true" : "false");
+    case Type::kExact:
+    case Type::kPrefix:
+    case Type::kSuffix:
+    case Type::kSafeRegex:
+    case Type::kContains:
+      return absl::StrFormat("HeaderMatcher{%s %s%s}", name_,
+                             invert_match_ ? "not " : "", matcher_.ToString());
+    default:
+      return "";
+  }
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/lib/matchers/matchers.h b/grpc/src/core/lib/matchers/matchers.h
new file mode 100644
index 0000000..af2ce59
--- /dev/null
+++ b/grpc/src/core/lib/matchers/matchers.h
@@ -0,0 +1,160 @@
+// Copyright 2021 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_LIB_MATCHERS_MATCHERS_H
+#define GRPC_CORE_LIB_MATCHERS_MATCHERS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <memory>
+#include <string>
+
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+#include "re2/re2.h"
+
+namespace grpc_core {
+
+class StringMatcher {
+ public:
+  enum class Type {
+    kExact,      // value stored in string_matcher_ field
+    kPrefix,     // value stored in string_matcher_ field
+    kSuffix,     // value stored in string_matcher_ field
+    kSafeRegex,  // pattern stored in regex_matcher_ field
+    kContains,   // value stored in string_matcher_ field
+  };
+
+  // Creates StringMatcher instance. Returns error status on failure.
+  static absl::StatusOr<StringMatcher> Create(Type type,
+                                              absl::string_view matcher,
+                                              bool case_sensitive = true);
+
+  StringMatcher() = default;
+  StringMatcher(const StringMatcher& other);
+  StringMatcher& operator=(const StringMatcher& other);
+  StringMatcher(StringMatcher&& other) noexcept;
+  StringMatcher& operator=(StringMatcher&& other) noexcept;
+  bool operator==(const StringMatcher& other) const;
+
+  bool Match(absl::string_view value) const;
+
+  std::string ToString() const;
+
+  Type type() const { return type_; }
+
+  // Valid for kExact, kPrefix, kSuffix and kContains.
+  const std::string& string_matcher() const { return string_matcher_; }
+
+  // Valid for kSafeRegex.
+  RE2* regex_matcher() const { return regex_matcher_.get(); }
+
+  bool case_sensitive() const { return case_sensitive_; }
+
+ private:
+  StringMatcher(Type type, absl::string_view matcher, bool case_sensitive);
+  StringMatcher(std::unique_ptr<RE2> regex_matcher, bool case_sensitive);
+
+  Type type_ = Type::kExact;
+  std::string string_matcher_;
+  std::unique_ptr<RE2> regex_matcher_;
+  bool case_sensitive_ = true;
+};
+
+class HeaderMatcher {
+ public:
+  enum class Type {
+    kExact,      // value stored in StringMatcher field
+    kPrefix,     // value stored in StringMatcher field
+    kSuffix,     // value stored in StringMatcher field
+    kSafeRegex,  // value stored in StringMatcher field
+    kContains,   // value stored in StringMatcher field
+    kRange,      // uses range_start and range_end fields
+    kPresent,    // uses present_match field
+  };
+
+  // Make sure that the first five HeaderMatcher::Type enum values match up to
+  // the corresponding StringMatcher::Type enum values, so that it's safe to
+  // convert by casting when delegating to StringMatcher.
+  static_assert(static_cast<StringMatcher::Type>(Type::kExact) ==
+                    StringMatcher::Type::kExact,
+                "");
+  static_assert(static_cast<StringMatcher::Type>(Type::kPrefix) ==
+                    StringMatcher::Type::kPrefix,
+                "");
+  static_assert(static_cast<StringMatcher::Type>(Type::kSuffix) ==
+                    StringMatcher::Type::kSuffix,
+                "");
+  static_assert(static_cast<StringMatcher::Type>(Type::kSafeRegex) ==
+                    StringMatcher::Type::kSafeRegex,
+                "");
+  static_assert(static_cast<StringMatcher::Type>(Type::kContains) ==
+                    StringMatcher::Type::kContains,
+                "");
+
+  // Creates HeaderMatcher instance. Returns error status on failure.
+  static absl::StatusOr<HeaderMatcher> Create(absl::string_view name, Type type,
+                                              absl::string_view matcher,
+                                              int64_t range_start = 0,
+                                              int64_t range_end = 0,
+                                              bool present_match = false,
+                                              bool invert_match = false);
+
+  HeaderMatcher() = default;
+  HeaderMatcher(const HeaderMatcher& other);
+  HeaderMatcher& operator=(const HeaderMatcher& other);
+  HeaderMatcher(HeaderMatcher&& other) noexcept;
+  HeaderMatcher& operator=(HeaderMatcher&& other) noexcept;
+  bool operator==(const HeaderMatcher& other) const;
+
+  const std::string& name() const { return name_; }
+
+  Type type() const { return type_; }
+
+  // Valid for kExact, kPrefix, kSuffix and kContains.
+  const std::string& string_matcher() const {
+    return matcher_.string_matcher();
+  }
+
+  // Valid for kSafeRegex.
+  RE2* regex_matcher() const { return matcher_.regex_matcher(); }
+
+  bool Match(const absl::optional<absl::string_view>& value) const;
+
+  std::string ToString() const;
+
+ private:
+  // For StringMatcher.
+  HeaderMatcher(absl::string_view name, Type type, StringMatcher matcher,
+                bool invert_match);
+  // For RangeMatcher.
+  HeaderMatcher(absl::string_view name, int64_t range_start, int64_t range_end,
+                bool invert_match);
+  // For PresentMatcher.
+  HeaderMatcher(absl::string_view name, bool present_match, bool invert_match);
+
+  std::string name_;
+  Type type_ = Type::kExact;
+  StringMatcher matcher_;
+  int64_t range_start_;
+  int64_t range_end_;
+  bool present_match_;
+  bool invert_match_ = false;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_MATCHERS_MATCHERS_H */
diff --git a/grpc/src/core/lib/security/authorization/authorization_engine.h b/grpc/src/core/lib/security/authorization/authorization_engine.h
index 809784c..7889e62 100644
--- a/grpc/src/core/lib/security/authorization/authorization_engine.h
+++ b/grpc/src/core/lib/security/authorization/authorization_engine.h
@@ -1,5 +1,4 @@
-
-// Copyright 2020 gRPC authors.
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -18,67 +17,28 @@
 
 #include <grpc/support/port_platform.h>
 
-#include <grpc/support/log.h>
-#include <map>
-#include <memory>
 #include <string>
-#include <vector>
-
-#include "absl/container/flat_hash_set.h"
-#include "envoy/config/rbac/v3/rbac.upb.h"
-#include "google/api/expr/v1alpha1/syntax.upb.h"
-#include "upb/upb.hpp"
 
 #include "src/core/lib/security/authorization/evaluate_args.h"
-#include "src/core/lib/security/authorization/mock_cel/activation.h"
 
 namespace grpc_core {
 
-// AuthorizationEngine makes an AuthorizationDecision to ALLOW or DENY the
-// current action based on the condition fields in provided RBAC policies.
-// The engine may be constructed with one or two policies. If two polcies,
-// the first policy is deny-if-matched and the second is allow-if-matched.
-// The engine returns UNDECIDED decision if it fails to find a match in any
-// policy. This engine ignores the principal and permission fields in RBAC
-// policies. It is the caller's responsibility to provide RBAC policies that
-// are compatible with this engine.
-//
-// Example:
-// AuthorizationEngine*
-// auth_engine = AuthorizationEngine::CreateAuthorizationEngine(rbac_policies);
-// auth_engine->Evaluate(evaluate_args); // returns authorization decision.
+// Interface for gRPC Authorization Engine.
 class AuthorizationEngine {
  public:
-  // rbac_policies must be a vector containing either a single policy of any
-  // kind, or one deny policy and one allow policy, in that order.
-  static std::unique_ptr<AuthorizationEngine> CreateAuthorizationEngine(
-      const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
-
-  // Users should use the CreateAuthorizationEngine factory function
-  // instead of calling the AuthorizationEngine constructor directly.
-  explicit AuthorizationEngine(
-      const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
-  // TODO(mywang@google.com): add an Evaluate member function.
-
- private:
-  enum Action {
-    kAllow,
-    kDeny,
+  struct Decision {
+    enum class Type {
+      kAllow,
+      kDeny,
+    };
+    Type type;
+    std::string matching_policy_name;
   };
 
-  std::unique_ptr<mock_cel::Activation> CreateActivation(
-      const EvaluateArgs& args);
-
-  std::map<const std::string, const google_api_expr_v1alpha1_Expr*>
-      deny_if_matched_;
-  std::map<const std::string, const google_api_expr_v1alpha1_Expr*>
-      allow_if_matched_;
-  upb::Arena arena_;
-  absl::flat_hash_set<std::string> envoy_attributes_;
-  absl::flat_hash_set<std::string> header_keys_;
-  std::unique_ptr<mock_cel::CelMap> headers_;
+  virtual ~AuthorizationEngine() = default;
+  virtual Decision Evaluate(const EvaluateArgs& args) const = 0;
 };
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H */
+#endif  // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H
diff --git a/grpc/src/core/lib/security/authorization/authorization_engine.cc b/grpc/src/core/lib/security/authorization/cel_authorization_engine.cc
similarity index 94%
rename from grpc/src/core/lib/security/authorization/authorization_engine.cc
rename to grpc/src/core/lib/security/authorization/cel_authorization_engine.cc
index 8e6a63d..844d9fb 100644
--- a/grpc/src/core/lib/security/authorization/authorization_engine.cc
+++ b/grpc/src/core/lib/security/authorization/cel_authorization_engine.cc
@@ -16,7 +16,7 @@
 
 #include "absl/memory/memory.h"
 
-#include "src/core/lib/security/authorization/authorization_engine.h"
+#include "src/core/lib/security/authorization/cel_authorization_engine.h"
 
 namespace grpc_core {
 
@@ -36,8 +36,8 @@
 
 }  // namespace
 
-std::unique_ptr<AuthorizationEngine>
-AuthorizationEngine::CreateAuthorizationEngine(
+std::unique_ptr<CelAuthorizationEngine>
+CelAuthorizationEngine::CreateCelAuthorizationEngine(
     const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies) {
   if (rbac_policies.empty() || rbac_policies.size() > 2) {
     gpr_log(GPR_ERROR,
@@ -52,11 +52,11 @@
                          policy and one allow policy, in that order.");
     return nullptr;
   } else {
-    return absl::make_unique<AuthorizationEngine>(rbac_policies);
+    return absl::make_unique<CelAuthorizationEngine>(rbac_policies);
   }
 }
 
-AuthorizationEngine::AuthorizationEngine(
+CelAuthorizationEngine::CelAuthorizationEngine(
     const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies) {
   for (const auto& rbac_policy : rbac_policies) {
     // Extract array of policies and store their condition fields in either
@@ -90,7 +90,7 @@
   }
 }
 
-std::unique_ptr<mock_cel::Activation> AuthorizationEngine::CreateActivation(
+std::unique_ptr<mock_cel::Activation> CelAuthorizationEngine::CreateActivation(
     const EvaluateArgs& args) {
   std::unique_ptr<mock_cel::Activation> activation;
   for (const auto& elem : envoy_attributes_) {
@@ -158,7 +158,7 @@
             kSpiffeId, mock_cel::CelValue::CreateStringView(spiffe_id));
       }
     } else if (elem == kCertServerName) {
-      absl::string_view cert_server_name(args.GetCertServerName());
+      absl::string_view cert_server_name(args.GetCommonName());
       if (!cert_server_name.empty()) {
         activation->InsertValue(
             kCertServerName,
diff --git a/grpc/src/core/lib/security/authorization/cel_authorization_engine.h b/grpc/src/core/lib/security/authorization/cel_authorization_engine.h
new file mode 100644
index 0000000..6f37bfb
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/cel_authorization_engine.h
@@ -0,0 +1,84 @@
+
+// Copyright 2020 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_LIB_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H
+#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/log.h>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/container/flat_hash_set.h"
+#include "envoy/config/rbac/v3/rbac.upb.h"
+#include "google/api/expr/v1alpha1/syntax.upb.h"
+#include "upb/upb.hpp"
+
+#include "src/core/lib/security/authorization/evaluate_args.h"
+#include "src/core/lib/security/authorization/mock_cel/activation.h"
+
+namespace grpc_core {
+
+// CelAuthorizationEngine makes an AuthorizationDecision to ALLOW or DENY the
+// current action based on the condition fields in provided RBAC policies.
+// The engine may be constructed with one or two policies. If two polcies,
+// the first policy is deny-if-matched and the second is allow-if-matched.
+// The engine returns UNDECIDED decision if it fails to find a match in any
+// policy. This engine ignores the principal and permission fields in RBAC
+// policies. It is the caller's responsibility to provide RBAC policies that
+// are compatible with this engine.
+//
+// Example:
+// CelAuthorizationEngine* engine =
+// CelAuthorizationEngine::CreateCelAuthorizationEngine(rbac_policies);
+// engine->Evaluate(evaluate_args); // returns authorization decision.
+class CelAuthorizationEngine {
+ public:
+  // rbac_policies must be a vector containing either a single policy of any
+  // kind, or one deny policy and one allow policy, in that order.
+  static std::unique_ptr<CelAuthorizationEngine> CreateCelAuthorizationEngine(
+      const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
+
+  // Users should use the CreateCelAuthorizationEngine factory function
+  // instead of calling the CelAuthorizationEngine constructor directly.
+  explicit CelAuthorizationEngine(
+      const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
+  // TODO(mywang@google.com): add an Evaluate member function.
+
+ private:
+  enum Action {
+    kAllow,
+    kDeny,
+  };
+
+  std::unique_ptr<mock_cel::Activation> CreateActivation(
+      const EvaluateArgs& args);
+
+  std::map<const std::string, const google_api_expr_v1alpha1_Expr*>
+      deny_if_matched_;
+  std::map<const std::string, const google_api_expr_v1alpha1_Expr*>
+      allow_if_matched_;
+  upb::Arena arena_;
+  absl::flat_hash_set<std::string> envoy_attributes_;
+  absl::flat_hash_set<std::string> header_keys_;
+  std::unique_ptr<mock_cel::CelMap> headers_;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H */
diff --git a/grpc/src/core/lib/security/authorization/evaluate_args.cc b/grpc/src/core/lib/security/authorization/evaluate_args.cc
index 6eaf106..12144df 100644
--- a/grpc/src/core/lib/security/authorization/evaluate_args.cc
+++ b/grpc/src/core/lib/security/authorization/evaluate_args.cc
@@ -1,6 +1,4 @@
-//
-//
-// Copyright 2020 gRPC authors.
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -13,20 +11,76 @@
 // 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>
 
 #include "src/core/lib/security/authorization/evaluate_args.h"
 
-#include "src/core/lib/iomgr/parse_address.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/slice/slice_utils.h"
 
 namespace grpc_core {
 
+namespace {
+
+absl::string_view GetAuthPropertyValue(grpc_auth_context* context,
+                                       const char* property_name) {
+  grpc_auth_property_iterator it =
+      grpc_auth_context_find_properties_by_name(context, property_name);
+  const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
+  if (prop == nullptr) {
+    gpr_log(GPR_DEBUG, "No value found for %s property.", property_name);
+    return "";
+  }
+  if (grpc_auth_property_iterator_next(&it) != nullptr) {
+    gpr_log(GPR_DEBUG, "Multiple values found for %s property.", property_name);
+    return "";
+  }
+  return absl::string_view(prop->value, prop->value_length);
+}
+
+void ParseEndpointUri(absl::string_view uri_text, std::string* address,
+                      int* port) {
+  absl::StatusOr<URI> uri = URI::Parse(uri_text);
+  if (!uri.ok()) {
+    gpr_log(GPR_DEBUG, "Failed to parse uri.");
+    return;
+  }
+  absl::string_view host_view;
+  absl::string_view port_view;
+  if (!SplitHostPort(uri->path(), &host_view, &port_view)) {
+    gpr_log(GPR_DEBUG, "Failed to split %s into host and port.",
+            uri->path().c_str());
+    return;
+  }
+  *address = std::string(host_view);
+  if (!absl::SimpleAtoi(port_view, port)) {
+    gpr_log(GPR_DEBUG, "Port %s is out of range or null.",
+            std::string(port_view).c_str());
+  }
+}
+
+}  // namespace
+
+EvaluateArgs::PerChannelArgs::PerChannelArgs(grpc_auth_context* auth_context,
+                                             grpc_endpoint* endpoint) {
+  if (auth_context != nullptr) {
+    transport_security_type = GetAuthPropertyValue(
+        auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME);
+    spiffe_id =
+        GetAuthPropertyValue(auth_context, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME);
+    common_name =
+        GetAuthPropertyValue(auth_context, GRPC_X509_CN_PROPERTY_NAME);
+  }
+  if (endpoint != nullptr) {
+    ParseEndpointUri(grpc_endpoint_get_local_address(endpoint), &local_address,
+                     &local_port);
+    ParseEndpointUri(grpc_endpoint_get_peer(endpoint), &peer_address,
+                     &peer_port);
+  }
+}
+
 absl::string_view EvaluateArgs::GetPath() const {
   absl::string_view path;
   if (metadata_ != nullptr && metadata_->idx.named.path != nullptr) {
@@ -72,77 +126,61 @@
   return headers;
 }
 
-absl::string_view EvaluateArgs::GetLocalAddress() const {
-  absl::string_view addr = grpc_endpoint_get_local_address(endpoint_);
-  size_t first_colon = addr.find(":");
-  size_t last_colon = addr.rfind(":");
-  if (first_colon == std::string::npos || last_colon == std::string::npos) {
-    return "";
-  } else {
-    return addr.substr(first_colon + 1, last_colon - first_colon - 1);
+absl::optional<absl::string_view> EvaluateArgs::GetHeaderValue(
+    absl::string_view key, std::string* concatenated_value) const {
+  if (metadata_ == nullptr) {
+    return absl::nullopt;
   }
+  return grpc_metadata_batch_get_value(metadata_, key, concatenated_value);
+}
+
+absl::string_view EvaluateArgs::GetLocalAddress() const {
+  if (channel_args_ == nullptr) {
+    return "";
+  }
+  return channel_args_->local_address;
 }
 
 int EvaluateArgs::GetLocalPort() const {
-  if (endpoint_ == nullptr) {
+  if (channel_args_ == nullptr) {
     return 0;
   }
-  absl::StatusOr<URI> uri =
-      URI::Parse(grpc_endpoint_get_local_address(endpoint_));
-  grpc_resolved_address resolved_addr;
-  if (!uri.ok() || !grpc_parse_uri(*uri, &resolved_addr)) {
-    return 0;
-  }
-  return grpc_sockaddr_get_port(&resolved_addr);
+  return channel_args_->local_port;
 }
 
 absl::string_view EvaluateArgs::GetPeerAddress() const {
-  absl::string_view addr = grpc_endpoint_get_peer(endpoint_);
-  size_t first_colon = addr.find(":");
-  size_t last_colon = addr.rfind(":");
-  if (first_colon == std::string::npos || last_colon == std::string::npos) {
+  if (channel_args_ == nullptr) {
     return "";
-  } else {
-    return addr.substr(first_colon + 1, last_colon - first_colon - 1);
   }
+  return channel_args_->peer_address;
 }
 
 int EvaluateArgs::GetPeerPort() const {
-  if (endpoint_ == nullptr) {
+  if (channel_args_ == nullptr) {
     return 0;
   }
-  absl::StatusOr<URI> uri = URI::Parse(grpc_endpoint_get_peer(endpoint_));
-  grpc_resolved_address resolved_addr;
-  if (!uri.ok() || !grpc_parse_uri(*uri, &resolved_addr)) {
-    return 0;
+  return channel_args_->peer_port;
+}
+
+absl::string_view EvaluateArgs::GetTransportSecurityType() const {
+  if (channel_args_ == nullptr) {
+    return "";
   }
-  return grpc_sockaddr_get_port(&resolved_addr);
+  return channel_args_->transport_security_type;
 }
 
 absl::string_view EvaluateArgs::GetSpiffeId() const {
-  if (auth_context_ == nullptr) {
+  if (channel_args_ == nullptr) {
     return "";
   }
-  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
-      auth_context_, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME);
-  const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
-  if (prop == nullptr || grpc_auth_property_iterator_next(&it) != nullptr) {
-    return "";
-  }
-  return absl::string_view(prop->value, prop->value_length);
+  return channel_args_->spiffe_id;
 }
 
-absl::string_view EvaluateArgs::GetCertServerName() const {
-  if (auth_context_ == nullptr) {
+absl::string_view EvaluateArgs::GetCommonName() const {
+  if (channel_args_ == nullptr) {
     return "";
   }
-  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
-      auth_context_, GRPC_X509_CN_PROPERTY_NAME);
-  const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
-  if (prop == nullptr || grpc_auth_property_iterator_next(&it) != nullptr) {
-    return "";
-  }
-  return absl::string_view(prop->value, prop->value_length);
+  return channel_args_->common_name;
 }
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/authorization/evaluate_args.h b/grpc/src/core/lib/security/authorization/evaluate_args.h
index 14e25bc..b3ac93c 100644
--- a/grpc/src/core/lib/security/authorization/evaluate_args.h
+++ b/grpc/src/core/lib/security/authorization/evaluate_args.h
@@ -1,6 +1,4 @@
-//
-//
-// Copyright 2020 gRPC authors.
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -13,8 +11,6 @@
 // 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_LIB_SECURITY_AUTHORIZATION_EVALUATE_ARGS_H
 #define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_EVALUATE_ARGS_H
@@ -23,6 +19,8 @@
 
 #include <map>
 
+#include "absl/types/optional.h"
+
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/transport/metadata_batch.h"
@@ -31,27 +29,48 @@
 
 class EvaluateArgs {
  public:
-  EvaluateArgs(grpc_metadata_batch* metadata, grpc_auth_context* auth_context,
-               grpc_endpoint* endpoint)
-      : metadata_(metadata), auth_context_(auth_context), endpoint_(endpoint) {}
+  // Caller is responsible for ensuring auth_context outlives PerChannelArgs
+  // struct.
+  struct PerChannelArgs {
+    PerChannelArgs(grpc_auth_context* auth_context, grpc_endpoint* endpoint);
+
+    absl::string_view transport_security_type;
+    absl::string_view spiffe_id;
+    absl::string_view common_name;
+    std::string local_address;
+    int local_port = 0;
+    std::string peer_address;
+    int peer_port = 0;
+  };
+
+  EvaluateArgs(grpc_metadata_batch* metadata, PerChannelArgs* channel_args)
+      : metadata_(metadata), channel_args_(channel_args) {}
 
   absl::string_view GetPath() const;
   absl::string_view GetHost() const;
   absl::string_view GetMethod() const;
   std::multimap<absl::string_view, absl::string_view> GetHeaders() const;
+  // Returns metadata value(s) for the specified key.
+  // If the key is not present in the batch, returns absl::nullopt.
+  // If the key is present exactly once in the batch, returns a string_view of
+  // that value.
+  // If the key is present more than once in the batch, constructs a
+  // comma-concatenated string of all values in concatenated_value and returns a
+  // string_view of that string.
+  absl::optional<absl::string_view> GetHeaderValue(
+      absl::string_view key, std::string* concatenated_value) const;
+
   absl::string_view GetLocalAddress() const;
   int GetLocalPort() const;
   absl::string_view GetPeerAddress() const;
   int GetPeerPort() const;
+  absl::string_view GetTransportSecurityType() const;
   absl::string_view GetSpiffeId() const;
-  absl::string_view GetCertServerName() const;
-
-  // TODO(unknown): Add a getter function for source.principal
+  absl::string_view GetCommonName() const;
 
  private:
   grpc_metadata_batch* metadata_;
-  grpc_auth_context* auth_context_;
-  grpc_endpoint* endpoint_;
+  PerChannelArgs* channel_args_;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/authorization/grpc_authorization_engine.cc b/grpc/src/core/lib/security/authorization/grpc_authorization_engine.cc
new file mode 100644
index 0000000..34fc976
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/grpc_authorization_engine.cc
@@ -0,0 +1,49 @@
+// Copyright 2021 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>
+
+#include "src/core/lib/security/authorization/grpc_authorization_engine.h"
+
+namespace grpc_core {
+
+GrpcAuthorizationEngine::GrpcAuthorizationEngine(Rbac policy)
+    : action_(policy.action) {
+  for (auto& sub_policy : policy.policies) {
+    Policy policy;
+    policy.name = sub_policy.first;
+    policy.matcher = absl::make_unique<PolicyAuthorizationMatcher>(
+        std::move(sub_policy.second));
+    policies_.push_back(std::move(policy));
+  }
+}
+
+AuthorizationEngine::Decision GrpcAuthorizationEngine::Evaluate(
+    const EvaluateArgs& args) const {
+  Decision decision;
+  bool matches = false;
+  for (const auto& policy : policies_) {
+    if (policy.matcher->Matches(args)) {
+      matches = true;
+      decision.matching_policy_name = policy.name;
+      break;
+    }
+  }
+  decision.type = (matches == (action_ == Rbac::Action::kAllow))
+                      ? Decision::Type::kAllow
+                      : Decision::Type::kDeny;
+  return decision;
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/authorization/grpc_authorization_engine.h b/grpc/src/core/lib/security/authorization/grpc_authorization_engine.h
new file mode 100644
index 0000000..5b7791a
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/grpc_authorization_engine.h
@@ -0,0 +1,55 @@
+// Copyright 2021 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_LIB_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H
+#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/authorization/authorization_engine.h"
+#include "src/core/lib/security/authorization/matchers.h"
+#include "src/core/lib/security/authorization/rbac_policy.h"
+
+namespace grpc_core {
+
+// GrpcAuthorizationEngine can be either an Allow engine or Deny engine. This
+// engine makes authorization decisions to Allow or Deny incoming RPC request
+// based on permission and principal configs in the provided RBAC policy and the
+// engine type. This engine ignores condition field in RBAC config. It is the
+// caller's responsibility to provide RBAC policies that are compatible with
+// this engine.
+class GrpcAuthorizationEngine : public AuthorizationEngine {
+ public:
+  // Builds GrpcAuthorizationEngine without any policies.
+  explicit GrpcAuthorizationEngine(Rbac::Action action) : action_(action) {}
+  // Builds GrpcAuthorizationEngine with allow/deny RBAC policy.
+  explicit GrpcAuthorizationEngine(Rbac policy);
+
+  // Evaluates incoming request against RBAC policy and makes a decision to
+  // whether allow/deny this request.
+  Decision Evaluate(const EvaluateArgs& args) const override;
+
+ private:
+  struct Policy {
+    std::string name;
+    std::unique_ptr<AuthorizationMatcher> matcher;
+  };
+
+  Rbac::Action action_;
+  std::vector<Policy> policies_;
+};
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H
diff --git a/grpc/src/core/lib/security/authorization/matchers.cc b/grpc/src/core/lib/security/authorization/matchers.cc
new file mode 100644
index 0000000..5613b74
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/matchers.cc
@@ -0,0 +1,202 @@
+// Copyright 2021 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>
+
+#include "src/core/lib/security/authorization/matchers.h"
+
+namespace grpc_core {
+
+namespace {
+
+bool AuthenticatedMatchesHelper(const EvaluateArgs& args,
+                                const StringMatcher& matcher) {
+  if (args.GetTransportSecurityType() != GRPC_SSL_TRANSPORT_SECURITY_TYPE) {
+    // Connection is not authenticated.
+    return false;
+  }
+  if (matcher.string_matcher().empty()) {
+    // Allows any authenticated user.
+    return true;
+  }
+  absl::string_view spiffe_id = args.GetSpiffeId();
+  if (!spiffe_id.empty()) {
+    return matcher.Match(spiffe_id);
+  }
+  // TODO(ashithasantosh): Check principal matches DNS SAN, followed by Subject
+  // field from certificate. This requires updating tsi_peer to expose these
+  // fields.
+  return false;
+}
+
+}  // namespace
+
+std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
+    Rbac::Permission permission) {
+  switch (permission.type) {
+    case Rbac::Permission::RuleType::kAnd:
+      return absl::make_unique<AndAuthorizationMatcher>(
+          std::move(permission.permissions), permission.not_rule);
+    case Rbac::Permission::RuleType::kOr:
+      return absl::make_unique<OrAuthorizationMatcher>(
+          std::move(permission.permissions), permission.not_rule);
+    case Rbac::Permission::RuleType::kAny:
+      return absl::make_unique<AlwaysAuthorizationMatcher>(permission.not_rule);
+    case Rbac::Permission::RuleType::kHeader:
+      return absl::make_unique<HeaderAuthorizationMatcher>(
+          std::move(permission.header_matcher), permission.not_rule);
+    case Rbac::Permission::RuleType::kPath:
+      return absl::make_unique<PathAuthorizationMatcher>(
+          std::move(permission.string_matcher), permission.not_rule);
+    case Rbac::Permission::RuleType::kDestIp:
+      return absl::make_unique<IpAuthorizationMatcher>(std::move(permission.ip),
+                                                       permission.not_rule);
+    case Rbac::Permission::RuleType::kDestPort:
+      return absl::make_unique<PortAuthorizationMatcher>(permission.port,
+                                                         permission.not_rule);
+    case Rbac::Permission::RuleType::kReqServerName:
+      return absl::make_unique<ReqServerNameAuthorizationMatcher>(
+          std::move(permission.string_matcher), permission.not_rule);
+  }
+  return nullptr;
+}
+
+std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
+    Rbac::Principal principal) {
+  switch (principal.type) {
+    case Rbac::Principal::RuleType::kAnd:
+      return absl::make_unique<AndAuthorizationMatcher>(
+          std::move(principal.principals), principal.not_rule);
+    case Rbac::Principal::RuleType::kOr:
+      return absl::make_unique<OrAuthorizationMatcher>(
+          std::move(principal.principals), principal.not_rule);
+    case Rbac::Principal::RuleType::kAny:
+      return absl::make_unique<AlwaysAuthorizationMatcher>(principal.not_rule);
+    case Rbac::Principal::RuleType::kPrincipalName:
+      return absl::make_unique<AuthenticatedAuthorizationMatcher>(
+          std::move(principal.string_matcher), principal.not_rule);
+    case Rbac::Principal::RuleType::kSourceIp:
+    case Rbac::Principal::RuleType::kDirectRemoteIp:
+    case Rbac::Principal::RuleType::kRemoteIp:
+      return absl::make_unique<IpAuthorizationMatcher>(std::move(principal.ip),
+                                                       principal.not_rule);
+    case Rbac::Principal::RuleType::kHeader:
+      return absl::make_unique<HeaderAuthorizationMatcher>(
+          std::move(principal.header_matcher), principal.not_rule);
+    case Rbac::Principal::RuleType::kPath:
+      return absl::make_unique<PathAuthorizationMatcher>(
+          std::move(principal.string_matcher), principal.not_rule);
+  }
+  return nullptr;
+}
+
+AndAuthorizationMatcher::AndAuthorizationMatcher(
+    std::vector<std::unique_ptr<Rbac::Permission>> rules, bool not_rule)
+    : not_rule_(not_rule) {
+  for (auto& rule : rules) {
+    matchers_.push_back(AuthorizationMatcher::Create(std::move(*rule)));
+  }
+}
+
+AndAuthorizationMatcher::AndAuthorizationMatcher(
+    std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule)
+    : not_rule_(not_rule) {
+  for (const auto& id : ids) {
+    matchers_.push_back(AuthorizationMatcher::Create(std::move(*id)));
+  }
+}
+
+bool AndAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  bool matches = true;
+  for (const auto& matcher : matchers_) {
+    if (!matcher->Matches(args)) {
+      matches = false;
+      break;
+    }
+  }
+  return matches != not_rule_;
+}
+
+OrAuthorizationMatcher::OrAuthorizationMatcher(
+    std::vector<std::unique_ptr<Rbac::Permission>> rules, bool not_rule)
+    : not_rule_(not_rule) {
+  for (const auto& rule : rules) {
+    matchers_.push_back(AuthorizationMatcher::Create(std::move(*rule)));
+  }
+}
+
+OrAuthorizationMatcher::OrAuthorizationMatcher(
+    std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule)
+    : not_rule_(not_rule) {
+  for (const auto& id : ids) {
+    matchers_.push_back(AuthorizationMatcher::Create(std::move(*id)));
+  }
+}
+
+bool OrAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  bool matches = false;
+  for (const auto& matcher : matchers_) {
+    if (matcher->Matches(args)) {
+      matches = true;
+      break;
+    }
+  }
+  return matches != not_rule_;
+}
+
+bool HeaderAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  std::string concatenated_value;
+  bool matches =
+      matcher_.Match(args.GetHeaderValue(matcher_.name(), &concatenated_value));
+  return matches != not_rule_;
+}
+
+// TODO(ashithasantosh): Implement IpAuthorizationMatcher::Matches.
+bool IpAuthorizationMatcher::Matches(const EvaluateArgs&) const {
+  bool matches = false;
+  return matches != not_rule_;
+}
+
+bool PortAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  bool matches = (port_ == args.GetLocalPort());
+  return matches != not_rule_;
+}
+
+bool AuthenticatedAuthorizationMatcher::Matches(
+    const EvaluateArgs& args) const {
+  bool matches = AuthenticatedMatchesHelper(args, matcher_);
+  return matches != not_rule_;
+}
+
+bool ReqServerNameAuthorizationMatcher::Matches(const EvaluateArgs&) const {
+  // Currently we do not support matching rules containing
+  // "requested_server_name".
+  bool matches = false;
+  return matches != not_rule_;
+}
+
+bool PathAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  bool matches = false;
+  absl::string_view path = args.GetPath();
+  if (!path.empty()) {
+    matches = matcher_.Match(path);
+  }
+  return matches != not_rule_;
+}
+
+bool PolicyAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
+  return permissions_->Matches(args) && principals_->Matches(args);
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/authorization/matchers.h b/grpc/src/core/lib/security/authorization/matchers.h
new file mode 100644
index 0000000..86b40ee
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/matchers.h
@@ -0,0 +1,206 @@
+// Copyright 2021 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_LIB_SECURITY_AUTHORIZATION_MATCHERS_H
+#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <memory>
+
+#include "src/core/lib/matchers/matchers.h"
+#include "src/core/lib/security/authorization/evaluate_args.h"
+#include "src/core/lib/security/authorization/rbac_policy.h"
+
+namespace grpc_core {
+
+// Describes the rules for matching permission or principal.
+class AuthorizationMatcher {
+ public:
+  virtual ~AuthorizationMatcher() = default;
+
+  // Returns whether or not the permission/principal matches the rules of the
+  // matcher.
+  virtual bool Matches(const EvaluateArgs& args) const = 0;
+
+  // Creates an instance of a matcher based off the rules defined in Permission
+  // config.
+  static std::unique_ptr<AuthorizationMatcher> Create(
+      Rbac::Permission permission);
+
+  // Creates an instance of a matcher based off the rules defined in Principal
+  // config.
+  static std::unique_ptr<AuthorizationMatcher> Create(
+      Rbac::Principal principal);
+};
+
+class AlwaysAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit AlwaysAuthorizationMatcher(bool not_rule = false)
+      : not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs&) const override { return !not_rule_; }
+
+ private:
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+class AndAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit AndAuthorizationMatcher(
+      std::vector<std::unique_ptr<Rbac::Permission>> rules,
+      bool not_rule = false);
+  explicit AndAuthorizationMatcher(
+      std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule = false);
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  std::vector<std::unique_ptr<AuthorizationMatcher>> matchers_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+class OrAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit OrAuthorizationMatcher(
+      std::vector<std::unique_ptr<Rbac::Permission>> rules,
+      bool not_rule = false);
+  explicit OrAuthorizationMatcher(
+      std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule = false);
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  std::vector<std::unique_ptr<AuthorizationMatcher>> matchers_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// TODO(ashithasantosh): Add matcher implementation for metadata field.
+
+// Perform a match against HTTP headers.
+class HeaderAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit HeaderAuthorizationMatcher(HeaderMatcher matcher,
+                                      bool not_rule = false)
+      : matcher_(std::move(matcher)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  const HeaderMatcher matcher_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Perform a match against IP Cidr Range.
+// TODO(ashithasantosh): Handle type of Ip or use seperate matchers for each
+// type. Implement Match functionality, this would require updating EvaluateArgs
+// getters, to return format of IP as well.
+class IpAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit IpAuthorizationMatcher(Rbac::CidrRange range, bool not_rule = false)
+      : range_(std::move(range)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs&) const override;
+
+ private:
+  const Rbac::CidrRange range_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Perform a match against port number of the destination (local) address.
+class PortAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit PortAuthorizationMatcher(int port, bool not_rule = false)
+      : port_(port), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  const int port_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Matches the principal name as described in the peer certificate. Uses URI SAN
+// or DNS SAN in that order, otherwise uses subject field.
+class AuthenticatedAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit AuthenticatedAuthorizationMatcher(StringMatcher auth,
+                                             bool not_rule = false)
+      : matcher_(std::move(auth)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  const StringMatcher matcher_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Perform a match against the request server from the client's connection
+// request. This is typically TLS SNI. Currently unsupported.
+class ReqServerNameAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit ReqServerNameAuthorizationMatcher(
+      StringMatcher requested_server_name, bool not_rule = false)
+      : matcher_(std::move(requested_server_name)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs&) const override;
+
+ private:
+  const StringMatcher matcher_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Perform a match against the path header of HTTP request.
+class PathAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit PathAuthorizationMatcher(StringMatcher path, bool not_rule = false)
+      : matcher_(std::move(path)), not_rule_(not_rule) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  const StringMatcher matcher_;
+  // Negates matching the provided permission/principal.
+  const bool not_rule_;
+};
+
+// Performs a match for policy field in RBAC, which is a collection of
+// permission and principal matchers. Policy matches iff, we find a match in one
+// of its permissions and a match in one of its principals.
+class PolicyAuthorizationMatcher : public AuthorizationMatcher {
+ public:
+  explicit PolicyAuthorizationMatcher(Rbac::Policy policy)
+      : permissions_(
+            AuthorizationMatcher::Create(std::move(policy.permissions))),
+        principals_(
+            AuthorizationMatcher::Create(std::move(policy.principals))) {}
+
+  bool Matches(const EvaluateArgs& args) const override;
+
+ private:
+  std::unique_ptr<AuthorizationMatcher> permissions_;
+  std::unique_ptr<AuthorizationMatcher> principals_;
+};
+
+}  // namespace grpc_core
+
+#endif  // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H
diff --git a/grpc/src/core/lib/security/authorization/mock_cel/activation.h b/grpc/src/core/lib/security/authorization/mock_cel/activation.h
index 693ed4d..0e6eed1 100644
--- a/grpc/src/core/lib/security/authorization/mock_cel/activation.h
+++ b/grpc/src/core/lib/security/authorization/mock_cel/activation.h
@@ -48,7 +48,7 @@
   Activation& operator=(const Activation&) = delete;
 
   // Insert value into Activation.
-  void InsertValue(absl::string_view name, const CelValue& value) {}
+  void InsertValue(absl::string_view /*name*/, const CelValue& /*value*/) {}
 };
 
 }  // namespace mock_cel
diff --git a/grpc/src/core/lib/security/authorization/mock_cel/cel_value.h b/grpc/src/core/lib/security/authorization/mock_cel/cel_value.h
index d037727..22d2324 100644
--- a/grpc/src/core/lib/security/authorization/mock_cel/cel_value.h
+++ b/grpc/src/core/lib/security/authorization/mock_cel/cel_value.h
@@ -61,23 +61,25 @@
   // We rely on copy elision to avoid extra copying.
   static CelValue CreateNull() { return CelValue(nullptr); }
 
-  static CelValue CreateInt64(int64_t value) { return CreateNull(); }
+  static CelValue CreateInt64(int64_t /*value*/) { return CreateNull(); }
 
-  static CelValue CreateUint64(uint64_t value) { return CreateNull(); }
+  static CelValue CreateUint64(uint64_t /*value*/) { return CreateNull(); }
 
-  static CelValue CreateStringView(absl::string_view value) {
+  static CelValue CreateStringView(absl::string_view /*value*/) {
     return CreateNull();
   }
 
-  static CelValue CreateString(const std::string* str) { return CreateNull(); }
+  static CelValue CreateString(const std::string* /*str*/) {
+    return CreateNull();
+  }
 
-  static CelValue CreateMap(const CelMap* value) { return CreateNull(); }
+  static CelValue CreateMap(const CelMap* /*value*/) { return CreateNull(); }
 
  private:
   // Constructs CelValue wrapping value supplied as argument.
   // Value type T should be supported by specification of ValueHolder.
   template <class T>
-  explicit CelValue(T value) {}
+  explicit CelValue(T /*value*/) {}
 };
 
 // CelMap implementation that uses STL map container as backing storage.
@@ -86,7 +88,7 @@
   ContainerBackedMapImpl() = default;
 
   static std::unique_ptr<CelMap> Create(
-      absl::Span<std::pair<CelValue, CelValue>> key_values) {
+      absl::Span<std::pair<CelValue, CelValue>> /*key_values*/) {
     return absl::make_unique<ContainerBackedMapImpl>();
   }
 };
diff --git a/grpc/src/core/lib/security/authorization/rbac_policy.cc b/grpc/src/core/lib/security/authorization/rbac_policy.cc
new file mode 100644
index 0000000..a081c51
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/rbac_policy.cc
@@ -0,0 +1,328 @@
+// Copyright 2021 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>
+
+#include "src/core/lib/security/authorization/rbac_policy.h"
+
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+
+namespace grpc_core {
+
+//
+// Rbac
+//
+
+Rbac::Rbac(Rbac::Action action, std::map<std::string, Policy> policies)
+    : action(action), policies(std::move(policies)) {}
+
+Rbac::Rbac(Rbac&& other) noexcept
+    : action(other.action), policies(std::move(other.policies)) {}
+
+Rbac& Rbac::operator=(Rbac&& other) noexcept {
+  action = other.action;
+  policies = std::move(other.policies);
+  return *this;
+}
+
+std::string Rbac::ToString() const {
+  std::vector<std::string> contents;
+  contents.push_back(absl::StrFormat(
+      "Rbac action=%s{", action == Rbac::Action::kAllow ? "Allow" : "Deny"));
+  for (const auto& p : policies) {
+    contents.push_back(absl::StrFormat("{\n  policy_name=%s\n%s\n}", p.first,
+                                       p.second.ToString()));
+  }
+  contents.push_back("}");
+  return absl::StrJoin(contents, "\n");
+}
+
+//
+// CidrRange
+//
+
+Rbac::CidrRange::CidrRange(std::string address_prefix, uint32_t prefix_len)
+    : address_prefix(std::move(address_prefix)), prefix_len(prefix_len) {}
+
+Rbac::CidrRange::CidrRange(Rbac::CidrRange&& other) noexcept
+    : address_prefix(std::move(other.address_prefix)),
+      prefix_len(other.prefix_len) {}
+
+Rbac::CidrRange& Rbac::CidrRange::operator=(Rbac::CidrRange&& other) noexcept {
+  address_prefix = std::move(other.address_prefix);
+  prefix_len = other.prefix_len;
+  return *this;
+}
+
+std::string Rbac::CidrRange::ToString() const {
+  return absl::StrFormat("CidrRange{address_prefix=%s,prefix_len=%d}",
+                         address_prefix, prefix_len);
+}
+
+//
+// Permission
+//
+
+Rbac::Permission::Permission(
+    Permission::RuleType type,
+    std::vector<std::unique_ptr<Permission>> permissions, bool not_rule)
+    : type(type), permissions(std::move(permissions)), not_rule(not_rule) {}
+Rbac::Permission::Permission(Permission::RuleType type, bool not_rule)
+    : type(type), not_rule(not_rule) {}
+Rbac::Permission::Permission(Permission::RuleType type,
+                             HeaderMatcher header_matcher, bool not_rule)
+    : type(type),
+      header_matcher(std::move(header_matcher)),
+      not_rule(not_rule) {}
+Rbac::Permission::Permission(Permission::RuleType type,
+                             StringMatcher string_matcher, bool not_rule)
+    : type(type),
+      string_matcher(std::move(string_matcher)),
+      not_rule(not_rule) {}
+Rbac::Permission::Permission(Permission::RuleType type, CidrRange ip,
+                             bool not_rule)
+    : type(type), ip(std::move(ip)), not_rule(not_rule) {}
+Rbac::Permission::Permission(Permission::RuleType type, int port, bool not_rule)
+    : type(type), port(port), not_rule(not_rule) {}
+
+Rbac::Permission::Permission(Rbac::Permission&& other) noexcept
+    : type(other.type), not_rule(other.not_rule) {
+  switch (type) {
+    case RuleType::kAnd:
+    case RuleType::kOr:
+      permissions = std::move(other.permissions);
+      break;
+    case RuleType::kAny:
+      break;
+    case RuleType::kHeader:
+      header_matcher = std::move(other.header_matcher);
+      break;
+    case RuleType::kPath:
+    case RuleType::kReqServerName:
+      string_matcher = std::move(other.string_matcher);
+      break;
+    case RuleType::kDestIp:
+      ip = std::move(other.ip);
+      break;
+    default:
+      port = other.port;
+  }
+}
+
+Rbac::Permission& Rbac::Permission::operator=(
+    Rbac::Permission&& other) noexcept {
+  type = other.type;
+  not_rule = other.not_rule;
+  switch (type) {
+    case RuleType::kAnd:
+    case RuleType::kOr:
+      permissions = std::move(other.permissions);
+      break;
+    case RuleType::kAny:
+      break;
+    case RuleType::kHeader:
+      header_matcher = std::move(other.header_matcher);
+      break;
+    case RuleType::kPath:
+    case RuleType::kReqServerName:
+      string_matcher = std::move(other.string_matcher);
+      break;
+    case RuleType::kDestIp:
+      ip = std::move(other.ip);
+      break;
+    default:
+      port = other.port;
+  }
+  return *this;
+}
+
+std::string Rbac::Permission::ToString() const {
+  switch (type) {
+    case RuleType::kAnd: {
+      std::vector<std::string> contents;
+      contents.reserve(permissions.size());
+      for (const auto& permission : permissions) {
+        contents.push_back(permission->ToString());
+      }
+      return absl::StrFormat("%sand=[%s]", not_rule ? "not " : "",
+                             absl::StrJoin(contents, ","));
+    }
+    case RuleType::kOr: {
+      std::vector<std::string> contents;
+      contents.reserve(permissions.size());
+      for (const auto& permission : permissions) {
+        contents.push_back(permission->ToString());
+      }
+      return absl::StrFormat("%sor=[%s]", not_rule ? "not " : "",
+                             absl::StrJoin(contents, ","));
+    }
+    case RuleType::kAny:
+      return absl::StrFormat("%sany", not_rule ? "not " : "");
+    case RuleType::kHeader:
+      return absl::StrFormat("%sheader=%s", not_rule ? "not " : "",
+                             header_matcher.ToString());
+    case RuleType::kPath:
+      return absl::StrFormat("%spath=%s", not_rule ? "not " : "",
+                             string_matcher.ToString());
+    case RuleType::kDestIp:
+      return absl::StrFormat("%sdest_ip=%s", not_rule ? "not " : "",
+                             ip.ToString());
+    case RuleType::kDestPort:
+      return absl::StrFormat("%sdest_port=%d", not_rule ? "not " : "", port);
+    case RuleType::kReqServerName:
+      return absl::StrFormat("%srequested_server_name=%s",
+                             not_rule ? "not " : "", string_matcher.ToString());
+    default:
+      return "";
+  }
+}
+
+//
+// Principal
+//
+
+Rbac::Principal::Principal(Principal::RuleType type,
+                           std::vector<std::unique_ptr<Principal>> principals,
+                           bool not_rule)
+    : type(type), principals(std::move(principals)), not_rule(not_rule) {}
+Rbac::Principal::Principal(Principal::RuleType type, bool not_rule)
+    : type(type), not_rule(not_rule) {}
+Rbac::Principal::Principal(Principal::RuleType type,
+                           StringMatcher string_matcher, bool not_rule)
+    : type(type),
+      string_matcher(std::move(string_matcher)),
+      not_rule(not_rule) {}
+Rbac::Principal::Principal(Principal::RuleType type, CidrRange ip,
+                           bool not_rule)
+    : type(type), ip(std::move(ip)), not_rule(not_rule) {}
+Rbac::Principal::Principal(Principal::RuleType type,
+                           HeaderMatcher header_matcher, bool not_rule)
+    : type(type),
+      header_matcher(std::move(header_matcher)),
+      not_rule(not_rule) {}
+
+Rbac::Principal::Principal(Rbac::Principal&& other) noexcept
+    : type(other.type), not_rule(other.not_rule) {
+  switch (type) {
+    case RuleType::kAnd:
+    case RuleType::kOr:
+      principals = std::move(other.principals);
+      break;
+    case RuleType::kAny:
+      break;
+    case RuleType::kHeader:
+      header_matcher = std::move(other.header_matcher);
+      break;
+    case RuleType::kPrincipalName:
+    case RuleType::kPath:
+      string_matcher = std::move(other.string_matcher);
+      break;
+    default:
+      ip = std::move(other.ip);
+  }
+}
+
+Rbac::Principal& Rbac::Principal::operator=(Rbac::Principal&& other) noexcept {
+  type = other.type;
+  not_rule = other.not_rule;
+  switch (type) {
+    case RuleType::kAnd:
+    case RuleType::kOr:
+      principals = std::move(other.principals);
+      break;
+    case RuleType::kAny:
+      break;
+    case RuleType::kHeader:
+      header_matcher = std::move(other.header_matcher);
+      break;
+    case RuleType::kPrincipalName:
+    case RuleType::kPath:
+      string_matcher = std::move(other.string_matcher);
+      break;
+    default:
+      ip = std::move(other.ip);
+  }
+  return *this;
+}
+
+std::string Rbac::Principal::ToString() const {
+  switch (type) {
+    case RuleType::kAnd: {
+      std::vector<std::string> contents;
+      contents.reserve(principals.size());
+      for (const auto& principal : principals) {
+        contents.push_back(principal->ToString());
+      }
+      return absl::StrFormat("%sand=[%s]", not_rule ? "not " : "",
+                             absl::StrJoin(contents, ","));
+    }
+    case RuleType::kOr: {
+      std::vector<std::string> contents;
+      contents.reserve(principals.size());
+      for (const auto& principal : principals) {
+        contents.push_back(principal->ToString());
+      }
+      return absl::StrFormat("%sor=[%s]", not_rule ? "not " : "",
+                             absl::StrJoin(contents, ","));
+    }
+    case RuleType::kAny:
+      return absl::StrFormat("%sany", not_rule ? "not " : "");
+    case RuleType::kPrincipalName:
+      return absl::StrFormat("%sprincipal_name=%s", not_rule ? "not " : "",
+                             string_matcher.ToString());
+    case RuleType::kSourceIp:
+      return absl::StrFormat("%ssource_ip=%s", not_rule ? "not " : "",
+                             ip.ToString());
+    case RuleType::kDirectRemoteIp:
+      return absl::StrFormat("%sdirect_remote_ip=%s", not_rule ? "not " : "",
+                             ip.ToString());
+    case RuleType::kRemoteIp:
+      return absl::StrFormat("%sremote_ip=%s", not_rule ? "not " : "",
+                             ip.ToString());
+    case RuleType::kHeader:
+      return absl::StrFormat("%sheader=%s", not_rule ? "not " : "",
+                             header_matcher.ToString());
+    case RuleType::kPath:
+      return absl::StrFormat("%spath=%s", not_rule ? "not " : "",
+                             string_matcher.ToString());
+    default:
+      return "";
+  }
+}
+
+//
+// Policy
+//
+
+Rbac::Policy::Policy(Permission permissions, Principal principals)
+    : permissions(std::move(permissions)), principals(std::move(principals)) {}
+
+Rbac::Policy::Policy(Rbac::Policy&& other) noexcept
+    : permissions(std::move(other.permissions)),
+      principals(std::move(other.principals)) {}
+
+Rbac::Policy& Rbac::Policy::operator=(Rbac::Policy&& other) noexcept {
+  permissions = std::move(other.permissions);
+  principals = std::move(other.principals);
+  return *this;
+}
+
+std::string Rbac::Policy::ToString() const {
+  return absl::StrFormat(
+      "  Policy  {\n    Permissions{%s}\n    Principals{%s}\n  }",
+      permissions.ToString(), principals.ToString());
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/authorization/rbac_policy.h b/grpc/src/core/lib/security/authorization/rbac_policy.h
new file mode 100644
index 0000000..027bf92
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/rbac_policy.h
@@ -0,0 +1,163 @@
+// Copyright 2021 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_LIB_SECURITY_AUTHORIZATION_RBAC_POLICY_H
+#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_POLICY_H
+
+#include <grpc/support/port_platform.h>
+
+#include <memory>
+
+#include "src/core/lib/matchers/matchers.h"
+
+namespace grpc_core {
+
+// Represents Envoy RBAC Proto. [See
+// https://github.com/envoyproxy/envoy/blob/release/v1.17/api/envoy/config/rbac/v3/rbac.proto]
+struct Rbac {
+  enum class Action {
+    kAllow,
+    kDeny,
+  };
+
+  struct CidrRange {
+    CidrRange() = default;
+    CidrRange(std::string address_prefix, uint32_t prefix_len);
+
+    CidrRange(CidrRange&& other) noexcept;
+    CidrRange& operator=(CidrRange&& other) noexcept;
+
+    std::string ToString() const;
+
+    std::string address_prefix;
+    uint32_t prefix_len;
+  };
+
+  // TODO(ashithasantosh): Add metadata field to Permission and Principal.
+  struct Permission {
+    enum class RuleType {
+      kAnd,
+      kOr,
+      kAny,
+      kHeader,
+      kPath,
+      kDestIp,
+      kDestPort,
+      kReqServerName,
+    };
+
+    Permission() = default;
+    // For AND/OR RuleType.
+    Permission(Permission::RuleType type,
+               std::vector<std::unique_ptr<Permission>> permissions,
+               bool not_rule = false);
+    // For ANY RuleType.
+    explicit Permission(Permission::RuleType type, bool not_rule = false);
+    // For HEADER RuleType.
+    Permission(Permission::RuleType type, HeaderMatcher header_matcher,
+               bool not_rule = false);
+    // For PATH/REQ_SERVER_NAME RuleType.
+    Permission(Permission::RuleType type, StringMatcher string_matcher,
+               bool not_rule = false);
+    // For DEST_IP RuleType.
+    Permission(Permission::RuleType type, CidrRange ip, bool not_rule = false);
+    // For DEST_PORT RuleType.
+    Permission(Permission::RuleType type, int port, bool not_rule = false);
+
+    Permission(Permission&& other) noexcept;
+    Permission& operator=(Permission&& other) noexcept;
+
+    std::string ToString() const;
+
+    RuleType type;
+    HeaderMatcher header_matcher;
+    StringMatcher string_matcher;
+    CidrRange ip;
+    int port;
+    // For type AND/OR.
+    std::vector<std::unique_ptr<Permission>> permissions;
+    bool not_rule = false;
+  };
+
+  struct Principal {
+    enum class RuleType {
+      kAnd,
+      kOr,
+      kAny,
+      kPrincipalName,
+      kSourceIp,
+      kDirectRemoteIp,
+      kRemoteIp,
+      kHeader,
+      kPath,
+    };
+
+    Principal() = default;
+    // For AND/OR RuleType.
+    Principal(Principal::RuleType type,
+              std::vector<std::unique_ptr<Principal>> principals,
+              bool not_rule = false);
+    // For ANY RuleType.
+    explicit Principal(Principal::RuleType type, bool not_rule = false);
+    // For PRINCIPAL_NAME/PATH RuleType.
+    Principal(Principal::RuleType type, StringMatcher string_matcher,
+              bool not_rule = false);
+    // For SOURCE_IP/DIRECT_REMOTE_IP/REMOTE_IP RuleType.
+    Principal(Principal::RuleType type, CidrRange ip, bool not_rule = false);
+    // For HEADER RuleType.
+    Principal(Principal::RuleType type, HeaderMatcher header_matcher,
+              bool not_rule = false);
+
+    Principal(Principal&& other) noexcept;
+    Principal& operator=(Principal&& other) noexcept;
+
+    std::string ToString() const;
+
+    RuleType type;
+    HeaderMatcher header_matcher;
+    StringMatcher string_matcher;
+    CidrRange ip;
+    // For type AND/OR.
+    std::vector<std::unique_ptr<Principal>> principals;
+    bool not_rule = false;
+  };
+
+  struct Policy {
+    Policy() = default;
+    Policy(Permission permissions, Principal principals);
+
+    Policy(Policy&& other) noexcept;
+    Policy& operator=(Policy&& other) noexcept;
+
+    std::string ToString() const;
+
+    Permission permissions;
+    Principal principals;
+  };
+
+  Rbac() = default;
+  Rbac(Rbac::Action action, std::map<std::string, Policy> policies);
+
+  Rbac(Rbac&& other) noexcept;
+  Rbac& operator=(Rbac&& other) noexcept;
+
+  std::string ToString() const;
+
+  Action action;
+  std::map<std::string, Policy> policies;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_POLICY_H */
diff --git a/grpc/src/core/lib/security/authorization/rbac_translator.cc b/grpc/src/core/lib/security/authorization/rbac_translator.cc
new file mode 100644
index 0000000..ea5599d
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/rbac_translator.cc
@@ -0,0 +1,354 @@
+// Copyright 2021 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>
+
+#include "src/core/lib/security/authorization/rbac_translator.h"
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/strip.h"
+
+#include "src/core/lib/matchers/matchers.h"
+
+namespace grpc_core {
+
+namespace {
+
+absl::string_view GetMatcherType(absl::string_view value,
+                                 StringMatcher::Type* type) {
+  if (value == "*") {
+    *type = StringMatcher::Type::kPrefix;
+    return "";
+  } else if (absl::StartsWith(value, "*")) {
+    *type = StringMatcher::Type::kSuffix;
+    return absl::StripPrefix(value, "*");
+  } else if (absl::EndsWith(value, "*")) {
+    *type = StringMatcher::Type::kPrefix;
+    return absl::StripSuffix(value, "*");
+  }
+  *type = StringMatcher::Type::kExact;
+  return value;
+}
+
+absl::StatusOr<StringMatcher> GetStringMatcher(absl::string_view value) {
+  StringMatcher::Type type;
+  absl::string_view matcher = GetMatcherType(value, &type);
+  return StringMatcher::Create(type, matcher);
+}
+
+absl::StatusOr<HeaderMatcher> GetHeaderMatcher(absl::string_view name,
+                                               absl::string_view value) {
+  StringMatcher::Type type;
+  absl::string_view matcher = GetMatcherType(value, &type);
+  return HeaderMatcher::Create(name, static_cast<HeaderMatcher::Type>(type),
+                               matcher);
+}
+
+absl::StatusOr<Rbac::Principal> ParsePrincipalsArray(const Json& json) {
+  std::vector<std::unique_ptr<Rbac::Principal>> principal_names;
+  for (size_t i = 0; i < json.array_value().size(); ++i) {
+    const Json& child = json.array_value().at(i);
+    if (child.type() != Json::Type::STRING) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("\"principals\" ", i, ": is not a string."));
+    }
+    auto matcher_or = GetStringMatcher(child.string_value());
+    if (!matcher_or.ok()) {
+      return absl::Status(matcher_or.status().code(),
+                          absl::StrCat("\"principals\" ", i, ": ",
+                                       matcher_or.status().message()));
+    }
+    principal_names.push_back(absl::make_unique<Rbac::Principal>(
+        Rbac::Principal::RuleType::kPrincipalName,
+        std::move(matcher_or.value())));
+  }
+  return Rbac::Principal(Rbac::Principal::RuleType::kOr,
+                         std::move(principal_names));
+}
+
+absl::StatusOr<Rbac::Principal> ParsePeer(const Json& json) {
+  std::vector<std::unique_ptr<Rbac::Principal>> peer;
+  auto it = json.object_value().find("principals");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::ARRAY) {
+      return absl::InvalidArgumentError("\"principals\" is not an array.");
+    }
+    auto principal_names_or = ParsePrincipalsArray(it->second);
+    if (!principal_names_or.ok()) return principal_names_or.status();
+    if (!principal_names_or.value().principals.empty()) {
+      peer.push_back(absl::make_unique<Rbac::Principal>(
+          std::move(principal_names_or.value())));
+    }
+  }
+  if (peer.empty()) {
+    return Rbac::Principal(Rbac::Principal::RuleType::kAny);
+  }
+  return Rbac::Principal(Rbac::Principal::RuleType::kAnd, std::move(peer));
+}
+
+absl::StatusOr<Rbac::Permission> ParseHeaderValues(
+    const Json& json, absl::string_view header_name) {
+  if (json.array_value().empty()) {
+    return absl::InvalidArgumentError("\"values\" list is empty.");
+  }
+  std::vector<std::unique_ptr<Rbac::Permission>> values;
+  for (size_t i = 0; i < json.array_value().size(); ++i) {
+    const Json& child = json.array_value().at(i);
+    if (child.type() != Json::Type::STRING) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("\"values\" ", i, ": is not a string."));
+    }
+    auto matcher_or = GetHeaderMatcher(header_name, child.string_value());
+    if (!matcher_or.ok()) {
+      return absl::Status(
+          matcher_or.status().code(),
+          absl::StrCat("\"values\" ", i, ": ", matcher_or.status().message()));
+    }
+    values.push_back(absl::make_unique<Rbac::Permission>(
+        Rbac::Permission::RuleType::kHeader, std::move(matcher_or.value())));
+  }
+  return Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(values));
+}
+
+absl::StatusOr<Rbac::Permission> ParseHeaders(const Json& json) {
+  auto it = json.object_value().find("key");
+  if (it == json.object_value().end()) {
+    return absl::InvalidArgumentError("\"key\" is not present.");
+  }
+  if (it->second.type() != Json::Type::STRING) {
+    return absl::InvalidArgumentError("\"key\" is not a string.");
+  }
+  absl::string_view header_name = it->second.string_value();
+  // TODO(ashithasantosh): Add connection headers below.
+  if (absl::StartsWith(header_name, ":") ||
+      absl::StartsWith(header_name, "grpc-") || header_name == "host" ||
+      header_name == "Host") {
+    return absl::InvalidArgumentError(
+        absl::StrFormat("Unsupported \"key\" %s.", header_name));
+  }
+  it = json.object_value().find("values");
+  if (it == json.object_value().end()) {
+    return absl::InvalidArgumentError("\"values\" is not present.");
+  }
+  if (it->second.type() != Json::Type::ARRAY) {
+    return absl::InvalidArgumentError("\"values\" is not an array.");
+  }
+  return ParseHeaderValues(it->second, header_name);
+}
+
+absl::StatusOr<Rbac::Permission> ParseHeadersArray(const Json& json) {
+  std::vector<std::unique_ptr<Rbac::Permission>> headers;
+  for (size_t i = 0; i < json.array_value().size(); ++i) {
+    const Json& child = json.array_value().at(i);
+    if (child.type() != Json::Type::OBJECT) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("\"headers\" ", i, ": is not an object."));
+    }
+    auto headers_or = ParseHeaders(child);
+    if (!headers_or.ok()) {
+      return absl::Status(
+          headers_or.status().code(),
+          absl::StrCat("\"headers\" ", i, ": ", headers_or.status().message()));
+    }
+    headers.push_back(
+        absl::make_unique<Rbac::Permission>(std::move(headers_or.value())));
+  }
+  return Rbac::Permission(Rbac::Permission::RuleType::kAnd, std::move(headers));
+}
+
+absl::StatusOr<Rbac::Permission> ParsePathsArray(const Json& json) {
+  std::vector<std::unique_ptr<Rbac::Permission>> paths;
+  for (size_t i = 0; i < json.array_value().size(); ++i) {
+    const Json& child = json.array_value().at(i);
+    if (child.type() != Json::Type::STRING) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("\"paths\" ", i, ": is not a string."));
+    }
+    auto matcher_or = GetStringMatcher(child.string_value());
+    if (!matcher_or.ok()) {
+      return absl::Status(
+          matcher_or.status().code(),
+          absl::StrCat("\"paths\" ", i, ": ", matcher_or.status().message()));
+    }
+    paths.push_back(absl::make_unique<Rbac::Permission>(
+        Rbac::Permission::RuleType::kPath, std::move(matcher_or.value())));
+  }
+  return Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(paths));
+}
+
+absl::StatusOr<Rbac::Permission> ParseRequest(const Json& json) {
+  std::vector<std::unique_ptr<Rbac::Permission>> request;
+  auto it = json.object_value().find("paths");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::ARRAY) {
+      return absl::InvalidArgumentError("\"paths\" is not an array.");
+    }
+    auto paths_or = ParsePathsArray(it->second);
+    if (!paths_or.ok()) return paths_or.status();
+    if (!paths_or.value().permissions.empty()) {
+      request.push_back(
+          absl::make_unique<Rbac::Permission>(std::move(paths_or.value())));
+    }
+  }
+  it = json.object_value().find("headers");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::ARRAY) {
+      return absl::InvalidArgumentError("\"headers\" is not an array.");
+    }
+    auto headers_or = ParseHeadersArray(it->second);
+    if (!headers_or.ok()) return headers_or.status();
+    if (!headers_or.value().permissions.empty()) {
+      request.push_back(
+          absl::make_unique<Rbac::Permission>(std::move(headers_or.value())));
+    }
+  }
+  if (request.empty()) {
+    return Rbac::Permission(Rbac::Permission::RuleType::kAny);
+  }
+  return Rbac::Permission(Rbac::Permission::RuleType::kAnd, std::move(request));
+}
+
+absl::StatusOr<Rbac::Policy> ParseRules(const Json& json) {
+  Rbac::Principal principals;
+  auto it = json.object_value().find("source");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::OBJECT) {
+      return absl::InvalidArgumentError("\"source\" is not an object.");
+    }
+    auto peer_or = ParsePeer(it->second);
+    if (!peer_or.ok()) return peer_or.status();
+    principals = std::move(peer_or.value());
+  } else {
+    principals = Rbac::Principal(Rbac::Principal::RuleType::kAny);
+  }
+  Rbac::Permission permissions;
+  it = json.object_value().find("request");
+  if (it != json.object_value().end()) {
+    if (it->second.type() != Json::Type::OBJECT) {
+      return absl::InvalidArgumentError("\"request\" is not an object.");
+    }
+    auto request_or = ParseRequest(it->second);
+    if (!request_or.ok()) return request_or.status();
+    permissions = std::move(request_or.value());
+  } else {
+    permissions = Rbac::Permission(Rbac::Permission::RuleType::kAny);
+  }
+  return Rbac::Policy(std::move(permissions), std::move(principals));
+}
+
+absl::StatusOr<std::map<std::string, Rbac::Policy>> ParseRulesArray(
+    const Json& json, absl::string_view name) {
+  std::map<std::string, Rbac::Policy> policies;
+  for (size_t i = 0; i < json.array_value().size(); ++i) {
+    const Json& child = json.array_value().at(i);
+    if (child.type() != Json::Type::OBJECT) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("rules ", i, ": is not an object."));
+    }
+    auto it = child.object_value().find("name");
+    if (it == child.object_value().end()) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("rules ", i, ": \"name\" is not present."));
+    }
+    if (it->second.type() != Json::Type::STRING) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("rules ", i, ": \"name\" is not a string."));
+    }
+    std::string policy_name =
+        std::string(name) + "_" + it->second.string_value();
+    auto policy_or = ParseRules(child);
+    if (!policy_or.ok()) {
+      return absl::Status(
+          policy_or.status().code(),
+          absl::StrCat("rules ", i, ": ", policy_or.status().message()));
+    }
+    policies[policy_name] = std::move(policy_or.value());
+  }
+  return std::move(policies);
+}
+
+absl::StatusOr<Rbac> ParseDenyRulesArray(const Json& json,
+                                         absl::string_view name) {
+  auto policies_or = ParseRulesArray(json, name);
+  if (!policies_or.ok()) return policies_or.status();
+  return Rbac(Rbac::Action::kDeny, std::move(policies_or.value()));
+}
+
+absl::StatusOr<Rbac> ParseAllowRulesArray(const Json& json,
+                                          absl::string_view name) {
+  auto policies_or = ParseRulesArray(json, name);
+  if (!policies_or.ok()) return policies_or.status();
+  return Rbac(Rbac::Action::kAllow, std::move(policies_or.value()));
+}
+
+}  // namespace
+
+absl::StatusOr<RbacPolicies> GenerateRbacPolicies(
+    absl::string_view authz_policy) {
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  Json json = Json::Parse(authz_policy, &error);
+  if (error != GRPC_ERROR_NONE) {
+    absl::Status status = absl::InvalidArgumentError(
+        absl::StrCat("Failed to parse SDK authorization policy. Error: ",
+                     grpc_error_std_string(error)));
+    GRPC_ERROR_UNREF(error);
+    return status;
+  }
+  if (json.type() != Json::Type::OBJECT) {
+    return absl::InvalidArgumentError(
+        "SDK authorization policy is not an object.");
+  }
+  auto it = json.mutable_object()->find("name");
+  if (it == json.mutable_object()->end()) {
+    return absl::InvalidArgumentError("\"name\" field is not present.");
+  }
+  if (it->second.type() != Json::Type::STRING) {
+    return absl::InvalidArgumentError("\"name\" is not a string.");
+  }
+  absl::string_view name = it->second.string_value();
+  RbacPolicies rbac_policies;
+  it = json.mutable_object()->find("deny_rules");
+  if (it != json.mutable_object()->end()) {
+    if (it->second.type() != Json::Type::ARRAY) {
+      return absl::InvalidArgumentError("\"deny_rules\" is not an array.");
+    }
+    auto deny_policy_or = ParseDenyRulesArray(it->second, name);
+    if (!deny_policy_or.ok()) {
+      return absl::Status(
+          deny_policy_or.status().code(),
+          absl::StrCat("deny_", deny_policy_or.status().message()));
+    }
+    rbac_policies.deny_policy = std::move(deny_policy_or.value());
+  } else {
+    rbac_policies.deny_policy.action = Rbac::Action::kDeny;
+  }
+  it = json.mutable_object()->find("allow_rules");
+  if (it == json.mutable_object()->end()) {
+    return absl::InvalidArgumentError("\"allow_rules\" is not present.");
+  }
+  if (it->second.type() != Json::Type::ARRAY) {
+    return absl::InvalidArgumentError("\"allow_rules\" is not an array.");
+  }
+  auto allow_policy_or = ParseAllowRulesArray(it->second, name);
+  if (!allow_policy_or.ok()) {
+    return absl::Status(
+        allow_policy_or.status().code(),
+        absl::StrCat("allow_", allow_policy_or.status().message()));
+  }
+  rbac_policies.allow_policy = std::move(allow_policy_or.value());
+  return std::move(rbac_policies);
+}
+
+}  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/authorization/rbac_translator.h b/grpc/src/core/lib/security/authorization/rbac_translator.h
new file mode 100644
index 0000000..51d7024
--- /dev/null
+++ b/grpc/src/core/lib/security/authorization/rbac_translator.h
@@ -0,0 +1,39 @@
+// Copyright 2021 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_LIB_SECURITY_AUTHORIZATION_RBAC_TRANSLATOR_H
+#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_TRANSLATOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include "absl/status/statusor.h"
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/security/authorization/rbac_policy.h"
+
+namespace grpc_core {
+
+struct RbacPolicies {
+  Rbac deny_policy;
+  Rbac allow_policy;
+};
+
+// Translates SDK authorization policy to Envoy RBAC policies. Returns error on
+// failure.
+// authz_policy: Authorization Policy string in JSON format.
+absl::StatusOr<RbacPolicies> GenerateRbacPolicies(
+    absl::string_view authz_policy);
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_TRANSLATOR_H */
diff --git a/grpc/src/core/lib/security/credentials/alts/alts_credentials.cc b/grpc/src/core/lib/security/credentials/alts/alts_credentials.cc
index 1bc76d9..30acd74 100644
--- a/grpc/src/core/lib/security/credentials/alts/alts_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/alts/alts_credentials.cc
@@ -70,7 +70,8 @@
 }
 
 grpc_core::RefCountedPtr<grpc_server_security_connector>
-grpc_alts_server_credentials::create_security_connector() {
+grpc_alts_server_credentials::create_security_connector(
+    const grpc_channel_args* /* args */) {
   return grpc_alts_server_security_connector_create(this->Ref());
 }
 
diff --git a/grpc/src/core/lib/security/credentials/alts/alts_credentials.h b/grpc/src/core/lib/security/credentials/alts/alts_credentials.h
index cc6d522..8e1362c 100644
--- a/grpc/src/core/lib/security/credentials/alts/alts_credentials.h
+++ b/grpc/src/core/lib/security/credentials/alts/alts_credentials.h
@@ -56,7 +56,7 @@
   ~grpc_alts_server_credentials() override;
 
   grpc_core::RefCountedPtr<grpc_server_security_connector>
-  create_security_connector() override;
+  create_security_connector(const grpc_channel_args* /* args */) override;
 
   const grpc_alts_credentials_options* options() const { return options_; }
   grpc_alts_credentials_options* mutable_options() { return options_; }
diff --git a/grpc/src/core/lib/security/credentials/composite/composite_credentials.cc b/grpc/src/core/lib/security/credentials/composite/composite_credentials.cc
index bccc034..5543ad1 100644
--- a/grpc/src/core/lib/security/credentials/composite/composite_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/composite/composite_credentials.cc
@@ -36,7 +36,7 @@
 
 /* -- Composite call credentials. -- */
 
-static void composite_call_metadata_cb(void* arg, grpc_error* error);
+static void composite_call_metadata_cb(void* arg, grpc_error_handle error);
 
 namespace {
 struct grpc_composite_call_credentials_metadata_context {
@@ -64,7 +64,7 @@
 };
 }  // namespace
 
-static void composite_call_metadata_cb(void* arg, grpc_error* error) {
+static void composite_call_metadata_cb(void* arg, grpc_error_handle error) {
   grpc_composite_call_credentials_metadata_context* ctx =
       static_cast<grpc_composite_call_credentials_metadata_context*>(arg);
   if (error == GRPC_ERROR_NONE) {
@@ -91,7 +91,7 @@
 bool grpc_composite_call_credentials::get_request_metadata(
     grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
-    grpc_error** error) {
+    grpc_error_handle* error) {
   grpc_composite_call_credentials_metadata_context* ctx;
   ctx = new grpc_composite_call_credentials_metadata_context(
       this, pollent, auth_md_context, md_array, on_request_metadata);
@@ -112,7 +112,7 @@
 }
 
 void grpc_composite_call_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* md_array, grpc_error* error) {
+    grpc_credentials_mdelem_array* md_array, grpc_error_handle error) {
   for (size_t i = 0; i < inner_.size(); ++i) {
     inner_[i]->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error));
   }
diff --git a/grpc/src/core/lib/security/credentials/composite/composite_credentials.h b/grpc/src/core/lib/security/credentials/composite/composite_credentials.h
index 6b9e9d1..8634627 100644
--- a/grpc/src/core/lib/security/credentials/composite/composite_credentials.h
+++ b/grpc/src/core/lib/security/credentials/composite/composite_credentials.h
@@ -83,10 +83,10 @@
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   grpc_security_level min_security_level() const override {
     return min_security_level_;
diff --git a/grpc/src/core/lib/security/credentials/credentials.h b/grpc/src/core/lib/security/credentials/credentials.h
index 61e56e5..b8609c5 100644
--- a/grpc/src/core/lib/security/credentials/credentials.h
+++ b/grpc/src/core/lib/security/credentials/credentials.h
@@ -187,13 +187,13 @@
                                     grpc_auth_metadata_context context,
                                     grpc_credentials_mdelem_array* md_array,
                                     grpc_closure* on_request_metadata,
-                                    grpc_error** error) = 0;
+                                    grpc_error_handle* error) = 0;
 
   // Cancels a pending asynchronous operation started by
   // grpc_call_credentials_get_request_metadata() with the corresponding
   // value of \a md_array.
   virtual void cancel_get_request_metadata(
-      grpc_credentials_mdelem_array* md_array, grpc_error* error) = 0;
+      grpc_credentials_mdelem_array* md_array, grpc_error_handle error) = 0;
 
   virtual grpc_security_level min_security_level() const {
     return min_security_level_;
@@ -227,8 +227,9 @@
 
   ~grpc_server_credentials() override { DestroyProcessor(); }
 
+  // Ownership of \a args is not passed.
   virtual grpc_core::RefCountedPtr<grpc_server_security_connector>
-  create_security_connector() = 0;
+  create_security_connector(const grpc_channel_args* args) = 0;
 
   const char* type() const { return type_; }
 
diff --git a/grpc/src/core/lib/security/credentials/external/aws_external_account_credentials.cc b/grpc/src/core/lib/security/credentials/external/aws_external_account_credentials.cc
index e9d60ea..c479bf0 100644
--- a/grpc/src/core/lib/security/credentials/external/aws_external_account_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/external/aws_external_account_credentials.cc
@@ -30,6 +30,7 @@
 const char* kExpectedEnvironmentId = "aws1";
 
 const char* kRegionEnvVar = "AWS_REGION";
+const char* kDefaultRegionEnvVar = "AWS_DEFAULT_REGION";
 const char* kAccessKeyIdEnvVar = "AWS_ACCESS_KEY_ID";
 const char* kSecretAccessKeyEnvVar = "AWS_SECRET_ACCESS_KEY";
 const char* kSessionTokenEnvVar = "AWS_SESSION_TOKEN";
@@ -57,7 +58,7 @@
 RefCountedPtr<AwsExternalAccountCredentials>
 AwsExternalAccountCredentials::Create(Options options,
                                       std::vector<std::string> scopes,
-                                      grpc_error** error) {
+                                      grpc_error_handle* error) {
   auto creds = MakeRefCounted<AwsExternalAccountCredentials>(
       std::move(options), std::move(scopes), error);
   if (*error == GRPC_ERROR_NONE) {
@@ -68,7 +69,7 @@
 }
 
 AwsExternalAccountCredentials::AwsExternalAccountCredentials(
-    Options options, std::vector<std::string> scopes, grpc_error** error)
+    Options options, std::vector<std::string> scopes, grpc_error_handle* error)
     : ExternalAccountCredentials(options, std::move(scopes)) {
   audience_ = options.audience;
   auto it = options.credential_source.object_value().find("environment_id");
@@ -120,8 +121,8 @@
 }
 
 void AwsExternalAccountCredentials::RetrieveSubjectToken(
-    HTTPRequestContext* ctx, const Options& options,
-    std::function<void(std::string, grpc_error*)> cb) {
+    HTTPRequestContext* ctx, const Options& /*options*/,
+    std::function<void(std::string, grpc_error_handle)> cb) {
   if (ctx == nullptr) {
     FinishRetrieveSubjectToken(
         "",
@@ -140,6 +141,9 @@
 
 void AwsExternalAccountCredentials::RetrieveRegion() {
   UniquePtr<char> region_from_env(gpr_getenv(kRegionEnvVar));
+  if (region_from_env == nullptr) {
+    region_from_env = UniquePtr<char>(gpr_getenv(kDefaultRegionEnvVar));
+  }
   if (region_from_env != nullptr) {
     region_ = std::string(region_from_env.get());
     if (url_.empty()) {
@@ -175,14 +179,14 @@
 }
 
 void AwsExternalAccountCredentials::OnRetrieveRegion(void* arg,
-                                                     grpc_error* error) {
+                                                     grpc_error_handle error) {
   AwsExternalAccountCredentials* self =
       static_cast<AwsExternalAccountCredentials*>(arg);
   self->OnRetrieveRegionInternal(GRPC_ERROR_REF(error));
 }
 
 void AwsExternalAccountCredentials::OnRetrieveRegionInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishRetrieveSubjectToken("", error);
     return;
@@ -224,15 +228,15 @@
   grpc_http_request_destroy(&request.http);
 }
 
-void AwsExternalAccountCredentials::OnRetrieveRoleName(void* arg,
-                                                       grpc_error* error) {
+void AwsExternalAccountCredentials::OnRetrieveRoleName(
+    void* arg, grpc_error_handle error) {
   AwsExternalAccountCredentials* self =
       static_cast<AwsExternalAccountCredentials*>(arg);
   self->OnRetrieveRoleNameInternal(GRPC_ERROR_REF(error));
 }
 
 void AwsExternalAccountCredentials::OnRetrieveRoleNameInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishRetrieveSubjectToken("", error);
     return;
@@ -287,15 +291,15 @@
   grpc_http_request_destroy(&request.http);
 }
 
-void AwsExternalAccountCredentials::OnRetrieveSigningKeys(void* arg,
-                                                          grpc_error* error) {
+void AwsExternalAccountCredentials::OnRetrieveSigningKeys(
+    void* arg, grpc_error_handle error) {
   AwsExternalAccountCredentials* self =
       static_cast<AwsExternalAccountCredentials*>(arg);
   self->OnRetrieveSigningKeysInternal(GRPC_ERROR_REF(error));
 }
 
 void AwsExternalAccountCredentials::OnRetrieveSigningKeysInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishRetrieveSubjectToken("", error);
     return;
@@ -350,7 +354,7 @@
 }
 
 void AwsExternalAccountCredentials::BuildSubjectToken() {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (signer_ == nullptr) {
     cred_verification_url_ = absl::StrReplaceAll(
         regional_cred_verification_url_, {{"{region}", region_}});
@@ -396,7 +400,7 @@
 }
 
 void AwsExternalAccountCredentials::FinishRetrieveSubjectToken(
-    std::string subject_token, grpc_error* error) {
+    std::string subject_token, grpc_error_handle error) {
   // Reset context
   ctx_ = nullptr;
   // Move object state into local variables.
diff --git a/grpc/src/core/lib/security/credentials/external/aws_external_account_credentials.h b/grpc/src/core/lib/security/credentials/external/aws_external_account_credentials.h
index edb7e82..50ccf19 100644
--- a/grpc/src/core/lib/security/credentials/external/aws_external_account_credentials.h
+++ b/grpc/src/core/lib/security/credentials/external/aws_external_account_credentials.h
@@ -28,31 +28,33 @@
 class AwsExternalAccountCredentials final : public ExternalAccountCredentials {
  public:
   static RefCountedPtr<AwsExternalAccountCredentials> Create(
-      Options options, std::vector<std::string> scopes, grpc_error** error);
+      Options options, std::vector<std::string> scopes,
+      grpc_error_handle* error);
 
   AwsExternalAccountCredentials(Options options,
                                 std::vector<std::string> scopes,
-                                grpc_error** error);
+                                grpc_error_handle* error);
 
  private:
   void RetrieveSubjectToken(
       HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) override;
+      std::function<void(std::string, grpc_error_handle)> cb) override;
 
   void RetrieveRegion();
-  static void OnRetrieveRegion(void* arg, grpc_error* error);
-  void OnRetrieveRegionInternal(grpc_error* error);
+  static void OnRetrieveRegion(void* arg, grpc_error_handle error);
+  void OnRetrieveRegionInternal(grpc_error_handle error);
 
   void RetrieveRoleName();
-  static void OnRetrieveRoleName(void* arg, grpc_error* error);
-  void OnRetrieveRoleNameInternal(grpc_error* error);
+  static void OnRetrieveRoleName(void* arg, grpc_error_handle error);
+  void OnRetrieveRoleNameInternal(grpc_error_handle error);
 
   void RetrieveSigningKeys();
-  static void OnRetrieveSigningKeys(void* arg, grpc_error* error);
-  void OnRetrieveSigningKeysInternal(grpc_error* error);
+  static void OnRetrieveSigningKeys(void* arg, grpc_error_handle error);
+  void OnRetrieveSigningKeysInternal(grpc_error_handle error);
 
   void BuildSubjectToken();
-  void FinishRetrieveSubjectToken(std::string subject_token, grpc_error* error);
+  void FinishRetrieveSubjectToken(std::string subject_token,
+                                  grpc_error_handle error);
 
   std::string audience_;
 
@@ -72,7 +74,7 @@
   std::string cred_verification_url_;
 
   HTTPRequestContext* ctx_ = nullptr;
-  std::function<void(std::string, grpc_error*)> cb_ = nullptr;
+  std::function<void(std::string, grpc_error_handle)> cb_ = nullptr;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/credentials/external/aws_request_signer.cc b/grpc/src/core/lib/security/credentials/external/aws_request_signer.cc
index af8531e..b665701 100644
--- a/grpc/src/core/lib/security/credentials/external/aws_request_signer.cc
+++ b/grpc/src/core/lib/security/credentials/external/aws_request_signer.cc
@@ -66,7 +66,8 @@
     std::string access_key_id, std::string secret_access_key, std::string token,
     std::string method, std::string url, std::string region,
     std::string request_payload,
-    std::map<std::string, std::string> additional_headers, grpc_error** error)
+    std::map<std::string, std::string> additional_headers,
+    grpc_error_handle* error)
     : access_key_id_(std::move(access_key_id)),
       secret_access_key_(std::move(secret_access_key)),
       token_(std::move(token)),
diff --git a/grpc/src/core/lib/security/credentials/external/aws_request_signer.h b/grpc/src/core/lib/security/credentials/external/aws_request_signer.h
index 62e112c..22c4ad6 100644
--- a/grpc/src/core/lib/security/credentials/external/aws_request_signer.h
+++ b/grpc/src/core/lib/security/credentials/external/aws_request_signer.h
@@ -45,7 +45,7 @@
                    std::string token, std::string method, std::string url,
                    std::string region, std::string request_payload,
                    std::map<std::string, std::string> additional_headers,
-                   grpc_error** error);
+                   grpc_error_handle* error);
 
   // This method triggers the signing process then returns the headers of the
   // signed request as a map. In case there is an error, the input `error`
diff --git a/grpc/src/core/lib/security/credentials/external/external_account_credentials.cc b/grpc/src/core/lib/security/credentials/external/external_account_credentials.cc
index 127a5f3..f5d9442 100644
--- a/grpc/src/core/lib/security/credentials/external/external_account_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/external/external_account_credentials.cc
@@ -63,7 +63,8 @@
 }  // namespace
 
 RefCountedPtr<ExternalAccountCredentials> ExternalAccountCredentials::Create(
-    const Json& json, std::vector<std::string> scopes, grpc_error** error) {
+    const Json& json, std::vector<std::string> scopes,
+    grpc_error_handle* error) {
   GPR_ASSERT(*error == GRPC_ERROR_NONE);
   Options options;
   options.type = GRPC_AUTH_JSON_TYPE_INVALID;
@@ -213,14 +214,14 @@
   ctx_ = new HTTPRequestContext(httpcli_context, pollent, deadline);
   metadata_req_ = metadata_req;
   response_cb_ = response_cb;
-  auto cb = [this](std::string token, grpc_error* error) {
+  auto cb = [this](std::string token, grpc_error_handle error) {
     OnRetrieveSubjectTokenInternal(token, error);
   };
   RetrieveSubjectToken(ctx_, options_, cb);
 }
 
 void ExternalAccountCredentials::OnRetrieveSubjectTokenInternal(
-    absl::string_view subject_token, grpc_error* error) {
+    absl::string_view subject_token, grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishTokenFetch(error);
   } else {
@@ -300,13 +301,15 @@
   grpc_http_request_destroy(&request.http);
 }
 
-void ExternalAccountCredentials::OnExchangeToken(void* arg, grpc_error* error) {
+void ExternalAccountCredentials::OnExchangeToken(void* arg,
+                                                 grpc_error_handle error) {
   ExternalAccountCredentials* self =
       static_cast<ExternalAccountCredentials*>(arg);
   self->OnExchangeTokenInternal(GRPC_ERROR_REF(error));
 }
 
-void ExternalAccountCredentials::OnExchangeTokenInternal(grpc_error* error) {
+void ExternalAccountCredentials::OnExchangeTokenInternal(
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishTokenFetch(error);
   } else {
@@ -316,7 +319,7 @@
           std::string(ctx_->response.body, ctx_->response.body_length).c_str());
       metadata_req_->response.hdrs = static_cast<grpc_http_header*>(
           gpr_malloc(sizeof(grpc_http_header) * ctx_->response.hdr_count));
-      for (int i = 0; i < ctx_->response.hdr_count; i++) {
+      for (size_t i = 0; i < ctx_->response.hdr_count; i++) {
         metadata_req_->response.hdrs[i].key =
             gpr_strdup(ctx_->response.hdrs[i].key);
         metadata_req_->response.hdrs[i].value =
@@ -330,7 +333,7 @@
 }
 
 void ExternalAccountCredentials::ImpersenateServiceAccount() {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   absl::string_view response_body(ctx_->response.body,
                                   ctx_->response.body_length);
   Json json = Json::Parse(response_body, &error);
@@ -389,14 +392,14 @@
 }
 
 void ExternalAccountCredentials::OnImpersenateServiceAccount(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   ExternalAccountCredentials* self =
       static_cast<ExternalAccountCredentials*>(arg);
   self->OnImpersenateServiceAccountInternal(GRPC_ERROR_REF(error));
 }
 
 void ExternalAccountCredentials::OnImpersenateServiceAccountInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishTokenFetch(error);
     return;
@@ -443,7 +446,7 @@
   metadata_req_->response.body_length = body.length();
   metadata_req_->response.hdrs = static_cast<grpc_http_header*>(
       gpr_malloc(sizeof(grpc_http_header) * ctx_->response.hdr_count));
-  for (int i = 0; i < ctx_->response.hdr_count; i++) {
+  for (size_t i = 0; i < ctx_->response.hdr_count; i++) {
     metadata_req_->response.hdrs[i].key =
         gpr_strdup(ctx_->response.hdrs[i].key);
     metadata_req_->response.hdrs[i].value =
@@ -452,7 +455,7 @@
   FinishTokenFetch(GRPC_ERROR_NONE);
 }
 
-void ExternalAccountCredentials::FinishTokenFetch(grpc_error* error) {
+void ExternalAccountCredentials::FinishTokenFetch(grpc_error_handle error) {
   GRPC_LOG_IF_ERROR("Fetch external account credentials access token",
                     GRPC_ERROR_REF(error));
   // Move object state into local variables.
@@ -473,12 +476,12 @@
 
 grpc_call_credentials* grpc_external_account_credentials_create(
     const char* json_string, const char* scopes_string) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json json = grpc_core::Json::Parse(json_string, &error);
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "External account credentials creation failed. Error: %s.",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return nullptr;
   }
@@ -489,7 +492,7 @@
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "External account credentials creation failed. Error: %s.",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     return nullptr;
   }
diff --git a/grpc/src/core/lib/security/credentials/external/external_account_credentials.h b/grpc/src/core/lib/security/credentials/external/external_account_credentials.h
index 0da7786..3c00096 100644
--- a/grpc/src/core/lib/security/credentials/external/external_account_credentials.h
+++ b/grpc/src/core/lib/security/credentials/external/external_account_credentials.h
@@ -49,7 +49,8 @@
   };
 
   static RefCountedPtr<ExternalAccountCredentials> Create(
-      const Json& json, std::vector<std::string> scopes, grpc_error** error);
+      const Json& json, std::vector<std::string> scopes,
+      grpc_error_handle* error);
 
   ExternalAccountCredentials(Options options, std::vector<std::string> scopes);
   ~ExternalAccountCredentials() override;
@@ -84,7 +85,7 @@
   // back.
   virtual void RetrieveSubjectToken(
       HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) = 0;
+      std::function<void(std::string, grpc_error_handle)> cb) = 0;
 
  private:
   // This method implements the common token fetch logic and it will be called
@@ -95,17 +96,17 @@
                     grpc_millis deadline) override;
 
   void OnRetrieveSubjectTokenInternal(absl::string_view subject_token,
-                                      grpc_error* error);
+                                      grpc_error_handle error);
 
   void ExchangeToken(absl::string_view subject_token);
-  static void OnExchangeToken(void* arg, grpc_error* error);
-  void OnExchangeTokenInternal(grpc_error* error);
+  static void OnExchangeToken(void* arg, grpc_error_handle error);
+  void OnExchangeTokenInternal(grpc_error_handle error);
 
   void ImpersenateServiceAccount();
-  static void OnImpersenateServiceAccount(void* arg, grpc_error* error);
-  void OnImpersenateServiceAccountInternal(grpc_error* error);
+  static void OnImpersenateServiceAccount(void* arg, grpc_error_handle error);
+  void OnImpersenateServiceAccountInternal(grpc_error_handle error);
 
-  void FinishTokenFetch(grpc_error* error);
+  void FinishTokenFetch(grpc_error_handle error);
 
   Options options_;
   std::vector<std::string> scopes_;
diff --git a/grpc/src/core/lib/security/credentials/external/file_external_account_credentials.cc b/grpc/src/core/lib/security/credentials/external/file_external_account_credentials.cc
index 730c095..d596d29 100644
--- a/grpc/src/core/lib/security/credentials/external/file_external_account_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/external/file_external_account_credentials.cc
@@ -28,7 +28,7 @@
 RefCountedPtr<FileExternalAccountCredentials>
 FileExternalAccountCredentials::Create(Options options,
                                        std::vector<std::string> scopes,
-                                       grpc_error** error) {
+                                       grpc_error_handle* error) {
   auto creds = MakeRefCounted<FileExternalAccountCredentials>(
       std::move(options), std::move(scopes), error);
   if (*error == GRPC_ERROR_NONE) {
@@ -39,7 +39,7 @@
 }
 
 FileExternalAccountCredentials::FileExternalAccountCredentials(
-    Options options, std::vector<std::string> scopes, grpc_error** error)
+    Options options, std::vector<std::string> scopes, grpc_error_handle* error)
     : ExternalAccountCredentials(options, std::move(scopes)) {
   auto it = options.credential_source.object_value().find("file");
   if (it == options.credential_source.object_value().end()) {
@@ -91,8 +91,8 @@
 }
 
 void FileExternalAccountCredentials::RetrieveSubjectToken(
-    HTTPRequestContext* ctx, const Options& options,
-    std::function<void(std::string, grpc_error*)> cb) {
+    HTTPRequestContext* /*ctx*/, const Options& /*options*/,
+    std::function<void(std::string, grpc_error_handle)> cb) {
   struct SliceWrapper {
     ~SliceWrapper() { grpc_slice_unref_internal(slice); }
     grpc_slice slice = grpc_empty_slice();
@@ -100,7 +100,8 @@
   SliceWrapper content_slice;
   // To retrieve the subject token, we read the file every time we make a
   // request because it may have changed since the last request.
-  grpc_error* error = grpc_load_file(file_.c_str(), 0, &content_slice.slice);
+  grpc_error_handle error =
+      grpc_load_file(file_.c_str(), 0, &content_slice.slice);
   if (error != GRPC_ERROR_NONE) {
     cb("", error);
     return;
diff --git a/grpc/src/core/lib/security/credentials/external/file_external_account_credentials.h b/grpc/src/core/lib/security/credentials/external/file_external_account_credentials.h
index 7df5b6b..23a6b6d 100644
--- a/grpc/src/core/lib/security/credentials/external/file_external_account_credentials.h
+++ b/grpc/src/core/lib/security/credentials/external/file_external_account_credentials.h
@@ -26,16 +26,17 @@
 class FileExternalAccountCredentials final : public ExternalAccountCredentials {
  public:
   static RefCountedPtr<FileExternalAccountCredentials> Create(
-      Options options, std::vector<std::string> scopes, grpc_error** error);
+      Options options, std::vector<std::string> scopes,
+      grpc_error_handle* error);
 
   FileExternalAccountCredentials(Options options,
                                  std::vector<std::string> scopes,
-                                 grpc_error** error);
+                                 grpc_error_handle* error);
 
  private:
   void RetrieveSubjectToken(
       HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) override;
+      std::function<void(std::string, grpc_error_handle)> cb) override;
 
   // Fields of credential source
   std::string file_;
diff --git a/grpc/src/core/lib/security/credentials/external/url_external_account_credentials.cc b/grpc/src/core/lib/security/credentials/external/url_external_account_credentials.cc
index 85d09be..55151b9 100644
--- a/grpc/src/core/lib/security/credentials/external/url_external_account_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/external/url_external_account_credentials.cc
@@ -26,7 +26,7 @@
 RefCountedPtr<UrlExternalAccountCredentials>
 UrlExternalAccountCredentials::Create(Options options,
                                       std::vector<std::string> scopes,
-                                      grpc_error** error) {
+                                      grpc_error_handle* error) {
   auto creds = MakeRefCounted<UrlExternalAccountCredentials>(
       std::move(options), std::move(scopes), error);
   if (*error == GRPC_ERROR_NONE) {
@@ -37,7 +37,7 @@
 }
 
 UrlExternalAccountCredentials::UrlExternalAccountCredentials(
-    Options options, std::vector<std::string> scopes, grpc_error** error)
+    Options options, std::vector<std::string> scopes, grpc_error_handle* error)
     : ExternalAccountCredentials(options, std::move(scopes)) {
   auto it = options.credential_source.object_value().find("url");
   if (it == options.credential_source.object_value().end()) {
@@ -112,8 +112,8 @@
 }
 
 void UrlExternalAccountCredentials::RetrieveSubjectToken(
-    HTTPRequestContext* ctx, const Options& options,
-    std::function<void(std::string, grpc_error*)> cb) {
+    HTTPRequestContext* ctx, const Options& /*options*/,
+    std::function<void(std::string, grpc_error_handle)> cb) {
   if (ctx == nullptr) {
     FinishRetrieveSubjectToken(
         "",
@@ -151,15 +151,15 @@
   grpc_http_request_destroy(&request.http);
 }
 
-void UrlExternalAccountCredentials::OnRetrieveSubjectToken(void* arg,
-                                                           grpc_error* error) {
+void UrlExternalAccountCredentials::OnRetrieveSubjectToken(
+    void* arg, grpc_error_handle error) {
   UrlExternalAccountCredentials* self =
       static_cast<UrlExternalAccountCredentials*>(arg);
   self->OnRetrieveSubjectTokenInternal(GRPC_ERROR_REF(error));
 }
 
 void UrlExternalAccountCredentials::OnRetrieveSubjectTokenInternal(
-    grpc_error* error) {
+    grpc_error_handle error) {
   if (error != GRPC_ERROR_NONE) {
     FinishRetrieveSubjectToken("", error);
     return;
@@ -167,7 +167,7 @@
   absl::string_view response_body(ctx_->response.body,
                                   ctx_->response.body_length);
   if (format_type_ == "json") {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     Json response_json = Json::Parse(response_body, &error);
     if (error != GRPC_ERROR_NONE ||
         response_json.type() != Json::Type::OBJECT) {
@@ -196,7 +196,7 @@
 }
 
 void UrlExternalAccountCredentials::FinishRetrieveSubjectToken(
-    std::string subject_token, grpc_error* error) {
+    std::string subject_token, grpc_error_handle error) {
   // Reset context
   ctx_ = nullptr;
   // Move object state into local variables.
diff --git a/grpc/src/core/lib/security/credentials/external/url_external_account_credentials.h b/grpc/src/core/lib/security/credentials/external/url_external_account_credentials.h
index 4e37c57..eaf984c 100644
--- a/grpc/src/core/lib/security/credentials/external/url_external_account_credentials.h
+++ b/grpc/src/core/lib/security/credentials/external/url_external_account_credentials.h
@@ -26,21 +26,23 @@
 class UrlExternalAccountCredentials final : public ExternalAccountCredentials {
  public:
   static RefCountedPtr<UrlExternalAccountCredentials> Create(
-      Options options, std::vector<std::string> scopes, grpc_error** error);
+      Options options, std::vector<std::string> scopes,
+      grpc_error_handle* error);
 
   UrlExternalAccountCredentials(Options options,
                                 std::vector<std::string> scopes,
-                                grpc_error** error);
+                                grpc_error_handle* error);
 
  private:
   void RetrieveSubjectToken(
       HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) override;
+      std::function<void(std::string, grpc_error_handle)> cb) override;
 
-  static void OnRetrieveSubjectToken(void* arg, grpc_error* error);
-  void OnRetrieveSubjectTokenInternal(grpc_error* error);
+  static void OnRetrieveSubjectToken(void* arg, grpc_error_handle error);
+  void OnRetrieveSubjectTokenInternal(grpc_error_handle error);
 
-  void FinishRetrieveSubjectToken(std::string subject_token, grpc_error* error);
+  void FinishRetrieveSubjectToken(std::string subject_token,
+                                  grpc_error_handle error);
 
   // Fields of credential source
   URI url_;
@@ -50,7 +52,7 @@
   std::string format_subject_token_field_name_;
 
   HTTPRequestContext* ctx_ = nullptr;
-  std::function<void(std::string, grpc_error*)> cb_ = nullptr;
+  std::function<void(std::string, grpc_error_handle)> cb_ = nullptr;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/credentials/fake/fake_credentials.cc b/grpc/src/core/lib/security/credentials/fake/fake_credentials.cc
index eef636d..57a897f 100644
--- a/grpc/src/core/lib/security/credentials/fake/fake_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/fake/fake_credentials.cc
@@ -59,7 +59,7 @@
   ~grpc_fake_server_credentials() override = default;
 
   grpc_core::RefCountedPtr<grpc_server_security_connector>
-  create_security_connector() override {
+  create_security_connector(const grpc_channel_args* /*args*/) override {
     return grpc_fake_server_security_connector_create(this->Ref());
   }
 };
@@ -92,7 +92,7 @@
 bool grpc_md_only_test_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
-    grpc_error** /*error*/) {
+    grpc_error_handle* /*error*/) {
   grpc_credentials_mdelem_array_add(md_array, md_);
   if (is_async_) {
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_request_metadata,
@@ -103,7 +103,7 @@
 }
 
 void grpc_md_only_test_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* /*md_array*/, grpc_error* error) {
+    grpc_credentials_mdelem_array* /*md_array*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
diff --git a/grpc/src/core/lib/security/credentials/fake/fake_credentials.h b/grpc/src/core/lib/security/credentials/fake/fake_credentials.h
index 3c2449f..ea8c813 100644
--- a/grpc/src/core/lib/security/credentials/fake/fake_credentials.h
+++ b/grpc/src/core/lib/security/credentials/fake/fake_credentials.h
@@ -72,10 +72,10 @@
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   std::string debug_string() override { return "MD only Test Credentials"; };
 
diff --git a/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc
index d1de87d..0e1a2a1 100644
--- a/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc
@@ -61,7 +61,7 @@
  * means the detection is done via network test that is unreliable and the
  * unreliable result should not be referred by successive calls. */
 static int g_metadata_server_available = 0;
-static gpr_mu g_state_mu;
+static grpc_core::Mutex* g_state_mu;
 /* Protect a metadata_server_detector instance that can be modified by more than
  * one gRPC threads */
 static gpr_mu* g_polling_mu;
@@ -69,7 +69,9 @@
 static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker =
     grpc_alts_is_running_on_gcp;
 
-static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); }
+static void init_default_credentials(void) {
+  g_state_mu = new grpc_core::Mutex();
+}
 
 struct metadata_server_detector {
   grpc_polling_entity pollent;
@@ -132,8 +134,8 @@
   return updated;
 }
 
-static void on_metadata_server_detection_http_response(void* user_data,
-                                                       grpc_error* error) {
+static void on_metadata_server_detection_http_response(
+    void* user_data, grpc_error_handle error) {
   metadata_server_detector* detector =
       static_cast<metadata_server_detector*>(user_data);
   if (error == GRPC_ERROR_NONE && detector->response.status == 200 &&
@@ -159,7 +161,7 @@
   gpr_mu_unlock(g_polling_mu);
 }
 
-static void destroy_pollset(void* p, grpc_error* /*e*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*e*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
@@ -219,14 +221,14 @@
 }
 
 /* Takes ownership of creds_path if not NULL. */
-static grpc_error* create_default_creds_from_path(
+static grpc_error_handle create_default_creds_from_path(
     const std::string& creds_path,
     grpc_core::RefCountedPtr<grpc_call_credentials>* creds) {
   grpc_auth_json_key key;
   grpc_auth_refresh_token token;
   grpc_core::RefCountedPtr<grpc_call_credentials> result;
   grpc_slice creds_data = grpc_empty_slice();
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json;
   if (creds_path.empty()) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("creds_path unset");
@@ -282,7 +284,7 @@
 
 static void update_tenancy() {
   gpr_once_init(&g_once, init_default_credentials);
-  grpc_core::MutexLock lock(&g_state_mu);
+  grpc_core::MutexLock lock(g_state_mu);
 
   /* Try a platform-provided hint for GCE. */
   if (!g_metadata_server_available) {
@@ -297,14 +299,14 @@
 }
 
 static bool metadata_server_available() {
-  grpc_core::MutexLock lock(&g_state_mu);
+  grpc_core::MutexLock lock(g_state_mu);
   return static_cast<bool>(g_metadata_server_available);
 }
 
 static grpc_core::RefCountedPtr<grpc_call_credentials> make_default_call_creds(
-    grpc_error** error) {
+    grpc_error_handle* error) {
   grpc_core::RefCountedPtr<grpc_call_credentials> call_creds;
-  grpc_error* err;
+  grpc_error_handle err;
 
   /* First, try the environment variable. */
   char* path_from_env = gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR);
@@ -342,7 +344,7 @@
     grpc_call_credentials* call_credentials) {
   grpc_channel_credentials* result = nullptr;
   grpc_core::RefCountedPtr<grpc_call_credentials> call_creds(call_credentials);
-  grpc_error* error = nullptr;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::ExecCtx exec_ctx;
 
   GRPC_API_TRACE("grpc_google_default_credentials_create(%p)", 1,
@@ -371,7 +373,7 @@
     GPR_ASSERT(result != nullptr);
   } else {
     gpr_log(GPR_ERROR, "Could not create google default credentials: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
   }
   GRPC_ERROR_UNREF(error);
   return result;
@@ -387,9 +389,8 @@
 void grpc_flush_cached_google_default_credentials(void) {
   grpc_core::ExecCtx exec_ctx;
   gpr_once_init(&g_once, init_default_credentials);
-  gpr_mu_lock(&g_state_mu);
+  grpc_core::MutexLock lock(g_state_mu);
   g_metadata_server_available = 0;
-  gpr_mu_unlock(&g_state_mu);
 }
 
 }  // namespace internal
diff --git a/grpc/src/core/lib/security/credentials/iam/iam_credentials.cc b/grpc/src/core/lib/security/credentials/iam/iam_credentials.cc
index 1aeaa88..c9dc223 100644
--- a/grpc/src/core/lib/security/credentials/iam/iam_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/iam/iam_credentials.cc
@@ -36,13 +36,13 @@
 bool grpc_google_iam_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
     grpc_credentials_mdelem_array* md_array,
-    grpc_closure* /*on_request_metadata*/, grpc_error** /*error*/) {
+    grpc_closure* /*on_request_metadata*/, grpc_error_handle* /*error*/) {
   grpc_credentials_mdelem_array_append(md_array, &md_array_);
   return true;
 }
 
 void grpc_google_iam_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* /*md_array*/, grpc_error* error) {
+    grpc_credentials_mdelem_array* /*md_array*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
diff --git a/grpc/src/core/lib/security/credentials/iam/iam_credentials.h b/grpc/src/core/lib/security/credentials/iam/iam_credentials.h
index 9d4a1e2..881ba26 100644
--- a/grpc/src/core/lib/security/credentials/iam/iam_credentials.h
+++ b/grpc/src/core/lib/security/credentials/iam/iam_credentials.h
@@ -35,10 +35,10 @@
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
   std::string debug_string() override { return debug_string_; }
 
  private:
diff --git a/grpc/src/core/lib/security/credentials/insecure/insecure_credentials.cc b/grpc/src/core/lib/security/credentials/insecure/insecure_credentials.cc
index 01c1ad7..4cf500e 100644
--- a/grpc/src/core/lib/security/credentials/insecure/insecure_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/insecure/insecure_credentials.cc
@@ -46,8 +46,8 @@
   InsecureServerCredentials()
       : grpc_server_credentials(kCredentialsTypeInsecure) {}
 
-  RefCountedPtr<grpc_server_security_connector> create_security_connector()
-      override {
+  RefCountedPtr<grpc_server_security_connector> create_security_connector(
+      const grpc_channel_args* /* args */) override {
     return MakeRefCounted<InsecureServerSecurityConnector>(Ref());
   }
 };
diff --git a/grpc/src/core/lib/security/credentials/jwt/json_token.cc b/grpc/src/core/lib/security/credentials/jwt/json_token.cc
index 8f5a94f..5e317c4 100644
--- a/grpc/src/core/lib/security/credentials/jwt/json_token.cc
+++ b/grpc/src/core/lib/security/credentials/jwt/json_token.cc
@@ -33,14 +33,11 @@
 #include "src/core/lib/security/util/json_util.h"
 #include "src/core/lib/slice/b64.h"
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmodule-import-in-extern-c"
 extern "C" {
 #include <openssl/bio.h>
 #include <openssl/evp.h>
 #include <openssl/pem.h>
 }
-#pragma clang diagnostic pop
 
 using grpc_core::Json;
 
@@ -75,7 +72,7 @@
   BIO* bio = nullptr;
   const char* prop_value;
   int success = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   memset(&result, 0, sizeof(grpc_auth_json_key));
   result.type = GRPC_AUTH_JSON_TYPE_INVALID;
@@ -127,7 +124,7 @@
 
 grpc_auth_json_key grpc_auth_json_key_create_from_string(
     const char* json_string) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_string, &error);
   GRPC_LOG_IF_ERROR("JSON key parsing", error);
   return grpc_auth_json_key_create_from_json(json);
diff --git a/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc b/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc
index e5edc05..27590f4 100644
--- a/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc
@@ -59,7 +59,7 @@
 bool grpc_service_account_jwt_access_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context context,
     grpc_credentials_mdelem_array* md_array,
-    grpc_closure* /*on_request_metadata*/, grpc_error** error) {
+    grpc_closure* /*on_request_metadata*/, grpc_error_handle* error) {
   gpr_timespec refresh_threshold = gpr_time_from_seconds(
       GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
 
@@ -109,7 +109,7 @@
 }
 
 void grpc_service_account_jwt_access_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* /*md_array*/, grpc_error* error) {
+    grpc_credentials_mdelem_array* /*md_array*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
@@ -141,7 +141,7 @@
 }
 
 static char* redact_private_key(const char* json_key) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_key, &error);
   if (error != GRPC_ERROR_NONE || json.type() != Json::Type::OBJECT) {
     GRPC_ERROR_UNREF(error);
diff --git a/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.h b/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.h
index d42fc25..5ae4c1f 100644
--- a/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.h
+++ b/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.h
@@ -41,10 +41,10 @@
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   const gpr_timespec& jwt_lifetime() const { return jwt_lifetime_; }
   const grpc_auth_json_key& key() const { return key_; }
diff --git a/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc b/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc
index ec3aed8..8d43cf9 100644
--- a/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc
+++ b/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc
@@ -28,14 +28,11 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmodule-import-in-extern-c"
 extern "C" {
 #include <openssl/bn.h>
 #include <openssl/pem.h>
 #include <openssl/rsa.h>
 }
-#pragma clang diagnostic pop
 
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
@@ -90,10 +87,11 @@
     return Json();  // JSON null
   }
   absl::string_view string = grpc_core::StringViewFromSlice(slice);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(string, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
     json = Json();  // JSON null
   }
@@ -415,7 +413,7 @@
             response->status);
     return Json();  // JSON null
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(
       absl::string_view(response->body, response->body_length), &error);
   if (error != GRPC_ERROR_NONE) {
@@ -630,7 +628,7 @@
   return result;
 }
 
-static void on_keys_retrieved(void* user_data, grpc_error* /*error*/) {
+static void on_keys_retrieved(void* user_data, grpc_error_handle /*error*/) {
   verifier_cb_ctx* ctx = static_cast<verifier_cb_ctx*>(user_data);
   Json json = json_from_http(&ctx->responses[HTTP_RESPONSE_KEYS]);
   EVP_PKEY* verification_key = nullptr;
@@ -669,7 +667,8 @@
   verifier_cb_ctx_destroy(ctx);
 }
 
-static void on_openid_config_retrieved(void* user_data, grpc_error* /*error*/) {
+static void on_openid_config_retrieved(void* user_data,
+                                       grpc_error_handle /*error*/) {
   verifier_cb_ctx* ctx = static_cast<verifier_cb_ctx*>(user_data);
   const grpc_http_response* response = &ctx->responses[HTTP_RESPONSE_OPENID];
   Json json = json_from_http(response);
diff --git a/grpc/src/core/lib/security/credentials/local/local_credentials.cc b/grpc/src/core/lib/security/credentials/local/local_credentials.cc
index 966a887..84caf1c 100644
--- a/grpc/src/core/lib/security/credentials/local/local_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/local/local_credentials.cc
@@ -39,7 +39,8 @@
 }
 
 grpc_core::RefCountedPtr<grpc_server_security_connector>
-grpc_local_server_credentials::create_security_connector() {
+grpc_local_server_credentials::create_security_connector(
+    const grpc_channel_args* /* args */) {
   return grpc_local_server_security_connector_create(this->Ref());
 }
 
diff --git a/grpc/src/core/lib/security/credentials/local/local_credentials.h b/grpc/src/core/lib/security/credentials/local/local_credentials.h
index 60a8a4f..a1857ad 100644
--- a/grpc/src/core/lib/security/credentials/local/local_credentials.h
+++ b/grpc/src/core/lib/security/credentials/local/local_credentials.h
@@ -50,7 +50,7 @@
   ~grpc_local_server_credentials() override = default;
 
   grpc_core::RefCountedPtr<grpc_server_security_connector>
-  create_security_connector() override;
+  create_security_connector(const grpc_channel_args* /* args */) override;
 
   grpc_local_connect_type connect_type() const { return connect_type_; }
 
diff --git a/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
index bbd2cb5..50d20e6 100644
--- a/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
@@ -61,7 +61,7 @@
   grpc_auth_refresh_token result;
   const char* prop_value;
   int success = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
 
   memset(&result, 0, sizeof(grpc_auth_refresh_token));
   result.type = GRPC_AUTH_JSON_TYPE_INVALID;
@@ -94,10 +94,11 @@
 
 grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
     const char* json_string) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(json_string, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parsing failed: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parsing failed: %s",
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
   }
   return grpc_auth_refresh_token_create_from_json(json);
@@ -164,11 +165,11 @@
     const char* token_type = nullptr;
     const char* expires_in = nullptr;
     Json::Object::const_iterator it;
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     json = Json::Parse(null_terminated_body, &error);
     if (error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR, "Could not parse JSON from %s: %s",
-              null_terminated_body, grpc_error_string(error));
+              null_terminated_body, grpc_error_std_string(error).c_str());
       GRPC_ERROR_UNREF(error);
       status = GRPC_CREDENTIALS_ERROR;
       goto end;
@@ -221,7 +222,7 @@
 }
 
 static void on_oauth2_token_fetcher_http_response(void* user_data,
-                                                  grpc_error* error) {
+                                                  grpc_error_handle error) {
   GRPC_LOG_IF_ERROR("oauth_fetch", GRPC_ERROR_REF(error));
   grpc_credentials_metadata_request* r =
       static_cast<grpc_credentials_metadata_request*>(user_data);
@@ -231,7 +232,7 @@
 }
 
 void grpc_oauth2_token_fetcher_credentials::on_http_response(
-    grpc_credentials_metadata_request* r, grpc_error* error) {
+    grpc_credentials_metadata_request* r, grpc_error_handle error) {
   grpc_mdelem access_token_md = GRPC_MDNULL;
   grpc_millis token_lifetime = 0;
   grpc_credentials_status status =
@@ -253,7 +254,7 @@
   gpr_mu_unlock(&mu_);
   // Invoke callbacks for all pending requests.
   while (pending_request != nullptr) {
-    grpc_error* new_error = GRPC_ERROR_NONE;
+    grpc_error_handle new_error = GRPC_ERROR_NONE;
     if (status == GRPC_CREDENTIALS_OK) {
       grpc_credentials_mdelem_array_add(pending_request->md_array,
                                         access_token_md);
@@ -277,7 +278,7 @@
 bool grpc_oauth2_token_fetcher_credentials::get_request_metadata(
     grpc_polling_entity* pollent, grpc_auth_metadata_context /*context*/,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
-    grpc_error** /*error*/) {
+    grpc_error_handle* /*error*/) {
   // Check if we can use the cached token.
   grpc_millis refresh_threshold =
       GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS * GPR_MS_PER_SEC;
@@ -325,7 +326,7 @@
 }
 
 void grpc_oauth2_token_fetcher_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* md_array, grpc_error* error) {
+    grpc_credentials_mdelem_array* md_array, grpc_error_handle error) {
   gpr_mu_lock(&mu_);
   grpc_oauth2_pending_get_request_metadata* prev = nullptr;
   grpc_oauth2_pending_get_request_metadata* pending_request = pending_requests_;
@@ -525,8 +526,8 @@
   body->push_back(absl::StrFormat("&%s=%s", field_name, field));
 }
 
-grpc_error* LoadTokenFile(const char* path, gpr_slice* token) {
-  grpc_error* err = grpc_load_file(path, 1, token);
+grpc_error_handle LoadTokenFile(const char* path, gpr_slice* token) {
+  grpc_error_handle err = grpc_load_file(path, 1, token);
   if (err != GRPC_ERROR_NONE) return err;
   if (GRPC_SLICE_LENGTH(*token) == 0) {
     gpr_log(GPR_ERROR, "Token file %s is empty", path);
@@ -565,7 +566,7 @@
                     grpc_millis deadline) override {
     char* body = nullptr;
     size_t body_length = 0;
-    grpc_error* err = FillBody(&body, &body_length);
+    grpc_error_handle err = FillBody(&body, &body_length);
     if (err != GRPC_ERROR_NONE) {
       response_cb(metadata_req, err);
       GRPC_ERROR_UNREF(err);
@@ -598,12 +599,12 @@
     gpr_free(body);
   }
 
-  grpc_error* FillBody(char** body, size_t* body_length) {
+  grpc_error_handle FillBody(char** body, size_t* body_length) {
     *body = nullptr;
     std::vector<std::string> body_parts;
     grpc_slice subject_token = grpc_empty_slice();
     grpc_slice actor_token = grpc_empty_slice();
-    grpc_error* err = GRPC_ERROR_NONE;
+    grpc_error_handle err = GRPC_ERROR_NONE;
 
     auto cleanup = [&body, &body_length, &body_parts, &subject_token,
                     &actor_token, &err]() {
@@ -656,7 +657,7 @@
 
 absl::StatusOr<URI> ValidateStsCredentialsOptions(
     const grpc_sts_credentials_options* options) {
-  absl::InlinedVector<grpc_error*, 3> error_list;
+  absl::InlinedVector<grpc_error_handle, 3> error_list;
   absl::StatusOr<URI> sts_url =
       URI::Parse(options->token_exchange_service_uri == nullptr
                      ? ""
@@ -685,7 +686,8 @@
   }
   auto grpc_error_vec = GRPC_ERROR_CREATE_FROM_VECTOR(
       "Invalid STS Credentials Options", &error_list);
-  auto retval = absl::InvalidArgumentError(grpc_error_string(grpc_error_vec));
+  auto retval =
+      absl::InvalidArgumentError(grpc_error_std_string(grpc_error_vec));
   GRPC_ERROR_UNREF(grpc_error_vec);
   return retval;
 }
@@ -718,13 +720,13 @@
 bool grpc_access_token_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
     grpc_credentials_mdelem_array* md_array,
-    grpc_closure* /*on_request_metadata*/, grpc_error** /*error*/) {
+    grpc_closure* /*on_request_metadata*/, grpc_error_handle* /*error*/) {
   grpc_credentials_mdelem_array_add(md_array, access_token_md_);
   return true;
 }
 
 void grpc_access_token_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* /*md_array*/, grpc_error* error) {
+    grpc_credentials_mdelem_array* /*md_array*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
diff --git a/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
index 2642919..f174112 100644
--- a/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
+++ b/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
@@ -78,13 +78,13 @@
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   void on_http_response(grpc_credentials_metadata_request* r,
-                        grpc_error* error);
+                        grpc_error_handle error);
   std::string debug_string() override;
 
  protected:
@@ -138,10 +138,10 @@
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   std::string debug_string() override;
 
diff --git a/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc
index a5b01cd..4c583ad 100644
--- a/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc
@@ -82,10 +82,10 @@
   Unref();
 }
 
-static grpc_error* process_plugin_result(
+static grpc_error_handle process_plugin_result(
     grpc_plugin_credentials::pending_request* r, const grpc_metadata* md,
     size_t num_md, grpc_status_code status, const char* error_details) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (status != GRPC_STATUS_OK) {
     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
         absl::StrCat("Getting metadata from plugin failed with error: ",
@@ -142,7 +142,7 @@
   r->creds->pending_request_complete(r);
   // If it has not been cancelled, process it.
   if (!r->cancelled) {
-    grpc_error* error =
+    grpc_error_handle error =
         process_plugin_result(r, md, num_md, status, error_details);
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_request_metadata, error);
   } else if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
@@ -157,7 +157,7 @@
 bool grpc_plugin_credentials::get_request_metadata(
     grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context context,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
-    grpc_error** error) {
+    grpc_error_handle* error) {
   bool retval = true;  // Synchronous return.
   if (plugin_.get_metadata != nullptr) {
     // Create pending_request object.
@@ -231,7 +231,7 @@
 }
 
 void grpc_plugin_credentials::cancel_get_request_metadata(
-    grpc_credentials_mdelem_array* md_array, grpc_error* error) {
+    grpc_credentials_mdelem_array* md_array, grpc_error_handle error) {
   gpr_mu_lock(&mu_);
   for (pending_request* pending_request = pending_requests_;
        pending_request != nullptr; pending_request = pending_request->next) {
diff --git a/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.h b/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.h
index 881eded..6835186 100644
--- a/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.h
+++ b/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.h
@@ -47,10 +47,10 @@
                             grpc_auth_metadata_context context,
                             grpc_credentials_mdelem_array* md_array,
                             grpc_closure* on_request_metadata,
-                            grpc_error** error) override;
+                            grpc_error_handle* error) override;
 
   void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override;
+                                   grpc_error_handle error) override;
 
   // Checks if the request has been cancelled.
   // If not, removes it from the pending list, so that it cannot be
diff --git a/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc b/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc
index e2a1ad0..469eb0c 100644
--- a/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc
@@ -190,7 +190,8 @@
   gpr_free(config_.pem_root_certs);
 }
 grpc_core::RefCountedPtr<grpc_server_security_connector>
-grpc_ssl_server_credentials::create_security_connector() {
+grpc_ssl_server_credentials::create_security_connector(
+    const grpc_channel_args* /* args */) {
   return grpc_ssl_server_security_connector_create(this->Ref());
 }
 
diff --git a/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.h b/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.h
index 0c5af81..0491eea 100644
--- a/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.h
+++ b/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.h
@@ -69,7 +69,7 @@
   ~grpc_ssl_server_credentials() override;
 
   grpc_core::RefCountedPtr<grpc_server_security_connector>
-  create_security_connector() override;
+  create_security_connector(const grpc_channel_args* /* args */) override;
 
   bool has_cert_config_fetcher() const {
     return certificate_config_fetcher_.cb != nullptr;
diff --git a/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc
index 179df8d..e831aa5 100644
--- a/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc
+++ b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc
@@ -100,8 +100,9 @@
 };
 
 void grpc_tls_certificate_distributor::SetErrorForCert(
-    const std::string& cert_name, absl::optional<grpc_error*> root_cert_error,
-    absl::optional<grpc_error*> identity_cert_error) {
+    const std::string& cert_name,
+    absl::optional<grpc_error_handle> root_cert_error,
+    absl::optional<grpc_error_handle> identity_cert_error) {
   GPR_ASSERT(root_cert_error.has_value() || identity_cert_error.has_value());
   grpc_core::MutexLock lock(&mu_);
   CertificateInfo& cert_info = certificate_info_map_[cert_name];
@@ -112,7 +113,7 @@
       GPR_ASSERT(watcher_it != watchers_.end());
       // identity_cert_error_to_report is the error of the identity cert this
       // watcher is watching, if there is any.
-      grpc_error* identity_cert_error_to_report = GRPC_ERROR_NONE;
+      grpc_error_handle identity_cert_error_to_report = GRPC_ERROR_NONE;
       if (identity_cert_error.has_value() &&
           watcher_it->second.identity_cert_name == cert_name) {
         identity_cert_error_to_report = *identity_cert_error;
@@ -133,7 +134,7 @@
       GPR_ASSERT(watcher_it != watchers_.end());
       // root_cert_error_to_report is the error of the root cert this watcher is
       // watching, if there is any.
-      grpc_error* root_cert_error_to_report = GRPC_ERROR_NONE;
+      grpc_error_handle root_cert_error_to_report = GRPC_ERROR_NONE;
       if (root_cert_error.has_value() &&
           watcher_it->second.root_cert_name == cert_name) {
         // In this case, We've already sent the error updates at the time when
@@ -151,7 +152,7 @@
   }
 };
 
-void grpc_tls_certificate_distributor::SetError(grpc_error* error) {
+void grpc_tls_certificate_distributor::SetError(grpc_error_handle error) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   grpc_core::MutexLock lock(&mu_);
   for (const auto& watcher : watchers_) {
@@ -194,8 +195,8 @@
                               identity_cert_name};
     absl::optional<absl::string_view> updated_root_certs;
     absl::optional<grpc_core::PemKeyCertPairList> updated_identity_pairs;
-    grpc_error* root_error = GRPC_ERROR_NONE;
-    grpc_error* identity_error = GRPC_ERROR_NONE;
+    grpc_error_handle root_error = GRPC_ERROR_NONE;
+    grpc_error_handle identity_error = GRPC_ERROR_NONE;
     if (root_cert_name.has_value()) {
       CertificateInfo& cert_info = certificate_info_map_[*root_cert_name];
       start_watching_root_cert = cert_info.root_cert_watchers.empty();
diff --git a/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
index 9ce9443..36c46be 100644
--- a/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
+++ b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
@@ -68,8 +68,8 @@
     // certificates.
     // @param identity_cert_error the error occurred while reloading identity
     // certificates.
-    virtual void OnError(grpc_error* root_cert_error,
-                         grpc_error* identity_cert_error) = 0;
+    virtual void OnError(grpc_error_handle root_cert_error,
+                         grpc_error_handle identity_cert_error) = 0;
   };
 
   // Sets the key materials based on their certificate name.
@@ -95,14 +95,14 @@
   // @param identity_cert_error The error that the caller encounters when
   // reloading identity certs.
   void SetErrorForCert(const std::string& cert_name,
-                       absl::optional<grpc_error*> root_cert_error,
-                       absl::optional<grpc_error*> identity_cert_error);
+                       absl::optional<grpc_error_handle> root_cert_error,
+                       absl::optional<grpc_error_handle> identity_cert_error);
 
   // Propagates the error that the caller (e.g. Producer) encounters to all
   // watchers.
   //
   // @param error The error that the caller encounters.
-  void SetError(grpc_error* error);
+  void SetError(grpc_error_handle error);
 
   // Sets the TLS certificate watch status callback function. The
   // grpc_tls_certificate_distributor will invoke this callback when a new
@@ -169,9 +169,9 @@
     // The contents of the identity key-certificate pairs.
     grpc_core::PemKeyCertPairList pem_key_cert_pairs;
     // The root cert reloading error propagated by the caller.
-    grpc_error* root_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle root_cert_error = GRPC_ERROR_NONE;
     // The identity cert reloading error propagated by the caller.
-    grpc_error* identity_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle identity_cert_error = GRPC_ERROR_NONE;
     // The set of watchers watching root certificates.
     // This is mainly used for quickly looking up the affected watchers while
     // performing a credential reloading.
@@ -185,11 +185,11 @@
       GRPC_ERROR_UNREF(root_cert_error);
       GRPC_ERROR_UNREF(identity_cert_error);
     }
-    void SetRootError(grpc_error* error) {
+    void SetRootError(grpc_error_handle error) {
       GRPC_ERROR_UNREF(root_cert_error);
       root_cert_error = error;
     }
-    void SetIdentityError(grpc_error* error) {
+    void SetIdentityError(grpc_error_handle error) {
       GRPC_ERROR_UNREF(identity_cert_error);
       identity_cert_error = error;
     }
diff --git a/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc
index 2dae03c..b4b6bf5 100644
--- a/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc
+++ b/grpc/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc
@@ -60,8 +60,8 @@
       distributor_->SetKeyMaterials(cert_name, std::move(root_certificate),
                                     std::move(pem_key_cert_pairs));
     }
-    grpc_error* root_cert_error = GRPC_ERROR_NONE;
-    grpc_error* identity_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle root_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle identity_cert_error = GRPC_ERROR_NONE;
     if (root_being_watched && !root_has_update) {
       root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "Unable to get latest root certificates.");
@@ -150,8 +150,8 @@
       distributor_->SetKeyMaterials(cert_name, root_certificate,
                                     pem_key_cert_pairs);
     }
-    grpc_error* root_cert_error = GRPC_ERROR_NONE;
-    grpc_error* identity_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle root_cert_error = GRPC_ERROR_NONE;
+    grpc_error_handle identity_cert_error = GRPC_ERROR_NONE;
     if (root_being_watched && !root_certificate.has_value()) {
       root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "Unable to get latest root certificates.");
@@ -210,10 +210,11 @@
   }
   if (root_cert_changed || identity_cert_changed) {
     ExecCtx exec_ctx;
-    grpc_error* root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+    grpc_error_handle root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Unable to get latest root certificates.");
-    grpc_error* identity_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "Unable to get latest identity certificates.");
+    grpc_error_handle identity_cert_error =
+        GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            "Unable to get latest identity certificates.");
     for (const auto& p : watcher_info_) {
       const std::string& cert_name = p.first;
       const WatcherInfo& info = p.second;
@@ -256,11 +257,12 @@
     const std::string& root_cert_full_path) {
   // Read the root file.
   grpc_slice root_slice = grpc_empty_slice();
-  grpc_error* root_error =
+  grpc_error_handle root_error =
       grpc_load_file(root_cert_full_path.c_str(), 0, &root_slice);
   if (root_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "Reading file %s failed: %s",
-            root_cert_full_path.c_str(), grpc_error_string(root_error));
+            root_cert_full_path.c_str(),
+            grpc_error_std_string(root_error).c_str());
     GRPC_ERROR_UNREF(root_error);
     return absl::nullopt;
   }
@@ -314,19 +316,21 @@
     }
     // Read the identity files.
     SliceWrapper key_slice, cert_slice;
-    grpc_error* key_error =
+    grpc_error_handle key_error =
         grpc_load_file(private_key_path.c_str(), 0, &key_slice.slice);
     if (key_error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR, "Reading file %s failed: %s. Start retrying...",
-              private_key_path.c_str(), grpc_error_string(key_error));
+              private_key_path.c_str(),
+              grpc_error_std_string(key_error).c_str());
       GRPC_ERROR_UNREF(key_error);
       continue;
     }
-    grpc_error* cert_error =
+    grpc_error_handle cert_error =
         grpc_load_file(identity_certificate_path.c_str(), 0, &cert_slice.slice);
     if (cert_error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR, "Reading file %s failed: %s. Start retrying...",
-              identity_certificate_path.c_str(), grpc_error_string(cert_error));
+              identity_certificate_path.c_str(),
+              grpc_error_std_string(cert_error).c_str());
       GRPC_ERROR_UNREF(cert_error);
       continue;
     }
@@ -367,6 +371,7 @@
 grpc_tls_certificate_provider* grpc_tls_certificate_provider_static_data_create(
     const char* root_certificate, grpc_tls_identity_pairs* pem_key_cert_pairs) {
   GPR_ASSERT(root_certificate != nullptr || pem_key_cert_pairs != nullptr);
+  grpc_core::ExecCtx exec_ctx;
   grpc_core::PemKeyCertPairList identity_pairs_core;
   if (pem_key_cert_pairs != nullptr) {
     identity_pairs_core = std::move(pem_key_cert_pairs->pem_key_cert_pairs);
@@ -384,6 +389,7 @@
 grpc_tls_certificate_provider_file_watcher_create(
     const char* private_key_path, const char* identity_certificate_path,
     const char* root_cert_path, unsigned int refresh_interval_sec) {
+  grpc_core::ExecCtx exec_ctx;
   return new grpc_core::FileWatcherCertificateProvider(
       private_key_path == nullptr ? "" : private_key_path,
       identity_certificate_path == nullptr ? "" : identity_certificate_path,
diff --git a/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc b/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc
index cf2b4c6..bf26e70 100644
--- a/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc
+++ b/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc
@@ -87,6 +87,7 @@
 /** -- Wrapper APIs declared in grpc_security.h -- **/
 
 grpc_tls_credentials_options* grpc_tls_credentials_options_create() {
+  grpc_core::ExecCtx exec_ctx;
   return new grpc_tls_credentials_options();
 }
 
@@ -109,6 +110,7 @@
     grpc_tls_certificate_provider* provider) {
   GPR_ASSERT(options != nullptr);
   GPR_ASSERT(provider != nullptr);
+  grpc_core::ExecCtx exec_ctx;
   options->set_certificate_provider(
       provider->Ref(DEBUG_LOCATION, "set_certificate_provider"));
 }
@@ -142,6 +144,7 @@
     grpc_tls_server_authorization_check_config* config) {
   GPR_ASSERT(options != nullptr);
   GPR_ASSERT(config != nullptr);
+  grpc_core::ExecCtx exec_ctx;
   options->set_server_authorization_check_config(config->Ref());
 }
 
@@ -159,6 +162,7 @@
             "check config.");
     return nullptr;
   }
+  grpc_core::ExecCtx exec_ctx;
   return new grpc_tls_server_authorization_check_config(
       config_user_data, schedule, cancel, destruct);
 }
diff --git a/grpc/src/core/lib/security/credentials/tls/tls_credentials.cc b/grpc/src/core/lib/security/credentials/tls/tls_credentials.cc
index 06887e7..f5b05d8 100644
--- a/grpc/src/core/lib/security/credentials/tls/tls_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/tls/tls_credentials.cc
@@ -106,7 +106,8 @@
 TlsServerCredentials::~TlsServerCredentials() {}
 
 grpc_core::RefCountedPtr<grpc_server_security_connector>
-TlsServerCredentials::create_security_connector() {
+TlsServerCredentials::create_security_connector(
+    const grpc_channel_args* /* args */) {
   return grpc_core::TlsServerSecurityConnector::
       CreateTlsServerSecurityConnector(this->Ref(), options_);
 }
diff --git a/grpc/src/core/lib/security/credentials/tls/tls_credentials.h b/grpc/src/core/lib/security/credentials/tls/tls_credentials.h
index 214bc90..a5e4f48 100644
--- a/grpc/src/core/lib/security/credentials/tls/tls_credentials.h
+++ b/grpc/src/core/lib/security/credentials/tls/tls_credentials.h
@@ -51,7 +51,7 @@
   ~TlsServerCredentials() override;
 
   grpc_core::RefCountedPtr<grpc_server_security_connector>
-  create_security_connector() override;
+  create_security_connector(const grpc_channel_args* /* args */) override;
 
   grpc_tls_credentials_options* options() const { return options_.get(); }
 
diff --git a/grpc/src/core/lib/security/credentials/xds/xds_credentials.cc b/grpc/src/core/lib/security/credentials/xds/xds_credentials.cc
index 9e00f70..15b8e90 100644
--- a/grpc/src/core/lib/security/credentials/xds/xds_credentials.cc
+++ b/grpc/src/core/lib/security/credentials/xds/xds_credentials.cc
@@ -20,6 +20,7 @@
 
 #include "src/core/lib/security/credentials/xds/xds_credentials.h"
 
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h"
 #include "src/core/ext/xds/xds_certificate_provider.h"
 #include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
 #include "src/core/lib/security/credentials/tls/tls_credentials.h"
@@ -35,17 +36,17 @@
 bool XdsVerifySubjectAlternativeNames(
     const char* const* subject_alternative_names,
     size_t subject_alternative_names_size,
-    const std::vector<XdsApi::StringMatcher>& matchers) {
+    const std::vector<StringMatcher>& matchers) {
   if (matchers.empty()) return true;
   for (size_t i = 0; i < subject_alternative_names_size; ++i) {
     for (const auto& matcher : matchers) {
-      if (matcher.type() == XdsApi::StringMatcher::StringMatcherType::EXACT) {
-        // For EXACT match, use DNS rules for verifying SANs
+      if (matcher.type() == StringMatcher::Type::kExact) {
+        // For Exact match, use DNS rules for verifying SANs
         // TODO(zhenlian): Right now, the SSL layer does not save the type of
         // the SAN, so we are doing a DNS style verification for all SANs when
         // the type is EXACT. When we expose the SAN type, change this to only
         // do this verification when the SAN type is DNS and match type is
-        // EXACT. For all other cases, we should use matcher.Match().
+        // kExact. For all other cases, we should use matcher.Match().
         if (VerifySubjectAlternativeName(subject_alternative_names[i],
                                          matcher.string_matcher())) {
           return true;
@@ -60,39 +61,51 @@
   return false;
 }
 
-int ServerAuthCheckSchedule(void* config_user_data,
-                            grpc_tls_server_authorization_check_arg* arg) {
-  XdsCertificateProvider* xds_certificate_provider =
-      static_cast<XdsCertificateProvider*>(config_user_data);
-  if (XdsVerifySubjectAlternativeNames(
-          arg->subject_alternative_names, arg->subject_alternative_names_size,
-          xds_certificate_provider->subject_alternative_name_matchers())) {
-    arg->success = 1;
-    arg->status = GRPC_STATUS_OK;
-  } else {
-    arg->success = 0;
-    arg->status = GRPC_STATUS_UNAUTHENTICATED;
-    if (arg->error_details) {
-      arg->error_details->set_error_details(
-          "SANs from certificate did not match SANs from xDS control plane");
-    }
+class ServerAuthCheck {
+ public:
+  ServerAuthCheck(
+      RefCountedPtr<XdsCertificateProvider> xds_certificate_provider,
+      std::string cluster_name)
+      : xds_certificate_provider_(std::move(xds_certificate_provider)),
+        cluster_name_(std::move(cluster_name)) {}
+
+  static int Schedule(void* config_user_data,
+                      grpc_tls_server_authorization_check_arg* arg) {
+    return static_cast<ServerAuthCheck*>(config_user_data)->ScheduleImpl(arg);
   }
 
-  return 0; /* synchronous check */
-}
+  static void Destroy(void* config_user_data) {
+    delete static_cast<ServerAuthCheck*>(config_user_data);
+  }
 
-void ServerAuthCheckDestroy(void* config_user_data) {
-  XdsCertificateProvider* xds_certificate_provider =
-      static_cast<XdsCertificateProvider*>(config_user_data);
-  xds_certificate_provider->Unref();
-}
+ private:
+  int ScheduleImpl(grpc_tls_server_authorization_check_arg* arg) {
+    if (XdsVerifySubjectAlternativeNames(
+            arg->subject_alternative_names, arg->subject_alternative_names_size,
+            xds_certificate_provider_->GetSanMatchers(cluster_name_))) {
+      arg->success = 1;
+      arg->status = GRPC_STATUS_OK;
+    } else {
+      arg->success = 0;
+      arg->status = GRPC_STATUS_UNAUTHENTICATED;
+      if (arg->error_details) {
+        arg->error_details->set_error_details(
+            "SANs from certificate did not match SANs from xDS control plane");
+      }
+    }
+    return 0; /* synchronous check */
+  }
+
+  RefCountedPtr<XdsCertificateProvider> xds_certificate_provider_;
+  std::string cluster_name_;
+};
 
 }  // namespace
 
 bool TestOnlyXdsVerifySubjectAlternativeNames(
     const char* const* subject_alternative_names,
     size_t subject_alternative_names_size,
-    const std::vector<XdsApi::StringMatcher>& matchers) {
+    const std::vector<StringMatcher>& matchers) {
   return XdsVerifySubjectAlternativeNames(
       subject_alternative_names, subject_alternative_names_size, matchers);
 }
@@ -105,49 +118,79 @@
 XdsCredentials::create_security_connector(
     RefCountedPtr<grpc_call_credentials> call_creds, const char* target_name,
     const grpc_channel_args* args, grpc_channel_args** new_args) {
-  auto xds_certificate_provider =
-      XdsCertificateProvider::GetFromChannelArgs(args);
+  struct ChannelArgsDeleter {
+    const grpc_channel_args* args;
+    bool owned;
+    ~ChannelArgsDeleter() {
+      if (owned) grpc_channel_args_destroy(args);
+    }
+  };
+  ChannelArgsDeleter temp_args{args, false};
   // TODO(yashykt): This arg will no longer need to be added after b/173119596
   // is fixed.
   grpc_arg override_arg = grpc_channel_arg_string_create(
       const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
       const_cast<char*>(target_name));
   const char* override_arg_name = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
-  const grpc_channel_args* temp_args = args;
   if (grpc_channel_args_find(args, override_arg_name) == nullptr) {
-    temp_args = grpc_channel_args_copy_and_add_and_remove(
+    temp_args.args = grpc_channel_args_copy_and_add_and_remove(
         args, &override_arg_name, 1, &override_arg, 1);
+    temp_args.owned = true;
   }
   RefCountedPtr<grpc_channel_security_connector> security_connector;
+  auto xds_certificate_provider =
+      XdsCertificateProvider::GetFromChannelArgs(args);
   if (xds_certificate_provider != nullptr) {
-    auto tls_credentials_options =
-        MakeRefCounted<grpc_tls_credentials_options>();
-    tls_credentials_options->set_certificate_provider(xds_certificate_provider);
-    if (xds_certificate_provider->ProvidesRootCerts()) {
-      tls_credentials_options->set_watch_root_cert(true);
+    std::string cluster_name =
+        grpc_channel_args_find_string(args, GRPC_ARG_XDS_CLUSTER_NAME);
+    GPR_ASSERT(cluster_name.data() != nullptr);
+    const bool watch_root =
+        xds_certificate_provider->ProvidesRootCerts(cluster_name);
+    const bool watch_identity =
+        xds_certificate_provider->ProvidesIdentityCerts(cluster_name);
+    if (watch_root || watch_identity) {
+      auto tls_credentials_options =
+          MakeRefCounted<grpc_tls_credentials_options>();
+      tls_credentials_options->set_certificate_provider(
+          xds_certificate_provider);
+      if (watch_root) {
+        tls_credentials_options->set_watch_root_cert(true);
+        tls_credentials_options->set_root_cert_name(cluster_name);
+      }
+      if (watch_identity) {
+        tls_credentials_options->set_watch_identity_pair(true);
+        tls_credentials_options->set_identity_cert_name(cluster_name);
+      }
+      tls_credentials_options->set_server_verification_option(
+          GRPC_TLS_SKIP_HOSTNAME_VERIFICATION);
+      auto* server_auth_check = new ServerAuthCheck(xds_certificate_provider,
+                                                    std::move(cluster_name));
+      tls_credentials_options->set_server_authorization_check_config(
+          MakeRefCounted<grpc_tls_server_authorization_check_config>(
+              server_auth_check, ServerAuthCheck::Schedule, nullptr,
+              ServerAuthCheck::Destroy));
+      // TODO(yashkt): Creating a new TlsCreds object each time we create a
+      // security connector means that the security connector's cmp() method
+      // returns unequal for each instance, which means that every time an LB
+      // policy updates, all the subchannels will be recreated.  This is
+      // going to lead to a lot of connection churn.  Instead, we should
+      // either (a) change the TLS security connector's cmp() method to be
+      // smarter somehow, so that it compares unequal only when the
+      // tls_credentials_options have changed, or (b) cache the TlsCreds
+      // objects in the XdsCredentials object so that we can reuse the
+      // same one when creating new security connectors, swapping out the
+      // TlsCreds object only when the tls_credentials_options change.
+      // Option (a) would probably be better, although it may require some
+      // structural changes to the security connector API.
+      auto tls_credentials =
+          MakeRefCounted<TlsCredentials>(std::move(tls_credentials_options));
+      return tls_credentials->create_security_connector(
+          std::move(call_creds), target_name, temp_args.args, new_args);
     }
-    if (xds_certificate_provider->ProvidesIdentityCerts()) {
-      tls_credentials_options->set_watch_identity_pair(true);
-    }
-    tls_credentials_options->set_server_verification_option(
-        GRPC_TLS_SKIP_HOSTNAME_VERIFICATION);
-    tls_credentials_options->set_server_authorization_check_config(
-        MakeRefCounted<grpc_tls_server_authorization_check_config>(
-            xds_certificate_provider->Ref().release(), ServerAuthCheckSchedule,
-            nullptr, ServerAuthCheckDestroy));
-    auto tls_credentials =
-        MakeRefCounted<TlsCredentials>(std::move(tls_credentials_options));
-    security_connector = tls_credentials->create_security_connector(
-        std::move(call_creds), target_name, temp_args, new_args);
-  } else {
-    GPR_ASSERT(fallback_credentials_ != nullptr);
-    security_connector = fallback_credentials_->create_security_connector(
-        std::move(call_creds), target_name, temp_args, new_args);
   }
-  if (temp_args != args) {
-    grpc_channel_args_destroy(temp_args);
-  }
-  return security_connector;
+  GPR_ASSERT(fallback_credentials_ != nullptr);
+  return fallback_credentials_->create_security_connector(
+      std::move(call_creds), target_name, temp_args.args, new_args);
 }
 
 //
@@ -155,9 +198,35 @@
 //
 
 RefCountedPtr<grpc_server_security_connector>
-XdsServerCredentials::create_security_connector() {
-  // TODO(yashkt): Fill this
-  return fallback_credentials_->create_security_connector();
+XdsServerCredentials::create_security_connector(const grpc_channel_args* args) {
+  auto xds_certificate_provider =
+      XdsCertificateProvider::GetFromChannelArgs(args);
+  // Identity certs are a must for TLS.
+  if (xds_certificate_provider != nullptr &&
+      xds_certificate_provider->ProvidesIdentityCerts("")) {
+    auto tls_credentials_options =
+        MakeRefCounted<grpc_tls_credentials_options>();
+    tls_credentials_options->set_watch_identity_pair(true);
+    tls_credentials_options->set_certificate_provider(xds_certificate_provider);
+    if (xds_certificate_provider->ProvidesRootCerts("")) {
+      tls_credentials_options->set_watch_root_cert(true);
+      if (xds_certificate_provider->GetRequireClientCertificate("")) {
+        tls_credentials_options->set_cert_request_type(
+            GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
+      } else {
+        tls_credentials_options->set_cert_request_type(
+            GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY);
+      }
+    } else {
+      // Do not request client certificate if there is no way to verify.
+      tls_credentials_options->set_cert_request_type(
+          GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
+    }
+    auto tls_credentials = MakeRefCounted<TlsServerCredentials>(
+        std::move(tls_credentials_options));
+    return tls_credentials->create_security_connector(args);
+  }
+  return fallback_credentials_->create_security_connector(args);
 }
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/lib/security/credentials/xds/xds_credentials.h b/grpc/src/core/lib/security/credentials/xds/xds_credentials.h
index e12608c..ee2e71c 100644
--- a/grpc/src/core/lib/security/credentials/xds/xds_credentials.h
+++ b/grpc/src/core/lib/security/credentials/xds/xds_credentials.h
@@ -52,8 +52,8 @@
       : grpc_server_credentials(kCredentialsTypeXds),
         fallback_credentials_(std::move(fallback_credentials)) {}
 
-  RefCountedPtr<grpc_server_security_connector> create_security_connector()
-      override;
+  RefCountedPtr<grpc_server_security_connector> create_security_connector(
+      const grpc_channel_args* /* args */) override;
 
  private:
   RefCountedPtr<grpc_server_credentials> fallback_credentials_;
@@ -62,7 +62,7 @@
 bool TestOnlyXdsVerifySubjectAlternativeNames(
     const char* const* subject_alternative_names,
     size_t subject_alternative_names_size,
-    const std::vector<XdsApi::StringMatcher>& matchers);
+    const std::vector<StringMatcher>& matchers);
 
 }  // namespace grpc_core
 
diff --git a/grpc/src/core/lib/security/security_connector/alts/alts_security_connector.cc b/grpc/src/core/lib/security/security_connector/alts/alts_security_connector.cc
index 64c39e6..131436d 100644
--- a/grpc/src/core/lib/security/security_connector/alts/alts_security_connector.cc
+++ b/grpc/src/core/lib/security/security_connector/alts/alts_security_connector.cc
@@ -54,7 +54,7 @@
   *auth_context =
       grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(&peer);
   tsi_peer_destruct(&peer);
-  grpc_error* error =
+  grpc_error_handle error =
       *auth_context != nullptr
           ? GRPC_ERROR_NONE
           : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -103,6 +103,11 @@
     alts_check_peer(peer, auth_context, on_peer_checked);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override {
     auto* other =
         reinterpret_cast<const grpc_alts_channel_security_connector*>(other_sc);
@@ -114,7 +119,7 @@
   bool check_call_host(absl::string_view host,
                        grpc_auth_context* /*auth_context*/,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** error) override {
+                       grpc_error_handle* error) override {
     if (host.empty() || host != target_name_) {
       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "ALTS call host does not match target name");
@@ -123,7 +128,7 @@
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -168,6 +173,11 @@
     alts_check_peer(peer, auth_context, on_peer_checked);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override {
     return server_security_connector_cmp(
         static_cast<const grpc_server_security_connector*>(other));
diff --git a/grpc/src/core/lib/security/security_connector/fake/fake_security_connector.cc b/grpc/src/core/lib/security/security_connector/fake/fake_security_connector.cc
index fdf750f..0e25fb0 100644
--- a/grpc/src/core/lib/security/security_connector/fake/fake_security_connector.cc
+++ b/grpc/src/core/lib/security/security_connector/fake/fake_security_connector.cc
@@ -79,6 +79,11 @@
                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override {
     auto* other =
         reinterpret_cast<const grpc_fake_channel_security_connector*>(other_sc);
@@ -105,7 +110,7 @@
   bool check_call_host(absl::string_view host,
                        grpc_auth_context* /*auth_context*/,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** /*error*/) override {
+                       grpc_error_handle* /*error*/) override {
     absl::string_view authority_hostname;
     absl::string_view authority_ignored_port;
     absl::string_view target_hostname;
@@ -135,7 +140,7 @@
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -214,7 +219,7 @@
     grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
     grpc_closure* on_peer_checked) {
   const char* prop_name;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   *auth_context = nullptr;
   if (peer.property_count != 2) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -287,6 +292,11 @@
     fake_check_peer(this, peer, auth_context, on_peer_checked);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   void add_handshakers(const grpc_channel_args* args,
                        grpc_pollset_set* /*interested_parties*/,
                        grpc_core::HandshakeManager* handshake_mgr) override {
diff --git a/grpc/src/core/lib/security/security_connector/insecure/insecure_security_connector.cc b/grpc/src/core/lib/security/security_connector/insecure/insecure_security_connector.cc
index 4cb7d21..360764e 100644
--- a/grpc/src/core/lib/security/security_connector/insecure/insecure_security_connector.cc
+++ b/grpc/src/core/lib/security/security_connector/insecure/insecure_security_connector.cc
@@ -51,14 +51,14 @@
 // check_call_host and cancel_check_call_host are no-ops since we want to
 // provide an insecure channel.
 bool InsecureChannelSecurityConnector::check_call_host(
-    absl::string_view host, grpc_auth_context* auth_context,
-    grpc_closure* on_call_host_checked, grpc_error** error) {
+    absl::string_view /*host*/, grpc_auth_context* /*auth_context*/,
+    grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) {
   *error = GRPC_ERROR_NONE;
   return true;
 }
 
 void InsecureChannelSecurityConnector::cancel_check_call_host(
-    grpc_closure* on_call_host_checked, grpc_error* error) {
+    grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
@@ -76,7 +76,7 @@
 }
 
 void InsecureChannelSecurityConnector::check_peer(
-    tsi_peer peer, grpc_endpoint* ep,
+    tsi_peer peer, grpc_endpoint* /*ep*/,
     RefCountedPtr<grpc_auth_context>* auth_context,
     grpc_closure* on_peer_checked) {
   *auth_context = MakeAuthContext();
@@ -104,7 +104,7 @@
 }
 
 void InsecureServerSecurityConnector::check_peer(
-    tsi_peer peer, grpc_endpoint* ep,
+    tsi_peer peer, grpc_endpoint* /*ep*/,
     grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
     grpc_closure* on_peer_checked) {
   *auth_context = MakeAuthContext();
diff --git a/grpc/src/core/lib/security/security_connector/insecure/insecure_security_connector.h b/grpc/src/core/lib/security/security_connector/insecure/insecure_security_connector.h
index 7d0f79e..352e346 100644
--- a/grpc/src/core/lib/security/security_connector/insecure/insecure_security_connector.h
+++ b/grpc/src/core/lib/security/security_connector/insecure/insecure_security_connector.h
@@ -47,10 +47,10 @@
 
   bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
                        grpc_closure* on_call_host_checked,
-                       grpc_error** error) override;
+                       grpc_error_handle* error) override;
 
   void cancel_check_call_host(grpc_closure* on_call_host_checked,
-                              grpc_error* error) override;
+                              grpc_error_handle error) override;
 
   void add_handshakers(const grpc_channel_args* args,
                        grpc_pollset_set* /* interested_parties */,
@@ -60,6 +60,11 @@
                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override;
 };
 
@@ -78,6 +83,11 @@
                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override;
 };
 
diff --git a/grpc/src/core/lib/security/security_connector/load_system_roots_linux.cc b/grpc/src/core/lib/security/security_connector/load_system_roots_linux.cc
index f7c6c2c..4cd709f 100644
--- a/grpc/src/core/lib/security/security_connector/load_system_roots_linux.cc
+++ b/grpc/src/core/lib/security/security_connector/load_system_roots_linux.cc
@@ -63,7 +63,7 @@
   grpc_slice valid_bundle_slice = grpc_empty_slice();
   size_t num_cert_files_ = GPR_ARRAY_SIZE(kLinuxCertFiles);
   for (size_t i = 0; i < num_cert_files_; i++) {
-    grpc_error* error =
+    grpc_error_handle error =
         grpc_load_file(kLinuxCertFiles[i], 1, &valid_bundle_slice);
     if (error == GRPC_ERROR_NONE) {
       return valid_bundle_slice;
diff --git a/grpc/src/core/lib/security/security_connector/local/local_security_connector.cc b/grpc/src/core/lib/security/security_connector/local/local_security_connector.cc
index 2cec0db..1c1cfe9 100644
--- a/grpc/src/core/lib/security/security_connector/local/local_security_connector.cc
+++ b/grpc/src/core/lib/security/security_connector/local/local_security_connector.cc
@@ -29,12 +29,12 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_utils.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/security/credentials/local/local_credentials.h"
@@ -103,7 +103,7 @@
       }
     }
   }
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (!is_endpoint_local) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Endpoint is neither UDS or TCP loopback address.");
@@ -181,10 +181,15 @@
                      creds->connect_type());
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   bool check_call_host(absl::string_view host,
                        grpc_auth_context* /*auth_context*/,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** error) override {
+                       grpc_error_handle* error) override {
     if (host.empty() || host != target_name_) {
       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "local call host does not match target name");
@@ -193,7 +198,7 @@
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -230,6 +235,11 @@
                      creds->connect_type());
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override {
     return server_security_connector_cmp(
         static_cast<const grpc_server_security_connector*>(other));
diff --git a/grpc/src/core/lib/security/security_connector/security_connector.h b/grpc/src/core/lib/security/security_connector/security_connector.h
index 204b695..50d9af3 100644
--- a/grpc/src/core/lib/security/security_connector/security_connector.h
+++ b/grpc/src/core/lib/security/security_connector/security_connector.h
@@ -55,13 +55,18 @@
         url_scheme_(url_scheme) {}
   ~grpc_security_connector() override = default;
 
-  /* Check the peer. Callee takes ownership of the peer object.
-     When done, sets *auth_context and invokes on_peer_checked. */
+  // Checks the peer. Callee takes ownership of the peer object.
+  // When done, sets *auth_context and invokes on_peer_checked.
   virtual void check_peer(
       tsi_peer peer, grpc_endpoint* ep,
       grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
       grpc_closure* on_peer_checked) = 0;
 
+  // Cancels the pending check_peer() request associated with on_peer_checked.
+  // If there is no such request pending, this is a no-op.
+  virtual void cancel_check_peer(grpc_closure* on_peer_checked,
+                                 grpc_error_handle error) = 0;
+
   /* Compares two security connectors. */
   virtual int cmp(const grpc_security_connector* other) const = 0;
 
@@ -103,12 +108,12 @@
   virtual bool check_call_host(absl::string_view host,
                                grpc_auth_context* auth_context,
                                grpc_closure* on_call_host_checked,
-                               grpc_error** error) = 0;
+                               grpc_error_handle* error) = 0;
   /// Cancels a pending asynchronous call to
   /// grpc_channel_security_connector_check_call_host() with
   /// \a on_call_host_checked as its callback.
   virtual void cancel_check_call_host(grpc_closure* on_call_host_checked,
-                                      grpc_error* error) = 0;
+                                      grpc_error_handle error) = 0;
   /// Registers handshakers with \a handshake_mgr.
   virtual void add_handshakers(const grpc_channel_args* args,
                                grpc_pollset_set* interested_parties,
diff --git a/grpc/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc b/grpc/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
index ee5672b..3e424e3 100644
--- a/grpc/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
+++ b/grpc/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
@@ -45,10 +45,10 @@
 #include "src/core/tsi/transport_security.h"
 
 namespace {
-grpc_error* ssl_check_peer(
+grpc_error_handle ssl_check_peer(
     const char* peer_name, const tsi_peer* peer,
     grpc_core::RefCountedPtr<grpc_auth_context>* auth_context) {
-  grpc_error* error = grpc_ssl_check_alpn(peer);
+  grpc_error_handle error = grpc_ssl_check_alpn(peer);
   if (error != GRPC_ERROR_NONE) {
     return error;
   }
@@ -145,7 +145,7 @@
     const char* target_name = overridden_target_name_.empty()
                                   ? target_name_.c_str()
                                   : overridden_target_name_.c_str();
-    grpc_error* error = ssl_check_peer(target_name, &peer, auth_context);
+    grpc_error_handle error = ssl_check_peer(target_name, &peer, auth_context);
     if (error == GRPC_ERROR_NONE &&
         verify_options_->verify_peer_callback != nullptr) {
       const tsi_peer_property* p =
@@ -173,6 +173,11 @@
     tsi_peer_destruct(&peer);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override {
     auto* other =
         reinterpret_cast<const grpc_ssl_channel_security_connector*>(other_sc);
@@ -185,14 +190,14 @@
 
   bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
                        grpc_closure* /*on_call_host_checked*/,
-                       grpc_error** error) override {
+                       grpc_error_handle* error) override {
     return grpc_ssl_check_call_host(host, target_name_.c_str(),
                                     overridden_target_name_.c_str(),
                                     auth_context, error);
   }
 
   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
-                              grpc_error* error) override {
+                              grpc_error_handle error) override {
     GRPC_ERROR_UNREF(error);
   }
 
@@ -288,11 +293,16 @@
   void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override {
-    grpc_error* error = ssl_check_peer(nullptr, &peer, auth_context);
+    grpc_error_handle error = ssl_check_peer(nullptr, &peer, auth_context);
     tsi_peer_destruct(&peer);
     grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
   }
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override {
     return server_security_connector_cmp(
         static_cast<const grpc_server_security_connector*>(other));
diff --git a/grpc/src/core/lib/security/security_connector/ssl_utils.cc b/grpc/src/core/lib/security/security_connector/ssl_utils.cc
index f1797d5..f445be9 100644
--- a/grpc/src/core/lib/security/security_connector/ssl_utils.cc
+++ b/grpc/src/core/lib/security/security_connector/ssl_utils.cc
@@ -41,11 +41,13 @@
 
 /* -- Constants. -- */
 
-#ifndef INSTALL_PREFIX
-static const char* installed_roots_path = "/usr/share/grpc/roots.pem";
-#else
+#if defined(GRPC_ROOT_PEM_PATH)
+static const char* installed_roots_path = GRPC_ROOT_PEM_PATH;
+#elif defined(INSTALL_PREFIX)
 static const char* installed_roots_path =
-    INSTALL_PREFIX "/share/grpc/roots.pem";
+    INSTALL_PREFIX "/usr/share/grpc/roots.pem";
+#else
+static const char* installed_roots_path = "/usr/share/grpc/roots.pem";
 #endif
 
 #ifndef TSI_OPENSSL_ALPN_SUPPORT
@@ -150,7 +152,7 @@
   }
 }
 
-grpc_error* grpc_ssl_check_alpn(const tsi_peer* peer) {
+grpc_error_handle grpc_ssl_check_alpn(const tsi_peer* peer) {
 #if TSI_OPENSSL_ALPN_SUPPORT
   /* Check the ALPN if ALPN is supported. */
   const tsi_peer_property* p =
@@ -167,8 +169,8 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_ssl_check_peer_name(absl::string_view peer_name,
-                                     const tsi_peer* peer) {
+grpc_error_handle grpc_ssl_check_peer_name(absl::string_view peer_name,
+                                           const tsi_peer* peer) {
   /* Check the peer name if specified. */
   if (!peer_name.empty() && !grpc_ssl_host_matches_name(peer, peer_name)) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -182,7 +184,7 @@
                               absl::string_view target_name,
                               absl::string_view overridden_target_name,
                               grpc_auth_context* auth_context,
-                              grpc_error** error) {
+                              grpc_error_handle* error) {
   grpc_security_status status = GRPC_SECURITY_ERROR;
   tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context);
   if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
@@ -303,6 +305,9 @@
       grpc_auth_context_add_property(
           ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
           prop->value.data, prop->value.length);
+    } else if (strcmp(prop->name, TSI_X509_DNS_PEER_PROPERTY) == 0) {
+      grpc_auth_context_add_property(ctx.get(), GRPC_PEER_DNS_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
     } else if (strcmp(prop->name, TSI_X509_URI_PEER_PROPERTY) == 0) {
       uri_count++;
       absl::string_view spiffe_id(prop->value.data, prop->value.length);
@@ -311,6 +316,12 @@
         spiffe_length = prop->value.length;
         has_spiffe_id = true;
       }
+    } else if (strcmp(prop->name, TSI_X509_EMAIL_PEER_PROPERTY) == 0) {
+      grpc_auth_context_add_property(ctx.get(), GRPC_PEER_EMAIL_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
+    } else if (strcmp(prop->name, TSI_X509_IP_PEER_PROPERTY) == 0) {
+      grpc_auth_context_add_property(ctx.get(), GRPC_PEER_IP_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
     }
   }
   if (peer_identity_property_name != nullptr) {
@@ -374,9 +385,18 @@
                  0) {
         add_shallow_auth_property_to_peer(&peer, prop,
                                           TSI_X509_PEM_CERT_CHAIN_PROPERTY);
+      } else if (strcmp(prop->name, GRPC_PEER_DNS_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(&peer, prop,
+                                          TSI_X509_DNS_PEER_PROPERTY);
       } else if (strcmp(prop->name, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME) == 0) {
         add_shallow_auth_property_to_peer(&peer, prop,
                                           TSI_X509_URI_PEER_PROPERTY);
+      } else if (strcmp(prop->name, GRPC_PEER_EMAIL_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(&peer, prop,
+                                          TSI_X509_EMAIL_PEER_PROPERTY);
+      } else if (strcmp(prop->name, GRPC_PEER_IP_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(&peer, prop,
+                                          TSI_X509_IP_PEER_PROPERTY);
       }
     }
   }
@@ -395,6 +415,9 @@
   const char* root_certs;
   const tsi_ssl_root_certs_store* root_store;
   if (pem_root_certs == nullptr) {
+    gpr_log(GPR_INFO,
+            "No root certificates specified; use ones stored in system default "
+            "locations instead");
     // Use default root certificates.
     root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts();
     if (root_certs == nullptr) {
diff --git a/grpc/src/core/lib/security/security_connector/ssl_utils.h b/grpc/src/core/lib/security/security_connector/ssl_utils.h
index 562a08c..1c41a54 100644
--- a/grpc/src/core/lib/security/security_connector/ssl_utils.h
+++ b/grpc/src/core/lib/security/security_connector/ssl_utils.h
@@ -44,11 +44,11 @@
 #define GRPC_SSL_URL_SCHEME "https"
 
 /* Check ALPN information returned from SSL handshakes. */
-grpc_error* grpc_ssl_check_alpn(const tsi_peer* peer);
+grpc_error_handle grpc_ssl_check_alpn(const tsi_peer* peer);
 
 /* Check peer name information returned from SSL handshakes. */
-grpc_error* grpc_ssl_check_peer_name(absl::string_view peer_name,
-                                     const tsi_peer* peer);
+grpc_error_handle grpc_ssl_check_peer_name(absl::string_view peer_name,
+                                           const tsi_peer* peer);
 /* Compare targer_name information extracted from SSL security connectors. */
 int grpc_ssl_cmp_target_name(absl::string_view target_name,
                              absl::string_view other_target_name,
@@ -59,7 +59,7 @@
                               absl::string_view target_name,
                               absl::string_view overridden_target_name,
                               grpc_auth_context* auth_context,
-                              grpc_error** error);
+                              grpc_error_handle* error);
 /* Return HTTP2-compliant cipher suites that gRPC accepts by default. */
 const char* grpc_get_ssl_cipher_suites(void);
 
diff --git a/grpc/src/core/lib/security/security_connector/tls/tls_security_connector.cc b/grpc/src/core/lib/security/security_connector/tls/tls_security_connector.cc
index a198bb5..ea6b42e 100644
--- a/grpc/src/core/lib/security/security_connector/tls/tls_security_connector.cc
+++ b/grpc/src/core/lib/security/security_connector/tls/tls_security_connector.cc
@@ -46,7 +46,7 @@
 namespace {
 
 tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair(
-    const grpc_core::PemKeyCertPairList& cert_pair_list) {
+    const PemKeyCertPairList& cert_pair_list) {
   tsi_ssl_pem_key_cert_pair* tsi_pairs = nullptr;
   size_t num_key_cert_pairs = cert_pair_list.size();
   if (num_key_cert_pairs > 0) {
@@ -68,11 +68,11 @@
 }  // namespace
 
 // -------------------channel security connector-------------------
-grpc_core::RefCountedPtr<grpc_channel_security_connector>
+RefCountedPtr<grpc_channel_security_connector>
 TlsChannelSecurityConnector::CreateTlsChannelSecurityConnector(
-    grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
-    grpc_core::RefCountedPtr<grpc_tls_credentials_options> options,
-    grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
+    RefCountedPtr<grpc_channel_credentials> channel_creds,
+    RefCountedPtr<grpc_tls_credentials_options> options,
+    RefCountedPtr<grpc_call_credentials> request_metadata_creds,
     const char* target_name, const char* overridden_target_name,
     tsi_ssl_session_cache* ssl_session_cache) {
   if (channel_creds == nullptr) {
@@ -93,18 +93,16 @@
             "TlsChannelSecurityConnectorCreate()");
     return nullptr;
   }
-  grpc_core::RefCountedPtr<TlsChannelSecurityConnector> c =
-      grpc_core::MakeRefCounted<TlsChannelSecurityConnector>(
-          std::move(channel_creds), std::move(options),
-          std::move(request_metadata_creds), target_name,
-          overridden_target_name, ssl_session_cache);
-  return c;
+  return MakeRefCounted<TlsChannelSecurityConnector>(
+      std::move(channel_creds), std::move(options),
+      std::move(request_metadata_creds), target_name, overridden_target_name,
+      ssl_session_cache);
 }
 
 TlsChannelSecurityConnector::TlsChannelSecurityConnector(
-    grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
-    grpc_core::RefCountedPtr<grpc_tls_credentials_options> options,
-    grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
+    RefCountedPtr<grpc_channel_credentials> channel_creds,
+    RefCountedPtr<grpc_tls_credentials_options> options,
+    RefCountedPtr<grpc_call_credentials> request_metadata_creds,
     const char* target_name, const char* overridden_target_name,
     tsi_ssl_session_cache* ssl_session_cache)
     : grpc_channel_security_connector(GRPC_SSL_URL_SCHEME,
@@ -120,7 +118,7 @@
   check_arg_ = ServerAuthorizationCheckArgCreate(this);
   absl::string_view host;
   absl::string_view port;
-  grpc_core::SplitHostPort(target_name, &host, &port);
+  SplitHostPort(target_name, &host, &port);
   target_name_ = std::string(host);
   // Create a watcher.
   auto watcher_ptr = absl::make_unique<TlsChannelCertificateWatcher>(this);
@@ -136,9 +134,20 @@
   if (options_->watch_identity_pair()) {
     watched_identity_cert_name = options_->identity_cert_name();
   }
-  distributor->WatchTlsCertificates(std::move(watcher_ptr),
-                                    watched_root_cert_name,
-                                    watched_identity_cert_name);
+  // We will use the root certs stored in system default locations if not
+  // watching root certs on the client side. We will handle this case
+  // differently here, because "watching a default roots without the identity
+  // certs" is a valid case(and hence we will need to call
+  // OnCertificatesChanged), but it requires nothing from the provider, and
+  // hence no need to register the watcher.
+  bool use_default_roots = !options_->watch_root_cert();
+  if (use_default_roots && !options_->watch_identity_pair()) {
+    watcher_ptr->OnCertificatesChanged(absl::nullopt, absl::nullopt);
+  } else {
+    distributor->WatchTlsCertificates(std::move(watcher_ptr),
+                                      watched_root_cert_name,
+                                      watched_identity_cert_name);
+  }
 }
 
 TlsChannelSecurityConnector::~TlsChannelSecurityConnector() {
@@ -148,7 +157,9 @@
   // Cancel all the watchers.
   grpc_tls_certificate_distributor* distributor =
       options_->certificate_distributor();
-  distributor->CancelTlsCertificatesWatch(certificate_watcher_);
+  if (distributor != nullptr) {
+    distributor->CancelTlsCertificatesWatch(certificate_watcher_);
+  }
   if (client_handshaker_factory_ != nullptr) {
     tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_);
   }
@@ -159,8 +170,8 @@
 
 void TlsChannelSecurityConnector::add_handshakers(
     const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
-    grpc_core::HandshakeManager* handshake_mgr) {
-  grpc_core::MutexLock lock(&mu_);
+    HandshakeManager* handshake_mgr) {
+  MutexLock lock(&mu_);
   if (client_handshaker_factory_ != nullptr) {
     // Instantiate TSI handshaker.
     tsi_handshaker* tsi_hs = nullptr;
@@ -175,7 +186,7 @@
       return;
     }
     // Create handshakers.
-    handshake_mgr->Add(grpc_core::SecurityHandshakerCreate(tsi_hs, this, args));
+    handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args));
     return;
   }
   // TODO(ZhenLian): Implement the logic(delegation to
@@ -186,14 +197,14 @@
 
 void TlsChannelSecurityConnector::check_peer(
     tsi_peer peer, grpc_endpoint* /*ep*/,
-    grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
+    RefCountedPtr<grpc_auth_context>* auth_context,
     grpc_closure* on_peer_checked) {
   const char* target_name = overridden_target_name_.empty()
                                 ? target_name_.c_str()
                                 : overridden_target_name_.c_str();
-  grpc_error* error = grpc_ssl_check_alpn(&peer);
+  grpc_error_handle error = grpc_ssl_check_alpn(&peer);
   if (error != GRPC_ERROR_NONE) {
-    grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
+    ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
     tsi_peer_destruct(&peer);
     return;
   }
@@ -203,7 +214,7 @@
     /* Do the default host name check if specifying the target name. */
     error = internal::TlsCheckHostName(target_name, &peer);
     if (error != GRPC_ERROR_NONE) {
-      grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
+      ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
       tsi_peer_destruct(&peer);
       return;
     }
@@ -286,7 +297,7 @@
       error = ProcessServerAuthorizationCheckResult(check_arg_);
     }
   }
-  grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
+  ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
   tsi_peer_destruct(&peer);
 }
 
@@ -304,39 +315,40 @@
 
 bool TlsChannelSecurityConnector::check_call_host(
     absl::string_view host, grpc_auth_context* auth_context,
-    grpc_closure* /*on_call_host_checked*/, grpc_error** error) {
+    grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) {
+  if (options_->server_verification_option() ==
+          GRPC_TLS_SKIP_HOSTNAME_VERIFICATION ||
+      options_->server_verification_option() ==
+          GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION) {
+    return true;
+  }
   return grpc_ssl_check_call_host(host, target_name_.c_str(),
                                   overridden_target_name_.c_str(), auth_context,
                                   error);
 }
 
 void TlsChannelSecurityConnector::cancel_check_call_host(
-    grpc_closure* /*on_call_host_checked*/, grpc_error* error) {
+    grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) {
   GRPC_ERROR_UNREF(error);
 }
 
 void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::
-    OnCertificatesChanged(
-        absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) {
+    OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
+                          absl::optional<PemKeyCertPairList> key_cert_pairs) {
   GPR_ASSERT(security_connector_ != nullptr);
-  grpc_core::MutexLock lock(&security_connector_->mu_);
+  MutexLock lock(&security_connector_->mu_);
   if (root_certs.has_value()) {
     security_connector_->pem_root_certs_ = root_certs;
   }
   if (key_cert_pairs.has_value()) {
     security_connector_->pem_key_cert_pair_list_ = std::move(key_cert_pairs);
   }
-  bool root_being_watched = security_connector_->options_->watch_root_cert();
-  bool root_has_value = security_connector_->pem_root_certs_.has_value();
-  bool identity_being_watched =
-      security_connector_->options_->watch_identity_pair();
-  bool identity_has_value =
+  const bool root_ready = !security_connector_->options_->watch_root_cert() ||
+                          security_connector_->pem_root_certs_.has_value();
+  const bool identity_ready =
+      !security_connector_->options_->watch_identity_pair() ||
       security_connector_->pem_key_cert_pair_list_.has_value();
-  if ((root_being_watched && root_has_value && identity_being_watched &&
-       identity_has_value) ||
-      (root_being_watched && root_has_value && !identity_being_watched) ||
-      (!root_being_watched && identity_being_watched && identity_has_value)) {
+  if (root_ready && identity_ready) {
     if (security_connector_->UpdateHandshakerFactoryLocked() !=
         GRPC_SECURITY_OK) {
       gpr_log(GPR_ERROR, "Update handshaker factory failed.");
@@ -347,16 +359,16 @@
 // TODO(ZhenLian): implement the logic to signal waiting handshakers once
 // BlockOnInitialCredentialHandshaker is implemented.
 void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::OnError(
-    grpc_error* root_cert_error, grpc_error* identity_cert_error) {
+    grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) {
   if (root_cert_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "TlsChannelCertificateWatcher getting root_cert_error: %s",
-            grpc_error_string(root_cert_error));
+            grpc_error_std_string(root_cert_error).c_str());
   }
   if (identity_cert_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "TlsChannelCertificateWatcher getting identity_cert_error: %s",
-            grpc_error_string(identity_cert_error));
+            grpc_error_std_string(identity_cert_error).c_str());
   }
   GRPC_ERROR_UNREF(root_cert_error);
   GRPC_ERROR_UNREF(identity_cert_error);
@@ -383,9 +395,11 @@
   if (pem_key_cert_pair_list_.has_value()) {
     pem_key_cert_pair = ConvertToTsiPemKeyCertPair(*pem_key_cert_pair_list_);
   }
+  bool use_default_roots = !options_->watch_root_cert();
   grpc_security_status status = grpc_ssl_tsi_client_handshaker_factory_init(
       pem_key_cert_pair,
-      pem_root_certs.empty() ? nullptr : pem_root_certs.c_str(),
+      pem_root_certs.empty() || use_default_roots ? nullptr
+                                                  : pem_root_certs.c_str(),
       skip_server_certificate_verification,
       grpc_get_tsi_tls_version(options_->min_tls_version()),
       grpc_get_tsi_tls_version(options_->max_tls_version()), ssl_session_cache_,
@@ -400,16 +414,17 @@
 void TlsChannelSecurityConnector::ServerAuthorizationCheckDone(
     grpc_tls_server_authorization_check_arg* arg) {
   GPR_ASSERT(arg != nullptr);
-  grpc_core::ExecCtx exec_ctx;
-  grpc_error* error = ProcessServerAuthorizationCheckResult(arg);
+  ExecCtx exec_ctx;
+  grpc_error_handle error = ProcessServerAuthorizationCheckResult(arg);
   TlsChannelSecurityConnector* connector =
       static_cast<TlsChannelSecurityConnector*>(arg->cb_user_data);
-  grpc_core::ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error);
+  ExecCtx::Run(DEBUG_LOCATION, connector->on_peer_checked_, error);
 }
 
-grpc_error* TlsChannelSecurityConnector::ProcessServerAuthorizationCheckResult(
+grpc_error_handle
+TlsChannelSecurityConnector::ProcessServerAuthorizationCheckResult(
     grpc_tls_server_authorization_check_arg* arg) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   /* Server authorization check is cancelled by caller. */
   if (arg->status == GRPC_STATUS_CANCELLED) {
     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
@@ -474,10 +489,10 @@
 }
 
 // -------------------server security connector-------------------
-grpc_core::RefCountedPtr<grpc_server_security_connector>
+RefCountedPtr<grpc_server_security_connector>
 TlsServerSecurityConnector::CreateTlsServerSecurityConnector(
-    grpc_core::RefCountedPtr<grpc_server_credentials> server_creds,
-    grpc_core::RefCountedPtr<grpc_tls_credentials_options> options) {
+    RefCountedPtr<grpc_server_credentials> server_creds,
+    RefCountedPtr<grpc_tls_credentials_options> options) {
   if (server_creds == nullptr) {
     gpr_log(GPR_ERROR,
             "server_creds is nullptr in "
@@ -490,15 +505,13 @@
             "TlsServerSecurityConnectorCreate()");
     return nullptr;
   }
-  grpc_core::RefCountedPtr<TlsServerSecurityConnector> c =
-      grpc_core::MakeRefCounted<TlsServerSecurityConnector>(
-          std::move(server_creds), std::move(options));
-  return c;
+  return MakeRefCounted<TlsServerSecurityConnector>(std::move(server_creds),
+                                                    std::move(options));
 }
 
 TlsServerSecurityConnector::TlsServerSecurityConnector(
-    grpc_core::RefCountedPtr<grpc_server_credentials> server_creds,
-    grpc_core::RefCountedPtr<grpc_tls_credentials_options> options)
+    RefCountedPtr<grpc_server_credentials> server_creds,
+    RefCountedPtr<grpc_tls_credentials_options> options)
     : grpc_server_security_connector(GRPC_SSL_URL_SCHEME,
                                      std::move(server_creds)),
       options_(std::move(options)) {
@@ -516,6 +529,7 @@
   if (options_->watch_identity_pair()) {
     watched_identity_cert_name = options_->identity_cert_name();
   }
+  // Server side won't use default system roots at any time.
   distributor->WatchTlsCertificates(std::move(watcher_ptr),
                                     watched_root_cert_name,
                                     watched_identity_cert_name);
@@ -533,8 +547,8 @@
 
 void TlsServerSecurityConnector::add_handshakers(
     const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
-    grpc_core::HandshakeManager* handshake_mgr) {
-  grpc_core::MutexLock lock(&mu_);
+    HandshakeManager* handshake_mgr) {
+  MutexLock lock(&mu_);
   if (server_handshaker_factory_ != nullptr) {
     // Instantiate TSI handshaker.
     tsi_handshaker* tsi_hs = nullptr;
@@ -546,7 +560,7 @@
       return;
     }
     // Create handshakers.
-    handshake_mgr->Add(grpc_core::SecurityHandshakerCreate(tsi_hs, this, args));
+    handshake_mgr->Add(SecurityHandshakerCreate(tsi_hs, this, args));
     return;
   }
   // TODO(ZhenLian): Implement the logic(delegation to
@@ -557,13 +571,13 @@
 
 void TlsServerSecurityConnector::check_peer(
     tsi_peer peer, grpc_endpoint* /*ep*/,
-    grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
+    RefCountedPtr<grpc_auth_context>* auth_context,
     grpc_closure* on_peer_checked) {
-  grpc_error* error = grpc_ssl_check_alpn(&peer);
+  grpc_error_handle error = grpc_ssl_check_alpn(&peer);
   *auth_context =
       grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE);
   tsi_peer_destruct(&peer);
-  grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
+  ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
 }
 
 int TlsServerSecurityConnector::cmp(
@@ -573,11 +587,10 @@
 }
 
 void TlsServerSecurityConnector::TlsServerCertificateWatcher::
-    OnCertificatesChanged(
-        absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) {
+    OnCertificatesChanged(absl::optional<absl::string_view> root_certs,
+                          absl::optional<PemKeyCertPairList> key_cert_pairs) {
   GPR_ASSERT(security_connector_ != nullptr);
-  grpc_core::MutexLock lock(&security_connector_->mu_);
+  MutexLock lock(&security_connector_->mu_);
   if (root_certs.has_value()) {
     security_connector_->pem_root_certs_ = root_certs;
   }
@@ -604,16 +617,16 @@
 // TODO(ZhenLian): implement the logic to signal waiting handshakers once
 // BlockOnInitialCredentialHandshaker is implemented.
 void TlsServerSecurityConnector::TlsServerCertificateWatcher::OnError(
-    grpc_error* root_cert_error, grpc_error* identity_cert_error) {
+    grpc_error_handle root_cert_error, grpc_error_handle identity_cert_error) {
   if (root_cert_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "TlsServerCertificateWatcher getting root_cert_error: %s",
-            grpc_error_string(root_cert_error));
+            grpc_error_std_string(root_cert_error).c_str());
   }
   if (identity_cert_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "TlsServerCertificateWatcher getting identity_cert_error: %s",
-            grpc_error_string(identity_cert_error));
+            grpc_error_std_string(identity_cert_error).c_str());
   }
   GRPC_ERROR_UNREF(root_cert_error);
   GRPC_ERROR_UNREF(identity_cert_error);
@@ -654,7 +667,8 @@
 
 namespace internal {
 
-grpc_error* TlsCheckHostName(const char* peer_name, const tsi_peer* peer) {
+grpc_error_handle TlsCheckHostName(const char* peer_name,
+                                   const tsi_peer* peer) {
   /* Check the peer name if specified. */
   if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
diff --git a/grpc/src/core/lib/security/security_connector/tls/tls_security_connector.h b/grpc/src/core/lib/security/security_connector/tls/tls_security_connector.h
index 453c531..80c2695 100644
--- a/grpc/src/core/lib/security/security_connector/tls/tls_security_connector.h
+++ b/grpc/src/core/lib/security/security_connector/tls/tls_security_connector.h
@@ -35,18 +35,18 @@
     : public grpc_channel_security_connector {
  public:
   // static factory method to create a TLS channel security connector.
-  static grpc_core::RefCountedPtr<grpc_channel_security_connector>
+  static RefCountedPtr<grpc_channel_security_connector>
   CreateTlsChannelSecurityConnector(
-      grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
-      grpc_core::RefCountedPtr<grpc_tls_credentials_options> options,
-      grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
+      RefCountedPtr<grpc_channel_credentials> channel_creds,
+      RefCountedPtr<grpc_tls_credentials_options> options,
+      RefCountedPtr<grpc_call_credentials> request_metadata_creds,
       const char* target_name, const char* overridden_target_name,
       tsi_ssl_session_cache* ssl_session_cache);
 
   TlsChannelSecurityConnector(
-      grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
-      grpc_core::RefCountedPtr<grpc_tls_credentials_options> options,
-      grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
+      RefCountedPtr<grpc_channel_credentials> channel_creds,
+      RefCountedPtr<grpc_tls_credentials_options> options,
+      RefCountedPtr<grpc_call_credentials> request_metadata_creds,
       const char* target_name, const char* overridden_target_name,
       tsi_ssl_session_cache* ssl_session_cache);
 
@@ -54,33 +54,39 @@
 
   void add_handshakers(const grpc_channel_args* args,
                        grpc_pollset_set* interested_parties,
-                       grpc_core::HandshakeManager* handshake_mgr) override;
+                       HandshakeManager* handshake_mgr) override;
 
   void check_peer(tsi_peer peer, grpc_endpoint* ep,
-                  grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
+                  RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    // TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other_sc) const override;
 
   bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
                        grpc_closure* on_call_host_checked,
-                       grpc_error** error) override;
+                       grpc_error_handle* error) override;
 
   void cancel_check_call_host(grpc_closure* on_call_host_checked,
-                              grpc_error* error) override;
+                              grpc_error_handle error) override;
 
   tsi_ssl_client_handshaker_factory* ClientHandshakerFactoryForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     return client_handshaker_factory_;
   };
 
   absl::optional<absl::string_view> RootCertsForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     return pem_root_certs_;
   }
 
-  absl::optional<grpc_core::PemKeyCertPairList> KeyCertPairListForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+  absl::optional<PemKeyCertPairList> KeyCertPairListForTesting() {
+    MutexLock lock(&mu_);
     return pem_key_cert_pair_list_;
   }
 
@@ -96,9 +102,9 @@
         : security_connector_(security_connector) {}
     void OnCertificatesChanged(
         absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) override;
-    void OnError(grpc_error* root_cert_error,
-                 grpc_error* identity_cert_error) override;
+        absl::optional<PemKeyCertPairList> key_cert_pairs) override;
+    void OnError(grpc_error_handle root_cert_error,
+                 grpc_error_handle identity_cert_error) override;
 
    private:
     TlsChannelSecurityConnector* security_connector_ = nullptr;
@@ -106,7 +112,8 @@
 
   // Updates |client_handshaker_factory_| when the certificates that
   // |certificate_watcher_| is watching get updated.
-  grpc_security_status UpdateHandshakerFactoryLocked();
+  grpc_security_status UpdateHandshakerFactoryLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
   // gRPC-provided callback executed by application, which servers to bring the
   // control back to gRPC core.
@@ -114,7 +121,7 @@
       grpc_tls_server_authorization_check_arg* arg);
 
   // A util function to process server authorization check result.
-  static grpc_error* ProcessServerAuthorizationCheckResult(
+  static grpc_error_handle ProcessServerAuthorizationCheckResult(
       grpc_tls_server_authorization_check_arg* arg);
 
   // A util function to create a server authorization check arg instance.
@@ -125,57 +132,65 @@
   static void ServerAuthorizationCheckArgDestroy(
       grpc_tls_server_authorization_check_arg* arg);
 
-  grpc_core::Mutex mu_;
-  grpc_core::RefCountedPtr<grpc_tls_credentials_options> options_;
+  RefCountedPtr<grpc_tls_credentials_options> options_;
   grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
       certificate_watcher_ = nullptr;
   grpc_closure* on_peer_checked_ = nullptr;
   std::string target_name_;
   std::string overridden_target_name_;
-  tsi_ssl_client_handshaker_factory* client_handshaker_factory_ = nullptr;
   grpc_tls_server_authorization_check_arg* check_arg_ = nullptr;
-  tsi_ssl_session_cache* ssl_session_cache_ = nullptr;
-  absl::optional<absl::string_view> pem_root_certs_;
-  absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pair_list_;
+
+  Mutex mu_;
+  tsi_ssl_client_handshaker_factory* client_handshaker_factory_
+      ABSL_GUARDED_BY(mu_) = nullptr;
+  tsi_ssl_session_cache* ssl_session_cache_ ABSL_GUARDED_BY(mu_) = nullptr;
+  absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_);
+  absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_
+      ABSL_GUARDED_BY(mu_);
 };
 
 // Server security connector using TLS as transport security protocol.
 class TlsServerSecurityConnector final : public grpc_server_security_connector {
  public:
   // static factory method to create a TLS server security connector.
-  static grpc_core::RefCountedPtr<grpc_server_security_connector>
+  static RefCountedPtr<grpc_server_security_connector>
   CreateTlsServerSecurityConnector(
-      grpc_core::RefCountedPtr<grpc_server_credentials> server_creds,
-      grpc_core::RefCountedPtr<grpc_tls_credentials_options> options);
+      RefCountedPtr<grpc_server_credentials> server_creds,
+      RefCountedPtr<grpc_tls_credentials_options> options);
 
   TlsServerSecurityConnector(
-      grpc_core::RefCountedPtr<grpc_server_credentials> server_creds,
-      grpc_core::RefCountedPtr<grpc_tls_credentials_options> options);
+      RefCountedPtr<grpc_server_credentials> server_creds,
+      RefCountedPtr<grpc_tls_credentials_options> options);
   ~TlsServerSecurityConnector() override;
 
   void add_handshakers(const grpc_channel_args* args,
                        grpc_pollset_set* interested_parties,
-                       grpc_core::HandshakeManager* handshake_mgr) override;
+                       HandshakeManager* handshake_mgr) override;
 
   void check_peer(tsi_peer peer, grpc_endpoint* ep,
-                  grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
+                  RefCountedPtr<grpc_auth_context>* auth_context,
                   grpc_closure* on_peer_checked) override;
 
+  void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
+                         grpc_error_handle error) override {
+    // TODO(ZhenLian): call verifier->cancel() once the verifier is ready.
+    GRPC_ERROR_UNREF(error);
+  }
+
   int cmp(const grpc_security_connector* other) const override;
 
   tsi_ssl_server_handshaker_factory* ServerHandshakerFactoryForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     return server_handshaker_factory_;
   };
 
   const absl::optional<absl::string_view>& RootCertsForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     return pem_root_certs_;
   }
 
-  const absl::optional<grpc_core::PemKeyCertPairList>&
-  KeyCertPairListForTesting() {
-    grpc_core::MutexLock lock(&mu_);
+  const absl::optional<PemKeyCertPairList>& KeyCertPairListForTesting() {
+    MutexLock lock(&mu_);
     return pem_key_cert_pair_list_;
   }
 
@@ -191,9 +206,9 @@
         : security_connector_(security_connector) {}
     void OnCertificatesChanged(
         absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) override;
-    void OnError(grpc_error* root_cert_error,
-                 grpc_error* identity_cert_error) override;
+        absl::optional<PemKeyCertPairList> key_cert_pairs) override;
+    void OnError(grpc_error_handle root_cert_error,
+                 grpc_error_handle identity_cert_error) override;
 
    private:
     TlsServerSecurityConnector* security_connector_ = nullptr;
@@ -201,16 +216,19 @@
 
   // Updates |server_handshaker_factory_| when the certificates that
   // |certificate_watcher_| is watching get updated.
-  grpc_security_status UpdateHandshakerFactoryLocked();
+  grpc_security_status UpdateHandshakerFactoryLocked()
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
 
-  grpc_core::Mutex mu_;
-  grpc_core::RefCountedPtr<grpc_tls_credentials_options> options_;
+  RefCountedPtr<grpc_tls_credentials_options> options_;
   grpc_tls_certificate_distributor::TlsCertificatesWatcherInterface*
       certificate_watcher_ = nullptr;
 
-  tsi_ssl_server_handshaker_factory* server_handshaker_factory_ = nullptr;
-  absl::optional<absl::string_view> pem_root_certs_;
-  absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pair_list_;
+  Mutex mu_;
+  tsi_ssl_server_handshaker_factory* server_handshaker_factory_
+      ABSL_GUARDED_BY(mu_) = nullptr;
+  absl::optional<absl::string_view> pem_root_certs_ ABSL_GUARDED_BY(mu_);
+  absl::optional<PemKeyCertPairList> pem_key_cert_pair_list_
+      ABSL_GUARDED_BY(mu_);
 };
 
 // ---- Functions below are exposed for testing only -----------------------
@@ -218,7 +236,7 @@
 
 // TlsCheckHostName checks if |peer_name| matches the identity information
 // contained in |peer|. This is AKA hostname check.
-grpc_error* TlsCheckHostName(const char* peer_name, const tsi_peer* peer);
+grpc_error_handle TlsCheckHostName(const char* peer_name, const tsi_peer* peer);
 
 }  // namespace internal
 
diff --git a/grpc/src/core/lib/security/transport/client_auth_filter.cc b/grpc/src/core/lib/security/transport/client_auth_filter.cc
index c155be8..babc90f 100644
--- a/grpc/src/core/lib/security/transport/client_auth_filter.cc
+++ b/grpc/src/core/lib/security/transport/client_auth_filter.cc
@@ -146,7 +146,7 @@
   }
 }
 
-static void add_error(grpc_error** combined, grpc_error* error) {
+static void add_error(grpc_error_handle* combined, grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) return;
   if (*combined == GRPC_ERROR_NONE) {
     *combined = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -155,14 +155,14 @@
   *combined = grpc_error_add_child(*combined, error);
 }
 
-static void on_credentials_metadata(void* arg, grpc_error* input_error) {
+static void on_credentials_metadata(void* arg, grpc_error_handle input_error) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   grpc_call_element* elem =
       static_cast<grpc_call_element*>(batch->handler_private.extra_arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_auth_metadata_context_reset(&calld->auth_md_context);
-  grpc_error* error = GRPC_ERROR_REF(input_error);
+  grpc_error_handle error = GRPC_ERROR_REF(input_error);
   if (error == GRPC_ERROR_NONE) {
     GPR_ASSERT(calld->md_array.size <= MAX_CREDENTIALS_METADATA_COUNT);
     GPR_ASSERT(batch->send_initial_metadata);
@@ -225,13 +225,14 @@
   gpr_free(host_and_port);
 }
 
-static void cancel_get_request_metadata(void* arg, grpc_error* error) {
+static void cancel_get_request_metadata(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
     calld->creds->cancel_get_request_metadata(&calld->md_array,
                                               GRPC_ERROR_REF(error));
   }
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_get_request_metadata");
 }
 
 static void send_security_metadata(grpc_call_element* elem,
@@ -311,7 +312,7 @@
   GRPC_CALL_STACK_REF(calld->owning_call, "get_request_metadata");
   GRPC_CLOSURE_INIT(&calld->async_result_closure, on_credentials_metadata,
                     batch, grpc_schedule_on_exec_ctx);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (calld->creds->get_request_metadata(
           calld->pollent, calld->auth_md_context, &calld->md_array,
           &calld->async_result_closure, &error)) {
@@ -320,13 +321,16 @@
     GRPC_ERROR_UNREF(error);
   } else {
     // Async return; register cancellation closure with call combiner.
+    // TODO(yashykt): We would not need this ref if call combiners used
+    // Closure::Run() instead of ExecCtx::Run()
+    GRPC_CALL_STACK_REF(calld->owning_call, "cancel_get_request_metadata");
     calld->call_combiner->SetNotifyOnCancel(GRPC_CLOSURE_INIT(
         &calld->get_request_metadata_cancel_closure,
         cancel_get_request_metadata, elem, grpc_schedule_on_exec_ctx));
   }
 }
 
-static void on_host_checked(void* arg, grpc_error* error) {
+static void on_host_checked(void* arg, grpc_error_handle error) {
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
   grpc_call_element* elem =
@@ -348,7 +352,7 @@
   GRPC_CALL_STACK_UNREF(calld->owning_call, "check_call_host");
 }
 
-static void cancel_check_call_host(void* arg, grpc_error* error) {
+static void cancel_check_call_host(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
@@ -356,6 +360,7 @@
     chand->security_connector->cancel_check_call_host(
         &calld->async_result_closure, GRPC_ERROR_REF(error));
   }
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_check_call_host");
 }
 
 static void client_auth_start_transport_stream_op_batch(
@@ -381,7 +386,7 @@
       GRPC_CLOSURE_INIT(&calld->async_result_closure, on_host_checked, batch,
                         grpc_schedule_on_exec_ctx);
       absl::string_view call_host(grpc_core::StringViewFromSlice(calld->host));
-      grpc_error* error = GRPC_ERROR_NONE;
+      grpc_error_handle error = GRPC_ERROR_NONE;
       if (chand->security_connector->check_call_host(
               call_host, chand->auth_context.get(),
               &calld->async_result_closure, &error)) {
@@ -390,6 +395,9 @@
         GRPC_ERROR_UNREF(error);
       } else {
         // Async return; register cancellation closure with call combiner.
+        // TODO(yashykt): We would not need this ref if call combiners used
+        // Closure::Run() instead of ExecCtx::Run()
+        GRPC_CALL_STACK_REF(calld->owning_call, "cancel_check_call_host");
         calld->call_combiner->SetNotifyOnCancel(GRPC_CLOSURE_INIT(
             &calld->check_call_host_cancel_closure, cancel_check_call_host,
             elem, grpc_schedule_on_exec_ctx));
@@ -403,7 +411,7 @@
 }
 
 /* Constructor for call_data */
-static grpc_error* client_auth_init_call_elem(
+static grpc_error_handle client_auth_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   new (elem->call_data) call_data(elem, *args);
   return GRPC_ERROR_NONE;
@@ -424,7 +432,7 @@
 }
 
 /* Constructor for channel_data */
-static grpc_error* client_auth_init_channel_elem(
+static grpc_error_handle client_auth_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   /* The first and the last filters tend to be implemented differently to
      handle the case that there's no 'next' filter to call on the up or down
diff --git a/grpc/src/core/lib/security/transport/secure_endpoint.cc b/grpc/src/core/lib/security/transport/secure_endpoint.cc
index 7ab4d7b..fc1fb7e 100644
--- a/grpc/src/core/lib/security/transport/secure_endpoint.cc
+++ b/grpc/src/core/lib/security/transport/secure_endpoint.cc
@@ -43,7 +43,7 @@
 
 #define STAGING_BUFFER_SIZE 8192
 
-static void on_read(void* user_data, grpc_error* error);
+static void on_read(void* user_data, grpc_error_handle error);
 
 namespace {
 struct secure_endpoint {
@@ -154,7 +154,7 @@
   *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);
 }
 
-static void call_read_cb(secure_endpoint* ep, grpc_error* error) {
+static void call_read_cb(secure_endpoint* ep, grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_secure_endpoint)) {
     size_t i;
     for (i = 0; i < ep->read_buffer->count; i++) {
@@ -169,7 +169,7 @@
   SECURE_ENDPOINT_UNREF(ep, "read");
 }
 
-static void on_read(void* user_data, grpc_error* error) {
+static void on_read(void* user_data, grpc_error_handle error) {
   unsigned i;
   uint8_t keep_looping = 0;
   tsi_result result = TSI_OK;
@@ -373,7 +373,7 @@
   grpc_endpoint_write(ep->wrapped_ep, &ep->output_buffer, cb, arg);
 }
 
-static void endpoint_shutdown(grpc_endpoint* secure_ep, grpc_error* why) {
+static void endpoint_shutdown(grpc_endpoint* secure_ep, grpc_error_handle why) {
   secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   grpc_endpoint_shutdown(ep->wrapped_ep, why);
 }
diff --git a/grpc/src/core/lib/security/transport/security_handshaker.cc b/grpc/src/core/lib/security/transport/security_handshaker.cc
index e7b9885..6d05c97 100644
--- a/grpc/src/core/lib/security/transport/security_handshaker.cc
+++ b/grpc/src/core/lib/security/transport/security_handshaker.cc
@@ -29,6 +29,7 @@
 #include <grpc/support/log.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channelz.h"
 #include "src/core/lib/channel/handshaker.h"
 #include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
@@ -50,41 +51,42 @@
                      grpc_security_connector* connector,
                      const grpc_channel_args* args);
   ~SecurityHandshaker() override;
-  void Shutdown(grpc_error* why) override;
+  void Shutdown(grpc_error_handle why) override;
   void DoHandshake(grpc_tcp_server_acceptor* acceptor,
                    grpc_closure* on_handshake_done,
                    HandshakerArgs* args) override;
   const char* name() const override { return "security"; }
 
  private:
-  grpc_error* DoHandshakerNextLocked(const unsigned char* bytes_received,
-                                     size_t bytes_received_size);
+  grpc_error_handle DoHandshakerNextLocked(const unsigned char* bytes_received,
+                                           size_t bytes_received_size);
 
-  grpc_error* OnHandshakeNextDoneLocked(
+  grpc_error_handle OnHandshakeNextDoneLocked(
       tsi_result result, const unsigned char* bytes_to_send,
       size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result);
-  void HandshakeFailedLocked(grpc_error* error);
+  void HandshakeFailedLocked(grpc_error_handle error);
   void CleanupArgsForFailureLocked();
 
-  static void OnHandshakeDataReceivedFromPeerFn(void* arg, grpc_error* error);
-  static void OnHandshakeDataSentToPeerFn(void* arg, grpc_error* error);
-  static void OnHandshakeDataReceivedFromPeerFnScheduler(void* arg,
-                                                         grpc_error* error);
+  static void OnHandshakeDataReceivedFromPeerFn(void* arg,
+                                                grpc_error_handle error);
+  static void OnHandshakeDataSentToPeerFn(void* arg, grpc_error_handle error);
+  static void OnHandshakeDataReceivedFromPeerFnScheduler(
+      void* arg, grpc_error_handle error);
   static void OnHandshakeDataSentToPeerFnScheduler(void* arg,
-                                                   grpc_error* error);
+                                                   grpc_error_handle error);
   static void OnHandshakeNextDoneGrpcWrapper(
       tsi_result result, void* user_data, const unsigned char* bytes_to_send,
       size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result);
-  static void OnPeerCheckedFn(void* arg, grpc_error* error);
-  void OnPeerCheckedInner(grpc_error* error);
+  static void OnPeerCheckedFn(void* arg, grpc_error_handle error);
+  void OnPeerCheckedInner(grpc_error_handle error);
   size_t MoveReadBufferIntoHandshakeBuffer();
-  grpc_error* CheckPeerLocked();
+  grpc_error_handle CheckPeerLocked();
 
   // State set at creation time.
   tsi_handshaker* handshaker_;
   RefCountedPtr<grpc_security_connector> connector_;
 
-  gpr_mu mu_;
+  Mutex mu_;
 
   bool is_shutdown_ = false;
   // Endpoint and read buffer to destroy after a shutdown.
@@ -120,14 +122,12 @@
     max_frame_size_ = grpc_channel_arg_get_integer(
         arg, {0, 0, std::numeric_limits<int>::max()});
   }
-  gpr_mu_init(&mu_);
   grpc_slice_buffer_init(&outgoing_);
   GRPC_CLOSURE_INIT(&on_peer_checked_, &SecurityHandshaker::OnPeerCheckedFn,
                     this, grpc_schedule_on_exec_ctx);
 }
 
 SecurityHandshaker::~SecurityHandshaker() {
-  gpr_mu_destroy(&mu_);
   tsi_handshaker_destroy(handshaker_);
   tsi_handshaker_result_destroy(handshaker_result_);
   if (endpoint_to_destroy_ != nullptr) {
@@ -174,15 +174,14 @@
 
 // If the handshake failed or we're shutting down, clean up and invoke the
 // callback with the error.
-void SecurityHandshaker::HandshakeFailedLocked(grpc_error* error) {
+void SecurityHandshaker::HandshakeFailedLocked(grpc_error_handle error) {
   if (error == GRPC_ERROR_NONE) {
     // If we were shut down after the handshake succeeded but before an
     // endpoint callback was invoked, we need to generate our own error.
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshaker shutdown");
   }
-  const char* msg = grpc_error_string(error);
-  gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg);
-
+  gpr_log(GPR_DEBUG, "Security handshake failed: %s",
+          grpc_error_std_string(error).c_str());
   if (!is_shutdown_) {
     tsi_handshaker_shutdown(handshaker_);
     // TODO(ctiller): It is currently necessary to shutdown endpoints
@@ -201,7 +200,32 @@
   ExecCtx::Run(DEBUG_LOCATION, on_handshake_done_, error);
 }
 
-void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) {
+namespace {
+
+RefCountedPtr<channelz::SocketNode::Security>
+MakeChannelzSecurityFromAuthContext(grpc_auth_context* auth_context) {
+  RefCountedPtr<channelz::SocketNode::Security> security =
+      MakeRefCounted<channelz::SocketNode::Security>();
+  // TODO(yashykt): Currently, we are assuming TLS by default and are only able
+  // to fill in the remote certificate but we should ideally be able to fill in
+  // other fields in
+  // https://github.com/grpc/grpc/blob/fcd43e90304862a823316b224ee733d17a8cfd90/src/proto/grpc/channelz/channelz.proto#L326
+  // from grpc_auth_context.
+  security->type = channelz::SocketNode::Security::ModelType::kTls;
+  security->tls = absl::make_optional<channelz::SocketNode::Security::Tls>();
+  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
+      auth_context, GRPC_X509_PEM_CERT_PROPERTY_NAME);
+  const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
+  if (prop != nullptr) {
+    security->tls->remote_certificate =
+        std::string(prop->value, prop->value_length);
+  }
+  return security;
+}
+
+}  // namespace
+
+void SecurityHandshaker::OnPeerCheckedInner(grpc_error_handle error) {
   MutexLock lock(&mu_);
   if (error != GRPC_ERROR_NONE || is_shutdown_) {
     HandshakeFailedLocked(error);
@@ -253,9 +277,13 @@
   tsi_handshaker_result_destroy(handshaker_result_);
   handshaker_result_ = nullptr;
   // Add auth context to channel args.
-  grpc_arg auth_context_arg = grpc_auth_context_to_arg(auth_context_.get());
+  absl::InlinedVector<grpc_arg, 2> args_to_add;
+  args_to_add.push_back(grpc_auth_context_to_arg(auth_context_.get()));
+  auto security = MakeChannelzSecurityFromAuthContext(auth_context_.get());
+  args_to_add.push_back(security->MakeChannelArg());
   grpc_channel_args* tmp_args = args_->args;
-  args_->args = grpc_channel_args_copy_and_add(tmp_args, &auth_context_arg, 1);
+  args_->args = grpc_channel_args_copy_and_add(tmp_args, args_to_add.data(),
+                                               args_to_add.size());
   grpc_channel_args_destroy(tmp_args);
   // Invoke callback.
   ExecCtx::Run(DEBUG_LOCATION, on_handshake_done_, GRPC_ERROR_NONE);
@@ -264,12 +292,12 @@
   is_shutdown_ = true;
 }
 
-void SecurityHandshaker::OnPeerCheckedFn(void* arg, grpc_error* error) {
+void SecurityHandshaker::OnPeerCheckedFn(void* arg, grpc_error_handle error) {
   RefCountedPtr<SecurityHandshaker>(static_cast<SecurityHandshaker*>(arg))
       ->OnPeerCheckedInner(GRPC_ERROR_REF(error));
 }
 
-grpc_error* SecurityHandshaker::CheckPeerLocked() {
+grpc_error_handle SecurityHandshaker::CheckPeerLocked() {
   tsi_peer peer;
   tsi_result result =
       tsi_handshaker_result_extract_peer(handshaker_result_, &peer);
@@ -282,10 +310,10 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* SecurityHandshaker::OnHandshakeNextDoneLocked(
+grpc_error_handle SecurityHandshaker::OnHandshakeNextDoneLocked(
     tsi_result result, const unsigned char* bytes_to_send,
     size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   // Handshaker was shutdown.
   if (is_shutdown_) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshaker shutdown");
@@ -346,7 +374,7 @@
   RefCountedPtr<SecurityHandshaker> h(
       static_cast<SecurityHandshaker*>(user_data));
   MutexLock lock(&h->mu_);
-  grpc_error* error = h->OnHandshakeNextDoneLocked(
+  grpc_error_handle error = h->OnHandshakeNextDoneLocked(
       result, bytes_to_send, bytes_to_send_size, handshaker_result);
   if (error != GRPC_ERROR_NONE) {
     h->HandshakeFailedLocked(error);
@@ -355,7 +383,7 @@
   }
 }
 
-grpc_error* SecurityHandshaker::DoHandshakerNextLocked(
+grpc_error_handle SecurityHandshaker::DoHandshakerNextLocked(
     const unsigned char* bytes_received, size_t bytes_received_size) {
   // Invoke TSI handshaker.
   const unsigned char* bytes_to_send = nullptr;
@@ -378,7 +406,7 @@
 // This callback might be run inline while we are still holding on to the mutex,
 // so schedule OnHandshakeDataReceivedFromPeerFn on ExecCtx to avoid a deadlock.
 void SecurityHandshaker::OnHandshakeDataReceivedFromPeerFnScheduler(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   SecurityHandshaker* h = static_cast<SecurityHandshaker*>(arg);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION,
@@ -388,8 +416,8 @@
       GRPC_ERROR_REF(error));
 }
 
-void SecurityHandshaker::OnHandshakeDataReceivedFromPeerFn(void* arg,
-                                                           grpc_error* error) {
+void SecurityHandshaker::OnHandshakeDataReceivedFromPeerFn(
+    void* arg, grpc_error_handle error) {
   RefCountedPtr<SecurityHandshaker> h(static_cast<SecurityHandshaker*>(arg));
   MutexLock lock(&h->mu_);
   if (error != GRPC_ERROR_NONE || h->is_shutdown_) {
@@ -412,7 +440,7 @@
 // This callback might be run inline while we are still holding on to the mutex,
 // so schedule OnHandshakeDataSentToPeerFn on ExecCtx to avoid a deadlock.
 void SecurityHandshaker::OnHandshakeDataSentToPeerFnScheduler(
-    void* arg, grpc_error* error) {
+    void* arg, grpc_error_handle error) {
   SecurityHandshaker* h = static_cast<SecurityHandshaker*>(arg);
   grpc_core::ExecCtx::Run(
       DEBUG_LOCATION,
@@ -423,7 +451,7 @@
 }
 
 void SecurityHandshaker::OnHandshakeDataSentToPeerFn(void* arg,
-                                                     grpc_error* error) {
+                                                     grpc_error_handle error) {
   RefCountedPtr<SecurityHandshaker> h(static_cast<SecurityHandshaker*>(arg));
   MutexLock lock(&h->mu_);
   if (error != GRPC_ERROR_NONE || h->is_shutdown_) {
@@ -454,10 +482,11 @@
 // public handshaker API
 //
 
-void SecurityHandshaker::Shutdown(grpc_error* why) {
+void SecurityHandshaker::Shutdown(grpc_error_handle why) {
   MutexLock lock(&mu_);
   if (!is_shutdown_) {
     is_shutdown_ = true;
+    connector_->cancel_check_peer(&on_peer_checked_, GRPC_ERROR_REF(why));
     tsi_handshaker_shutdown(handshaker_);
     grpc_endpoint_shutdown(args_->endpoint, GRPC_ERROR_REF(why));
     CleanupArgsForFailureLocked();
@@ -473,7 +502,7 @@
   args_ = args;
   on_handshake_done_ = on_handshake_done;
   size_t bytes_received_size = MoveReadBufferIntoHandshakeBuffer();
-  grpc_error* error =
+  grpc_error_handle error =
       DoHandshakerNextLocked(handshake_buffer_, bytes_received_size);
   if (error != GRPC_ERROR_NONE) {
     HandshakeFailedLocked(error);
@@ -489,7 +518,7 @@
 class FailHandshaker : public Handshaker {
  public:
   const char* name() const override { return "security_fail"; }
-  void Shutdown(grpc_error* why) override { GRPC_ERROR_UNREF(why); }
+  void Shutdown(grpc_error_handle why) override { GRPC_ERROR_UNREF(why); }
   void DoHandshake(grpc_tcp_server_acceptor* /*acceptor*/,
                    grpc_closure* on_handshake_done,
                    HandshakerArgs* /*args*/) override {
diff --git a/grpc/src/core/lib/security/transport/server_auth_filter.cc b/grpc/src/core/lib/security/transport/server_auth_filter.cc
index 6735189..65a7e40 100644
--- a/grpc/src/core/lib/security/transport/server_auth_filter.cc
+++ b/grpc/src/core/lib/security/transport/server_auth_filter.cc
@@ -28,8 +28,9 @@
 #include "src/core/lib/security/transport/auth_filters.h"
 #include "src/core/lib/slice/slice_internal.h"
 
-static void recv_initial_metadata_ready(void* arg, grpc_error* error);
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
+static void recv_initial_metadata_ready(void* arg, grpc_error_handle error);
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle error);
 
 namespace {
 enum async_state {
@@ -79,10 +80,10 @@
   grpc_transport_stream_op_batch* recv_initial_metadata_batch;
   grpc_closure* original_recv_initial_metadata_ready;
   grpc_closure recv_initial_metadata_ready;
-  grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
+  grpc_error_handle recv_initial_metadata_error = GRPC_ERROR_NONE;
   grpc_closure recv_trailing_metadata_ready;
   grpc_closure* original_recv_trailing_metadata_ready;
-  grpc_error* recv_trailing_metadata_error;
+  grpc_error_handle recv_trailing_metadata_error;
   bool seen_recv_trailing_metadata_ready = false;
   grpc_metadata_array md;
   const grpc_metadata* consumed_md;
@@ -135,7 +136,7 @@
                                         size_t num_consumed_md,
                                         const grpc_metadata* response_md,
                                         size_t num_response_md,
-                                        grpc_error* error) {
+                                        grpc_error_handle error) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_transport_stream_op_batch* batch = calld->recv_initial_metadata_batch;
   /* TODO(jboeuf): Implement support for response_md. */
@@ -175,7 +176,7 @@
   // If the call was not cancelled while we were in flight, process the result.
   if (gpr_atm_full_cas(&calld->state, static_cast<gpr_atm>(STATE_INIT),
                        static_cast<gpr_atm>(STATE_DONE))) {
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (status != GRPC_STATUS_OK) {
       if (error_details == nullptr) {
         error_details = "Authentication metadata processing failed.";
@@ -196,7 +197,7 @@
   GRPC_CALL_STACK_UNREF(calld->owning_call, "server_auth_metadata");
 }
 
-static void cancel_call(void* arg, grpc_error* error) {
+static void cancel_call(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   // If the result was not already processed, invoke the callback now.
@@ -206,9 +207,10 @@
     on_md_processing_done_inner(elem, nullptr, 0, nullptr, 0,
                                 GRPC_ERROR_REF(error));
   }
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_call");
 }
 
-static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
+static void recv_initial_metadata_ready(void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
@@ -218,6 +220,9 @@
         chand->creds->auth_metadata_processor().process != nullptr) {
       // We're calling out to the application, so we need to make sure
       // to drop the call combiner early if we get cancelled.
+      // TODO(yashykt): We would not need this ref if call combiners used
+      // Closure::Run() instead of ExecCtx::Run()
+      GRPC_CALL_STACK_REF(calld->owning_call, "cancel_call");
       GRPC_CLOSURE_INIT(&calld->cancel_closure, cancel_call, elem,
                         grpc_schedule_on_exec_ctx);
       calld->call_combiner->SetNotifyOnCancel(&calld->cancel_closure);
@@ -242,7 +247,8 @@
   grpc_core::Closure::Run(DEBUG_LOCATION, closure, GRPC_ERROR_REF(error));
 }
 
-static void recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
+static void recv_trailing_metadata_ready(void* user_data,
+                                         grpc_error_handle err) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->original_recv_initial_metadata_ready != nullptr) {
@@ -280,7 +286,7 @@
 }
 
 /* Constructor for call_data */
-static grpc_error* server_auth_init_call_elem(
+static grpc_error_handle server_auth_init_call_elem(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   new (elem->call_data) call_data(elem, *args);
   return GRPC_ERROR_NONE;
@@ -295,11 +301,18 @@
 }
 
 /* Constructor for channel_data */
-static grpc_error* server_auth_init_channel_elem(
+static grpc_error_handle server_auth_init_channel_elem(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   grpc_auth_context* auth_context =
       grpc_find_auth_context_in_args(args->channel_args);
+  if (auth_context == nullptr) {
+    grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "No authorization context found. This might be a TRANSIENT failure due "
+        "to certificates not having been loaded yet.");
+    gpr_log(GPR_DEBUG, "%s", grpc_error_std_string(error).c_str());
+    return error;
+  }
   GPR_ASSERT(auth_context != nullptr);
   grpc_server_credentials* creds =
       grpc_find_server_credentials_in_args(args->channel_args);
diff --git a/grpc/src/core/lib/security/transport/tsi_error.cc b/grpc/src/core/lib/security/transport/tsi_error.cc
index f78bb8d..4d337b4 100644
--- a/grpc/src/core/lib/security/transport/tsi_error.cc
+++ b/grpc/src/core/lib/security/transport/tsi_error.cc
@@ -20,7 +20,8 @@
 
 #include "src/core/lib/security/transport/tsi_error.h"
 
-grpc_error* grpc_set_tsi_error_result(grpc_error* error, tsi_result result) {
+grpc_error_handle grpc_set_tsi_error_result(grpc_error_handle error,
+                                            tsi_result result) {
   return grpc_error_set_int(
       grpc_error_set_str(
           error, GRPC_ERROR_STR_TSI_ERROR,
diff --git a/grpc/src/core/lib/security/transport/tsi_error.h b/grpc/src/core/lib/security/transport/tsi_error.h
index 16e04f7..26b8806 100644
--- a/grpc/src/core/lib/security/transport/tsi_error.h
+++ b/grpc/src/core/lib/security/transport/tsi_error.h
@@ -24,6 +24,7 @@
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/tsi/transport_security_interface.h"
 
-grpc_error* grpc_set_tsi_error_result(grpc_error* error, tsi_result result);
+grpc_error_handle grpc_set_tsi_error_result(grpc_error_handle error,
+                                            tsi_result result);
 
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H */
diff --git a/grpc/src/core/lib/security/util/json_util.cc b/grpc/src/core/lib/security/util/json_util.cc
index ff2fbc8..34bf88f 100644
--- a/grpc/src/core/lib/security/util/json_util.cc
+++ b/grpc/src/core/lib/security/util/json_util.cc
@@ -30,7 +30,7 @@
 
 const char* grpc_json_get_string_property(const grpc_core::Json& json,
                                           const char* prop_name,
-                                          grpc_error** error) {
+                                          grpc_error_handle* error) {
   if (json.type() != grpc_core::Json::Type::OBJECT) {
     if (error != nullptr) {
       *error =
@@ -62,7 +62,7 @@
 bool grpc_copy_json_string_property(const grpc_core::Json& json,
                                     const char* prop_name,
                                     char** copied_value) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   const char* prop_value =
       grpc_json_get_string_property(json, prop_name, &error);
   GRPC_LOG_IF_ERROR("Could not copy JSON property", error);
diff --git a/grpc/src/core/lib/security/util/json_util.h b/grpc/src/core/lib/security/util/json_util.h
index cde9ca9..d3c6ec3 100644
--- a/grpc/src/core/lib/security/util/json_util.h
+++ b/grpc/src/core/lib/security/util/json_util.h
@@ -35,7 +35,7 @@
 // Gets a child property from a json node.
 const char* grpc_json_get_string_property(const grpc_core::Json& json,
                                           const char* prop_name,
-                                          grpc_error** error);
+                                          grpc_error_handle* error);
 
 // Copies the value of the json child property specified by prop_name.
 // Returns false if the property was not found.
diff --git a/grpc/src/core/lib/slice/slice_intern.cc b/grpc/src/core/lib/slice/slice_intern.cc
index 6e03f48..0468130 100644
--- a/grpc/src/core/lib/slice/slice_intern.cc
+++ b/grpc/src/core/lib/slice/slice_intern.cc
@@ -44,13 +44,13 @@
 using grpc_core::InternedSliceRefcount;
 
 typedef struct slice_shard {
-  gpr_mu mu;
+  grpc_core::Mutex mu;
   InternedSliceRefcount** strs;
   size_t count;
   size_t capacity;
 } slice_shard;
 
-static slice_shard g_shards[SHARD_COUNT];
+static slice_shard* g_shards;
 
 struct static_metadata_hash_ent {
   uint32_t hash;
@@ -259,13 +259,12 @@
 static InternedSliceRefcount* FindOrCreateInternedSlice(uint32_t hash,
                                                         const SliceArgs& args) {
   slice_shard* shard = &g_shards[SHARD_IDX(hash)];
-  gpr_mu_lock(&shard->mu);
+  grpc_core::MutexLock lock(&shard->mu);
   const size_t idx = TABLE_IDX(hash, shard->capacity);
   InternedSliceRefcount* s = MatchInternedSliceLocked(hash, idx, args);
   if (s == nullptr) {
     s = InternNewStringLocked(shard, idx, hash, args);
   }
-  gpr_mu_unlock(&shard->mu);
   return s;
 }
 
@@ -312,9 +311,9 @@
     grpc_core::g_hash_seed =
         static_cast<uint32_t>(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   }
+  g_shards = new slice_shard[SHARD_COUNT];
   for (size_t i = 0; i < SHARD_COUNT; i++) {
     slice_shard* shard = &g_shards[i];
-    gpr_mu_init(&shard->mu);
     shard->count = 0;
     shard->capacity = INITIAL_SHARD_CAPACITY;
     shard->strs = static_cast<InternedSliceRefcount**>(
@@ -352,7 +351,6 @@
 void grpc_slice_intern_shutdown(void) {
   for (size_t i = 0; i < SHARD_COUNT; i++) {
     slice_shard* shard = &g_shards[i];
-    gpr_mu_destroy(&shard->mu);
     /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
     if (shard->count != 0) {
       gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
@@ -371,4 +369,5 @@
     }
     gpr_free(shard->strs);
   }
+  delete[] g_shards;
 }
diff --git a/grpc/src/core/lib/surface/call.cc b/grpc/src/core/lib/surface/call.cc
index d749d39..ac0854c 100644
--- a/grpc/src/core/lib/surface/call.cc
+++ b/grpc/src/core/lib/surface/call.cc
@@ -290,14 +290,15 @@
 
 static void cancel_with_status(grpc_call* c, grpc_status_code status,
                                const char* description);
-static void cancel_with_error(grpc_call* c, grpc_error* error);
-static void destroy_call(void* call_stack, grpc_error* error);
-static void receiving_slice_ready(void* bctlp, grpc_error* error);
-static void set_final_status(grpc_call* call, grpc_error* error);
+static void cancel_with_error(grpc_call* c, grpc_error_handle error);
+static void destroy_call(void* call_stack, grpc_error_handle error);
+static void receiving_slice_ready(void* bctlp, grpc_error_handle error);
+static void set_final_status(grpc_call* call, grpc_error_handle error);
 static void process_data_after_md(batch_control* bctl);
 static void post_batch_completion(batch_control* bctl);
 
-static void add_init_error(grpc_error** composite, grpc_error* new_err) {
+static void add_init_error(grpc_error_handle* composite,
+                           grpc_error_handle new_err) {
   if (new_err == GRPC_ERROR_NONE) return;
   if (*composite == GRPC_ERROR_NONE) {
     *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Call creation failed");
@@ -335,15 +336,15 @@
          sizeof(grpc_linked_mdelem) * ESTIMATED_MDELEM_COUNT;
 }
 
-grpc_error* grpc_call_create(const grpc_call_create_args* args,
-                             grpc_call** out_call) {
+grpc_error_handle grpc_call_create(const grpc_call_create_args* args,
+                                   grpc_call** out_call) {
   GPR_TIMER_SCOPE("grpc_call_create", 0);
 
   GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
 
   grpc_core::Arena* arena;
   grpc_call* call;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_channel_stack* channel_stack =
       grpc_channel_get_channel_stack(args->channel);
   size_t initial_size = grpc_channel_get_call_size_estimate(args->channel);
@@ -524,7 +525,7 @@
   GRPC_CALL_STACK_UNREF(CALL_STACK_FROM_CALL(c), REF_REASON);
 }
 
-static void release_call(void* call, grpc_error* /*error*/) {
+static void release_call(void* call, grpc_error_handle /*error*/) {
   grpc_call* c = static_cast<grpc_call*>(call);
   grpc_channel* channel = c->channel;
   grpc_core::Arena* arena = c->arena;
@@ -533,7 +534,7 @@
   GRPC_CHANNEL_INTERNAL_UNREF(channel, "call");
 }
 
-static void destroy_call(void* call, grpc_error* /*error*/) {
+static void destroy_call(void* call, grpc_error_handle /*error*/) {
   GPR_TIMER_SCOPE("destroy_call", 0);
   size_t i;
   int ii;
@@ -559,8 +560,8 @@
     GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
   }
 
-  grpc_error* status_error =
-      reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&c->status_error));
+  grpc_error_handle status_error =
+      reinterpret_cast<grpc_error_handle>(gpr_atm_acq_load(&c->status_error));
   grpc_error_get_status(status_error, c->send_deadline,
                         &c->final_info.final_status, nullptr, nullptr,
                         &(c->final_info.error_string));
@@ -610,11 +611,8 @@
     // Unset the call combiner cancellation closure.  This has the
     // effect of scheduling the previously set cancellation closure, if
     // any, so that it can release any internal references it may be
-    // holding to the call stack. Also flush the closures on exec_ctx so that
-    // filters that schedule cancel notification closures on exec_ctx do not
-    // need to take a ref of the call stack to guarantee closure liveness.
+    // holding to the call stack.
     c->call_combiner.SetNotifyOnCancel(nullptr);
-    grpc_core::ExecCtx::Get()->Flush();
   }
   GRPC_CALL_INTERNAL_UNREF(c, "destroy");
 }
@@ -630,7 +628,8 @@
 
 // This is called via the call combiner to start sending a batch down
 // the filter stack.
-static void execute_batch_in_call_combiner(void* arg, grpc_error* /*ignored*/) {
+static void execute_batch_in_call_combiner(void* arg,
+                                           grpc_error_handle /*ignored*/) {
   GPR_TIMER_SCOPE("execute_batch_in_call_combiner", 0);
   grpc_transport_stream_op_batch* batch =
       static_cast<grpc_transport_stream_op_batch*>(arg);
@@ -691,7 +690,7 @@
 };
 // The on_complete callback used when sending a cancel_stream batch down
 // the filter stack.  Yields the call combiner when the batch is done.
-static void done_termination(void* arg, grpc_error* /*error*/) {
+static void done_termination(void* arg, grpc_error_handle /*error*/) {
   cancel_state* state = static_cast<cancel_state*>(arg);
   GRPC_CALL_COMBINER_STOP(&state->call->call_combiner,
                           "on_complete for cancel_stream op");
@@ -699,7 +698,7 @@
   gpr_free(state);
 }
 
-static void cancel_with_error(grpc_call* c, grpc_error* error) {
+static void cancel_with_error(grpc_call* c, grpc_error_handle error) {
   if (!gpr_atm_rel_cas(&c->cancelled_with_error, 0, 1)) {
     GRPC_ERROR_UNREF(error);
     return;
@@ -725,8 +724,8 @@
   cancel_with_error(call, GRPC_ERROR_CANCELLED);
 }
 
-static grpc_error* error_from_status(grpc_status_code status,
-                                     const char* description) {
+static grpc_error_handle error_from_status(grpc_status_code status,
+                                           const char* description) {
   // copying 'description' is needed to ensure the grpc_call_cancel_with_status
   // guarantee that can be short-lived.
   return grpc_error_set_int(
@@ -741,10 +740,10 @@
   cancel_with_error(c, error_from_status(status, description));
 }
 
-static void set_final_status(grpc_call* call, grpc_error* error) {
+static void set_final_status(grpc_call* call, grpc_error_handle error) {
   if (GRPC_TRACE_FLAG_ENABLED(grpc_call_error_trace)) {
     gpr_log(GPR_DEBUG, "set_final_status %s", call->is_client ? "CLI" : "SVR");
-    gpr_log(GPR_DEBUG, "%s", grpc_error_string(error));
+    gpr_log(GPR_DEBUG, "%s", grpc_error_std_string(error).c_str());
   }
   if (call->is_client) {
     grpc_error_get_status(error, call->send_deadline,
@@ -770,7 +769,7 @@
         call->final_op.server.core_server->channelz_node();
     if (channelz_node != nullptr) {
       if (*call->final_op.server.cancelled ||
-          reinterpret_cast<grpc_error*>(
+          reinterpret_cast<grpc_error_handle>(
               gpr_atm_acq_load(&call->status_error)) != GRPC_ERROR_NONE) {
         channelz_node->RecordCallFailed();
       } else {
@@ -952,7 +951,7 @@
   for (i = 0; i < total_count; i++) {
     grpc_metadata* md = get_md_elem(metadata, additional_metadata, i, count);
     grpc_linked_mdelem* l = linked_from_md(md);
-    grpc_error* error = grpc_metadata_batch_link_tail(batch, l);
+    grpc_error_handle error = grpc_metadata_batch_link_tail(batch, l);
     if (error != GRPC_ERROR_NONE) {
       GRPC_MDELEM_UNREF(l->md);
     }
@@ -1053,14 +1052,14 @@
 }
 
 static void recv_trailing_filter(void* args, grpc_metadata_batch* b,
-                                 grpc_error* batch_error) {
+                                 grpc_error_handle batch_error) {
   grpc_call* call = static_cast<grpc_call*>(args);
   if (batch_error != GRPC_ERROR_NONE) {
     set_final_status(call, batch_error);
   } else if (b->idx.named.grpc_status != nullptr) {
     grpc_status_code status_code =
         grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
-    grpc_error* error = GRPC_ERROR_NONE;
+    grpc_error_handle error = GRPC_ERROR_NONE;
     if (status_code != GRPC_STATUS_OK) {
       char* peer = grpc_call_get_peer(call);
       error = grpc_error_set_int(
@@ -1171,8 +1170,8 @@
 }
 
 static void reset_batch_errors(batch_control* bctl) {
-  GRPC_ERROR_UNREF(
-      reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)));
+  GRPC_ERROR_UNREF(reinterpret_cast<grpc_error_handle>(
+      gpr_atm_acq_load(&bctl->batch_error)));
   gpr_atm_rel_store(&bctl->batch_error,
                     reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE));
 }
@@ -1180,8 +1179,8 @@
 static void post_batch_completion(batch_control* bctl) {
   grpc_call* next_child_call;
   grpc_call* call = bctl->call;
-  grpc_error* error = GRPC_ERROR_REF(
-      reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)));
+  grpc_error_handle error = GRPC_ERROR_REF(reinterpret_cast<grpc_error_handle>(
+      gpr_atm_acq_load(&bctl->batch_error)));
 
   if (bctl->op.send_initial_metadata) {
     grpc_metadata_batch_destroy(
@@ -1254,7 +1253,7 @@
 }
 
 static void continue_receiving_slices(batch_control* bctl) {
-  grpc_error* error;
+  grpc_error_handle error;
   grpc_call* call = bctl->call;
   for (;;) {
     size_t remaining = call->receiving_stream->length() -
@@ -1285,7 +1284,7 @@
   }
 }
 
-static void receiving_slice_ready(void* bctlp, grpc_error* error) {
+static void receiving_slice_ready(void* bctlp, grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   bool release_error = false;
@@ -1345,13 +1344,13 @@
   }
 }
 
-static void receiving_stream_ready(void* bctlp, grpc_error* error) {
+static void receiving_stream_ready(void* bctlp, grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   if (error != GRPC_ERROR_NONE) {
     call->receiving_stream.reset();
-    if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
-        GRPC_ERROR_NONE) {
+    if (reinterpret_cast<grpc_error_handle>(
+            gpr_atm_acq_load(&bctl->batch_error)) == GRPC_ERROR_NONE) {
       gpr_atm_rel_store(&bctl->batch_error,
                         reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
     }
@@ -1371,7 +1370,7 @@
 // a recv_message op down the filter stack.  Yields the call combiner
 // before processing the received message.
 static void receiving_stream_ready_in_call_combiner(void* bctlp,
-                                                    grpc_error* error) {
+                                                    grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_message_ready");
@@ -1464,7 +1463,8 @@
   }
 }
 
-static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
+static void receiving_initial_metadata_ready(void* bctlp,
+                                             grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
 
@@ -1483,8 +1483,8 @@
       call->send_deadline = md->deadline;
     }
   } else {
-    if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
-        GRPC_ERROR_NONE) {
+    if (reinterpret_cast<grpc_error_handle>(
+            gpr_atm_acq_load(&bctl->batch_error)) == GRPC_ERROR_NONE) {
       gpr_atm_rel_store(&bctl->batch_error,
                         reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
     }
@@ -1523,7 +1523,8 @@
   finish_batch_step(bctl);
 }
 
-static void receiving_trailing_metadata_ready(void* bctlp, grpc_error* error) {
+static void receiving_trailing_metadata_ready(void* bctlp,
+                                              grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_trailing_metadata_ready");
@@ -1533,12 +1534,12 @@
   finish_batch_step(bctl);
 }
 
-static void finish_batch(void* bctlp, grpc_error* error) {
+static void finish_batch(void* bctlp, grpc_error_handle error) {
   batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "on_complete");
-  if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
-      GRPC_ERROR_NONE) {
+  if (reinterpret_cast<grpc_error_handle>(
+          gpr_atm_acq_load(&bctl->batch_error)) == GRPC_ERROR_NONE) {
     gpr_atm_rel_store(&bctl->batch_error,
                       reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
   }
@@ -1755,7 +1756,7 @@
         call->send_extra_metadata_count = 1;
         call->send_extra_metadata[0].md = grpc_get_reffed_status_elem(
             op->data.send_status_from_server.status);
-        grpc_error* status_error =
+        grpc_error_handle status_error =
             op->data.send_status_from_server.status == GRPC_STATUS_OK
                 ? GRPC_ERROR_NONE
                 : grpc_error_set_int(
diff --git a/grpc/src/core/lib/surface/call.h b/grpc/src/core/lib/surface/call.h
index 34d01db..a6ad3ca 100644
--- a/grpc/src/core/lib/surface/call.h
+++ b/grpc/src/core/lib/surface/call.h
@@ -55,8 +55,8 @@
 /* Create a new call based on \a args.
    Regardless of success or failure, always returns a valid new call into *call
    */
-grpc_error* grpc_call_create(const grpc_call_create_args* args,
-                             grpc_call** call);
+grpc_error_handle grpc_call_create(const grpc_call_create_args* args,
+                                   grpc_call** call);
 
 void grpc_call_set_completion_queue(grpc_call* call, grpc_completion_queue* cq);
 
diff --git a/grpc/src/core/lib/surface/channel.cc b/grpc/src/core/lib/surface/channel.cc
index d68f43f..d3552c8 100644
--- a/grpc/src/core/lib/surface/channel.cc
+++ b/grpc/src/core/lib/surface/channel.cc
@@ -54,11 +54,11 @@
  *  (OK, Cancelled, Unknown). */
 #define NUM_CACHED_STATUS_ELEMS 3
 
-static void destroy_channel(void* arg, grpc_error* error);
+static void destroy_channel(void* arg, grpc_error_handle error);
 
 grpc_channel* grpc_channel_create_with_builder(
     grpc_channel_stack_builder* builder,
-    grpc_channel_stack_type channel_stack_type, grpc_error** error) {
+    grpc_channel_stack_type channel_stack_type, grpc_error_handle* error) {
   char* target = gpr_strdup(grpc_channel_stack_builder_get_target(builder));
   grpc_channel_args* args = grpc_channel_args_copy(
       grpc_channel_stack_builder_get_channel_arguments(builder));
@@ -70,12 +70,12 @@
   } else {
     GRPC_STATS_INC_CLIENT_CHANNELS_CREATED();
   }
-  grpc_error* builder_error = grpc_channel_stack_builder_finish(
+  grpc_error_handle builder_error = grpc_channel_stack_builder_finish(
       builder, sizeof(grpc_channel), 1, destroy_channel, nullptr,
       reinterpret_cast<void**>(&channel));
   if (builder_error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "channel stack builder failed: %s",
-            grpc_error_string(builder_error));
+            grpc_error_std_string(builder_error).c_str());
     GPR_ASSERT(channel == nullptr);
     if (error != nullptr) {
       *error = builder_error;
@@ -225,7 +225,7 @@
                                   grpc_channel_stack_type channel_stack_type,
                                   grpc_transport* optional_transport,
                                   grpc_resource_user* resource_user,
-                                  grpc_error** error) {
+                                  grpc_error_handle* error) {
   // We need to make sure that grpc_shutdown() does not shut things down
   // until after the channel is destroyed.  However, the channel may not
   // actually be destroyed by the time grpc_channel_destroy() returns,
@@ -497,7 +497,7 @@
   return call;
 }
 
-static void destroy_channel(void* arg, grpc_error* /*error*/) {
+static void destroy_channel(void* arg, grpc_error_handle /*error*/) {
   grpc_channel* channel = static_cast<grpc_channel*>(arg);
   if (channel->channelz_node != nullptr) {
     channel->channelz_node->AddTraceEvent(
diff --git a/grpc/src/core/lib/surface/channel.h b/grpc/src/core/lib/surface/channel.h
index 659bc8e..8a14a72 100644
--- a/grpc/src/core/lib/surface/channel.h
+++ b/grpc/src/core/lib/surface/channel.h
@@ -35,7 +35,7 @@
                                   grpc_channel_stack_type channel_stack_type,
                                   grpc_transport* optional_transport,
                                   grpc_resource_user* resource_user = nullptr,
-                                  grpc_error** error = nullptr);
+                                  grpc_error_handle* error = nullptr);
 
 /** The same as grpc_channel_destroy, but doesn't create an ExecCtx, and so
  * is safe to use from within core. */
@@ -43,7 +43,8 @@
 
 grpc_channel* grpc_channel_create_with_builder(
     grpc_channel_stack_builder* builder,
-    grpc_channel_stack_type channel_stack_type, grpc_error** error = nullptr);
+    grpc_channel_stack_type channel_stack_type,
+    grpc_error_handle* error = nullptr);
 
 /** Create a call given a grpc_channel, in order to call \a method.
     Progress is tied to activity on \a pollset_set. The returned call object is
@@ -94,9 +95,9 @@
   // The map key should be owned strings rather than unowned char*'s to
   // guarantee that it outlives calls on the core channel (which may outlast the
   // C++ or other wrapped language Channel that registered these calls).
-  std::map<std::pair<std::string, std::string>, RegisteredCall>
-      map /* GUARDED_BY(mu) */;
-  int method_registration_attempts /* GUARDED_BY(mu) */ = 0;
+  std::map<std::pair<std::string, std::string>, RegisteredCall> map
+      ABSL_GUARDED_BY(mu);
+  int method_registration_attempts ABSL_GUARDED_BY(mu) = 0;
 };
 
 }  // namespace grpc_core
diff --git a/grpc/src/core/lib/surface/channel_ping.cc b/grpc/src/core/lib/surface/channel_ping.cc
index 82e5521..a6e53ec 100644
--- a/grpc/src/core/lib/surface/channel_ping.cc
+++ b/grpc/src/core/lib/surface/channel_ping.cc
@@ -38,7 +38,7 @@
   gpr_free(arg);
 }
 
-static void ping_done(void* arg, grpc_error* error) {
+static void ping_done(void* arg, grpc_error_handle error) {
   ping_result* pr = static_cast<ping_result*>(arg);
   grpc_cq_end_op(pr->cq, pr->tag, GRPC_ERROR_REF(error), ping_destroy, pr,
                  &pr->completion_storage);
diff --git a/grpc/src/core/lib/surface/completion_queue.cc b/grpc/src/core/lib/surface/completion_queue.cc
index 02ac506..2b889e0 100644
--- a/grpc/src/core/lib/surface/completion_queue.cc
+++ b/grpc/src/core/lib/surface/completion_queue.cc
@@ -70,10 +70,10 @@
   bool can_listen;
   size_t (*size)(void);
   void (*init)(grpc_pollset* pollset, gpr_mu** mu);
-  grpc_error* (*kick)(grpc_pollset* pollset,
-                      grpc_pollset_worker* specific_worker);
-  grpc_error* (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
-                      grpc_millis deadline);
+  grpc_error_handle (*kick)(grpc_pollset* pollset,
+                            grpc_pollset_worker* specific_worker);
+  grpc_error_handle (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
+                            grpc_millis deadline);
   void (*shutdown)(grpc_pollset* pollset, grpc_closure* closure);
   void (*destroy)(grpc_pollset* pollset);
 };
@@ -103,9 +103,9 @@
   gpr_mu_destroy(&npp->mu);
 }
 
-grpc_error* non_polling_poller_work(grpc_pollset* pollset,
-                                    grpc_pollset_worker** worker,
-                                    grpc_millis deadline) {
+grpc_error_handle non_polling_poller_work(grpc_pollset* pollset,
+                                          grpc_pollset_worker** worker,
+                                          grpc_millis deadline) {
   non_polling_poller* npp = reinterpret_cast<non_polling_poller*>(pollset);
   if (npp->shutdown) return GRPC_ERROR_NONE;
   if (npp->kicked_without_poller) {
@@ -145,8 +145,8 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* non_polling_poller_kick(grpc_pollset* pollset,
-                                    grpc_pollset_worker* specific_worker) {
+grpc_error_handle non_polling_poller_kick(
+    grpc_pollset* pollset, grpc_pollset_worker* specific_worker) {
   non_polling_poller* p = reinterpret_cast<non_polling_poller*>(pollset);
   if (specific_worker == nullptr) {
     specific_worker = reinterpret_cast<grpc_pollset_worker*>(p->root);
@@ -202,7 +202,7 @@
   void (*shutdown)(grpc_completion_queue* cq);
   void (*destroy)(void* data);
   bool (*begin_op)(grpc_completion_queue* cq, void* tag);
-  void (*end_op)(grpc_completion_queue* cq, void* tag, grpc_error* error,
+  void (*end_op)(grpc_completion_queue* cq, void* tag, grpc_error_handle error,
                  void (*done)(void* done_arg, grpc_cq_completion* storage),
                  void* done_arg, grpc_cq_completion* storage, bool internal);
   grpc_event (*next)(grpc_completion_queue* cq, gpr_timespec deadline,
@@ -376,17 +376,17 @@
 // safe to free up that storage. The storage MUST NOT be freed until the
 // done callback is invoked.
 static void cq_end_op_for_next(
-    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle error,
     void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
     grpc_cq_completion* storage, bool internal);
 
 static void cq_end_op_for_pluck(
-    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle error,
     void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
     grpc_cq_completion* storage, bool internal);
 
 static void cq_end_op_for_callback(
-    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle error,
     void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
     grpc_cq_completion* storage, bool internal);
 
@@ -439,7 +439,7 @@
     }                                                    \
   } while (0)
 
-static void on_pollset_shutdown_done(void* arg, grpc_error* error);
+static void on_pollset_shutdown_done(void* arg, grpc_error_handle error);
 
 void grpc_cq_global_init() {
   gpr_tls_init(&g_cached_event);
@@ -604,7 +604,7 @@
   cq->owning_refs.Ref(debug_location, reason);
 }
 
-static void on_pollset_shutdown_done(void* arg, grpc_error* /*error*/) {
+static void on_pollset_shutdown_done(void* arg, grpc_error_handle /*error*/) {
   grpc_completion_queue* cq = static_cast<grpc_completion_queue*>(arg);
   GRPC_CQ_INTERNAL_UNREF(cq, "pollset_destroy");
 }
@@ -690,7 +690,7 @@
  * completion
  * type of GRPC_CQ_NEXT) */
 static void cq_end_op_for_next(
-    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle error,
     void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
     grpc_cq_completion* storage, bool /*internal*/) {
   GPR_TIMER_SCOPE("cq_end_op_for_next", 0);
@@ -698,14 +698,15 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
       (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
        error != GRPC_ERROR_NONE)) {
-    const char* errmsg = grpc_error_string(error);
+    std::string errmsg = grpc_error_std_string(error);
     GRPC_API_TRACE(
         "cq_end_op_for_next(cq=%p, tag=%p, error=%s, "
         "done=%p, done_arg=%p, storage=%p)",
-        6, (cq, tag, errmsg, done, done_arg, storage));
+        6, (cq, tag, errmsg.c_str(), done, done_arg, storage));
     if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
         error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
+      gpr_log(GPR_INFO, "Operation failed: tag=%p, error=%s", tag,
+              errmsg.c_str());
     }
   }
   cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
@@ -736,13 +737,13 @@
       /* Only kick if this is the first item queued */
       if (is_first) {
         gpr_mu_lock(cq->mu);
-        grpc_error* kick_error =
+        grpc_error_handle kick_error =
             cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), nullptr);
         gpr_mu_unlock(cq->mu);
 
         if (kick_error != GRPC_ERROR_NONE) {
-          const char* msg = grpc_error_string(kick_error);
-          gpr_log(GPR_ERROR, "Kick failed: %s", msg);
+          gpr_log(GPR_ERROR, "Kick failed: %s",
+                  grpc_error_std_string(kick_error).c_str());
           GRPC_ERROR_UNREF(kick_error);
         }
       }
@@ -771,7 +772,7 @@
  * completion
  * type of GRPC_CQ_PLUCK) */
 static void cq_end_op_for_pluck(
-    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle error,
     void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
     grpc_cq_completion* storage, bool /*internal*/) {
   GPR_TIMER_SCOPE("cq_end_op_for_pluck", 0);
@@ -782,14 +783,15 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
       (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
        error != GRPC_ERROR_NONE)) {
-    const char* errmsg = grpc_error_string(error);
+    std::string errmsg = grpc_error_std_string(error).c_str();
     GRPC_API_TRACE(
         "cq_end_op_for_pluck(cq=%p, tag=%p, error=%s, "
         "done=%p, done_arg=%p, storage=%p)",
-        6, (cq, tag, errmsg, done, done_arg, storage));
+        6, (cq, tag, errmsg.c_str(), done, done_arg, storage));
     if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
         error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
+      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag,
+              errmsg.c_str());
     }
   }
 
@@ -820,15 +822,12 @@
       }
     }
 
-    grpc_error* kick_error =
+    grpc_error_handle kick_error =
         cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), pluck_worker);
-
     gpr_mu_unlock(cq->mu);
-
     if (kick_error != GRPC_ERROR_NONE) {
-      const char* msg = grpc_error_string(kick_error);
-      gpr_log(GPR_ERROR, "Kick failed: %s", msg);
-
+      gpr_log(GPR_ERROR, "Kick failed: %s",
+              grpc_error_std_string(kick_error).c_str());
       GRPC_ERROR_UNREF(kick_error);
     }
   }
@@ -836,14 +835,14 @@
   GRPC_ERROR_UNREF(error);
 }
 
-static void functor_callback(void* arg, grpc_error* error) {
+static void functor_callback(void* arg, grpc_error_handle error) {
   auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(arg);
   functor->functor_run(functor, error == GRPC_ERROR_NONE);
 }
 
 /* Complete an event on a completion queue of type GRPC_CQ_CALLBACK */
 static void cq_end_op_for_callback(
-    grpc_completion_queue* cq, void* tag, grpc_error* error,
+    grpc_completion_queue* cq, void* tag, grpc_error_handle error,
     void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
     grpc_cq_completion* storage, bool internal) {
   GPR_TIMER_SCOPE("cq_end_op_for_callback", 0);
@@ -853,14 +852,15 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
       (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
        error != GRPC_ERROR_NONE)) {
-    const char* errmsg = grpc_error_string(error);
+    std::string errmsg = grpc_error_std_string(error);
     GRPC_API_TRACE(
         "cq_end_op_for_callback(cq=%p, tag=%p, error=%s, "
         "done=%p, done_arg=%p, storage=%p)",
-        6, (cq, tag, errmsg, done, done_arg, storage));
+        6, (cq, tag, errmsg.c_str(), done, done_arg, storage));
     if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
         error != GRPC_ERROR_NONE) {
-      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
+      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag,
+              errmsg.c_str());
     }
   }
 
@@ -896,7 +896,8 @@
       GRPC_CLOSURE_CREATE(functor_callback, functor, nullptr), error);
 }
 
-void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
+void grpc_cq_end_op(grpc_completion_queue* cq, void* tag,
+                    grpc_error_handle error,
                     void (*done)(void* done_arg, grpc_cq_completion* storage),
                     void* done_arg, grpc_cq_completion* storage,
                     bool internal) {
@@ -1056,14 +1057,13 @@
     /* The main polling work happens in grpc_pollset_work */
     gpr_mu_lock(cq->mu);
     cq->num_polls++;
-    grpc_error* err = cq->poller_vtable->work(POLLSET_FROM_CQ(cq), nullptr,
-                                              iteration_deadline);
+    grpc_error_handle err = cq->poller_vtable->work(
+        POLLSET_FROM_CQ(cq), nullptr, iteration_deadline);
     gpr_mu_unlock(cq->mu);
 
     if (err != GRPC_ERROR_NONE) {
-      const char* msg = grpc_error_string(err);
-      gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
-
+      gpr_log(GPR_ERROR, "Completion queue next failed: %s",
+              grpc_error_std_string(err).c_str());
       GRPC_ERROR_UNREF(err);
       ret.type = GRPC_QUEUE_TIMEOUT;
       ret.success = 0;
@@ -1299,14 +1299,13 @@
       break;
     }
     cq->num_polls++;
-    grpc_error* err =
+    grpc_error_handle err =
         cq->poller_vtable->work(POLLSET_FROM_CQ(cq), &worker, deadline_millis);
     if (err != GRPC_ERROR_NONE) {
       del_plucker(cq, tag, &worker);
       gpr_mu_unlock(cq->mu);
-      const char* msg = grpc_error_string(err);
-      gpr_log(GPR_ERROR, "Completion queue pluck failed: %s", msg);
-
+      gpr_log(GPR_ERROR, "Completion queue pluck failed: %s",
+              grpc_error_std_string(err).c_str());
       GRPC_ERROR_UNREF(err);
       ret.type = GRPC_QUEUE_TIMEOUT;
       ret.success = 0;
diff --git a/grpc/src/core/lib/surface/completion_queue.h b/grpc/src/core/lib/surface/completion_queue.h
index 59116d4..2bf91fa 100644
--- a/grpc/src/core/lib/surface/completion_queue.h
+++ b/grpc/src/core/lib/surface/completion_queue.h
@@ -77,7 +77,8 @@
 
 /* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to
    grpc_cq_begin_op */
-void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
+void grpc_cq_end_op(grpc_completion_queue* cq, void* tag,
+                    grpc_error_handle error,
                     void (*done)(void* done_arg, grpc_cq_completion* storage),
                     void* done_arg, grpc_cq_completion* storage,
                     bool internal = false);
diff --git a/grpc/src/core/lib/surface/init.cc b/grpc/src/core/lib/surface/init.cc
index 0b2151b..41866f1 100644
--- a/grpc/src/core/lib/surface/init.cc
+++ b/grpc/src/core/lib/surface/init.cc
@@ -63,16 +63,15 @@
 #define MAX_PLUGINS 128
 
 static gpr_once g_basic_init = GPR_ONCE_INIT;
-static gpr_mu g_init_mu;
+static grpc_core::Mutex* g_init_mu;
 static int g_initializations;
-static gpr_cv* g_shutting_down_cv;
+static grpc_core::CondVar* g_shutting_down_cv;
 static bool g_shutting_down;
 
 static void do_basic_init(void) {
   gpr_log_verbosity_init();
-  gpr_mu_init(&g_init_mu);
-  g_shutting_down_cv = static_cast<gpr_cv*>(malloc(sizeof(gpr_cv)));
-  gpr_cv_init(g_shutting_down_cv);
+  g_init_mu = new grpc_core::Mutex();
+  g_shutting_down_cv = new grpc_core::CondVar();
   g_shutting_down = false;
   grpc_register_built_in_plugins();
   grpc_cq_global_init();
@@ -130,11 +129,11 @@
   int i;
   gpr_once_init(&g_basic_init, do_basic_init);
 
-  grpc_core::MutexLock lock(&g_init_mu);
+  grpc_core::MutexLock lock(g_init_mu);
   if (++g_initializations == 1) {
     if (g_shutting_down) {
       g_shutting_down = false;
-      gpr_cv_broadcast(g_shutting_down_cv);
+      g_shutting_down_cv->SignalAll();
     }
     grpc_core::Fork::GlobalInit();
     grpc_fork_handlers_auto_register();
@@ -196,14 +195,14 @@
   grpc_core::ExecCtx::GlobalShutdown();
   grpc_core::ApplicationCallbackExecCtx::GlobalShutdown();
   g_shutting_down = false;
-  gpr_cv_broadcast(g_shutting_down_cv);
+  g_shutting_down_cv->SignalAll();
   // Absolute last action will be to delete static metadata context.
   grpc_destroy_static_metadata_ctx();
 }
 
 void grpc_shutdown_internal(void* /*ignored*/) {
   GRPC_API_TRACE("grpc_shutdown_internal", 0, ());
-  grpc_core::MutexLock lock(&g_init_mu);
+  grpc_core::MutexLock lock(g_init_mu);
   // We have released lock from the shutdown thread and it is possible that
   // another grpc_init has been called, and do nothing if that is the case.
   if (--g_initializations != 0) {
@@ -214,7 +213,7 @@
 
 void grpc_shutdown(void) {
   GRPC_API_TRACE("grpc_shutdown(void)", 0, ());
-  grpc_core::MutexLock lock(&g_init_mu);
+  grpc_core::MutexLock lock(g_init_mu);
 
   if (--g_initializations == 0) {
     grpc_core::ApplicationCallbackExecCtx* acec =
@@ -243,7 +242,7 @@
 
 void grpc_shutdown_blocking(void) {
   GRPC_API_TRACE("grpc_shutdown_blocking(void)", 0, ());
-  grpc_core::MutexLock lock(&g_init_mu);
+  grpc_core::MutexLock lock(g_init_mu);
   if (--g_initializations == 0) {
     g_shutting_down = true;
     grpc_shutdown_internal_locked();
@@ -253,16 +252,15 @@
 int grpc_is_initialized(void) {
   int r;
   gpr_once_init(&g_basic_init, do_basic_init);
-  grpc_core::MutexLock lock(&g_init_mu);
+  grpc_core::MutexLock lock(g_init_mu);
   r = g_initializations > 0;
   return r;
 }
 
 void grpc_maybe_wait_for_async_shutdown(void) {
   gpr_once_init(&g_basic_init, do_basic_init);
-  grpc_core::MutexLock lock(&g_init_mu);
+  grpc_core::MutexLock lock(g_init_mu);
   while (g_shutting_down) {
-    gpr_cv_wait(g_shutting_down_cv, &g_init_mu,
-                gpr_inf_future(GPR_CLOCK_REALTIME));
+    g_shutting_down_cv->Wait(g_init_mu);
   }
 }
diff --git a/grpc/src/core/lib/surface/lame_client.cc b/grpc/src/core/lib/surface/lame_client.cc
index d32cc28..65e659a 100644
--- a/grpc/src/core/lib/surface/lame_client.cc
+++ b/grpc/src/core/lib/surface/lame_client.cc
@@ -35,15 +35,23 @@
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/static_metadata.h"
 
+#define GRPC_ARG_LAME_FILTER_ERROR "grpc.lame_filter_error"
+
 namespace grpc_core {
 
 namespace {
 
 struct ChannelData {
-  ChannelData() : state_tracker("lame_channel", GRPC_CHANNEL_SHUTDOWN) {}
+  explicit ChannelData(grpc_channel_element_args* args)
+      : state_tracker("lame_channel", GRPC_CHANNEL_SHUTDOWN) {
+    grpc_error_handle err = grpc_channel_args_find_pointer<grpc_error>(
+        args->channel_args, GRPC_ARG_LAME_FILTER_ERROR);
+    if (err != nullptr) error = GRPC_ERROR_REF(err);
+  }
+
   ~ChannelData() { GRPC_ERROR_UNREF(error); }
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Mutex mu;
   ConnectivityStateTracker state_tracker;
 };
@@ -90,8 +98,8 @@
   }
 }
 
-static grpc_error* lame_init_call_elem(grpc_call_element* elem,
-                                       const grpc_call_element_args* args) {
+static grpc_error_handle lame_init_call_elem(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   CallData* calld = static_cast<CallData*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
   return GRPC_ERROR_NONE;
@@ -103,11 +111,9 @@
   ExecCtx::Run(DEBUG_LOCATION, then_schedule_closure, GRPC_ERROR_NONE);
 }
 
-static grpc_error* lame_init_channel_elem(grpc_channel_element* elem,
-                                          grpc_channel_element_args* args) {
-  GPR_ASSERT(args->is_first);
-  GPR_ASSERT(args->is_last);
-  new (elem->channel_data) ChannelData;
+static grpc_error_handle lame_init_channel_elem(
+    grpc_channel_element* elem, grpc_channel_element_args* args) {
+  new (elem->channel_data) ChannelData(args);
   return GRPC_ERROR_NONE;
 }
 
@@ -116,12 +122,25 @@
   chand->~ChannelData();
 }
 
+// Channel arg vtable for a grpc_error_handle.
+void* ErrorCopy(void* p) {
+  grpc_error_handle error = static_cast<grpc_error_handle>(p);
+  return GRPC_ERROR_REF(error);
+}
+void ErrorDestroy(void* p) {
+  grpc_error_handle error = static_cast<grpc_error_handle>(p);
+  GRPC_ERROR_UNREF(error);
+}
+int ErrorCompare(void* p, void* q) { return GPR_ICMP(p, q); }
+const grpc_arg_pointer_vtable kLameFilterErrorArgVtable = {
+    ErrorCopy, ErrorDestroy, ErrorCompare};
+
 }  // namespace
 
-void SetLameFilterError(grpc_channel_element* elem, grpc_error* error) {
-  GPR_ASSERT(elem->filter == &grpc_lame_filter);
-  auto chand = static_cast<grpc_core::ChannelData*>(elem->channel_data);
-  chand->error = error;
+grpc_arg MakeLameClientErrorArg(grpc_error_handle error) {
+  return grpc_channel_arg_pointer_create(
+      const_cast<char*>(GRPC_ARG_LAME_FILTER_ERROR), error,
+      &kLameFilterErrorArgVtable);
 }
 
 }  // namespace grpc_core
@@ -146,20 +165,20 @@
                                               grpc_status_code error_code,
                                               const char* error_message) {
   grpc_core::ExecCtx exec_ctx;
-  grpc_channel_element* elem;
-  grpc_channel* channel =
-      grpc_channel_create(target, nullptr, GRPC_CLIENT_LAME_CHANNEL, nullptr);
-  elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
   GRPC_API_TRACE(
       "grpc_lame_client_channel_create(target=%s, error_code=%d, "
       "error_message=%s)",
       3, (target, (int)error_code, error_message));
-  grpc_core::SetLameFilterError(
-      elem, grpc_error_set_str(
-                grpc_error_set_int(
-                    GRPC_ERROR_CREATE_FROM_STATIC_STRING("lame client channel"),
-                    GRPC_ERROR_INT_GRPC_STATUS, error_code),
-                GRPC_ERROR_STR_GRPC_MESSAGE,
-                grpc_slice_from_static_string(error_message)));
+  grpc_error_handle error = grpc_error_set_str(
+      grpc_error_set_int(
+          GRPC_ERROR_CREATE_FROM_STATIC_STRING("lame client channel"),
+          GRPC_ERROR_INT_GRPC_STATUS, error_code),
+      GRPC_ERROR_STR_GRPC_MESSAGE,
+      grpc_slice_from_static_string(error_message));
+  grpc_arg error_arg = grpc_core::MakeLameClientErrorArg(error);
+  grpc_channel_args args = {1, &error_arg};
+  grpc_channel* channel =
+      grpc_channel_create(target, &args, GRPC_CLIENT_LAME_CHANNEL, nullptr);
+  GRPC_ERROR_UNREF(error);
   return channel;
 }
diff --git a/grpc/src/core/lib/surface/lame_client.h b/grpc/src/core/lib/surface/lame_client.h
index 8fd3f4e..41759cb 100644
--- a/grpc/src/core/lib/surface/lame_client.h
+++ b/grpc/src/core/lib/surface/lame_client.h
@@ -23,10 +23,11 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-extern const grpc_channel_filter grpc_lame_filter;
-
 namespace grpc_core {
-void SetLameFilterError(grpc_channel_element* elem, grpc_error* error);
+// Does NOT take ownership of error.
+grpc_arg MakeLameClientErrorArg(grpc_error_handle error);
 }  // namespace grpc_core
 
+extern const grpc_channel_filter grpc_lame_filter;
+
 #endif /* GRPC_CORE_LIB_SURFACE_LAME_CLIENT_H */
diff --git a/grpc/src/core/lib/surface/server.cc b/grpc/src/core/lib/surface/server.cc
index 852c93d..a8b4aaa 100644
--- a/grpc/src/core/lib/surface/server.cc
+++ b/grpc/src/core/lib/surface/server.cc
@@ -159,7 +159,7 @@
   // Mark all application-requested RPCs failed if they have not been matched to
   // an incoming RPC. The error parameter indicates why the RPCs are being
   // failed (always server shutdown in all current implementations).
-  virtual void KillRequests(grpc_error* error) = 0;
+  virtual void KillRequests(grpc_error_handle error) = 0;
 
   // How many request queues are supported by this matcher. This is an abstract
   // concept that essentially maps to gRPC completion queues.
@@ -211,7 +211,7 @@
     }
   }
 
-  void KillRequests(grpc_error* error) override {
+  void KillRequests(grpc_error_handle error) override {
     for (size_t i = 0; i < requests_per_cq_.size(); i++) {
       RequestedCall* rc;
       while ((rc = reinterpret_cast<RequestedCall*>(
@@ -318,7 +318,8 @@
 // advance or queue up any incoming RPC for later match. Instead, MatchOrQueue
 // will call out to an allocation function passed in at the construction of the
 // object. These request matchers are designed for the C++ callback API, so they
-// only support 1 completion queue (passed in at the constructor).
+// only support 1 completion queue (passed in at the constructor). They are also
+// used for the sync API.
 class Server::AllocatingRequestMatcherBase : public RequestMatcherInterface {
  public:
   AllocatingRequestMatcherBase(Server* server, grpc_completion_queue* cq)
@@ -335,7 +336,9 @@
 
   void ZombifyPending() override {}
 
-  void KillRequests(grpc_error* error) override { GRPC_ERROR_UNREF(error); }
+  void KillRequests(grpc_error_handle error) override {
+    GRPC_ERROR_UNREF(error);
+  }
 
   size_t request_queue_count() const override { return 0; }
 
@@ -370,15 +373,20 @@
 
   void MatchOrQueue(size_t /*start_request_queue_index*/,
                     CallData* calld) override {
-    BatchCallAllocation call_info = allocator_();
-    GPR_ASSERT(server()->ValidateServerRequest(
-                   cq(), static_cast<void*>(call_info.tag), nullptr, nullptr) ==
-               GRPC_CALL_OK);
-    RequestedCall* rc = new RequestedCall(
-        static_cast<void*>(call_info.tag), cq(), call_info.call,
-        call_info.initial_metadata, call_info.details);
-    calld->SetState(CallData::CallState::ACTIVATED);
-    calld->Publish(cq_idx(), rc);
+    if (server()->ShutdownRefOnRequest()) {
+      BatchCallAllocation call_info = allocator_();
+      GPR_ASSERT(server()->ValidateServerRequest(
+                     cq(), static_cast<void*>(call_info.tag), nullptr,
+                     nullptr) == GRPC_CALL_OK);
+      RequestedCall* rc = new RequestedCall(
+          static_cast<void*>(call_info.tag), call_info.cq, call_info.call,
+          call_info.initial_metadata, call_info.details);
+      calld->SetState(CallData::CallState::ACTIVATED);
+      calld->Publish(cq_idx(), rc);
+    } else {
+      calld->FailCallCreation();
+    }
+    server()->ShutdownUnrefOnRequest();
   }
 
  private:
@@ -398,17 +406,21 @@
 
   void MatchOrQueue(size_t /*start_request_queue_index*/,
                     CallData* calld) override {
-    RegisteredCallAllocation call_info = allocator_();
-    GPR_ASSERT(
-        server()->ValidateServerRequest(cq(), static_cast<void*>(call_info.tag),
-                                        call_info.optional_payload,
-                                        registered_method_) == GRPC_CALL_OK);
-    RequestedCall* rc = new RequestedCall(
-        static_cast<void*>(call_info.tag), cq(), call_info.call,
-        call_info.initial_metadata, registered_method_, call_info.deadline,
-        call_info.optional_payload);
-    calld->SetState(CallData::CallState::ACTIVATED);
-    calld->Publish(cq_idx(), rc);
+    if (server()->ShutdownRefOnRequest()) {
+      RegisteredCallAllocation call_info = allocator_();
+      GPR_ASSERT(server()->ValidateServerRequest(
+                     cq(), call_info.tag, call_info.optional_payload,
+                     registered_method_) == GRPC_CALL_OK);
+      RequestedCall* rc =
+          new RequestedCall(call_info.tag, call_info.cq, call_info.call,
+                            call_info.initial_metadata, registered_method_,
+                            call_info.deadline, call_info.optional_payload);
+      calld->SetState(CallData::CallState::ACTIVATED);
+      calld->Publish(cq_idx(), rc);
+    } else {
+      calld->FailCallCreation();
+    }
+    server()->ShutdownUnrefOnRequest();
   }
 
  private:
@@ -434,7 +446,7 @@
   }
 
   // Broadcasts a shutdown on each channel.
-  void BroadcastShutdown(bool send_goaway, grpc_error* force_disconnect) {
+  void BroadcastShutdown(bool send_goaway, grpc_error_handle force_disconnect) {
     for (grpc_channel* channel : channels_) {
       SendShutdown(channel, send_goaway, GRPC_ERROR_REF(force_disconnect));
       GRPC_CHANNEL_INTERNAL_UNREF(channel, "broadcast");
@@ -449,14 +461,14 @@
     grpc_slice slice;
   };
 
-  static void ShutdownCleanup(void* arg, grpc_error* /*error*/) {
+  static void ShutdownCleanup(void* arg, grpc_error_handle /*error*/) {
     ShutdownCleanupArgs* a = static_cast<ShutdownCleanupArgs*>(arg);
     grpc_slice_unref_internal(a->slice);
     delete a;
   }
 
   static void SendShutdown(grpc_channel* channel, bool send_goaway,
-                           grpc_error* send_disconnect) {
+                           grpc_error_handle send_disconnect) {
     ShutdownCleanupArgs* sc = new ShutdownCleanupArgs;
     GRPC_CLOSURE_INIT(&sc->closure, ShutdownCleanup, sc,
                       grpc_schedule_on_exec_ctx);
@@ -513,7 +525,7 @@
 }
 
 RefCountedPtr<channelz::ServerNode> CreateChannelzNode(
-    Server* server, const grpc_channel_args* args) {
+    const grpc_channel_args* args) {
   RefCountedPtr<channelz::ServerNode> channelz_node;
   if (grpc_channel_args_find_bool(args, GRPC_ARG_ENABLE_CHANNELZ,
                                   GRPC_ENABLE_CHANNELZ_DEFAULT)) {
@@ -534,7 +546,7 @@
 Server::Server(const grpc_channel_args* args)
     : channel_args_(grpc_channel_args_copy(args)),
       default_resource_user_(CreateDefaultResourceUser(args)),
-      channelz_node_(CreateChannelzNode(this, args)) {}
+      channelz_node_(CreateChannelzNode(args)) {}
 
 Server::~Server() {
   grpc_channel_args_destroy(channel_args_);
@@ -597,13 +609,13 @@
   starting_cv_.Signal();
 }
 
-grpc_error* Server::SetupTransport(
+grpc_error_handle Server::SetupTransport(
     grpc_transport* transport, grpc_pollset* accepting_pollset,
     const grpc_channel_args* args,
     const RefCountedPtr<grpc_core::channelz::SocketNode>& socket_node,
     grpc_resource_user* resource_user) {
   // Create channel.
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_channel* channel = grpc_channel_create(
       nullptr, args, GRPC_SERVER_CHANNEL, transport, resource_user, &error);
   if (channel == nullptr) {
@@ -700,7 +712,8 @@
   delete static_cast<RequestedCall*>(req);
 }
 
-void Server::FailCall(size_t cq_idx, RequestedCall* rc, grpc_error* error) {
+void Server::FailCall(size_t cq_idx, RequestedCall* rc,
+                      grpc_error_handle error) {
   *rc->call = nullptr;
   rc->initial_metadata->count = 0;
   GPR_ASSERT(error != GRPC_ERROR_NONE);
@@ -711,7 +724,7 @@
 // Before calling MaybeFinishShutdown(), we must hold mu_global_ and not
 // hold mu_call_.
 void Server::MaybeFinishShutdown() {
-  if (!shutdown_flag_.load(std::memory_order_acquire) || shutdown_published_) {
+  if (!ShutdownReady() || shutdown_published_) {
     return;
   }
   {
@@ -740,7 +753,7 @@
   }
 }
 
-void Server::KillPendingWorkLocked(grpc_error* error) {
+void Server::KillPendingWorkLocked(grpc_error_handle error) {
   if (started_) {
     unregistered_request_matcher_->KillRequests(GRPC_ERROR_REF(error));
     unregistered_request_matcher_->ZombifyPending();
@@ -762,7 +775,7 @@
   return channels;
 }
 
-void Server::ListenerDestroyDone(void* arg, grpc_error* /*error*/) {
+void Server::ListenerDestroyDone(void* arg, grpc_error_handle /*error*/) {
   Server* server = static_cast<Server*>(arg);
   MutexLock lock(&server->mu_global_);
   server->listeners_destroyed_++;
@@ -796,7 +809,7 @@
   {
     // Wait for startup to be finished.  Locks mu_global.
     MutexLock lock(&mu_global_);
-    starting_cv_.WaitUntil(&mu_global_, [this] { return !starting_; });
+    WaitUntil(&starting_cv_, &mu_global_, [this] { return !starting_; });
     // Stay locked, and gather up some stuff to do.
     GPR_ASSERT(grpc_cq_begin_op(cq, tag));
     if (shutdown_published_) {
@@ -805,19 +818,18 @@
       return;
     }
     shutdown_tags_.emplace_back(tag, cq);
-    if (shutdown_flag_.load(std::memory_order_acquire)) {
+    if (ShutdownCalled()) {
       return;
     }
     last_shutdown_message_time_ = gpr_now(GPR_CLOCK_REALTIME);
     broadcaster.FillChannelsLocked(GetChannelsLocked());
-    shutdown_flag_.store(true, std::memory_order_release);
     // Collect all unregistered then registered calls.
     {
       MutexLock lock(&mu_call_);
       KillPendingWorkLocked(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown"));
     }
-    MaybeFinishShutdown();
+    ShutdownUnrefOnShutdownCall();
   }
   // Shutdown listeners.
   for (auto& listener : listeners_) {
@@ -849,8 +861,7 @@
 void Server::Orphan() {
   {
     MutexLock lock(&mu_global_);
-    GPR_ASSERT(shutdown_flag_.load(std::memory_order_acquire) ||
-               listeners_.empty());
+    GPR_ASSERT(ShutdownCalled() || listeners_.empty());
     GPR_ASSERT(listeners_destroyed_ == listeners_.size());
   }
   if (default_resource_user_ != nullptr) {
@@ -869,7 +880,7 @@
                            (rm->payload_handling == GRPC_SRM_PAYLOAD_NONE)))) {
     return GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH;
   }
-  if (grpc_cq_begin_op(cq_for_notification, tag) == false) {
+  if (!grpc_cq_begin_op(cq_for_notification, tag)) {
     return GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN;
   }
   return GRPC_CALL_OK;
@@ -897,7 +908,7 @@
 }
 
 grpc_call_error Server::QueueRequestedCall(size_t cq_idx, RequestedCall* rc) {
-  if (shutdown_flag_.load(std::memory_order_acquire)) {
+  if (ShutdownCalled()) {
     FailCall(cq_idx, rc,
              GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown"));
     return GRPC_CALL_OK;
@@ -1066,7 +1077,7 @@
   op->set_accept_stream_fn = AcceptStream;
   op->set_accept_stream_user_data = this;
   op->start_connectivity_watch = MakeOrphanable<ConnectivityWatcher>(this);
-  if (server_->shutdown_flag_.load(std::memory_order_acquire)) {
+  if (server_->ShutdownCalled()) {
     op->disconnect_with_error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown");
   }
@@ -1126,7 +1137,7 @@
   args.add_initial_metadata_count = 0;
   args.send_deadline = GRPC_MILLIS_INF_FUTURE;
   grpc_call* call;
-  grpc_error* error = grpc_call_create(&args, &call);
+  grpc_error_handle error = grpc_call_create(&args, &call);
   grpc_call_element* elem =
       grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
   auto* calld = static_cast<Server::CallData*>(elem->call_data);
@@ -1138,7 +1149,8 @@
   calld->Start(elem);
 }
 
-void Server::ChannelData::FinishDestroy(void* arg, grpc_error* /*error*/) {
+void Server::ChannelData::FinishDestroy(void* arg,
+                                        grpc_error_handle /*error*/) {
   auto* chand = static_cast<Server::ChannelData*>(arg);
   Server* server = chand->server_.get();
   GRPC_CHANNEL_INTERNAL_UNREF(chand->channel_, "server");
@@ -1165,7 +1177,7 @@
       op);
 }
 
-grpc_error* Server::ChannelData::InitChannelElement(
+grpc_error_handle Server::ChannelData::InitChannelElement(
     grpc_channel_element* elem, grpc_channel_element_args* args) {
   GPR_ASSERT(args->is_first);
   GPR_ASSERT(!args->is_last);
@@ -1276,14 +1288,13 @@
                  rc, &rc->completion, true);
 }
 
-void Server::CallData::PublishNewRpc(void* arg, grpc_error* error) {
+void Server::CallData::PublishNewRpc(void* arg, grpc_error_handle error) {
   grpc_call_element* call_elem = static_cast<grpc_call_element*>(arg);
   auto* calld = static_cast<Server::CallData*>(call_elem->call_data);
   auto* chand = static_cast<Server::ChannelData*>(call_elem->channel_data);
   RequestMatcherInterface* rm = calld->matcher_;
   Server* server = rm->server();
-  if (error != GRPC_ERROR_NONE ||
-      server->shutdown_flag_.load(std::memory_order_acquire)) {
+  if (error != GRPC_ERROR_NONE || server->ShutdownCalled()) {
     calld->state_.Store(CallState::ZOMBIED, MemoryOrder::RELAXED);
     calld->KillZombie();
     return;
@@ -1293,7 +1304,7 @@
 
 namespace {
 
-void KillZombieClosure(void* call, grpc_error* /*error*/) {
+void KillZombieClosure(void* call, grpc_error_handle /*error*/) {
   grpc_call_unref(static_cast<grpc_call*>(call));
 }
 
@@ -1307,7 +1318,7 @@
 
 void Server::CallData::StartNewRpc(grpc_call_element* elem) {
   auto* chand = static_cast<ChannelData*>(elem->channel_data);
-  if (server_->shutdown_flag_.load(std::memory_order_acquire)) {
+  if (server_->ShutdownCalled()) {
     state_.Store(CallState::ZOMBIED, MemoryOrder::RELAXED);
     KillZombie();
     return;
@@ -1345,8 +1356,8 @@
   }
 }
 
-void Server::CallData::RecvInitialMetadataBatchComplete(void* arg,
-                                                        grpc_error* error) {
+void Server::CallData::RecvInitialMetadataBatchComplete(
+    void* arg, grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   auto* calld = static_cast<Server::CallData*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
@@ -1378,7 +1389,8 @@
   grpc_call_next_op(elem, batch);
 }
 
-void Server::CallData::RecvInitialMetadataReady(void* arg, grpc_error* error) {
+void Server::CallData::RecvInitialMetadataReady(void* arg,
+                                                grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   grpc_millis op_deadline;
@@ -1404,7 +1416,7 @@
     /* do nothing */
   } else {
     /* Pass the error reference to calld->recv_initial_metadata_error */
-    grpc_error* src_error = error;
+    grpc_error_handle src_error = error;
     error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
         "Missing :authority or :path", &src_error, 1);
     GRPC_ERROR_UNREF(src_error);
@@ -1421,7 +1433,8 @@
   Closure::Run(DEBUG_LOCATION, closure, error);
 }
 
-void Server::CallData::RecvTrailingMetadataReady(void* arg, grpc_error* error) {
+void Server::CallData::RecvTrailingMetadataReady(void* arg,
+                                                 grpc_error_handle error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   CallData* calld = static_cast<CallData*>(elem->call_data);
   if (calld->original_recv_initial_metadata_ready_ != nullptr) {
@@ -1442,7 +1455,7 @@
                error);
 }
 
-grpc_error* Server::CallData::InitCallElement(
+grpc_error_handle Server::CallData::InitCallElement(
     grpc_call_element* elem, const grpc_call_element_args* args) {
   auto* chand = static_cast<ChannelData*>(elem->channel_data);
   new (elem->call_data) Server::CallData(elem, *args, chand->server());
diff --git a/grpc/src/core/lib/surface/server.h b/grpc/src/core/lib/surface/server.h
index 06bdd4d..413a5a8 100644
--- a/grpc/src/core/lib/surface/server.h
+++ b/grpc/src/core/lib/surface/server.h
@@ -22,6 +22,7 @@
 #include <list>
 #include <vector>
 
+#include "absl/status/statusor.h"
 #include "absl/types/optional.h"
 
 #include <grpc/grpc.h>
@@ -31,6 +32,7 @@
 #include "src/core/lib/channel/channelz.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/atomic.h"
+#include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/surface/completion_queue.h"
 #include "src/core/lib/transport/transport.h"
 
@@ -49,21 +51,23 @@
   // An object to represent the most relevant characteristics of a
   // newly-allocated call object when using an AllocatingRequestMatcherBatch.
   struct BatchCallAllocation {
-    grpc_experimental_completion_queue_functor* tag;
+    void* tag;
     grpc_call** call;
     grpc_metadata_array* initial_metadata;
     grpc_call_details* details;
+    grpc_completion_queue* cq;
   };
 
   // An object to represent the most relevant characteristics of a
   // newly-allocated call object when using an
   // AllocatingRequestMatcherRegistered.
   struct RegisteredCallAllocation {
-    grpc_experimental_completion_queue_functor* tag;
+    void* tag;
     grpc_call** call;
     grpc_metadata_array* initial_metadata;
     gpr_timespec* deadline;
     grpc_byte_buffer** optional_payload;
+    grpc_completion_queue* cq;
   };
 
   /// Interface for listeners.
@@ -90,7 +94,7 @@
   explicit Server(const grpc_channel_args* args);
   ~Server() override;
 
-  void Orphan() override;
+  void Orphan() ABSL_LOCKS_EXCLUDED(mu_global_) override;
 
   const grpc_channel_args* channel_args() const { return channel_args_; }
   grpc_resource_user* default_resource_user() const {
@@ -112,7 +116,7 @@
     config_fetcher_ = std::move(config_fetcher);
   }
 
-  bool HasOpenConnections();
+  bool HasOpenConnections() ABSL_LOCKS_EXCLUDED(mu_global_);
 
   // Adds a listener to the server.  When the server starts, it will call
   // the listener's Start() method, and when it shuts down, it will orphan
@@ -120,11 +124,11 @@
   void AddListener(OrphanablePtr<ListenerInterface> listener);
 
   // Starts listening for connections.
-  void Start();
+  void Start() ABSL_LOCKS_EXCLUDED(mu_global_);
 
   // Sets up a transport.  Creates a channel stack and binds the transport to
   // the server.  Called from the listener when a new connection is accepted.
-  grpc_error* SetupTransport(
+  grpc_error_handle SetupTransport(
       grpc_transport* transport, grpc_pollset* accepting_pollset,
       const grpc_channel_args* args,
       const RefCountedPtr<channelz::SocketNode>& socket_node,
@@ -158,9 +162,10 @@
       grpc_completion_queue* cq_bound_to_call,
       grpc_completion_queue* cq_for_notification, void* tag_new);
 
-  void ShutdownAndNotify(grpc_completion_queue* cq, void* tag);
+  void ShutdownAndNotify(grpc_completion_queue* cq, void* tag)
+      ABSL_LOCKS_EXCLUDED(mu_global_, mu_call_);
 
-  void CancelAllCalls();
+  void CancelAllCalls() ABSL_LOCKS_EXCLUDED(mu_global_);
 
  private:
   struct RequestedCall;
@@ -197,8 +202,8 @@
                                                  bool is_idempotent);
 
     // Filter vtable functions.
-    static grpc_error* InitChannelElement(grpc_channel_element* elem,
-                                          grpc_channel_element_args* args);
+    static grpc_error_handle InitChannelElement(
+        grpc_channel_element* elem, grpc_channel_element_args* args);
     static void DestroyChannelElement(grpc_channel_element* elem);
 
    private:
@@ -207,9 +212,9 @@
     static void AcceptStream(void* arg, grpc_transport* /*transport*/,
                              const void* transport_server_data);
 
-    void Destroy();
+    void Destroy() ABSL_EXCLUSIVE_LOCKS_REQUIRED(server_->mu_global_);
 
-    static void FinishDestroy(void* arg, grpc_error* error);
+    static void FinishDestroy(void* arg, grpc_error_handle error);
 
     RefCountedPtr<Server> server_;
     grpc_channel* channel_;
@@ -259,8 +264,8 @@
     void FailCallCreation();
 
     // Filter vtable functions.
-    static grpc_error* InitCallElement(grpc_call_element* elem,
-                                       const grpc_call_element_args* args);
+    static grpc_error_handle InitCallElement(
+        grpc_call_element* elem, const grpc_call_element_args* args);
     static void DestroyCallElement(grpc_call_element* elem,
                                    const grpc_call_final_info* /*final_info*/,
                                    grpc_closure* /*ignored*/);
@@ -269,15 +274,16 @@
 
    private:
     // Helper functions for handling calls at the top of the call stack.
-    static void RecvInitialMetadataBatchComplete(void* arg, grpc_error* error);
+    static void RecvInitialMetadataBatchComplete(void* arg,
+                                                 grpc_error_handle error);
     void StartNewRpc(grpc_call_element* elem);
-    static void PublishNewRpc(void* arg, grpc_error* error);
+    static void PublishNewRpc(void* arg, grpc_error_handle error);
 
     // Functions used inside the call stack.
     void StartTransportStreamOpBatchImpl(grpc_call_element* elem,
                                          grpc_transport_stream_op_batch* batch);
-    static void RecvInitialMetadataReady(void* arg, grpc_error* error);
-    static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
+    static void RecvInitialMetadataReady(void* arg, grpc_error_handle error);
+    static void RecvTrailingMetadataReady(void* arg, grpc_error_handle error);
 
     RefCountedPtr<Server> server_;
 
@@ -304,12 +310,12 @@
     uint32_t recv_initial_metadata_flags_ = 0;
     grpc_closure recv_initial_metadata_ready_;
     grpc_closure* original_recv_initial_metadata_ready_;
-    grpc_error* recv_initial_metadata_error_ = GRPC_ERROR_NONE;
+    grpc_error_handle recv_initial_metadata_error_ = GRPC_ERROR_NONE;
 
     bool seen_recv_trailing_metadata_ready_ = false;
     grpc_closure recv_trailing_metadata_ready_;
     grpc_closure* original_recv_trailing_metadata_ready_;
-    grpc_error* recv_trailing_metadata_error_ = GRPC_ERROR_NONE;
+    grpc_error_handle recv_trailing_metadata_error_ = GRPC_ERROR_NONE;
 
     grpc_closure publish_;
 
@@ -331,7 +337,7 @@
     grpc_cq_completion completion;
   };
 
-  static void ListenerDestroyDone(void* arg, grpc_error* error);
+  static void ListenerDestroyDone(void* arg, grpc_error_handle error);
 
   static void DoneShutdownEvent(void* server,
                                 grpc_cq_completion* /*completion*/) {
@@ -340,12 +346,14 @@
 
   static void DoneRequestEvent(void* req, grpc_cq_completion* completion);
 
-  void FailCall(size_t cq_idx, RequestedCall* rc, grpc_error* error);
+  void FailCall(size_t cq_idx, RequestedCall* rc, grpc_error_handle error);
   grpc_call_error QueueRequestedCall(size_t cq_idx, RequestedCall* rc);
 
-  void MaybeFinishShutdown();
+  void MaybeFinishShutdown() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_global_)
+      ABSL_LOCKS_EXCLUDED(mu_call_);
 
-  void KillPendingWorkLocked(grpc_error* error);
+  void KillPendingWorkLocked(grpc_error_handle error)
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_call_);
 
   static grpc_call_error ValidateServerRequest(
       grpc_completion_queue* cq_for_notification, void* tag,
@@ -356,6 +364,39 @@
 
   std::vector<grpc_channel*> GetChannelsLocked() const;
 
+  // Take a shutdown ref for a request (increment by 2) and return if shutdown
+  // has already been called.
+  bool ShutdownRefOnRequest() {
+    int old_value = shutdown_refs_.FetchAdd(2, MemoryOrder::ACQ_REL);
+    return (old_value & 1) != 0;
+  }
+
+  // Decrement the shutdown ref counter by either 1 (for shutdown call) or 2
+  // (for in-flight request) and possibly call MaybeFinishShutdown if
+  // appropriate.
+  void ShutdownUnrefOnRequest() ABSL_LOCKS_EXCLUDED(mu_global_) {
+    if (shutdown_refs_.FetchSub(2, MemoryOrder::ACQ_REL) == 2) {
+      MutexLock lock(&mu_global_);
+      MaybeFinishShutdown();
+    }
+  }
+  void ShutdownUnrefOnShutdownCall() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_global_) {
+    if (shutdown_refs_.FetchSub(1, MemoryOrder::ACQ_REL) == 1) {
+      MaybeFinishShutdown();
+    }
+  }
+
+  bool ShutdownCalled() const {
+    return (shutdown_refs_.Load(MemoryOrder::ACQUIRE) & 1) == 0;
+  }
+
+  // Returns whether there are no more shutdown refs, which means that shutdown
+  // has been called and all accepted requests have been published if using an
+  // AllocatingRequestMatcher.
+  bool ShutdownReady() const {
+    return shutdown_refs_.Load(MemoryOrder::ACQUIRE) == 0;
+  }
+
   grpc_channel_args* const channel_args_;
   grpc_resource_user* default_resource_user_ = nullptr;
   RefCountedPtr<channelz::ServerNode> channelz_node_;
@@ -385,9 +426,15 @@
   // Request matcher for unregistered methods.
   std::unique_ptr<RequestMatcherInterface> unregistered_request_matcher_;
 
-  std::atomic_bool shutdown_flag_{false};
-  bool shutdown_published_ = false;
-  std::vector<ShutdownTag> shutdown_tags_;
+  // The shutdown refs counter tracks whether or not shutdown has been called
+  // and whether there are any AllocatingRequestMatcher requests that have been
+  // accepted but not yet started (+2 on each one). If shutdown has been called,
+  // the lowest bit will be 0 (defaults to 1) and the counter will be even. The
+  // server should not notify on shutdown until the counter is 0 (shutdown is
+  // called and there are no requests that are accepted but not started).
+  Atomic<int> shutdown_refs_{1};
+  bool shutdown_published_ ABSL_GUARDED_BY(mu_global_) = false;
+  std::vector<ShutdownTag> shutdown_tags_ ABSL_GUARDED_BY(mu_global_);
 
   std::list<ChannelData*> channels_;
 
@@ -412,15 +459,31 @@
 // approaches here.
 struct grpc_server_config_fetcher {
  public:
+  class ConnectionManager : public grpc_core::RefCounted<ConnectionManager> {
+   public:
+    // Ownership of \a args is transfered.
+    virtual absl::StatusOr<grpc_channel_args*> UpdateChannelArgsForConnection(
+        grpc_channel_args* args, grpc_endpoint* tcp) = 0;
+  };
+
   class WatcherInterface {
    public:
     virtual ~WatcherInterface() = default;
-    virtual void UpdateConfig(grpc_channel_args* args) = 0;
+    // UpdateConnectionManager() is invoked by the config fetcher when a new
+    // config is available. Implementations should update the connection manager
+    // and start serving if not already serving.
+    virtual void UpdateConnectionManager(
+        grpc_core::RefCountedPtr<ConnectionManager> manager) = 0;
+    // Implementations should stop serving when this is called. Serving should
+    // only resume when UpdateConfig() is invoked.
+    virtual void StopServing() = 0;
   };
 
   virtual ~grpc_server_config_fetcher() = default;
 
+  // Ownership of \a args is transferred.
   virtual void StartWatch(std::string listening_address,
+                          grpc_channel_args* args,
                           std::unique_ptr<WatcherInterface> watcher) = 0;
   virtual void CancelWatch(WatcherInterface* watcher) = 0;
   virtual grpc_pollset_set* interested_parties() = 0;
diff --git a/grpc/src/core/lib/surface/validate_metadata.cc b/grpc/src/core/lib/surface/validate_metadata.cc
index 138f574..c1ec936 100644
--- a/grpc/src/core/lib/surface/validate_metadata.cc
+++ b/grpc/src/core/lib/surface/validate_metadata.cc
@@ -30,9 +30,9 @@
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/surface/validate_metadata.h"
 
-static grpc_error* conforms_to(const grpc_slice& slice,
-                               const uint8_t* legal_bits,
-                               const char* err_desc) {
+static grpc_error_handle conforms_to(const grpc_slice& slice,
+                                     const uint8_t* legal_bits,
+                                     const char* err_desc) {
   const uint8_t* p = GRPC_SLICE_START_PTR(slice);
   const uint8_t* e = GRPC_SLICE_END_PTR(slice);
   for (; p != e; p++) {
@@ -40,7 +40,7 @@
     int byte = idx / 8;
     int bit = idx % 8;
     if ((legal_bits[byte] & (1 << bit)) == 0) {
-      grpc_error* error = grpc_error_set_str(
+      grpc_error_handle error = grpc_error_set_str(
           grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_desc),
                              GRPC_ERROR_INT_OFFSET,
                              p - GRPC_SLICE_START_PTR(slice)),
@@ -52,13 +52,13 @@
   return GRPC_ERROR_NONE;
 }
 
-static int error2int(grpc_error* error) {
+static int error2int(grpc_error_handle error) {
   int r = (error == GRPC_ERROR_NONE);
   GRPC_ERROR_UNREF(error);
   return r;
 }
 
-grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice) {
+grpc_error_handle grpc_validate_header_key_is_legal(const grpc_slice& slice) {
   static const uint8_t legal_header_bits[256 / 8] = {
       0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00,
       0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -82,7 +82,7 @@
   return error2int(grpc_validate_header_key_is_legal(slice));
 }
 
-grpc_error* grpc_validate_header_nonbin_value_is_legal(
+grpc_error_handle grpc_validate_header_nonbin_value_is_legal(
     const grpc_slice& slice) {
   static const uint8_t legal_header_bits[256 / 8] = {
       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
diff --git a/grpc/src/core/lib/surface/validate_metadata.h b/grpc/src/core/lib/surface/validate_metadata.h
index 07c802c..daaaa1a 100644
--- a/grpc/src/core/lib/surface/validate_metadata.h
+++ b/grpc/src/core/lib/surface/validate_metadata.h
@@ -27,8 +27,9 @@
 
 #include "src/core/lib/iomgr/error.h"
 
-grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice);
-grpc_error* grpc_validate_header_nonbin_value_is_legal(const grpc_slice& slice);
+grpc_error_handle grpc_validate_header_key_is_legal(const grpc_slice& slice);
+grpc_error_handle grpc_validate_header_nonbin_value_is_legal(
+    const grpc_slice& slice);
 
 int grpc_is_binary_header_internal(const grpc_slice& slice);
 inline int grpc_key_is_binary_header(const uint8_t* buf, size_t length) {
diff --git a/grpc/src/core/lib/surface/version.cc b/grpc/src/core/lib/surface/version.cc
index 03cb2ec..8061df0 100644
--- a/grpc/src/core/lib/surface/version.cc
+++ b/grpc/src/core/lib/surface/version.cc
@@ -23,6 +23,8 @@
 
 #include <grpc/grpc.h>
 
-const char* grpc_version_string(void) { return "14.0.0"; }
+const char* grpc_version_string(void) { return "16.0.0"; }
 
-const char* grpc_g_stands_for(void) { return "gecko"; }
+const char* grpc_g_stands_for(void) {
+  return "guadalupe_river_park_conservancy";
+}
diff --git a/grpc/src/core/lib/transport/byte_stream.cc b/grpc/src/core/lib/transport/byte_stream.cc
index 82f34ca..3cc5275 100644
--- a/grpc/src/core/lib/transport/byte_stream.cc
+++ b/grpc/src/core/lib/transport/byte_stream.cc
@@ -59,7 +59,7 @@
   return true;
 }
 
-grpc_error* SliceBufferByteStream::Pull(grpc_slice* slice) {
+grpc_error_handle SliceBufferByteStream::Pull(grpc_slice* slice) {
   if (GPR_UNLIKELY(shutdown_error_ != GRPC_ERROR_NONE)) {
     return GRPC_ERROR_REF(shutdown_error_);
   }
@@ -67,7 +67,7 @@
   return GRPC_ERROR_NONE;
 }
 
-void SliceBufferByteStream::Shutdown(grpc_error* error) {
+void SliceBufferByteStream::Shutdown(grpc_error_handle error) {
   GRPC_ERROR_UNREF(shutdown_error_);
   shutdown_error_ = error;
 }
@@ -117,7 +117,7 @@
   return cache_->underlying_stream_->Next(max_size_hint, on_complete);
 }
 
-grpc_error* ByteStreamCache::CachingByteStream::Pull(grpc_slice* slice) {
+grpc_error_handle ByteStreamCache::CachingByteStream::Pull(grpc_slice* slice) {
   if (shutdown_error_ != GRPC_ERROR_NONE) {
     return GRPC_ERROR_REF(shutdown_error_);
   }
@@ -128,7 +128,7 @@
     return GRPC_ERROR_NONE;
   }
   GPR_ASSERT(cache_->underlying_stream_ != nullptr);
-  grpc_error* error = cache_->underlying_stream_->Pull(slice);
+  grpc_error_handle error = cache_->underlying_stream_->Pull(slice);
   if (error == GRPC_ERROR_NONE) {
     grpc_slice_buffer_add(&cache_->cache_buffer_,
                           grpc_slice_ref_internal(*slice));
@@ -142,7 +142,7 @@
   return error;
 }
 
-void ByteStreamCache::CachingByteStream::Shutdown(grpc_error* error) {
+void ByteStreamCache::CachingByteStream::Shutdown(grpc_error_handle error) {
   GRPC_ERROR_UNREF(shutdown_error_);
   shutdown_error_ = GRPC_ERROR_REF(error);
   if (cache_->underlying_stream_ != nullptr) {
diff --git a/grpc/src/core/lib/transport/byte_stream.h b/grpc/src/core/lib/transport/byte_stream.h
index e83fb62..09a3032 100644
--- a/grpc/src/core/lib/transport/byte_stream.h
+++ b/grpc/src/core/lib/transport/byte_stream.h
@@ -56,7 +56,7 @@
   // indicated by Next().
   //
   // Once a slice is returned into *slice, it is owned by the caller.
-  virtual grpc_error* Pull(grpc_slice* slice) = 0;
+  virtual grpc_error_handle Pull(grpc_slice* slice) = 0;
 
   // Shuts down the byte stream.
   //
@@ -65,7 +65,7 @@
   //
   // The next call to Pull() (if any) will return the error passed to
   // Shutdown().
-  virtual void Shutdown(grpc_error* error) = 0;
+  virtual void Shutdown(grpc_error_handle error) = 0;
 
   uint32_t length() const { return length_; }
   uint32_t flags() const { return flags_; }
@@ -97,11 +97,11 @@
   void Orphan() override;
 
   bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
-  grpc_error* Pull(grpc_slice* slice) override;
-  void Shutdown(grpc_error* error) override;
+  grpc_error_handle Pull(grpc_slice* slice) override;
+  void Shutdown(grpc_error_handle error) override;
 
  private:
-  grpc_error* shutdown_error_ = GRPC_ERROR_NONE;
+  grpc_error_handle shutdown_error_ = GRPC_ERROR_NONE;
   grpc_slice_buffer backing_buffer_;
 };
 
@@ -131,8 +131,8 @@
     void Orphan() override;
 
     bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
-    grpc_error* Pull(grpc_slice* slice) override;
-    void Shutdown(grpc_error* error) override;
+    grpc_error_handle Pull(grpc_slice* slice) override;
+    void Shutdown(grpc_error_handle error) override;
 
     // Resets the byte stream to the start of the underlying stream.
     void Reset();
@@ -141,7 +141,7 @@
     ByteStreamCache* cache_;
     size_t cursor_ = 0;
     size_t offset_ = 0;
-    grpc_error* shutdown_error_ = GRPC_ERROR_NONE;
+    grpc_error_handle shutdown_error_ = GRPC_ERROR_NONE;
   };
 
   explicit ByteStreamCache(OrphanablePtr<ByteStream> underlying_stream);
diff --git a/grpc/src/core/lib/transport/connectivity_state.cc b/grpc/src/core/lib/transport/connectivity_state.cc
index c2008ab..01a4f5c 100644
--- a/grpc/src/core/lib/transport/connectivity_state.cc
+++ b/grpc/src/core/lib/transport/connectivity_state.cc
@@ -73,7 +73,7 @@
   }
 
  private:
-  static void SendNotification(void* arg, grpc_error* /*ignored*/) {
+  static void SendNotification(void* arg, grpc_error_handle /*ignored*/) {
     Notifier* self = static_cast<Notifier*>(arg);
     if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) {
       gpr_log(GPR_INFO, "watcher %p: delivering async notification for %s (%s)",
diff --git a/grpc/src/core/lib/transport/error_utils.cc b/grpc/src/core/lib/transport/error_utils.cc
index c6ef8ae..e8f0555 100644
--- a/grpc/src/core/lib/transport/error_utils.cc
+++ b/grpc/src/core/lib/transport/error_utils.cc
@@ -25,8 +25,8 @@
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/status_conversion.h"
 
-static grpc_error* recursively_find_error_with_field(grpc_error* error,
-                                                     grpc_error_ints which) {
+static grpc_error_handle recursively_find_error_with_field(
+    grpc_error_handle error, grpc_error_ints which) {
   intptr_t unused;
   // If the error itself has a status code, return it.
   if (grpc_error_get_int(error, which, &unused)) {
@@ -38,14 +38,15 @@
   while (slot != UINT8_MAX) {
     grpc_linked_error* lerr =
         reinterpret_cast<grpc_linked_error*>(error->arena + slot);
-    grpc_error* result = recursively_find_error_with_field(lerr->err, which);
+    grpc_error_handle result =
+        recursively_find_error_with_field(lerr->err, which);
     if (result) return result;
     slot = lerr->next;
   }
   return nullptr;
 }
 
-void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
+void grpc_error_get_status(grpc_error_handle error, grpc_millis deadline,
                            grpc_status_code* code, grpc_slice* slice,
                            grpc_http2_error_code* http_error,
                            const char** error_string) {
@@ -71,7 +72,7 @@
 
   // Start with the parent error and recurse through the tree of children
   // until we find the first one that has a status code.
-  grpc_error* found_error =
+  grpc_error_handle found_error =
       recursively_find_error_with_field(error, GRPC_ERROR_INT_GRPC_STATUS);
   if (found_error == nullptr) {
     /// If no grpc-status exists, retry through the tree to find a http2 error
@@ -96,7 +97,7 @@
   if (code != nullptr) *code = status;
 
   if (error_string != nullptr && status != GRPC_STATUS_OK) {
-    *error_string = gpr_strdup(grpc_error_string(error));
+    *error_string = gpr_strdup(grpc_error_std_string(error).c_str());
   }
 
   if (http_error != nullptr) {
@@ -123,7 +124,7 @@
   }
 }
 
-absl::Status grpc_error_to_absl_status(grpc_error* error) {
+absl::Status grpc_error_to_absl_status(grpc_error_handle error) {
   grpc_status_code status;
   // TODO(yashykt): This should be updated once we decide on how to use the
   // absl::Status payload to capture all the contents of grpc_error.
@@ -136,7 +137,17 @@
                                         GRPC_SLICE_LENGTH(message)));
 }
 
-bool grpc_error_has_clear_grpc_status(grpc_error* error) {
+grpc_error_handle absl_status_to_grpc_error(absl::Status status) {
+  // Special error checks
+  if (status.ok()) {
+    return GRPC_ERROR_NONE;
+  }
+  return grpc_error_set_int(
+      GRPC_ERROR_CREATE_FROM_STRING_VIEW(status.message()),
+      GRPC_ERROR_INT_GRPC_STATUS, static_cast<grpc_status_code>(status.code()));
+}
+
+bool grpc_error_has_clear_grpc_status(grpc_error_handle error) {
   intptr_t unused;
   if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &unused)) {
     return true;
diff --git a/grpc/src/core/lib/transport/error_utils.h b/grpc/src/core/lib/transport/error_utils.h
index c61320d..777e632 100644
--- a/grpc/src/core/lib/transport/error_utils.h
+++ b/grpc/src/core/lib/transport/error_utils.h
@@ -34,19 +34,25 @@
 /// be populated with the entire error string. If any of the attributes (code,
 /// msg, http_status, error_string) are unneeded, they can be passed as
 /// NULL.
-void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
+void grpc_error_get_status(grpc_error_handle error, grpc_millis deadline,
                            grpc_status_code* code, grpc_slice* slice,
                            grpc_http2_error_code* http_error,
                            const char** error_string);
 
-/// Utility Function to convert a grpc_error * \a error to an absl::Status.
-/// Does NOT consume a ref to grpc_error.
-absl::Status grpc_error_to_absl_status(grpc_error* error);
+/// Utility Function to convert a grpc_error_handle  \a error to an
+/// absl::Status. Does NOT consume a ref to grpc_error.
+absl::Status grpc_error_to_absl_status(grpc_error_handle error);
+
+/// Utility function to convert an absl::Status \a status to grpc_error. Note
+/// that this method does not return "special case" errors such as
+/// GRPC_ERROR_CANCELLED, with the exception of GRPC_ERROR_NONE returned for
+/// \a absl::OkStatus().
+grpc_error_handle absl_status_to_grpc_error(absl::Status status);
 
 /// A utility function to check whether there is a clear status code that
 /// doesn't need to be guessed in \a error. This means that \a error or some
 /// child has GRPC_ERROR_INT_GRPC_STATUS set, or that it is GRPC_ERROR_NONE or
 /// GRPC_ERROR_CANCELLED
-bool grpc_error_has_clear_grpc_status(grpc_error* error);
+bool grpc_error_has_clear_grpc_status(grpc_error_handle error);
 
 #endif /* GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H */
diff --git a/grpc/src/core/lib/transport/metadata.cc b/grpc/src/core/lib/transport/metadata.cc
index 33d4d5a..ef1e07d 100644
--- a/grpc/src/core/lib/transport/metadata.cc
+++ b/grpc/src/core/lib/transport/metadata.cc
@@ -252,7 +252,7 @@
     if (shard->count != 0) {
       gpr_log(GPR_ERROR, "WARNING: %" PRIuPTR " metadata elements were leaked",
               shard->count);
-      for (int i = 0; i < shard->capacity; i++) {
+      for (size_t i = 0; i < shard->capacity; i++) {
         for (InternedMetadata* md = shard->elems[i].next; md;
              md = md->bucket_next()) {
           char* key_str = grpc_slice_to_c_string(md->key());
@@ -596,7 +596,7 @@
   grpc_core::ReleasableMutexLock lock(&ud->mu_user_data);
   if (ud->destroy_user_data.Load(grpc_core::MemoryOrder::RELAXED)) {
     /* user data can only be set once */
-    lock.Unlock();
+    lock.Release();
     if (destroy_func != nullptr) {
       destroy_func(data);
     }
@@ -673,6 +673,10 @@
 
 void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
                                 uint32_t hash DEBUG_ARGS) {
+#ifndef NDEBUG
+  (void)file;
+  (void)line;
+#endif
   switch (storage) {
     case GRPC_MDELEM_STORAGE_EXTERNAL:
     case GRPC_MDELEM_STORAGE_STATIC:
diff --git a/grpc/src/core/lib/transport/metadata_batch.cc b/grpc/src/core/lib/transport/metadata_batch.cc
index 66749b6..e85b476 100644
--- a/grpc/src/core/lib/transport/metadata_batch.cc
+++ b/grpc/src/core/lib/transport/metadata_batch.cc
@@ -23,6 +23,9 @@
 #include <stdbool.h>
 #include <string.h>
 
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/str_join.h"
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
@@ -91,22 +94,23 @@
   }
 }
 
-grpc_error* grpc_attach_md_to_error(grpc_error* src, grpc_mdelem md) {
-  grpc_error* out = grpc_error_set_str(
+grpc_error_handle grpc_attach_md_to_error(grpc_error_handle src,
+                                          grpc_mdelem md) {
+  grpc_error_handle out = grpc_error_set_str(
       grpc_error_set_str(src, GRPC_ERROR_STR_KEY,
                          grpc_slice_ref_internal(GRPC_MDKEY(md))),
       GRPC_ERROR_STR_VALUE, grpc_slice_ref_internal(GRPC_MDVALUE(md)));
   return out;
 }
 
-static grpc_error* GPR_ATTRIBUTE_NOINLINE error_with_md(grpc_mdelem md) {
+static grpc_error_handle GPR_ATTRIBUTE_NOINLINE error_with_md(grpc_mdelem md) {
   return grpc_attach_md_to_error(
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unallowed duplicate metadata"), md);
 }
 
-static grpc_error* link_callout(grpc_metadata_batch* batch,
-                                grpc_linked_mdelem* storage,
-                                grpc_metadata_batch_callouts_index idx) {
+static grpc_error_handle link_callout(grpc_metadata_batch* batch,
+                                      grpc_linked_mdelem* storage,
+                                      grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(idx >= 0 && idx < GRPC_BATCH_CALLOUTS_COUNT);
   if (GPR_LIKELY(batch->idx.array[idx] == nullptr)) {
     ++batch->list.default_count;
@@ -116,12 +120,12 @@
   return error_with_md(storage->md);
 }
 
-static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
-                                      grpc_linked_mdelem* storage)
+static grpc_error_handle maybe_link_callout(grpc_metadata_batch* batch,
+                                            grpc_linked_mdelem* storage)
     GRPC_MUST_USE_RESULT;
 
-static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
-                                      grpc_linked_mdelem* storage) {
+static grpc_error_handle maybe_link_callout(grpc_metadata_batch* batch,
+                                            grpc_linked_mdelem* storage) {
   grpc_metadata_batch_callouts_index idx =
       GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md));
   if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
@@ -142,9 +146,9 @@
   batch->idx.array[idx] = nullptr;
 }
 
-grpc_error* grpc_metadata_batch_add_head(grpc_metadata_batch* batch,
-                                         grpc_linked_mdelem* storage,
-                                         grpc_mdelem elem_to_add) {
+grpc_error_handle grpc_metadata_batch_add_head(grpc_metadata_batch* batch,
+                                               grpc_linked_mdelem* storage,
+                                               grpc_mdelem elem_to_add) {
   GPR_DEBUG_ASSERT(!GRPC_MDISNULL(elem_to_add));
   storage->md = elem_to_add;
   return grpc_metadata_batch_link_head(batch, storage);
@@ -166,10 +170,10 @@
   assert_valid_list(list);
 }
 
-grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
-                                          grpc_linked_mdelem* storage) {
+grpc_error_handle grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
+                                                grpc_linked_mdelem* storage) {
   assert_valid_callouts(batch);
-  grpc_error* err = maybe_link_callout(batch, storage);
+  grpc_error_handle err = maybe_link_callout(batch, storage);
   if (err != GRPC_ERROR_NONE) {
     assert_valid_callouts(batch);
     return err;
@@ -182,12 +186,12 @@
 // TODO(arjunroy): Need to revisit this and see what guarantees exist between
 // C-core and the internal-metadata subsystem. E.g. can we ensure a particular
 // metadata is never added twice, even in the presence of user supplied data?
-grpc_error* grpc_metadata_batch_link_head(
+grpc_error_handle grpc_metadata_batch_link_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md)) == idx);
   assert_valid_callouts(batch);
-  grpc_error* err = link_callout(batch, storage, idx);
+  grpc_error_handle err = link_callout(batch, storage, idx);
   if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) {
     assert_valid_callouts(batch);
     return err;
@@ -197,9 +201,9 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_metadata_batch_add_tail(grpc_metadata_batch* batch,
-                                         grpc_linked_mdelem* storage,
-                                         grpc_mdelem elem_to_add) {
+grpc_error_handle grpc_metadata_batch_add_tail(grpc_metadata_batch* batch,
+                                               grpc_linked_mdelem* storage,
+                                               grpc_mdelem elem_to_add) {
   GPR_DEBUG_ASSERT(!GRPC_MDISNULL(elem_to_add));
   storage->md = elem_to_add;
   return grpc_metadata_batch_link_tail(batch, storage);
@@ -221,10 +225,10 @@
   assert_valid_list(list);
 }
 
-grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
-                                          grpc_linked_mdelem* storage) {
+grpc_error_handle grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
+                                                grpc_linked_mdelem* storage) {
   assert_valid_callouts(batch);
-  grpc_error* err = maybe_link_callout(batch, storage);
+  grpc_error_handle err = maybe_link_callout(batch, storage);
   if (err != GRPC_ERROR_NONE) {
     assert_valid_callouts(batch);
     return err;
@@ -234,12 +238,12 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_metadata_batch_link_tail(
+grpc_error_handle grpc_metadata_batch_link_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(GRPC_BATCH_INDEX_OF(GRPC_MDKEY(storage->md)) == idx);
   assert_valid_callouts(batch);
-  grpc_error* err = link_callout(batch, storage, idx);
+  grpc_error_handle err = link_callout(batch, storage, idx);
   if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) {
     assert_valid_callouts(batch);
     return err;
@@ -296,11 +300,35 @@
   GRPC_MDELEM_UNREF(old_mdelem);
 }
 
-grpc_error* grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
-                                           grpc_linked_mdelem* storage,
-                                           grpc_mdelem new_mdelem) {
+absl::optional<absl::string_view> grpc_metadata_batch_get_value(
+    grpc_metadata_batch* batch, absl::string_view target_key,
+    std::string* concatenated_value) {
+  // Find all values for the specified key.
+  GPR_DEBUG_ASSERT(batch != nullptr);
+  absl::InlinedVector<absl::string_view, 1> values;
+  for (grpc_linked_mdelem* md = batch->list.head; md != nullptr;
+       md = md->next) {
+    absl::string_view key = grpc_core::StringViewFromSlice(GRPC_MDKEY(md->md));
+    absl::string_view value =
+        grpc_core::StringViewFromSlice(GRPC_MDVALUE(md->md));
+    if (target_key == key) values.push_back(value);
+  }
+  // If none found, no match.
+  if (values.empty()) return absl::nullopt;
+  // If exactly one found, return it as-is.
+  if (values.size() == 1) return values.front();
+  // If more than one found, concatenate the values, using
+  // *concatenated_values as a temporary holding place for the
+  // concatenated string.
+  *concatenated_value = absl::StrJoin(values, ",");
+  return *concatenated_value;
+}
+
+grpc_error_handle grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
+                                                 grpc_linked_mdelem* storage,
+                                                 grpc_mdelem new_mdelem) {
   assert_valid_callouts(batch);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_mdelem old_mdelem = storage->md;
   if (!grpc_slice_eq(GRPC_MDKEY(new_mdelem), GRPC_MDKEY(old_mdelem))) {
     maybe_unlink_callout(batch, storage);
@@ -337,7 +365,7 @@
   return size;
 }
 
-static void add_error(grpc_error** composite, grpc_error* error,
+static void add_error(grpc_error_handle* composite, grpc_error_handle error,
                       const char* composite_error_string) {
   if (error == GRPC_ERROR_NONE) return;
   if (*composite == GRPC_ERROR_NONE) {
@@ -346,12 +374,11 @@
   *composite = grpc_error_add_child(*composite, error);
 }
 
-grpc_error* grpc_metadata_batch_filter(grpc_metadata_batch* batch,
-                                       grpc_metadata_batch_filter_func func,
-                                       void* user_data,
-                                       const char* composite_error_string) {
+grpc_error_handle grpc_metadata_batch_filter(
+    grpc_metadata_batch* batch, grpc_metadata_batch_filter_func func,
+    void* user_data, const char* composite_error_string) {
   grpc_linked_mdelem* l = batch->list.head;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   while (l) {
     grpc_linked_mdelem* next = l->next;
     grpc_filtered_mdelem new_mdelem = func(user_data, l->md);
@@ -375,7 +402,7 @@
   for (grpc_linked_mdelem* elem = src->list.head; elem != nullptr;
        elem = elem->next) {
     // Error unused in non-debug builds.
-    grpc_error* GRPC_UNUSED error = grpc_metadata_batch_add_tail(
+    grpc_error_handle GRPC_UNUSED error = grpc_metadata_batch_add_tail(
         dst, &storage[i++], GRPC_MDELEM_REF(elem->md));
     // The only way that grpc_metadata_batch_add_tail() can fail is if
     // there's a duplicate entry for a callout.  However, that can't be
diff --git a/grpc/src/core/lib/transport/metadata_batch.h b/grpc/src/core/lib/transport/metadata_batch.h
index 69864c1..b72859f 100644
--- a/grpc/src/core/lib/transport/metadata_batch.h
+++ b/grpc/src/core/lib/transport/metadata_batch.h
@@ -23,9 +23,12 @@
 
 #include <stdbool.h>
 
+#include "absl/types/optional.h"
+
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
 #include <grpc/support/time.h>
+
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/static_metadata.h"
@@ -71,22 +74,33 @@
                                 grpc_metadata_batch_callouts_index idx);
 
 /** Substitute a new mdelem for an old value */
-grpc_error* grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
-                                           grpc_linked_mdelem* storage,
-                                           grpc_mdelem new_mdelem);
+grpc_error_handle grpc_metadata_batch_substitute(grpc_metadata_batch* batch,
+                                                 grpc_linked_mdelem* storage,
+                                                 grpc_mdelem new_mdelem);
 
 void grpc_metadata_batch_set_value(grpc_linked_mdelem* storage,
                                    const grpc_slice& value);
 
+/** Returns metadata value(s) for the specified key.
+    If the key is not present in the batch, returns absl::nullopt.
+    If the key is present exactly once in the batch, returns a string_view of
+    that value.
+    If the key is present more than once in the batch, constructs a
+    comma-concatenated string of all values in concatenated_value and returns a
+    string_view of that string. */
+absl::optional<absl::string_view> grpc_metadata_batch_get_value(
+    grpc_metadata_batch* batch, absl::string_view target_key,
+    std::string* concatenated_value);
+
 /** Add \a storage to the beginning of \a batch. storage->md is
     assumed to be valid.
     \a storage is owned by the caller and must survive for the
     lifetime of batch. This usually means it should be around
     for the lifetime of the call. */
-grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
-                                          grpc_linked_mdelem* storage)
+grpc_error_handle grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
+                                                grpc_linked_mdelem* storage)
     GRPC_MUST_USE_RESULT;
-grpc_error* grpc_metadata_batch_link_head(
+grpc_error_handle grpc_metadata_batch_link_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) GRPC_MUST_USE_RESULT;
 
@@ -95,10 +109,10 @@
     \a storage is owned by the caller and must survive for the
     lifetime of batch. This usually means it should be around
     for the lifetime of the call. */
-grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
-                                          grpc_linked_mdelem* storage)
+grpc_error_handle grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
+                                                grpc_linked_mdelem* storage)
     GRPC_MUST_USE_RESULT;
-grpc_error* grpc_metadata_batch_link_tail(
+grpc_error_handle grpc_metadata_batch_link_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) GRPC_MUST_USE_RESULT;
 
@@ -108,19 +122,19 @@
     lifetime of batch. This usually means it should be around
     for the lifetime of the call.
     Takes ownership of \a elem_to_add */
-grpc_error* grpc_metadata_batch_add_head(
+grpc_error_handle grpc_metadata_batch_add_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
 
 // TODO(arjunroy, roth): Remove redundant methods.
 // add/link_head/tail are almost identical.
-inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
+inline grpc_error_handle GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) {
   return grpc_metadata_batch_link_head(batch, storage, idx);
 }
 
-inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
+inline grpc_error_handle GRPC_MUST_USE_RESULT grpc_metadata_batch_add_head(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_mdelem elem_to_add, grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(!GRPC_MDISNULL(elem_to_add));
@@ -134,17 +148,17 @@
     lifetime of batch. This usually means it should be around
     for the lifetime of the call.
     Takes ownership of \a elem_to_add */
-grpc_error* grpc_metadata_batch_add_tail(
+grpc_error_handle grpc_metadata_batch_add_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
 
-inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
+inline grpc_error_handle GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_metadata_batch_callouts_index idx) {
   return grpc_metadata_batch_link_tail(batch, storage, idx);
 }
 
-inline grpc_error* GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
+inline grpc_error_handle GRPC_MUST_USE_RESULT grpc_metadata_batch_add_tail(
     grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
     grpc_mdelem elem_to_add, grpc_metadata_batch_callouts_index idx) {
   GPR_DEBUG_ASSERT(!GRPC_MDISNULL(elem_to_add));
@@ -152,10 +166,11 @@
   return grpc_metadata_batch_add_tail(batch, storage, idx);
 }
 
-grpc_error* grpc_attach_md_to_error(grpc_error* src, grpc_mdelem md);
+grpc_error_handle grpc_attach_md_to_error(grpc_error_handle src,
+                                          grpc_mdelem md);
 
 struct grpc_filtered_mdelem {
-  grpc_error* error;
+  grpc_error_handle error;
   grpc_mdelem md;
 };
 #define GRPC_FILTERED_ERROR(error) \
@@ -167,7 +182,7 @@
 
 typedef grpc_filtered_mdelem (*grpc_metadata_batch_filter_func)(
     void* user_data, grpc_mdelem elem);
-grpc_error* grpc_metadata_batch_filter(
+grpc_error_handle grpc_metadata_batch_filter(
     grpc_metadata_batch* batch, grpc_metadata_batch_filter_func func,
     void* user_data, const char* composite_error_string) GRPC_MUST_USE_RESULT;
 
diff --git a/grpc/src/core/lib/transport/transport.cc b/grpc/src/core/lib/transport/transport.cc
index dccab66..36060a6 100644
--- a/grpc/src/core/lib/transport/transport.cc
+++ b/grpc/src/core/lib/transport/transport.cc
@@ -177,7 +177,7 @@
 // though it lives in lib, it handles transport stream ops sure
 // it's grpc_transport_stream_op_batch_finish_with_failure
 void grpc_transport_stream_op_batch_finish_with_failure(
-    grpc_transport_stream_op_batch* batch, grpc_error* error,
+    grpc_transport_stream_op_batch* batch, grpc_error_handle error,
     grpc_core::CallCombiner* call_combiner) {
   if (batch->send_message) {
     batch->payload->send_message.send_message.reset();
@@ -219,7 +219,7 @@
   }
 };
 
-static void destroy_made_transport_op(void* arg, grpc_error* error) {
+static void destroy_made_transport_op(void* arg, grpc_error_handle error) {
   made_transport_op* op = static_cast<made_transport_op*>(arg);
   grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->inner_on_complete,
                           GRPC_ERROR_REF(error));
@@ -241,7 +241,8 @@
   grpc_transport_stream_op_batch op;
   grpc_transport_stream_op_batch_payload payload;
 };
-static void destroy_made_transport_stream_op(void* arg, grpc_error* error) {
+static void destroy_made_transport_stream_op(void* arg,
+                                             grpc_error_handle error) {
   made_transport_stream_op* op = static_cast<made_transport_stream_op*>(arg);
   grpc_closure* c = op->inner_on_complete;
   gpr_free(op);
diff --git a/grpc/src/core/lib/transport/transport.h b/grpc/src/core/lib/transport/transport.h
index 4076048..7372b38 100644
--- a/grpc/src/core/lib/transport/transport.h
+++ b/grpc/src/core/lib/transport/transport.h
@@ -319,7 +319,7 @@
   struct {
     // Error contract: the transport that gets this op must cause cancel_error
     //                 to be unref'ed after processing it
-    grpc_error* cancel_error = GRPC_ERROR_NONE;
+    grpc_error_handle cancel_error = GRPC_ERROR_NONE;
   } cancel_stream;
 
   /* Indexes correspond to grpc_context_index enum values */
@@ -339,11 +339,11 @@
   /** should the transport be disconnected
    * Error contract: the transport that gets this op must cause
    *                 disconnect_with_error to be unref'ed after processing it */
-  grpc_error* disconnect_with_error = nullptr;
+  grpc_error_handle disconnect_with_error = GRPC_ERROR_NONE;
   /** what should the goaway contain?
    * Error contract: the transport that gets this op must cause
    *                 goaway_error to be unref'ed after processing it */
-  grpc_error* goaway_error = nullptr;
+  grpc_error_handle goaway_error = GRPC_ERROR_NONE;
   /** set the callback for accepting new streams;
       this is a permanent callback, unlike the other one-shot closures.
       If true, the callback is set to set_accept_stream_fn, with its
@@ -411,7 +411,7 @@
                                    grpc_closure* then_schedule_closure);
 
 void grpc_transport_stream_op_batch_finish_with_failure(
-    grpc_transport_stream_op_batch* batch, grpc_error* error,
+    grpc_transport_stream_op_batch* batch, grpc_error_handle error,
     grpc_core::CallCombiner* call_combiner);
 
 std::string grpc_transport_stream_op_batch_string(
diff --git a/grpc/src/core/lib/transport/transport_op_string.cc b/grpc/src/core/lib/transport/transport_op_string.cc
index 722a64e..49dec38 100644
--- a/grpc/src/core/lib/transport/transport_op_string.cc
+++ b/grpc/src/core/lib/transport/transport_op_string.cc
@@ -109,7 +109,7 @@
   if (op->cancel_stream) {
     out.push_back(absl::StrCat(
         " CANCEL:",
-        grpc_error_string(op->payload->cancel_stream.cancel_error)));
+        grpc_error_std_string(op->payload->cancel_stream.cancel_error)));
   }
 
   return absl::StrJoin(out, "");
@@ -131,13 +131,13 @@
   }
 
   if (op->disconnect_with_error != GRPC_ERROR_NONE) {
-    out.push_back(absl::StrCat(" DISCONNECT:",
-                               grpc_error_string(op->disconnect_with_error)));
+    out.push_back(absl::StrCat(
+        " DISCONNECT:", grpc_error_std_string(op->disconnect_with_error)));
   }
 
   if (op->goaway_error) {
-    out.push_back(
-        absl::StrCat(" SEND_GOAWAY:%s", grpc_error_string(op->goaway_error)));
+    out.push_back(absl::StrCat(" SEND_GOAWAY:%s",
+                               grpc_error_std_string(op->goaway_error)));
   }
 
   if (op->set_accept_stream) {
diff --git a/grpc/src/core/plugin_registry/grpc_plugin_registry.cc b/grpc/src/core/plugin_registry/grpc_plugin_registry.cc
index ae3993a..d3def27 100644
--- a/grpc/src/core/plugin_registry/grpc_plugin_registry.cc
+++ b/grpc/src/core/plugin_registry/grpc_plugin_registry.cc
@@ -60,6 +60,10 @@
 void grpc_client_authority_filter_shutdown(void);
 void grpc_workaround_cronet_compression_filter_init(void);
 void grpc_workaround_cronet_compression_filter_shutdown(void);
+namespace grpc_core {
+void FaultInjectionFilterInit(void);
+void FaultInjectionFilterShutdown(void);
+}  // namespace grpc_core
 
 #ifndef GRPC_NO_XDS
 namespace grpc_core {
@@ -82,6 +86,10 @@
 void grpc_lb_policy_xds_cluster_manager_shutdown(void);
 void grpc_resolver_xds_init(void);
 void grpc_resolver_xds_shutdown(void);
+namespace grpc_core {
+void GoogleCloud2ProdResolverInit();
+void GoogleCloud2ProdResolverShutdown();
+}
 #endif
 
 void grpc_register_built_in_plugins(void) {
@@ -119,6 +127,8 @@
                        grpc_max_age_filter_shutdown);
   grpc_register_plugin(grpc_message_size_filter_init,
                        grpc_message_size_filter_shutdown);
+  grpc_register_plugin(grpc_core::FaultInjectionFilterInit,
+                       grpc_core::FaultInjectionFilterShutdown);
   grpc_register_plugin(grpc_service_config_channel_arg_filter_init,
                        grpc_service_config_channel_arg_filter_shutdown);
   grpc_register_plugin(grpc_client_authority_filter_init,
@@ -142,5 +152,7 @@
                        grpc_lb_policy_xds_cluster_manager_shutdown);
   grpc_register_plugin(grpc_resolver_xds_init,
                        grpc_resolver_xds_shutdown);
+  grpc_register_plugin(grpc_core::GoogleCloud2ProdResolverInit,
+                       grpc_core::GoogleCloud2ProdResolverShutdown);
 #endif
 }
diff --git a/grpc/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc b/grpc/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
index fd9bf9c..5e74529 100644
--- a/grpc/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
+++ b/grpc/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
@@ -54,6 +54,10 @@
 void grpc_max_age_filter_shutdown(void);
 void grpc_message_size_filter_init(void);
 void grpc_message_size_filter_shutdown(void);
+namespace grpc_core {
+void FaultInjectionFilterInit(void);
+void FaultInjectionFilterShutdown(void);
+}  // namespace grpc_core
 void grpc_service_config_channel_arg_filter_init(void);
 void grpc_service_config_channel_arg_filter_shutdown(void);
 void grpc_client_authority_filter_init(void);
@@ -96,6 +100,8 @@
                        grpc_max_age_filter_shutdown);
   grpc_register_plugin(grpc_message_size_filter_init,
                        grpc_message_size_filter_shutdown);
+  grpc_register_plugin(grpc_core::FaultInjectionFilterInit,
+                       grpc_core::FaultInjectionFilterShutdown);
   grpc_register_plugin(grpc_service_config_channel_arg_filter_init,
                        grpc_service_config_channel_arg_filter_shutdown);
   grpc_register_plugin(grpc_client_authority_filter_init,
diff --git a/grpc/src/core/tsi/alts/crypt/gsec.h b/grpc/src/core/tsi/alts/crypt/gsec.h
index 4d65caa..c330ca6 100644
--- a/grpc/src/core/tsi/alts/crypt/gsec.h
+++ b/grpc/src/core/tsi/alts/crypt/gsec.h
@@ -21,16 +21,20 @@
 
 #include <grpc/support/port_platform.h>
 
+#include <grpc/event_engine/port.h>
+
 #include <assert.h>
 #include <stdint.h>
 #include <stdlib.h>
 
 #include <grpc/grpc.h>
 
+#ifndef GRPC_EVENT_ENGINE_POSIX
 struct iovec {
   void* iov_base;
   size_t iov_len;
 };
+#endif  // GRPC_EVENT_ENGINE_POSIX
 
 /**
  * A gsec interface for AEAD encryption schemes. The API is thread-compatible.
diff --git a/grpc/src/core/tsi/alts/handshaker/alts_handshaker_client.cc b/grpc/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
index 845b23f..ed70d81 100644
--- a/grpc/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
+++ b/grpc/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
@@ -69,9 +69,9 @@
   grpc_closure on_handshaker_service_resp_recv;
   /* Buffers containing information to be sent (or received) to (or from) the
    * handshaker service. */
-  grpc_byte_buffer* send_buffer;
-  grpc_byte_buffer* recv_buffer;
-  grpc_status_code status;
+  grpc_byte_buffer* send_buffer = nullptr;
+  grpc_byte_buffer* recv_buffer = nullptr;
+  grpc_status_code status = GRPC_STATUS_OK;
   /* Initial metadata to be received from handshaker service. */
   grpc_metadata_array recv_initial_metadata;
   /* A callback function provided by an application to be invoked when response
@@ -95,15 +95,15 @@
   /** callback for receiving handshake call status */
   grpc_closure on_status_received;
   /** gRPC status code of handshake call */
-  grpc_status_code handshake_status_code;
+  grpc_status_code handshake_status_code = GRPC_STATUS_OK;
   /** gRPC status details of handshake call */
   grpc_slice handshake_status_details;
   /* mu synchronizes all fields below including their internal fields. */
-  gpr_mu mu;
+  grpc_core::Mutex mu;
   /* indicates if the handshaker call's RECV_STATUS_ON_CLIENT op is done. */
-  bool receive_status_finished;
+  bool receive_status_finished = false;
   /* if non-null, contains arguments to complete a TSI next callback. */
-  recv_message_result* pending_recv_message_result;
+  recv_message_result* pending_recv_message_result = nullptr;
   /* Maximum frame size used by frame protector. */
   size_t max_frame_size;
 } alts_grpc_handshaker_client;
@@ -117,10 +117,7 @@
 
 static bool is_handshake_finished_properly(grpc_gcp_HandshakerResp* resp) {
   GPR_ASSERT(resp != nullptr);
-  if (grpc_gcp_HandshakerResp_result(resp)) {
-    return true;
-  }
-  return false;
+  return grpc_gcp_HandshakerResp_result(resp) != nullptr;
 }
 
 static void alts_grpc_handshaker_client_unref(
@@ -140,8 +137,7 @@
     grpc_alts_credentials_options_destroy(client->options);
     gpr_free(client->buffer);
     grpc_slice_unref_internal(client->handshake_status_details);
-    gpr_mu_destroy(&client->mu);
-    gpr_free(client);
+    delete client;
   }
 }
 
@@ -443,7 +439,7 @@
   }
 }
 
-static void on_status_received(void* arg, grpc_error* error) {
+static void on_status_received(void* arg, grpc_error_handle error) {
   alts_grpc_handshaker_client* client =
       static_cast<alts_grpc_handshaker_client*>(arg);
   if (client->handshake_status_code != GRPC_STATUS_OK) {
@@ -455,7 +451,7 @@
             "alts_grpc_handshaker_client:%p on_status_received "
             "status:%d details:|%s| error:|%s|",
             client, client->handshake_status_code, status_details,
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     gpr_free(status_details);
   }
   maybe_complete_tsi_next(client, true /* receive_status_finished */,
@@ -646,7 +642,7 @@
   }
 }
 
-static void handshaker_call_unref(void* arg, grpc_error* /* error */) {
+static void handshaker_call_unref(void* arg, grpc_error_handle /* error */) {
   grpc_call* call = static_cast<grpc_call*>(arg);
   grpc_call_unref(call);
 }
@@ -695,24 +691,24 @@
     gpr_log(GPR_ERROR, "Invalid arguments to alts_handshaker_client_create()");
     return nullptr;
   }
-  alts_grpc_handshaker_client* client =
-      static_cast<alts_grpc_handshaker_client*>(gpr_zalloc(sizeof(*client)));
-  gpr_mu_init(&client->mu);
+  alts_grpc_handshaker_client* client = new alts_grpc_handshaker_client();
+  memset(&client->base, 0, sizeof(client->base));
+  client->base.vtable =
+      vtable_for_testing == nullptr ? &vtable : vtable_for_testing;
   gpr_ref_init(&client->refs, 1);
-  client->grpc_caller = grpc_call_start_batch_and_execute;
   client->handshaker = handshaker;
+  client->grpc_caller = grpc_call_start_batch_and_execute;
+  grpc_metadata_array_init(&client->recv_initial_metadata);
   client->cb = cb;
   client->user_data = user_data;
-  client->send_buffer = nullptr;
-  client->recv_buffer = nullptr;
   client->options = grpc_alts_credentials_options_copy(options);
   client->target_name = grpc_slice_copy(target_name);
-  client->recv_bytes = grpc_empty_slice();
-  grpc_metadata_array_init(&client->recv_initial_metadata);
   client->is_client = is_client;
-  client->max_frame_size = max_frame_size;
+  client->recv_bytes = grpc_empty_slice();
   client->buffer_size = TSI_ALTS_INITIAL_BUFFER_SIZE;
   client->buffer = static_cast<unsigned char*>(gpr_zalloc(client->buffer_size));
+  client->handshake_status_details = grpc_empty_slice();
+  client->max_frame_size = max_frame_size;
   grpc_slice slice = grpc_slice_from_copied_string(handshaker_service_url);
   client->call =
       strcmp(handshaker_service_url, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING) ==
@@ -722,8 +718,6 @@
                 channel, nullptr, GRPC_PROPAGATE_DEFAULTS, interested_parties,
                 grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice,
                 GRPC_MILLIS_INF_FUTURE, nullptr);
-  client->base.vtable =
-      vtable_for_testing == nullptr ? &vtable : vtable_for_testing;
   GRPC_CLOSURE_INIT(&client->on_handshaker_service_resp_recv, grpc_cb, client,
                     grpc_schedule_on_exec_ctx);
   GRPC_CLOSURE_INIT(&client->on_status_received, on_status_received, client,
@@ -844,7 +838,8 @@
 }
 
 void alts_handshaker_client_on_status_received_for_testing(
-    alts_handshaker_client* c, grpc_status_code status, grpc_error* error) {
+    alts_handshaker_client* c, grpc_status_code status,
+    grpc_error_handle error) {
   // We first make sure that the handshake queue has been initialized
   // here because there are tests that use this API that mock out
   // other parts of the alts_handshaker_client in such a way that the
diff --git a/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc b/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
index 19f41fe..9cca8ab 100644
--- a/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
+++ b/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
@@ -48,23 +48,23 @@
   tsi_handshaker base;
   grpc_slice target_name;
   bool is_client;
-  bool has_sent_start_message;
-  bool has_created_handshaker_client;
+  bool has_sent_start_message = false;
+  bool has_created_handshaker_client = false;
   char* handshaker_service_url;
   grpc_pollset_set* interested_parties;
   grpc_alts_credentials_options* options;
-  alts_handshaker_client_vtable* client_vtable_for_testing;
-  grpc_channel* channel;
+  alts_handshaker_client_vtable* client_vtable_for_testing = nullptr;
+  grpc_channel* channel = nullptr;
   bool use_dedicated_cq;
   // mu synchronizes all fields below. Note these are the
   // only fields that can be concurrently accessed (due to
   // potential concurrency of tsi_handshaker_shutdown and
   // tsi_handshaker_next).
-  gpr_mu mu;
-  alts_handshaker_client* client;
+  grpc_core::Mutex mu;
+  alts_handshaker_client* client = nullptr;
   // shutdown effectively follows base.handshake_shutdown,
   // but is synchronized by the mutex of this object.
-  bool shutdown;
+  bool shutdown = false;
   // Maximum frame size used by frame protector.
   size_t max_frame_size;
 };
@@ -372,7 +372,8 @@
 }
 
 /* gRPC provided callback used when gRPC thread model is applied. */
-static void on_handshaker_service_resp_recv(void* arg, grpc_error* error) {
+static void on_handshaker_service_resp_recv(void* arg,
+                                            grpc_error_handle error) {
   alts_handshaker_client* client = static_cast<alts_handshaker_client*>(arg);
   if (client == nullptr) {
     gpr_log(GPR_ERROR, "ALTS handshaker client is nullptr");
@@ -382,7 +383,7 @@
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR,
             "ALTS handshaker on_handshaker_service_resp_recv error: %s",
-            grpc_error_string(error));
+            grpc_error_std_string(error).c_str());
     success = false;
   }
   alts_handshaker_client_handle_response(client, success);
@@ -390,8 +391,8 @@
 
 /* gRPC provided callback used when dedicatd CQ and thread are used.
  * It serves to safely bring the control back to application. */
-static void on_handshaker_service_resp_recv_dedicated(void* arg,
-                                                      grpc_error* /*error*/) {
+static void on_handshaker_service_resp_recv_dedicated(
+    void* arg, grpc_error_handle /*error*/) {
   alts_shared_resource_dedicated* resource =
       grpc_alts_get_shared_resource_dedicated();
   grpc_cq_end_op(
@@ -480,8 +481,8 @@
   grpc_closure closure;
 };
 
-static void alts_tsi_handshaker_create_channel(void* arg,
-                                               grpc_error* /* unused_error */) {
+static void alts_tsi_handshaker_create_channel(
+    void* arg, grpc_error_handle /* unused_error */) {
   alts_tsi_handshaker_continue_handshaker_next_args* next_args =
       static_cast<alts_tsi_handshaker_continue_handshaker_next_args*>(arg);
   alts_tsi_handshaker* handshaker = next_args->handshaker;
@@ -592,8 +593,7 @@
     grpc_channel_destroy_internal(handshaker->channel);
   }
   gpr_free(handshaker->handshaker_service_url);
-  gpr_mu_destroy(&handshaker->mu);
-  gpr_free(handshaker);
+  delete handshaker;
 }
 
 static const tsi_handshaker_vtable handshaker_vtable = {
@@ -628,26 +628,22 @@
     gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()");
     return TSI_INVALID_ARGUMENT;
   }
-  alts_tsi_handshaker* handshaker =
-      static_cast<alts_tsi_handshaker*>(gpr_zalloc(sizeof(*handshaker)));
-  gpr_mu_init(&handshaker->mu);
-  handshaker->use_dedicated_cq = interested_parties == nullptr;
-  handshaker->client = nullptr;
-  handshaker->is_client = is_client;
-  handshaker->has_sent_start_message = false;
+  bool use_dedicated_cq = interested_parties == nullptr;
+  alts_tsi_handshaker* handshaker = new alts_tsi_handshaker();
+  memset(&handshaker->base, 0, sizeof(handshaker->base));
+  handshaker->base.vtable =
+      use_dedicated_cq ? &handshaker_vtable_dedicated : &handshaker_vtable;
   handshaker->target_name = target_name == nullptr
                                 ? grpc_empty_slice()
                                 : grpc_slice_from_static_string(target_name);
-  handshaker->interested_parties = interested_parties;
-  handshaker->has_created_handshaker_client = false;
+  handshaker->is_client = is_client;
   handshaker->handshaker_service_url = gpr_strdup(handshaker_service_url);
+  handshaker->interested_parties = interested_parties;
   handshaker->options = grpc_alts_credentials_options_copy(options);
+  handshaker->use_dedicated_cq = use_dedicated_cq;
   handshaker->max_frame_size = user_specified_max_frame_size != 0
                                    ? user_specified_max_frame_size
                                    : kTsiAltsMaxFrameSize;
-  handshaker->base.vtable = handshaker->use_dedicated_cq
-                                ? &handshaker_vtable_dedicated
-                                : &handshaker_vtable;
   *self = &handshaker->base;
   return TSI_OK;
 }
diff --git a/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h b/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
index e1ae985..1c3605a 100644
--- a/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
+++ b/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
@@ -41,7 +41,7 @@
 // Frame size negotiation extends send frame size range to
 // [kTsiAltsMinFrameSize, kTsiAltsMaxFrameSize].
 const size_t kTsiAltsMinFrameSize = 16 * 1024;
-const size_t kTsiAltsMaxFrameSize = 128 * 1024;
+const size_t kTsiAltsMaxFrameSize = 1024 * 1024;
 
 typedef struct alts_tsi_handshaker alts_tsi_handshaker;
 
diff --git a/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h b/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
index cb99fdc..d5ab14d 100644
--- a/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
+++ b/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
@@ -78,7 +78,8 @@
     alts_handshaker_client* client);
 
 void alts_handshaker_client_on_status_received_for_testing(
-    alts_handshaker_client* client, grpc_status_code status, grpc_error* error);
+    alts_handshaker_client* client, grpc_status_code status,
+    grpc_error_handle error);
 
 void alts_handshaker_client_ref_for_testing(alts_handshaker_client* c);
 
diff --git a/grpc/src/core/tsi/alts/handshaker/transport_security_common_api.cc b/grpc/src/core/tsi/alts/handshaker/transport_security_common_api.cc
index a0462b2..402bf13 100644
--- a/grpc/src/core/tsi/alts/handshaker/transport_security_common_api.cc
+++ b/grpc/src/core/tsi/alts/handshaker/transport_security_common_api.cc
@@ -214,9 +214,7 @@
           ? &local_versions->min_rpc_version
           : &peer_versions->min_rpc_version;
   bool result = grpc_core::internal::grpc_gcp_rpc_protocol_version_compare(
-                    max_common_version, min_common_version) >= 0
-                    ? true
-                    : false;
+                    max_common_version, min_common_version) >= 0;
   if (result && highest_common_version != nullptr) {
     memcpy(highest_common_version, max_common_version,
            sizeof(grpc_gcp_rpc_protocol_versions_version));
diff --git a/grpc/src/core/tsi/fake_transport_security.cc b/grpc/src/core/tsi/fake_transport_security.cc
index 0b256a1..5e63f11 100644
--- a/grpc/src/core/tsi/fake_transport_security.cc
+++ b/grpc/src/core/tsi/fake_transport_security.cc
@@ -474,12 +474,21 @@
   gpr_free(impl);
 }
 
+static tsi_result fake_zero_copy_grpc_protector_max_frame_size(
+    tsi_zero_copy_grpc_protector* self, size_t* max_frame_size) {
+  if (self == nullptr || max_frame_size == nullptr) return TSI_INVALID_ARGUMENT;
+  tsi_fake_zero_copy_grpc_protector* impl =
+      reinterpret_cast<tsi_fake_zero_copy_grpc_protector*>(self);
+  *max_frame_size = impl->max_frame_size;
+  return TSI_OK;
+}
+
 static const tsi_zero_copy_grpc_protector_vtable
     zero_copy_grpc_protector_vtable = {
         fake_zero_copy_grpc_protector_protect,
         fake_zero_copy_grpc_protector_unprotect,
         fake_zero_copy_grpc_protector_destroy,
-        nullptr /* fake_zero_copy_grpc_protector_max_frame_size */
+        fake_zero_copy_grpc_protector_max_frame_size,
 };
 
 /* --- tsi_handshaker_result methods implementation. ---*/
@@ -490,7 +499,7 @@
   size_t unused_bytes_size;
 };
 static tsi_result fake_handshaker_result_extract_peer(
-    const tsi_handshaker_result* self, tsi_peer* peer) {
+    const tsi_handshaker_result* /*self*/, tsi_peer* peer) {
   /* Construct a tsi_peer with 1 property: certificate type, security_level. */
   tsi_result result = tsi_construct_peer(2, peer);
   if (result != TSI_OK) return result;
diff --git a/grpc/src/core/tsi/ssl/session_cache/ssl_session.h b/grpc/src/core/tsi/ssl/session_cache/ssl_session.h
index 69a91ad..108c0cd 100644
--- a/grpc/src/core/tsi/ssl/session_cache/ssl_session.h
+++ b/grpc/src/core/tsi/ssl/session_cache/ssl_session.h
@@ -23,12 +23,9 @@
 
 #include <grpc/slice.h>
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmodule-import-in-extern-c"
 extern "C" {
 #include <openssl/ssl.h>
 }
-#pragma clang diagnostic pop
 
 #include "src/core/lib/gprpp/ref_counted.h"
 
diff --git a/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc b/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc
index 6da4fb4..9254dce 100644
--- a/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc
+++ b/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc
@@ -84,7 +84,6 @@
 
 SslSessionLRUCache::SslSessionLRUCache(size_t capacity) : capacity_(capacity) {
   GPR_ASSERT(capacity > 0);
-  gpr_mu_init(&lock_);
   entry_by_key_ = grpc_avl_create(&cache_avl_vtable);
 }
 
@@ -96,7 +95,6 @@
     node = next;
   }
   grpc_avl_unref(entry_by_key_, nullptr);
-  gpr_mu_destroy(&lock_);
 }
 
 size_t SslSessionLRUCache::Size() {
diff --git a/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.h b/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.h
index fcdc8b6..0aa3f16 100644
--- a/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.h
+++ b/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.h
@@ -24,16 +24,14 @@
 #include <grpc/slice.h>
 #include <grpc/support/sync.h>
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmodule-import-in-extern-c"
 extern "C" {
 #include <openssl/ssl.h>
 }
-#pragma clang diagnostic pop
 
 #include "src/core/lib/avl/avl.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/sync.h"
 #include "src/core/tsi/ssl/session_cache/ssl_session.h"
 
 /// Cache for SSL sessions for sessions resumption.
@@ -79,7 +77,7 @@
   void PushFront(Node* node);
   void AssertInvariants();
 
-  gpr_mu lock_;
+  grpc_core::Mutex lock_;
   size_t capacity_;
 
   Node* use_order_list_head_ = nullptr;
diff --git a/grpc/src/core/tsi/ssl_transport_security.cc b/grpc/src/core/tsi/ssl_transport_security.cc
index 7f8749c..4241b6f 100644
--- a/grpc/src/core/tsi/ssl_transport_security.cc
+++ b/grpc/src/core/tsi/ssl_transport_security.cc
@@ -45,8 +45,6 @@
 #include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmodule-import-in-extern-c"
 extern "C" {
 #include <openssl/bio.h>
 #include <openssl/crypto.h> /* For OPENSSL_free */
@@ -57,7 +55,6 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 }
-#pragma clang diagnostic pop
 
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
@@ -360,13 +357,17 @@
         subject_alt_name->type == GEN_URI) {
       unsigned char* name = nullptr;
       int name_size;
+      std::string property_name;
       if (subject_alt_name->type == GEN_DNS) {
         name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
+        property_name = TSI_X509_DNS_PEER_PROPERTY;
       } else if (subject_alt_name->type == GEN_EMAIL) {
         name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.rfc822Name);
+        property_name = TSI_X509_EMAIL_PEER_PROPERTY;
       } else {
         name_size = ASN1_STRING_to_UTF8(
             &name, subject_alt_name->d.uniformResourceIdentifier);
+        property_name = TSI_X509_URI_PEER_PROPERTY;
       }
       if (name_size < 0) {
         gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
@@ -381,12 +382,10 @@
         OPENSSL_free(name);
         break;
       }
-      if (subject_alt_name->type == GEN_URI) {
-        result = tsi_construct_string_peer_property(
-            TSI_X509_URI_PEER_PROPERTY, reinterpret_cast<const char*>(name),
-            static_cast<size_t>(name_size),
-            &peer->properties[(*current_insert_index)++]);
-      }
+      result = tsi_construct_string_peer_property(
+          property_name.c_str(), reinterpret_cast<const char*>(name),
+          static_cast<size_t>(name_size),
+          &peer->properties[(*current_insert_index)++]);
       OPENSSL_free(name);
     } else if (subject_alt_name->type == GEN_IPADD) {
       char ntop_buf[INET6_ADDRSTRLEN];
@@ -412,6 +411,10 @@
       result = tsi_construct_string_peer_property_from_cstring(
           TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
           &peer->properties[(*current_insert_index)++]);
+      if (result != TSI_OK) break;
+      result = tsi_construct_string_peer_property_from_cstring(
+          TSI_X509_IP_PEER_PROPERTY, name,
+          &peer->properties[(*current_insert_index)++]);
     } else {
       result = tsi_construct_string_peer_property_from_cstring(
           TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, "other types of SAN",
@@ -441,7 +444,14 @@
   for (int i = 0; i < subject_alt_name_count; i++) {
     GENERAL_NAME* subject_alt_name =
         sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
-    if (subject_alt_name->type == GEN_URI) {
+    // TODO(zhenlian): Clean up tsi_peer to avoid duplicate entries.
+    // URI, DNS, email and ip address SAN fields are plumbed to tsi_peer, in
+    // addition to all SAN fields (results in duplicate values). This code
+    // snippet updates property_count accordingly.
+    if (subject_alt_name->type == GEN_URI ||
+        subject_alt_name->type == GEN_DNS ||
+        subject_alt_name->type == GEN_EMAIL ||
+        subject_alt_name->type == GEN_IPADD) {
       property_count += 1;
     }
   }
@@ -1914,14 +1924,16 @@
 #else
   ssl_context = SSL_CTX_new(TLSv1_2_method());
 #endif
-  result = tsi_set_min_and_max_tls_versions(
-      ssl_context, options->min_tls_version, options->max_tls_version);
-  if (result != TSI_OK) return result;
   if (ssl_context == nullptr) {
+    log_ssl_error_stack();
     gpr_log(GPR_ERROR, "Could not create ssl context.");
     return TSI_INVALID_ARGUMENT;
   }
 
+  result = tsi_set_min_and_max_tls_versions(
+      ssl_context, options->min_tls_version, options->max_tls_version);
+  if (result != TSI_OK) return result;
+
   impl = static_cast<tsi_ssl_client_handshaker_factory*>(
       gpr_zalloc(sizeof(*impl)));
   tsi_ssl_handshaker_factory_init(&impl->base);
@@ -2081,15 +2093,18 @@
 #else
       impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
 #endif
-      result = tsi_set_min_and_max_tls_versions(impl->ssl_contexts[i],
-                                                options->min_tls_version,
-                                                options->max_tls_version);
-      if (result != TSI_OK) return result;
       if (impl->ssl_contexts[i] == nullptr) {
+        log_ssl_error_stack();
         gpr_log(GPR_ERROR, "Could not create ssl context.");
         result = TSI_OUT_OF_RESOURCES;
         break;
       }
+
+      result = tsi_set_min_and_max_tls_versions(impl->ssl_contexts[i],
+                                                options->min_tls_version,
+                                                options->max_tls_version);
+      if (result != TSI_OK) return result;
+
       result = populate_ssl_context(impl->ssl_contexts[i],
                                     &options->pem_key_cert_pairs[i],
                                     options->cipher_suites);
diff --git a/grpc/src/core/tsi/ssl_transport_security.h b/grpc/src/core/tsi/ssl_transport_security.h
index f25e067..c3d30a8 100644
--- a/grpc/src/core/tsi/ssl_transport_security.h
+++ b/grpc/src/core/tsi/ssl_transport_security.h
@@ -25,12 +25,9 @@
 #include "absl/strings/string_view.h"
 #include "src/core/tsi/transport_security_interface.h"
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmodule-import-in-extern-c"
 extern "C" {
 #include <openssl/x509.h>
 }
-#pragma clang diagnostic pop
 
 /* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */
 #define TSI_X509_CERTIFICATE_TYPE "X509"
@@ -40,14 +37,13 @@
 #define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \
   "x509_subject_alternative_name"
 #define TSI_SSL_SESSION_REUSED_PEER_PROPERTY "ssl_session_reused"
-
 #define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert"
-
 #define TSI_X509_PEM_CERT_CHAIN_PROPERTY "x509_pem_cert_chain"
-
 #define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
-
+#define TSI_X509_DNS_PEER_PROPERTY "x509_dns"
 #define TSI_X509_URI_PEER_PROPERTY "x509_uri"
+#define TSI_X509_EMAIL_PEER_PROPERTY "x509_email"
+#define TSI_X509_IP_PEER_PROPERTY "x509_ip"
 
 /* --- tsi_ssl_root_certs_store object ---
 
diff --git a/grpc/src/core/tsi/test_creds/multi-domain-openssl.cnf b/grpc/src/core/tsi/test_creds/multi-domain-openssl.cnf
index 265950f..33ecc9d 100644
--- a/grpc/src/core/tsi/test_creds/multi-domain-openssl.cnf
+++ b/grpc/src/core/tsi/test_creds/multi-domain-openssl.cnf
@@ -28,3 +28,6 @@
 URI.3 = spiffe://foo.com/bar/baz
 email.1 = foo@test.domain.com
 email.2 = bar@test.domain.com
+IP.1 = 192.168.7.1
+IP.2 = 13::17
+RID.1 = 1.2.3.4
diff --git a/grpc/src/core/tsi/test_creds/multi-domain.key b/grpc/src/core/tsi/test_creds/multi-domain.key
index b5789e9..2b9cce0 100644
--- a/grpc/src/core/tsi/test_creds/multi-domain.key
+++ b/grpc/src/core/tsi/test_creds/multi-domain.key
@@ -1,28 +1,28 @@
 -----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCuGVBYD3P/D2eT
-nhBhZ0izP+nuozNCEO/iQu/kyy6ZCzIEFvykt0aPzJVLcsCHCaWcNJVFPSqVDVRm
-9S5ZHUyLlnSl53mKUltZI4tDDVMcEdr7KpfXeBc86lm/93DqFDgAYDkvebekRr/8
-B1OJhVJRGowXjAU9sYABzuUqjkra522BleIik3m+7DborGHS4Io5X/8D8VjlXjeB
-Vht6QA8ij5JVfHvO6DsZr99EITPpha6i182O6S6lO2t1V+bdWP+EPjiOQJktrmvM
-QYTFjmjYkRKLCZI1xxSfCK8t7ia5sLPFOF6uDH91ck8mXmuHs96nSOyB1i/LdBy9
-XdInSRGXAgMBAAECggEAWoqZqSJoPfah9DhY5n8TZP1RSKUhTDOIvc/3+LHeSwNy
-gIP/4h3amYBZCELmc5QFx8Xk93xG//tNsLnD396H53RYt8s4/0GzdhkxHK76UPfM
-PaE6FHnFBA4QnPAvjdzz/uYL92/CnLGauJSK0lM+qyU2RCyysRH1s3sI3Wfg8BRd
-C9Xik+YzYirhCEGlYKju2D2As/tB2L0b/PRpM9FWeqd/YGCj8pUpceNrbvU8udc7
-4xQS6ssgMI2H1xGc50kJVDjoZix5OLiTaHDO4oRBZT+QdPTtfkam0/y2yZ9oX6UN
-Byl+ybtUpxsmsvl+I7bb/fZsILrXE3GHXtcsCMi5iQKBgQDmKi1HfmQo6KeDSnjp
-R+yIMc77QpZpLuzjPlKWGxY915KlL77GOUYR2cm0rPP9CPGN2Nj5IyuR32u6uHtI
-WKewR7cn69prxZI3VSNFQmsatWKBoR7dwyJ4j93cN54naEuBLA1BJQ0uXgYJtgwT
-x5KP97LcudpoDNVsh+FUopon8wKBgQDBpBMeDoc+7YVLnlx4FRJudzVfWWb4bPCL
-2cusycOVAlN2E0VsrD2vbVWoinpVPIeOfGgD0RZZLtVQL5Ui8mZcANmuoRXtEqaS
-sQ6VxkdC62uDXgrsi+i/0nsxvACmfde4sxALu3DZ7rjNlWUW7amJt34CsDBMlVeL
-eDAmD0WczQKBgQCHzSLiKATYzkzn/izRF4rL4PeK8ILmlLVYbxEzV9ALtQHlTQJ2
-2pwpNCL644EiLwC2/NcoSEQQ0Y4yoV68FPL745SBjXtWU0AuPaGN395p59OzQGmB
-1vyjvd7dbEN4ZOUH1gIMCdx5Gyjc2fjOQtaK808pRM9EzS2v14xv73CdWQKBgC/8
-qiQrs4Z7tCm+L+ouRqgLcLWVYTg1PxNZQOksAwT9U5OSSQUaVhsQPEcNMi3HV0yP
-NfOkMCafvYsmj43ehlFMgKWPE/DxS0hVCmlBfs1tq/IdLxXZwi8vSQpVLdAUpY4H
-CfXuWJQZXcDMwgWBlh8j0t11rjJ8W/qbKUt1Q2oNAoGBALdy/RpspFttVvthzFbg
-FLHUAwUhEsK1VSi26AYy4L0ZHw/KLnbIGEzKCEFWqn6nfWOlb9Rw5C7QlGx/1UCC
-Tnn9KnZoziK4JDQw6SEl/3hNQ5+FYI8y7QGsqAm1W9dobbgl0a1IfmbtBeEOZt+e
-7oFnqaxVruVmNr56M9IMCwA1
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAg51YU8NkgC7w
+Hx7Jf9Zj+wjHcLxedY6czsFjhl9wUlYRkQ+wdt3suH998TrbdVMc38tpI460pGk7
+gGBpMkbZgo1YNnwz/U1jAOR11EVGHN1QDy3H0BI2E5RYtl/vTWQLFo1khIaKK4eS
+3ptrPd+1XB6L25E4ISOVgd3yn4b5eTMGRbEei+wrkZIyZAVgCIw8d6BHHwldWz3A
+ljKRErMPzKtnyVL+ctp0Kx6ObppiBPPOWhNNTtMkmLgfeZQK3U7cPN5WI13Fso05
+FA3wVo/w6sXTtz4inIT14Y57E34V6sWZezrBbTtAI0yN3DqXSKTBgGjOQUbjqVxS
+i/JzRbZpAgMBAAECggEAXJMt59qn3D1T1P5yFJ2X4A5Io3eP7bCEOt2l25EzddTy
+NJJYRBh1Ea+LB2ooTn410G3B6DZEGpPxUr6iHhQiQ9hm1eOliG6ndxNnyU2hXlzl
+A+m4rxxclYqGzL4ulenWUQqwRYUBGZJjKHpJrKFdYV4CBmk4hRBSh0OjElgqVO5g
+nliMl3fC+GgUXtdMDGoPnC6MwD8q0RSJxbzpd8r+yREgX6KveEfPTfgSLAUieJrf
+2qqEk0Prdrwzsu0iyDYCaWLOq0cUstnHCo3e5synV4VzAFnaqxMT7lCVuUHgFpHj
+62rTwBCG/n3s+IVAp9CGBe37+SiJPRE8t5PDr65F3QKBgQDovkKLWzXxVJauTF/E
+tFRA+HqNDzYC3yiN0MIBmcF7IntdwCHznMyqydkaSE6WYn+NKglbH3c4RD5Hmdxc
+PUta8wgpmTg264568Svgna5jhwoqStrzh7qeBPXHmJvK4MkWALH4ukr3hIsWzsAh
+881ebstQDke8uHzyNZBY/URebwKBgQDTwEP6hgcgDOaf9yzipeMhtsArIm7zXn+r
+1RknpKUA8wM6fpEMpdUTgReu9tdJDgrcKac6imSZoNM6DBoOb/Hdj6FourHiTTvE
+dXAOjAzkDz/c86HFuDNoz27usoMPu/3iJPwuLQSO0IlflccLuOirhnnY8yVxIuy2
++9g+2iOkpwKBgE/Kin3EM2YdHdt7i4mgWRI9HaamhFnPr9OOsjRiRha0555odDtU
+kkYrFScRiv+7nQcEVljLHNBJdSCO+yEUUnVHxJCeWstZTmuPqv9Cj7rHXRDKwO2k
+prHt+WUISMDw9393lYw0MedRpW2YS/5X2xx413MGsklc5lkTS/12Nq45AoGAaVCf
+vrL4Sj2AWqEhxtwAmlz9OLbYfdxLHVhQOYJOuqkiuu4GEEdOMXQsJk4IhwIf7p4c
+2SXJoQr241DviKyum6Z6/c6U+Fu3VR+fiuym4Kqg9bCKjf7uOruojbllK+cw/0+r
+yP+E287l9A9XPwJJXj30zi0oOxvGpb+eLqxpu9MCgYEAxIgVhzyfRvoAdNYk7FE7
+JDig38EGC4m9grh/9G0tMvWT/E+F1Hb5V9NDK/iWA25dD3hOASxza1Hqkt1dP5on
+FMZrmP2T9Ov0wgfVuRIf8/c3YyiS1wJXb3wROVaJJDSvE5c2UszR5pfqvNE5C1YV
+zpc3ITQSAX66LK6ImkHb9Jw=
 -----END PRIVATE KEY-----
diff --git a/grpc/src/core/tsi/test_creds/multi-domain.pem b/grpc/src/core/tsi/test_creds/multi-domain.pem
index d4ff936..727b8ff 100644
--- a/grpc/src/core/tsi/test_creds/multi-domain.pem
+++ b/grpc/src/core/tsi/test_creds/multi-domain.pem
@@ -1,24 +1,24 @@
 -----BEGIN CERTIFICATE-----
-MIID/jCCAuagAwIBAgIUV2eOzlQQj1U+++TDdNyRHjRNamQwDQYJKoZIhvcNAQEL
+MIIEGzCCAwOgAwIBAgIUVwCmP2zKfeoWdaMbn32PjFgpdRswDQYJKoZIhvcNAQEL
 BQAwSjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEPMA0G
-A1UECwwGR29vZ2xlMRAwDgYDVQQDDAd4cGlnb3JzMB4XDTIwMDYwNzIyNTk1MFoX
-DTMwMDYwNTIyNTk1MFowSjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYD
+A1UECwwGR29vZ2xlMRAwDgYDVQQDDAd4cGlnb3JzMB4XDTIxMDQwOTE5MzgxOVoX
+DTMxMDQwNzE5MzgxOVowSjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYD
 VQQHDAJTRjEPMA0GA1UECwwGR29vZ2xlMRAwDgYDVQQDDAd4cGlnb3JzMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArhlQWA9z/w9nk54QYWdIsz/p7qMz
-QhDv4kLv5MsumQsyBBb8pLdGj8yVS3LAhwmlnDSVRT0qlQ1UZvUuWR1Mi5Z0ped5
-ilJbWSOLQw1THBHa+yqX13gXPOpZv/dw6hQ4AGA5L3m3pEa//AdTiYVSURqMF4wF
-PbGAAc7lKo5K2udtgZXiIpN5vuw26Kxh0uCKOV//A/FY5V43gVYbekAPIo+SVXx7
-zug7Ga/fRCEz6YWuotfNjukupTtrdVfm3Vj/hD44jkCZLa5rzEGExY5o2JESiwmS
-NccUnwivLe4mubCzxThergx/dXJPJl5rh7Pep0jsgdYvy3QcvV3SJ0kRlwIDAQAB
-o4HbMIHYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMIG9BgNVHREEgbUwgbKCE2Zv
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwIOdWFPDZIAu8B8eyX/WY/sIx3C8
+XnWOnM7BY4ZfcFJWEZEPsHbd7Lh/ffE623VTHN/LaSOOtKRpO4BgaTJG2YKNWDZ8
+M/1NYwDkddRFRhzdUA8tx9ASNhOUWLZf701kCxaNZISGiiuHkt6baz3ftVwei9uR
+OCEjlYHd8p+G+XkzBkWxHovsK5GSMmQFYAiMPHegRx8JXVs9wJYykRKzD8yrZ8lS
+/nLadCsejm6aYgTzzloTTU7TJJi4H3mUCt1O3DzeViNdxbKNORQN8FaP8OrF07c+
+IpyE9eGOexN+FerFmXs6wW07QCNMjdw6l0ikwYBozkFG46lcUovyc0W2aQIDAQAB
+o4H4MIH1MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMIHaBgNVHREEgdIwgc+CE2Zv
 by50ZXN0LmRvbWFpbi5jb22CE2Jhci50ZXN0LmRvbWFpbi5jb22GIGh0dHBzOi8v
 Zm9vLnRlc3QuZG9tYWluLmNvbS90ZXN0hiBodHRwczovL2Jhci50ZXN0LmRvbWFp
 bi5jb20vdGVzdIYYc3BpZmZlOi8vZm9vLmNvbS9iYXIvYmF6gRNmb29AdGVzdC5k
-b21haW4uY29tgRNiYXJAdGVzdC5kb21haW4uY29tMA0GCSqGSIb3DQEBCwUAA4IB
-AQBlLNl/uXN01VARQFd5CNFMhwez879uB5N3s/pGBjzE8Z+NA9YjsBFkBSQlebFM
-5UP304rsvG2opHwcSkblG9a3TbpQVNaYjcHgudip3FqLTJ3NhYtx1A3uCBp4ABeP
-+AVlCcsNVysGwGvMzXlN++Y++U0A9BbfrP85VBslLaKn4rYpfB5pAdzu277ICdEy
-nyFZ+jo2OS1lbv7kE7IW6slCXbCFaxPIKvjPbpGFngsLt44sZ9VvSJCeKhDglMfn
-HKkhd4/UMnRn+8tZZ6eH/C5tpeKAChMUF+bkuwk3dBwnHq484KbBAKd2cwzZhTB7
-8unku1S1GumvoEYAgbG1P4gC
+b21haW4uY29tgRNiYXJAdGVzdC5kb21haW4uY29thwTAqAcBhxAAEwAAAAAAAAAA
+AAAAAAAXiAMqAwQwDQYJKoZIhvcNAQELBQADggEBAIHzi/MWANQDYqpNDGVA6HGg
+vYPnwxjLXL/8apVf1ZMHzS/R6Eudu8ugppnnEL7Cjsd4oA0r/sJLjBvhaZtf0r4S
+GguWdmai2RR1ghwkCLPF/HlCqiBKwUfWrjTxq8GOwwodhW7lk4hLPzhFRzh/I93g
+uN5/ugPKcloWQ7X/0okMdkdPmk8uLpMckXNKj13Lupl/0BgDggghVXRTA2t0ujhx
+TvRWfYi5H1eJtNcj824PaIDifPiSOpzeXZi+na2XzzVmCz5n/e2H4nlTMVcN6YGG
+M3U3uJqjjjpKkCrrdNAJJpqqJpln4P6fVvO2ND1QmyE5YIKV3tZ8p38AJOheUcw=
 -----END CERTIFICATE-----
diff --git a/grpc/src/cpp/Protobuf-C++.podspec b/grpc/src/cpp/Protobuf-C++.podspec
index 16168b1..7b239a6 100644
--- a/grpc/src/cpp/Protobuf-C++.podspec
+++ b/grpc/src/cpp/Protobuf-C++.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name     = 'Protobuf-C++'
-  s.version  = '3.14.0'
+  s.version  = '3.15.8'
   s.summary  = 'Protocol Buffers v3 runtime library for C++.'
   s.homepage = 'https://github.com/google/protobuf'
   s.license  = '3-Clause BSD License'
diff --git a/grpc/src/cpp/client/channel_cc.cc b/grpc/src/cpp/client/channel_cc.cc
index 1395c72..a9f2083 100644
--- a/grpc/src/cpp/client/channel_cc.cc
+++ b/grpc/src/cpp/client/channel_cc.cc
@@ -38,7 +38,9 @@
 #include <grpcpp/support/channel_arguments.h>
 #include <grpcpp/support/config.h>
 #include <grpcpp/support/status.h>
+
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/surface/completion_queue.h"
 
 namespace grpc {
@@ -55,8 +57,14 @@
 
 Channel::~Channel() {
   grpc_channel_destroy(c_channel_);
-  if (callback_cq_ != nullptr) {
-    callback_cq_->Shutdown();
+  CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_relaxed);
+  if (callback_cq != nullptr) {
+    if (grpc_iomgr_run_in_background()) {
+      // gRPC-core provides the backing needed for the preferred CQ type
+      callback_cq->Shutdown();
+    } else {
+      CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
+    }
   }
 }
 
@@ -139,9 +147,9 @@
   // ClientRpcInfo should be set before call because set_call also checks
   // whether the call has been cancelled, and if the call was cancelled, we
   // should notify the interceptors too.
-  auto* info =
-      context->set_client_rpc_info(method.name(), method.method_type(), this,
-                                   interceptor_creators_, interceptor_pos);
+  auto* info = context->set_client_rpc_info(
+      method.name(), method.suffix_for_stats(), method.method_type(), this,
+      interceptor_creators_, interceptor_pos);
   context->set_call(c_call, shared_from_this());
 
   return ::grpc::internal::Call(c_call, this, cq, info);
@@ -236,17 +244,33 @@
 ::grpc::CompletionQueue* Channel::CallbackCQ() {
   // TODO(vjpai): Consider using a single global CQ for the default CQ
   // if there is no explicit per-channel CQ registered
-  grpc::internal::MutexLock l(&mu_);
-  if (callback_cq_ == nullptr) {
-    auto* shutdown_callback = new ShutdownCallback;
-    callback_cq_ = new ::grpc::CompletionQueue(grpc_completion_queue_attributes{
-        GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
-        shutdown_callback});
-
-    // Transfer ownership of the new cq to its own shutdown callback
-    shutdown_callback->TakeCQ(callback_cq_);
+  CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_acquire);
+  if (callback_cq != nullptr) {
+    return callback_cq;
   }
-  return callback_cq_;
+  // The callback_cq_ wasn't already set, so grab a lock and set it up exactly
+  // once for this channel.
+  grpc::internal::MutexLock l(&mu_);
+  callback_cq = callback_cq_.load(std::memory_order_relaxed);
+  if (callback_cq == nullptr) {
+    if (grpc_iomgr_run_in_background()) {
+      // gRPC-core provides the backing needed for the preferred CQ type
+
+      auto* shutdown_callback = new ShutdownCallback;
+      callback_cq =
+          new ::grpc::CompletionQueue(grpc_completion_queue_attributes{
+              GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK,
+              GRPC_CQ_DEFAULT_POLLING, shutdown_callback});
+
+      // Transfer ownership of the new cq to its own shutdown callback
+      shutdown_callback->TakeCQ(callback_cq);
+    } else {
+      // Otherwise we need to use the alternative CQ variant
+      callback_cq = CompletionQueue::CallbackAlternativeCQ();
+    }
+    callback_cq_.store(callback_cq, std::memory_order_release);
+  }
+  return callback_cq;
 }
 
 }  // namespace grpc
diff --git a/grpc/src/cpp/client/client_callback.cc b/grpc/src/cpp/client/client_callback.cc
index a05761a..a10e1b5 100644
--- a/grpc/src/cpp/client/client_callback.cc
+++ b/grpc/src/cpp/client/client_callback.cc
@@ -36,7 +36,7 @@
         : reactor(reactor_arg), status(std::move(s)) {
       GRPC_CLOSURE_INIT(
           &closure,
-          [](void* void_arg, grpc_error*) {
+          [](void* void_arg, grpc_error_handle) {
             ClosureWithArg* arg = static_cast<ClosureWithArg*>(void_arg);
             arg->reactor->OnDone(arg->status);
             delete arg;
diff --git a/grpc/src/cpp/client/client_context.cc b/grpc/src/cpp/client/client_context.cc
index 1817767..386b731 100644
--- a/grpc/src/cpp/client/client_context.cc
+++ b/grpc/src/cpp/client/client_context.cc
@@ -62,6 +62,7 @@
       propagate_from_call_(nullptr),
       compression_algorithm_(GRPC_COMPRESS_NONE),
       initial_metadata_corked_(false) {
+  g_gli_initializer.summon();
   g_client_callbacks->DefaultConstructor(this);
 }
 
diff --git a/grpc/src/cpp/client/secure_credentials.cc b/grpc/src/cpp/client/secure_credentials.cc
index 4facd2b..be99d54 100644
--- a/grpc/src/cpp/client/secure_credentials.cc
+++ b/grpc/src/cpp/client/secure_credentials.cc
@@ -109,8 +109,6 @@
       grpc_google_default_credentials_create(nullptr));
 }
 
-namespace experimental {
-
 std::shared_ptr<CallCredentials> ExternalAccountCredentials(
     const grpc::string& json_string, const std::vector<grpc::string>& scopes) {
   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
@@ -118,8 +116,6 @@
       json_string.c_str(), absl::StrJoin(scopes, ",").c_str()));
 }
 
-}  // namespace experimental
-
 // Builds SSL Credentials given SSL specific options
 std::shared_ptr<ChannelCredentials> SslCredentials(
     const SslCredentialsOptions& options) {
@@ -161,7 +157,7 @@
                         "options cannot be nullptr.");
   }
   ClearStsCredentialsOptions(options);
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json json = grpc_core::Json::Parse(json_string.c_str(), &error);
   if (error != GRPC_ERROR_NONE ||
       json.type() != grpc_core::Json::Type::OBJECT) {
@@ -219,7 +215,7 @@
   ClearStsCredentialsOptions(options);
   grpc_slice json_string = grpc_empty_slice();
   char* sts_creds_path = gpr_getenv("STS_CREDENTIALS");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc::Status status;
   auto cleanup = [&json_string, &sts_creds_path, &error, &status]() {
     grpc_slice_unref_internal(json_string);
@@ -236,7 +232,7 @@
   error = grpc_load_file(sts_creds_path, 1, &json_string);
   if (error != GRPC_ERROR_NONE) {
     status =
-        grpc::Status(grpc::StatusCode::NOT_FOUND, grpc_error_string(error));
+        grpc::Status(grpc::StatusCode::NOT_FOUND, grpc_error_std_string(error));
     return cleanup();
   }
   status = StsCredentialsOptionsFromJson(
@@ -410,7 +406,7 @@
 }
 
 namespace {
-void DeleteWrapper(void* wrapper, grpc_error* /*ignored*/) {
+void DeleteWrapper(void* wrapper, grpc_error_handle /*ignored*/) {
   MetadataCredentialsPluginWrapper* w =
       static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
   delete w;
diff --git a/grpc/src/cpp/common/alarm.cc b/grpc/src/cpp/common/alarm.cc
index ac1b747..10d633c 100644
--- a/grpc/src/cpp/common/alarm.cc
+++ b/grpc/src/cpp/common/alarm.cc
@@ -56,7 +56,7 @@
     GPR_ASSERT(grpc_cq_begin_op(cq_, this));
     GRPC_CLOSURE_INIT(
         &on_alarm_,
-        [](void* arg, grpc_error* error) {
+        [](void* arg, grpc_error_handle error) {
           // queue the op on the completion queue
           AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
           alarm->Ref();
@@ -82,10 +82,10 @@
     Ref();
     GRPC_CLOSURE_INIT(
         &on_alarm_,
-        [](void* arg, grpc_error* error) {
+        [](void* arg, grpc_error_handle error) {
           grpc_core::Executor::Run(
               GRPC_CLOSURE_CREATE(
-                  [](void* arg, grpc_error* error) {
+                  [](void* arg, grpc_error_handle error) {
                     AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
                     alarm->callback_(error == GRPC_ERROR_NONE);
                     alarm->Unref();
diff --git a/grpc/src/cpp/common/auth_property_iterator.cc b/grpc/src/cpp/common/auth_property_iterator.cc
index fbb18e9..0f380b0 100644
--- a/grpc/src/cpp/common/auth_property_iterator.cc
+++ b/grpc/src/cpp/common/auth_property_iterator.cc
@@ -61,7 +61,7 @@
   return !operator==(rhs);
 }
 
-const AuthProperty AuthPropertyIterator::operator*() {
+AuthProperty AuthPropertyIterator::operator*() {
   return std::pair<grpc::string_ref, grpc::string_ref>(
       property_->name,
       grpc::string_ref(property_->value, property_->value_length));
diff --git a/grpc/src/cpp/common/channel_filter.h b/grpc/src/cpp/common/channel_filter.h
index 5ce720b..d588056 100644
--- a/grpc/src/cpp/common/channel_filter.h
+++ b/grpc/src/cpp/common/channel_filter.h
@@ -60,7 +60,7 @@
                                               const grpc_mdelem> {
    public:
     const grpc_mdelem& operator*() const { return elem_->md; }
-    const grpc_mdelem operator->() const { return elem_->md; }
+    grpc_mdelem operator->() const { return elem_->md; }
 
     const_iterator& operator++() {
       elem_ = elem_->next;
@@ -113,7 +113,7 @@
   grpc_transport_op* op() const { return op_; }
 
   // TODO(roth): Add a C++ wrapper for grpc_error?
-  grpc_error* disconnect_with_error() const {
+  grpc_error_handle disconnect_with_error() const {
     return op_->disconnect_with_error;
   }
   bool send_goaway() const { return op_->goaway_error != GRPC_ERROR_NONE; }
@@ -236,8 +236,8 @@
   // TODO(roth): Come up with a more C++-like API for the channel element.
 
   /// Initializes the channel data.
-  virtual grpc_error* Init(grpc_channel_element* /*elem*/,
-                           grpc_channel_element_args* /*args*/) {
+  virtual grpc_error_handle Init(grpc_channel_element* /*elem*/,
+                                 grpc_channel_element_args* /*args*/) {
     return GRPC_ERROR_NONE;
   }
 
@@ -259,8 +259,8 @@
   // TODO(roth): Come up with a more C++-like API for the call element.
 
   /// Initializes the call data.
-  virtual grpc_error* Init(grpc_call_element* /*elem*/,
-                           const grpc_call_element_args* /*args*/) {
+  virtual grpc_error_handle Init(grpc_call_element* /*elem*/,
+                                 const grpc_call_element_args* /*args*/) {
     return GRPC_ERROR_NONE;
   }
 
@@ -288,8 +288,8 @@
  public:
   static const size_t channel_data_size = sizeof(ChannelDataType);
 
-  static grpc_error* InitChannelElement(grpc_channel_element* elem,
-                                        grpc_channel_element_args* args) {
+  static grpc_error_handle InitChannelElement(grpc_channel_element* elem,
+                                              grpc_channel_element_args* args) {
     // Construct the object in the already-allocated memory.
     ChannelDataType* channel_data = new (elem->channel_data) ChannelDataType();
     return channel_data->Init(elem, args);
@@ -319,8 +319,8 @@
 
   static const size_t call_data_size = sizeof(CallDataType);
 
-  static grpc_error* InitCallElement(grpc_call_element* elem,
-                                     const grpc_call_element_args* args) {
+  static grpc_error_handle InitCallElement(grpc_call_element* elem,
+                                           const grpc_call_element_args* args) {
     // Construct the object in the already-allocated memory.
     CallDataType* call_data = new (elem->call_data) CallDataType();
     return call_data->Init(elem, args);
diff --git a/grpc/src/cpp/common/completion_queue_cc.cc b/grpc/src/cpp/common/completion_queue_cc.cc
index 96a7105..015b5c1 100644
--- a/grpc/src/cpp/common/completion_queue_cc.cc
+++ b/grpc/src/cpp/common/completion_queue_cc.cc
@@ -20,13 +20,106 @@
 #include <memory>
 
 #include <grpc/grpc.h>
+#include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
 #include <grpcpp/impl/grpc_library.h>
 #include <grpcpp/support/time.h>
 
-namespace grpc {
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/sync.h"
+#include "src/core/lib/gprpp/thd.h"
 
-static internal::GrpcLibraryInitializer g_gli_initializer;
+namespace grpc {
+namespace {
+
+internal::GrpcLibraryInitializer g_gli_initializer;
+
+gpr_once g_once_init_callback_alternative = GPR_ONCE_INIT;
+grpc_core::Mutex* g_callback_alternative_mu;
+
+// Implement a ref-counted callback CQ for global use in the alternative
+// implementation so that its threads are only created once. Do this using
+// explicit ref-counts and raw pointers rather than a shared-ptr since that
+// has a non-trivial destructor and thus can't be used for global variables.
+struct CallbackAlternativeCQ {
+  int refs ABSL_GUARDED_BY(g_callback_alternative_mu) = 0;
+  CompletionQueue* cq ABSL_GUARDED_BY(g_callback_alternative_mu);
+  std::vector<grpc_core::Thread>* nexting_threads
+      ABSL_GUARDED_BY(g_callback_alternative_mu);
+
+  CompletionQueue* Ref() {
+    grpc_core::MutexLock lock(&*g_callback_alternative_mu);
+    refs++;
+    if (refs == 1) {
+      cq = new CompletionQueue;
+      int num_nexting_threads = GPR_CLAMP(gpr_cpu_num_cores() / 2, 2, 16);
+      nexting_threads = new std::vector<grpc_core::Thread>;
+      for (int i = 0; i < num_nexting_threads; i++) {
+        nexting_threads->emplace_back(
+            "nexting_thread",
+            [](void* arg) {
+              grpc_completion_queue* cq =
+                  static_cast<CompletionQueue*>(arg)->cq();
+              while (true) {
+                // Use the raw Core next function rather than the C++ Next since
+                // Next incorporates FinalizeResult and we actually want that
+                // called from the callback functor itself.
+                // TODO(vjpai): Migrate below to next without a timeout or idle
+                // phase. That's currently starving out some other polling,
+                // though.
+                auto ev = grpc_completion_queue_next(
+                    cq,
+                    gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                 gpr_time_from_millis(1000, GPR_TIMESPAN)),
+                    nullptr);
+                if (ev.type == GRPC_QUEUE_SHUTDOWN) {
+                  return;
+                }
+                if (ev.type == GRPC_QUEUE_TIMEOUT) {
+                  gpr_sleep_until(
+                      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                   gpr_time_from_millis(100, GPR_TIMESPAN)));
+                  continue;
+                }
+                GPR_DEBUG_ASSERT(ev.type == GRPC_OP_COMPLETE);
+                // We can always execute the callback inline rather than
+                // pushing it to another Executor thread because this
+                // thread is definitely running on a background thread, does not
+                // hold any application locks before executing the callback,
+                // and cannot be entered recursively.
+                auto* functor =
+                    static_cast<grpc_experimental_completion_queue_functor*>(
+                        ev.tag);
+                functor->functor_run(functor, ev.success);
+              }
+            },
+            cq);
+      }
+      for (auto& th : *nexting_threads) {
+        th.Start();
+      }
+    }
+    return cq;
+  }
+
+  void Unref() {
+    grpc_core::MutexLock lock(g_callback_alternative_mu);
+    refs--;
+    if (refs == 0) {
+      cq->Shutdown();
+      for (auto& th : *nexting_threads) {
+        th.Join();
+      }
+      delete nexting_threads;
+      delete cq;
+    }
+  }
+};
+
+CallbackAlternativeCQ g_callback_alternative_cq;
+
+}  // namespace
 
 // 'CompletionQueue' constructor can safely call GrpcLibraryCodegen(false) here
 // i.e not have GrpcLibraryCodegen call grpc_init(). This is because, to create
@@ -96,4 +189,19 @@
   return false;
 }
 
+CompletionQueue* CompletionQueue::CallbackAlternativeCQ() {
+  gpr_once_init(&g_once_init_callback_alternative,
+                [] { g_callback_alternative_mu = new grpc_core::Mutex(); });
+  return g_callback_alternative_cq.Ref();
+}
+
+void CompletionQueue::ReleaseCallbackAlternativeCQ(CompletionQueue* cq)
+    ABSL_NO_THREAD_SAFETY_ANALYSIS {
+  (void)cq;
+  // This accesses g_callback_alternative_cq without acquiring the mutex
+  // but it's considered safe because it just reads the pointer address.
+  GPR_DEBUG_ASSERT(cq == g_callback_alternative_cq.cq);
+  g_callback_alternative_cq.Unref();
+}
+
 }  // namespace grpc
diff --git a/grpc/src/cpp/common/tls_credentials_options.cc b/grpc/src/cpp/common/tls_credentials_options.cc
index 02bc6d9..729e6a4 100644
--- a/grpc/src/cpp/common/tls_credentials_options.cc
+++ b/grpc/src/cpp/common/tls_credentials_options.cc
@@ -124,10 +124,13 @@
   grpc_tls_server_authorization_check_config_release(c_config_);
 }
 
-TlsCredentialsOptions::TlsCredentialsOptions(
-    std::shared_ptr<CertificateProviderInterface> certificate_provider)
-    : certificate_provider_(std::move(certificate_provider)) {
+TlsCredentialsOptions::TlsCredentialsOptions() {
   c_credentials_options_ = grpc_tls_credentials_options_create();
+}
+
+void TlsCredentialsOptions::set_certificate_provider(
+    std::shared_ptr<CertificateProviderInterface> certificate_provider) {
+  certificate_provider_ = std::move(certificate_provider);
   if (certificate_provider_ != nullptr) {
     grpc_tls_credentials_options_set_certificate_provider(
         c_credentials_options_, certificate_provider_->c_provider());
diff --git a/grpc/src/cpp/common/validate_service_config.cc b/grpc/src/cpp/common/validate_service_config.cc
index 720c090..cac39ad 100644
--- a/grpc/src/cpp/common/validate_service_config.cc
+++ b/grpc/src/cpp/common/validate_service_config.cc
@@ -25,12 +25,12 @@
 namespace experimental {
 std::string ValidateServiceConfigJSON(const std::string& service_config_json) {
   grpc_init();
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::ServiceConfig::Create(/*args=*/nullptr,
                                    service_config_json.c_str(), &error);
   std::string return_value;
   if (error != GRPC_ERROR_NONE) {
-    return_value = grpc_error_string(error);
+    return_value = grpc_error_std_string(error);
     GRPC_ERROR_UNREF(error);
   }
   grpc_shutdown();
diff --git a/grpc/src/cpp/common/version_cc.cc b/grpc/src/cpp/common/version_cc.cc
index 64da15a..b7afff4 100644
--- a/grpc/src/cpp/common/version_cc.cc
+++ b/grpc/src/cpp/common/version_cc.cc
@@ -22,5 +22,5 @@
 #include <grpcpp/grpcpp.h>
 
 namespace grpc {
-std::string Version() { return "1.35.0"; }
+std::string Version() { return "1.38.0"; }
 }  // namespace grpc
diff --git a/grpc/src/cpp/ext/filters/census/channel_filter.cc b/grpc/src/cpp/ext/filters/census/channel_filter.cc
index 4ac684d..ea3bce9 100644
--- a/grpc/src/cpp/ext/filters/census/channel_filter.cc
+++ b/grpc/src/cpp/ext/filters/census/channel_filter.cc
@@ -22,8 +22,8 @@
 
 namespace grpc {
 
-grpc_error* CensusChannelData::Init(grpc_channel_element* elem,
-                                    grpc_channel_element_args* args) {
+grpc_error_handle CensusChannelData::Init(grpc_channel_element* /*elem*/,
+                                          grpc_channel_element_args* /*args*/) {
   return GRPC_ERROR_NONE;
 }
 
diff --git a/grpc/src/cpp/ext/filters/census/channel_filter.h b/grpc/src/cpp/ext/filters/census/channel_filter.h
index 0b7c682..d756f23 100644
--- a/grpc/src/cpp/ext/filters/census/channel_filter.h
+++ b/grpc/src/cpp/ext/filters/census/channel_filter.h
@@ -27,8 +27,8 @@
 
 class CensusChannelData : public ChannelData {
  public:
-  grpc_error* Init(grpc_channel_element* elem,
-                   grpc_channel_element_args* args) override;
+  grpc_error_handle Init(grpc_channel_element* elem,
+                         grpc_channel_element_args* args) override;
 };
 
 }  // namespace grpc
diff --git a/grpc/src/cpp/ext/filters/census/client_filter.cc b/grpc/src/cpp/ext/filters/census/client_filter.cc
index 3d90921..380ad5b 100644
--- a/grpc/src/cpp/ext/filters/census/client_filter.cc
+++ b/grpc/src/cpp/ext/filters/census/client_filter.cc
@@ -53,8 +53,8 @@
 
 }  // namespace
 
-void CensusClientCallData::OnDoneRecvTrailingMetadataCb(void* user_data,
-                                                        grpc_error* error) {
+void CensusClientCallData::OnDoneRecvTrailingMetadataCb(
+    void* user_data, grpc_error_handle error) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
   CensusClientCallData* calld =
       reinterpret_cast<CensusClientCallData*>(elem->call_data);
@@ -70,7 +70,7 @@
 }
 
 void CensusClientCallData::OnDoneRecvMessageCb(void* user_data,
-                                               grpc_error* error) {
+                                               grpc_error_handle error) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
   CensusClientCallData* calld =
       reinterpret_cast<CensusClientCallData*>(elem->call_data);
@@ -138,8 +138,8 @@
   grpc_call_next_op(elem, op->op());
 }
 
-grpc_error* CensusClientCallData::Init(grpc_call_element* elem,
-                                       const grpc_call_element_args* args) {
+grpc_error_handle CensusClientCallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   path_ = grpc_slice_ref_internal(args->path);
   start_time_ = absl::Now();
   method_ = GetMethod(&path_);
@@ -152,9 +152,9 @@
   return GRPC_ERROR_NONE;
 }
 
-void CensusClientCallData::Destroy(grpc_call_element* elem,
+void CensusClientCallData::Destroy(grpc_call_element* /*elem*/,
                                    const grpc_call_final_info* final_info,
-                                   grpc_closure* then_call_closure) {
+                                   grpc_closure* /*then_call_closure*/) {
   const uint64_t request_size = GetOutgoingDataSize(final_info);
   const uint64_t response_size = GetIncomingDataSize(final_info);
   double latency_ms = absl::ToDoubleMilliseconds(absl::Now() - start_time_);
diff --git a/grpc/src/cpp/ext/filters/census/client_filter.h b/grpc/src/cpp/ext/filters/census/client_filter.h
index 8510228..f55a4b5 100644
--- a/grpc/src/cpp/ext/filters/census/client_filter.h
+++ b/grpc/src/cpp/ext/filters/census/client_filter.h
@@ -54,8 +54,8 @@
     memset(&on_done_recv_message_, 0, sizeof(grpc_closure));
   }
 
-  grpc_error* Init(grpc_call_element* elem,
-                   const grpc_call_element_args* args) override;
+  grpc_error_handle Init(grpc_call_element* elem,
+                         const grpc_call_element_args* args) override;
 
   void Destroy(grpc_call_element* elem, const grpc_call_final_info* final_info,
                grpc_closure* then_call_closure) override;
@@ -63,11 +63,13 @@
   void StartTransportStreamOpBatch(grpc_call_element* elem,
                                    TransportStreamOpBatch* op) override;
 
-  static void OnDoneRecvTrailingMetadataCb(void* user_data, grpc_error* error);
+  static void OnDoneRecvTrailingMetadataCb(void* user_data,
+                                           grpc_error_handle error);
 
-  static void OnDoneSendInitialMetadataCb(void* user_data, grpc_error* error);
+  static void OnDoneSendInitialMetadataCb(void* user_data,
+                                          grpc_error_handle error);
 
-  static void OnDoneRecvMessageCb(void* user_data, grpc_error* error);
+  static void OnDoneRecvMessageCb(void* user_data, grpc_error_handle error);
 
  private:
   CensusContext context_;
diff --git a/grpc/src/cpp/ext/filters/census/context.cc b/grpc/src/cpp/ext/filters/census/context.cc
index 2deeedf..0650bd1 100644
--- a/grpc/src/cpp/ext/filters/census/context.cc
+++ b/grpc/src/cpp/ext/filters/census/context.cc
@@ -20,6 +20,7 @@
 
 #include "opencensus/tags/context_util.h"
 #include "opencensus/trace/context_util.h"
+#include "opencensus/trace/propagation/grpc_trace_bin.h"
 #include "src/cpp/ext/filters/census/context.h"
 
 namespace grpc {
@@ -28,20 +29,16 @@
 using ::opencensus::trace::Span;
 using ::opencensus::trace::SpanContext;
 
-void GenerateServerContext(absl::string_view tracing, absl::string_view stats,
-                           absl::string_view primary_role,
-                           absl::string_view method, CensusContext* context) {
+void GenerateServerContext(absl::string_view tracing, absl::string_view method,
+                           CensusContext* context) {
   // Destruct the current CensusContext to free the Span memory before
   // overwriting it below.
   context->~CensusContext();
-  GrpcTraceContext trace_ctxt;
-  if (TraceContextEncoding::Decode(tracing, &trace_ctxt) !=
-      TraceContextEncoding::kEncodeDecodeFailure) {
-    SpanContext parent_ctx = trace_ctxt.ToSpanContext();
-    if (parent_ctx.IsValid()) {
-      new (context) CensusContext(method, parent_ctx);
-      return;
-    }
+  SpanContext parent_ctx =
+      opencensus::trace::propagation::FromGrpcTraceBinHeader(tracing);
+  if (parent_ctx.IsValid()) {
+    new (context) CensusContext(method, parent_ctx);
+    return;
   }
   new (context) CensusContext(method, TagMap{});
 }
@@ -72,12 +69,16 @@
 
 size_t TraceContextSerialize(const ::opencensus::trace::SpanContext& context,
                              char* tracing_buf, size_t tracing_buf_size) {
-  GrpcTraceContext trace_ctxt(context);
-  return TraceContextEncoding::Encode(trace_ctxt, tracing_buf,
-                                      tracing_buf_size);
+  if (tracing_buf_size <
+      opencensus::trace::propagation::kGrpcTraceBinHeaderLen) {
+    return 0;
+  }
+  opencensus::trace::propagation::ToGrpcTraceBinHeader(
+      context, reinterpret_cast<uint8_t*>(tracing_buf));
+  return opencensus::trace::propagation::kGrpcTraceBinHeaderLen;
 }
 
-size_t StatsContextSerialize(size_t max_tags_len, grpc_slice* tags) {
+size_t StatsContextSerialize(size_t /*max_tags_len*/, grpc_slice* /*tags*/) {
   // TODO(unknown): Add implementation. Waiting on stats tagging to be added.
   return 0;
 }
diff --git a/grpc/src/cpp/ext/filters/census/context.h b/grpc/src/cpp/ext/filters/census/context.h
index 0c945b5..67f5704 100644
--- a/grpc/src/cpp/ext/filters/census/context.h
+++ b/grpc/src/cpp/ext/filters/census/context.h
@@ -75,8 +75,8 @@
   ::opencensus::tags::TagMap tags_;
 };
 
-// Serializes the outgoing trace context. Field IDs are 1 byte followed by
-// field data. A 1 byte version ID is always encoded first.
+// Serializes the outgoing trace context. tracing_buf must be
+// opencensus::trace::propagation::kGrpcTraceBinHeaderLen bytes long.
 size_t TraceContextSerialize(const ::opencensus::trace::SpanContext& context,
                              char* tracing_buf, size_t tracing_buf_size);
 
@@ -96,9 +96,8 @@
 // Deserialize the incoming SpanContext and generate a new server context based
 // on that. This new span will never be a root span. This should only be called
 // with a blank CensusContext as it overwrites it.
-void GenerateServerContext(absl::string_view tracing, absl::string_view stats,
-                           absl::string_view primary_role,
-                           absl::string_view method, CensusContext* context);
+void GenerateServerContext(absl::string_view tracing, absl::string_view method,
+                           CensusContext* context);
 
 // Creates a new client context that is by default a new root context.
 // If the current context is the default context then the newly created
diff --git a/grpc/src/cpp/ext/filters/census/rpc_encoding.cc b/grpc/src/cpp/ext/filters/census/rpc_encoding.cc
index 45a66d9..7ce3e94 100644
--- a/grpc/src/cpp/ext/filters/census/rpc_encoding.cc
+++ b/grpc/src/cpp/ext/filters/census/rpc_encoding.cc
@@ -22,13 +22,6 @@
 
 namespace grpc {
 
-constexpr size_t TraceContextEncoding::kGrpcTraceContextSize;
-constexpr size_t TraceContextEncoding::kEncodeDecodeFailure;
-constexpr size_t TraceContextEncoding::kVersionIdSize;
-constexpr size_t TraceContextEncoding::kFieldIdSize;
-constexpr size_t TraceContextEncoding::kVersionIdOffset;
-constexpr size_t TraceContextEncoding::kVersionId;
-
 constexpr size_t RpcServerStatsEncoding::kRpcServerStatsSize;
 constexpr size_t RpcServerStatsEncoding::kEncodeDecodeFailure;
 constexpr size_t RpcServerStatsEncoding::kVersionIdSize;
diff --git a/grpc/src/cpp/ext/filters/census/rpc_encoding.h b/grpc/src/cpp/ext/filters/census/rpc_encoding.h
index b897dfc..821c715 100644
--- a/grpc/src/cpp/ext/filters/census/rpc_encoding.h
+++ b/grpc/src/cpp/ext/filters/census/rpc_encoding.h
@@ -31,175 +31,6 @@
 
 namespace grpc {
 
-// TODO(unknown): Rename to GrpcTraceContextV0.
-struct GrpcTraceContext {
-  GrpcTraceContext() {}
-
-  explicit GrpcTraceContext(const ::opencensus::trace::SpanContext& ctx) {
-    ctx.trace_id().CopyTo(trace_id);
-    ctx.span_id().CopyTo(span_id);
-    ctx.trace_options().CopyTo(trace_options);
-  }
-
-  ::opencensus::trace::SpanContext ToSpanContext() const {
-    return ::opencensus::trace::SpanContext(
-        ::opencensus::trace::TraceId(trace_id),
-        ::opencensus::trace::SpanId(span_id),
-        ::opencensus::trace::TraceOptions(trace_options));
-  }
-
-  // TODO(unknown): For performance:
-  // uint8_t version;
-  // uint8_t trace_id_field_id;
-  uint8_t trace_id[::opencensus::trace::TraceId::kSize];
-  // uint8_t span_id_field_id;
-  uint8_t span_id[::opencensus::trace::SpanId::kSize];
-  // uint8_t trace_options_field_id;
-  uint8_t trace_options[::opencensus::trace::TraceOptions::kSize];
-};
-
-// TraceContextEncoding encapsulates the logic for encoding and decoding of
-// trace contexts.
-class TraceContextEncoding {
- public:
-  // Size of encoded GrpcTraceContext. (16 + 8 + 1 + 4)
-  static constexpr size_t kGrpcTraceContextSize = 29;
-  // Error value.
-  static constexpr size_t kEncodeDecodeFailure = 0;
-
-  // Deserializes a GrpcTraceContext from the incoming buffer. Returns the
-  // number of bytes deserialized from the buffer. If the incoming buffer is
-  // empty or the encoding version is not supported it will return 0 bytes,
-  // currently only version 0 is supported. If an unknown field ID is
-  // encountered it will return immediately without parsing the rest of the
-  // buffer. Inlined for performance reasons.
-  static size_t Decode(absl::string_view buf, GrpcTraceContext* tc) {
-    if (buf.empty()) {
-      return kEncodeDecodeFailure;
-    }
-    uint8_t version = buf[kVersionIdOffset];
-    // TODO(unknown): Support other versions later. Only support version 0 for
-    // now.
-    if (version != kVersionId) {
-      return kEncodeDecodeFailure;
-    }
-
-    size_t pos = kVersionIdSize;
-    while (pos < buf.size()) {
-      size_t bytes_read =
-          ParseField(absl::string_view(&buf[pos], buf.size() - pos), tc);
-      if (bytes_read == 0) {
-        break;
-      } else {
-        pos += bytes_read;
-      }
-    }
-    return pos;
-  }
-
-  // Serializes a GrpcTraceContext into the provided buffer. Returns the number
-  // of bytes serialized into the buffer. If the buffer is not of sufficient
-  // size (it must be at least kGrpcTraceContextSize bytes) it will drop
-  // everything and return 0 bytes serialized. Inlined for performance reasons.
-  static size_t Encode(const GrpcTraceContext& tc, char* buf, size_t buf_size) {
-    if (buf_size < kGrpcTraceContextSize) {
-      return kEncodeDecodeFailure;
-    }
-    buf[kVersionIdOffset] = kVersionId;
-    buf[kTraceIdOffset] = kTraceIdField;
-    memcpy(&buf[kTraceIdOffset + 1], tc.trace_id,
-           opencensus::trace::TraceId::kSize);
-    buf[kSpanIdOffset] = kSpanIdField;
-    memcpy(&buf[kSpanIdOffset + 1], tc.span_id,
-           opencensus::trace::SpanId::kSize);
-    buf[kTraceOptionsOffset] = kTraceOptionsField;
-    memcpy(&buf[kTraceOptionsOffset + 1], tc.trace_options,
-           opencensus::trace::TraceOptions::kSize);
-    return kGrpcTraceContextSize;
-  }
-
- private:
-  // Parses the next field from the incoming buffer and stores the parsed value
-  // in a GrpcTraceContext struct.  If it does not recognize the field ID it
-  // will return 0, otherwise it returns the number of bytes read.
-  static size_t ParseField(absl::string_view buf, GrpcTraceContext* tc) {
-    // TODO(unknown): Add support for multi-byte field IDs.
-    if (buf.empty()) {
-      return 0;
-    }
-    // Field ID is always the first byte in a field.
-    uint32_t field_id = buf[0];
-    size_t bytes_read = kFieldIdSize;
-    switch (field_id) {
-      case kTraceIdField:
-        bytes_read += kTraceIdSize;
-        if (bytes_read > buf.size()) {
-          return 0;
-        }
-        memcpy(tc->trace_id, &buf[kFieldIdSize],
-               opencensus::trace::TraceId::kSize);
-        break;
-      case kSpanIdField:
-        bytes_read += kSpanIdSize;
-        if (bytes_read > buf.size()) {
-          return 0;
-        }
-        memcpy(tc->span_id, &buf[kFieldIdSize],
-               opencensus::trace::SpanId::kSize);
-        break;
-      case kTraceOptionsField:
-        bytes_read += kTraceOptionsSize;
-        if (bytes_read > buf.size()) {
-          return 0;
-        }
-        memcpy(tc->trace_options, &buf[kFieldIdSize],
-               opencensus::trace::TraceOptions::kSize);
-        break;
-      default:  // Invalid field ID
-        return 0;
-    }
-
-    return bytes_read;
-  }
-
-  // Size of Version ID.
-  static constexpr size_t kVersionIdSize = 1;
-  // Size of Field ID.
-  static constexpr size_t kFieldIdSize = 1;
-
-  // Offset and value for currently supported version ID.
-  static constexpr size_t kVersionIdOffset = 0;
-  static constexpr size_t kVersionId = 0;
-
-  // Fixed Field ID values:
-  enum FieldIdValue {
-    kTraceIdField = 0,
-    kSpanIdField = 1,
-    kTraceOptionsField = 2,
-  };
-
-  // Field data sizes in bytes
-  enum FieldSize {
-    kTraceIdSize = 16,
-    kSpanIdSize = 8,
-    kTraceOptionsSize = 1,
-  };
-
-  // Fixed size offsets for field ID start positions during encoding.  Field
-  // data immediately follows.
-  enum FieldIdOffset {
-    kTraceIdOffset = kVersionIdSize,
-    kSpanIdOffset = kTraceIdOffset + kFieldIdSize + kTraceIdSize,
-    kTraceOptionsOffset = kSpanIdOffset + kFieldIdSize + kSpanIdSize,
-  };
-
-  TraceContextEncoding() = delete;
-  TraceContextEncoding(const TraceContextEncoding&) = delete;
-  TraceContextEncoding(TraceContextEncoding&&) = delete;
-  TraceContextEncoding operator=(const TraceContextEncoding&) = delete;
-  TraceContextEncoding operator=(TraceContextEncoding&&) = delete;
-};
-
 // TODO(unknown): This may not be needed. Check to see if opencensus requires
 // a trailing server response.
 // RpcServerStatsEncoding encapsulates the logic for encoding and decoding of
diff --git a/grpc/src/cpp/ext/filters/census/server_filter.cc b/grpc/src/cpp/ext/filters/census/server_filter.cc
index ab7fadc..72ee8e1 100644
--- a/grpc/src/cpp/ext/filters/census/server_filter.cc
+++ b/grpc/src/cpp/ext/filters/census/server_filter.cc
@@ -62,7 +62,7 @@
 }  // namespace
 
 void CensusServerCallData::OnDoneRecvMessageCb(void* user_data,
-                                               grpc_error* error) {
+                                               grpc_error_handle error) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
   CensusServerCallData* calld =
       reinterpret_cast<CensusServerCallData*>(elem->call_data);
@@ -78,8 +78,8 @@
                           GRPC_ERROR_REF(error));
 }
 
-void CensusServerCallData::OnDoneRecvInitialMetadataCb(void* user_data,
-                                                       grpc_error* error) {
+void CensusServerCallData::OnDoneRecvInitialMetadataCb(
+    void* user_data, grpc_error_handle error) {
   grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
   CensusServerCallData* calld =
       reinterpret_cast<CensusServerCallData*>(elem->call_data);
@@ -103,19 +103,8 @@
     size_t tracing_str_len = GRPC_SLICE_IS_EMPTY(sml.tracing_slice)
                                  ? 0
                                  : GRPC_SLICE_LENGTH(sml.tracing_slice);
-    const char* census_str = GRPC_SLICE_IS_EMPTY(sml.census_proto)
-                                 ? ""
-                                 : reinterpret_cast<const char*>(
-                                       GRPC_SLICE_START_PTR(sml.census_proto));
-    size_t census_str_len = GRPC_SLICE_IS_EMPTY(sml.census_proto)
-                                ? 0
-                                : GRPC_SLICE_LENGTH(sml.census_proto);
-
     GenerateServerContext(absl::string_view(tracing_str, tracing_str_len),
-                          absl::string_view(census_str, census_str_len),
-                          /*primary_role*/ "", calld->qualified_method_,
-                          &calld->context_);
-
+                          calld->qualified_method_, &calld->context_);
     grpc_slice_unref_internal(sml.tracing_slice);
     grpc_slice_unref_internal(sml.census_proto);
     grpc_slice_unref_internal(sml.path);
@@ -165,8 +154,8 @@
   grpc_call_next_op(elem, op->op());
 }
 
-grpc_error* CensusServerCallData::Init(grpc_call_element* elem,
-                                       const grpc_call_element_args* args) {
+grpc_error_handle CensusServerCallData::Init(
+    grpc_call_element* elem, const grpc_call_element_args* args) {
   start_time_ = absl::Now();
   gc_ =
       grpc_call_from_top_element(grpc_call_stack_element(args->call_stack, 0));
@@ -179,9 +168,9 @@
   return GRPC_ERROR_NONE;
 }
 
-void CensusServerCallData::Destroy(grpc_call_element* elem,
+void CensusServerCallData::Destroy(grpc_call_element* /*elem*/,
                                    const grpc_call_final_info* final_info,
-                                   grpc_closure* then_call_closure) {
+                                   grpc_closure* /*then_call_closure*/) {
   const uint64_t request_size = GetOutgoingDataSize(final_info);
   const uint64_t response_size = GetIncomingDataSize(final_info);
   double elapsed_time_ms = absl::ToDoubleMilliseconds(elapsed_time_);
diff --git a/grpc/src/cpp/ext/filters/census/server_filter.h b/grpc/src/cpp/ext/filters/census/server_filter.h
index e393ed3..81bec8f 100644
--- a/grpc/src/cpp/ext/filters/census/server_filter.h
+++ b/grpc/src/cpp/ext/filters/census/server_filter.h
@@ -54,8 +54,8 @@
     memset(&on_done_recv_message_, 0, sizeof(grpc_closure));
   }
 
-  grpc_error* Init(grpc_call_element* elem,
-                   const grpc_call_element_args* args) override;
+  grpc_error_handle Init(grpc_call_element* elem,
+                         const grpc_call_element_args* args) override;
 
   void Destroy(grpc_call_element* elem, const grpc_call_final_info* final_info,
                grpc_closure* then_call_closure) override;
@@ -63,9 +63,10 @@
   void StartTransportStreamOpBatch(grpc_call_element* elem,
                                    TransportStreamOpBatch* op) override;
 
-  static void OnDoneRecvInitialMetadataCb(void* user_data, grpc_error* error);
+  static void OnDoneRecvInitialMetadataCb(void* user_data,
+                                          grpc_error_handle error);
 
-  static void OnDoneRecvMessageCb(void* user_data, grpc_error* error);
+  static void OnDoneRecvMessageCb(void* user_data, grpc_error_handle error);
 
  private:
   CensusContext context_;
diff --git a/grpc/src/cpp/server/admin/admin_services.cc b/grpc/src/cpp/server/admin/admin_services.cc
new file mode 100644
index 0000000..5159b3a
--- /dev/null
+++ b/grpc/src/cpp/server/admin/admin_services.cc
@@ -0,0 +1,52 @@
+//
+//
+// Copyright 2021 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>
+
+#include "absl/memory/memory.h"
+
+#include <grpcpp/ext/admin_services.h>
+#include <grpcpp/impl/server_builder_plugin.h>
+
+#include <grpcpp/server_builder.h>
+
+// TODO(lidiz) build a real registration system that can pull in services
+// automatically with minimum amount of code.
+#include "src/cpp/server/channelz/channelz_service.h"
+#if !defined(GRPC_NO_XDS) && !defined(DISABLED_XDS_PROTO_IN_CC)
+#include "src/cpp/server/csds/csds.h"
+#endif  // GRPC_NO_XDS or DISABLED_XDS_PROTO_IN_CC
+namespace grpc {
+
+namespace {
+
+static auto* g_channelz_service = new ChannelzService();
+#if !defined(GRPC_NO_XDS) && !defined(DISABLED_XDS_PROTO_IN_CC)
+static auto* g_csds = new xds::experimental::ClientStatusDiscoveryService();
+#endif  // GRPC_NO_XDS or DISABLED_XDS_PROTO_IN_CC
+
+}  // namespace
+
+void AddAdminServices(ServerBuilder* builder) {
+  builder->RegisterService(g_channelz_service);
+#if !defined(GRPC_NO_XDS) && !defined(DISABLED_XDS_PROTO_IN_CC)
+  builder->RegisterService(g_csds);
+#endif  // GRPC_NO_XDS or DISABLED_XDS_PROTO_IN_CC
+}
+
+}  // namespace grpc
diff --git a/grpc/src/cpp/server/csds/csds.cc b/grpc/src/cpp/server/csds/csds.cc
new file mode 100644
index 0000000..fc8e7e0
--- /dev/null
+++ b/grpc/src/cpp/server/csds/csds.cc
@@ -0,0 +1,94 @@
+//
+//
+// Copyright 2021 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>
+
+#include "src/cpp/server/csds/csds.h"
+
+#include "absl/status/statusor.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpcpp/impl/codegen/slice.h>
+
+#include <string>
+
+#include "src/proto/grpc/testing/xds/v3/csds.grpc.pb.h"
+
+namespace grpc {
+namespace xds {
+namespace experimental {
+
+using envoy::service::status::v3::ClientConfig;
+using envoy::service::status::v3::ClientStatusRequest;
+using envoy::service::status::v3::ClientStatusResponse;
+
+namespace {
+
+absl::StatusOr<ClientConfig> DumpClientConfig() {
+  ClientConfig client_config;
+  grpc_slice serialized_client_config = grpc_dump_xds_configs();
+  std::string bytes = StringFromCopiedSlice(serialized_client_config);
+  grpc_slice_unref(serialized_client_config);
+  if (!client_config.ParseFromString(bytes)) {
+    return absl::InternalError("Failed to parse ClientConfig.");
+  }
+  return client_config;
+}
+
+}  // namespace
+
+Status ClientStatusDiscoveryService::StreamClientStatus(
+    ServerContext* /*context*/,
+    ServerReaderWriter<ClientStatusResponse, ClientStatusRequest>* stream) {
+  ClientStatusRequest request;
+  while (stream->Read(&request)) {
+    ClientStatusResponse response;
+    absl::StatusOr<ClientConfig> s = DumpClientConfig();
+    if (!s.ok()) {
+      if (s.status().code() == absl::StatusCode::kUnavailable) {
+        // If the xDS client is not initialized, return empty response
+        stream->Write(response);
+        continue;
+      }
+      return Status(StatusCode(s.status().raw_code()), s.status().ToString());
+    }
+    *response.add_config() = std::move(s.value());
+    stream->Write(response);
+  }
+  return Status::OK;
+}
+
+Status ClientStatusDiscoveryService::FetchClientStatus(
+    ServerContext* /*context*/, const ClientStatusRequest* /*request*/,
+    ClientStatusResponse* response) {
+  absl::StatusOr<ClientConfig> s = DumpClientConfig();
+  if (!s.ok()) {
+    if (s.status().code() == absl::StatusCode::kUnavailable) {
+      // If the xDS client is not initialized, return empty response
+      return Status::OK;
+    }
+    return Status(StatusCode(s.status().raw_code()), s.status().ToString());
+  }
+  *response->add_config() = std::move(s.value());
+  return Status::OK;
+}
+
+}  // namespace experimental
+}  // namespace xds
+}  // namespace grpc
diff --git a/grpc/src/cpp/server/csds/csds.h b/grpc/src/cpp/server/csds/csds.h
new file mode 100644
index 0000000..be2a4aa
--- /dev/null
+++ b/grpc/src/cpp/server/csds/csds.h
@@ -0,0 +1,55 @@
+//
+//
+// Copyright 2021 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_INTERNAL_CPP_SERVER_CSDS_H
+#define GRPC_INTERNAL_CPP_SERVER_CSDS_H
+
+#include <grpc/support/port_platform.h>
+#include <grpcpp/grpcpp.h>
+#include "absl/status/status.h"
+
+#include "src/proto/grpc/testing/xds/v3/csds.grpc.pb.h"
+
+namespace grpc {
+namespace xds {
+namespace experimental {
+
+// The implementation of
+// envoy::service::status::v3::ClientStatusDiscoveryService
+class ClientStatusDiscoveryService final
+    : public envoy::service::status::v3::ClientStatusDiscoveryService::Service {
+ public:
+  // A streaming call that responds client status for each request.
+  Status StreamClientStatus(
+      ServerContext* /*context*/,
+      ServerReaderWriter<envoy::service::status::v3::ClientStatusResponse,
+                         envoy::service::status::v3::ClientStatusRequest>*
+          stream) override;
+
+  // An unary call to fetch client status.
+  Status FetchClientStatus(
+      ServerContext* /*unused*/,
+      const envoy::service::status::v3::ClientStatusRequest* /*request*/,
+      envoy::service::status::v3::ClientStatusResponse* response) override;
+};
+
+}  // namespace experimental
+}  // namespace xds
+}  // namespace grpc
+
+#endif  // GRPC_INTERNAL_CPP_SERVER_CSDS_H
diff --git a/grpc/src/cpp/server/dynamic_thread_pool.cc b/grpc/src/cpp/server/dynamic_thread_pool.cc
index 4131dc6..e96dc4c 100644
--- a/grpc/src/cpp/server/dynamic_thread_pool.cc
+++ b/grpc/src/cpp/server/dynamic_thread_pool.cc
@@ -68,7 +68,7 @@
     if (!callbacks_.empty()) {
       auto cb = callbacks_.front();
       callbacks_.pop();
-      lock.Unlock();
+      lock.Release();
       cb();
     } else if (shutdown_) {
       break;
@@ -97,7 +97,7 @@
 DynamicThreadPool::~DynamicThreadPool() {
   grpc_core::MutexLock lock(&mu_);
   shutdown_ = true;
-  cv_.Broadcast();
+  cv_.SignalAll();
   while (nthreads_ != 0) {
     shutdown_cv_.Wait(&mu_);
   }
diff --git a/grpc/src/cpp/server/health/default_health_check_service.cc b/grpc/src/cpp/server/health/default_health_check_service.cc
index 2ba2e8c..42c55c5 100644
--- a/grpc/src/cpp/server/health/default_health_check_service.cc
+++ b/grpc/src/cpp/server/health/default_health_check_service.cc
@@ -243,10 +243,9 @@
       grpc_health_v1_HealthCheckResponse_new(arena.ptr());
   grpc_health_v1_HealthCheckResponse_set_status(
       response_struct,
-      status == NOT_FOUND
-          ? grpc_health_v1_HealthCheckResponse_SERVICE_UNKNOWN
-          : status == SERVING ? grpc_health_v1_HealthCheckResponse_SERVING
-                              : grpc_health_v1_HealthCheckResponse_NOT_SERVING);
+      status == NOT_FOUND ? grpc_health_v1_HealthCheckResponse_SERVICE_UNKNOWN
+      : status == SERVING ? grpc_health_v1_HealthCheckResponse_SERVING
+                          : grpc_health_v1_HealthCheckResponse_NOT_SERVING);
   size_t buf_length;
   char* buf = grpc_health_v1_HealthCheckResponse_serialize(
       response_struct, arena.ptr(), &buf_length);
diff --git a/grpc/src/cpp/server/load_reporter/load_reporter.cc b/grpc/src/cpp/server/load_reporter/load_reporter.cc
index 2ef1b49..613cf3a 100644
--- a/grpc/src/cpp/server/load_reporter/load_reporter.cc
+++ b/grpc/src/cpp/server/load_reporter/load_reporter.cc
@@ -18,6 +18,7 @@
 
 #include <grpc/impl/codegen/port_platform.h>
 
+#include <inttypes.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <chrono>
@@ -227,7 +228,7 @@
     GPR_ASSERT(lb_id >= 0);
     // Convert to padded hex string for a 32-bit LB ID. E.g, "0000ca5b".
     char buf[kLbIdLength + 1];
-    snprintf(buf, sizeof(buf), "%08lx", lb_id);
+    snprintf(buf, sizeof(buf), "%08" PRIx64, lb_id);
     std::string lb_id_str(buf, kLbIdLength);
     // The client may send requests with LB ID that has never been allocated
     // by this load reporter. Those IDs are tracked and will be skipped when
@@ -278,7 +279,7 @@
   double cpu_limit = newest->cpu_limit - oldest->cpu_limit;
   std::chrono::duration<double> duration_seconds =
       newest->end_time - oldest->end_time;
-  lock.Unlock();
+  lock.Release();
   ::grpc::lb::v1::LoadBalancingFeedback feedback;
   feedback.set_server_utilization(static_cast<float>(cpu_usage / cpu_limit));
   feedback.set_calls_per_second(
diff --git a/grpc/src/cpp/server/load_reporter/load_reporter_async_service_impl.cc b/grpc/src/cpp/server/load_reporter/load_reporter_async_service_impl.cc
index 47ef526..e2a14ef 100644
--- a/grpc/src/cpp/server/load_reporter/load_reporter_async_service_impl.cc
+++ b/grpc/src/cpp/server/load_reporter/load_reporter_async_service_impl.cc
@@ -18,6 +18,8 @@
 
 #include <grpc/support/port_platform.h>
 
+#include <inttypes.h>
+
 #include "absl/memory/memory.h"
 
 #include "src/cpp/server/load_reporter/load_reporter_async_service_impl.h"
@@ -169,7 +171,7 @@
   {
     grpc_core::ReleasableMutexLock lock(&service_->cq_shutdown_mu_);
     if (service_->shutdown_) {
-      lock.Unlock();
+      lock.Release();
       Shutdown(std::move(self), "OnRequestDelivered");
       return;
     }
@@ -216,18 +218,18 @@
       load_report_interval_ms_ =
           static_cast<unsigned long>(load_report_interval.seconds() * 1000 +
                                      load_report_interval.nanos() / 1000);
-      gpr_log(
-          GPR_INFO,
-          "[LRS %p] Initial request received. Start load reporting (load "
-          "balanced host: %s, interval: %lu ms, lb_id_: %s, handler: %p)...",
-          service_, load_balanced_hostname_.c_str(), load_report_interval_ms_,
-          lb_id_.c_str(), this);
+      gpr_log(GPR_INFO,
+              "[LRS %p] Initial request received. Start load reporting (load "
+              "balanced host: %s, interval: %" PRIu64
+              " ms, lb_id_: %s, handler: %p)...",
+              service_, load_balanced_hostname_.c_str(),
+              load_report_interval_ms_, lb_id_.c_str(), this);
       SendReport(self, true /* ok */);
       // Expect this read to fail.
       {
         grpc_core::ReleasableMutexLock lock(&service_->cq_shutdown_mu_);
         if (service_->shutdown_) {
-          lock.Unlock();
+          lock.Release();
           Shutdown(std::move(self), "OnReadDone");
           return;
         }
@@ -259,7 +261,7 @@
   {
     grpc_core::ReleasableMutexLock lock(&service_->cq_shutdown_mu_);
     if (service_->shutdown_) {
-      lock.Unlock();
+      lock.Release();
       Shutdown(std::move(self), "ScheduleNextReport");
       return;
     }
@@ -299,7 +301,7 @@
   {
     grpc_core::ReleasableMutexLock lock(&service_->cq_shutdown_mu_);
     if (service_->shutdown_) {
-      lock.Unlock();
+      lock.Release();
       Shutdown(std::move(self), "SendReport");
       return;
     }
@@ -362,7 +364,7 @@
 
 void LoadReporterAsyncServiceImpl::ReportLoadHandler::OnFinishDone(
     // NOLINTNEXTLINE(performance-unnecessary-value-param)
-    std::shared_ptr<ReportLoadHandler> self, bool ok) {
+    std::shared_ptr<ReportLoadHandler> /*self*/, bool ok) {
   if (ok) {
     gpr_log(GPR_INFO,
             "[LRS %p] Load reporting finished (lb_id_: %s, handler: %p).",
diff --git a/grpc/src/cpp/server/load_reporter/load_reporting_service_server_builder_plugin.cc b/grpc/src/cpp/server/load_reporter/load_reporting_service_server_builder_plugin.cc
index c2c5dd5..aa0ac19 100644
--- a/grpc/src/cpp/server/load_reporter/load_reporting_service_server_builder_plugin.cc
+++ b/grpc/src/cpp/server/load_reporter/load_reporting_service_server_builder_plugin.cc
@@ -51,7 +51,7 @@
 }
 
 void LoadReportingServiceServerBuilderPlugin::Finish(
-    grpc::ServerInitializer* si) {
+    grpc::ServerInitializer* /*si*/) {
   service_->StartThread();
   service_.reset();
 }
diff --git a/grpc/src/cpp/server/load_reporter/load_reporting_service_server_builder_plugin.h b/grpc/src/cpp/server/load_reporter/load_reporting_service_server_builder_plugin.h
index 781bbe1..22b8a72 100644
--- a/grpc/src/cpp/server/load_reporter/load_reporting_service_server_builder_plugin.h
+++ b/grpc/src/cpp/server/load_reporter/load_reporting_service_server_builder_plugin.h
@@ -44,8 +44,8 @@
   // Starts the load reporter service.
   void Finish(ServerInitializer* si) override;
 
-  void ChangeArguments(const std::string& name, void* value) override {}
-  void UpdateChannelArguments(grpc::ChannelArguments* args) override {}
+  void ChangeArguments(const std::string& /*name*/, void* /*value*/) override {}
+  void UpdateChannelArguments(grpc::ChannelArguments* /*args*/) override {}
   bool has_sync_methods() const override;
   bool has_async_methods() const override;
 
diff --git a/grpc/src/cpp/server/server_builder.cc b/grpc/src/cpp/server/server_builder.cc
index dc38125..695aa54 100644
--- a/grpc/src/cpp/server/server_builder.cc
+++ b/grpc/src/cpp/server/server_builder.cc
@@ -130,6 +130,12 @@
 }
 #endif
 
+ServerBuilder& ServerBuilder::experimental_type::SetContextAllocator(
+    std::unique_ptr<grpc::ContextAllocator> context_allocator) {
+  builder_->context_allocator_ = std::move(context_allocator);
+  return *builder_;
+}
+
 std::unique_ptr<grpc::experimental::ExternalConnectionAcceptor>
 ServerBuilder::experimental_type::AddExternalConnectionAcceptor(
     experimental_type::ExternalConnectionType type,
@@ -217,8 +223,8 @@
   return *this;
 }
 
-std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
-  grpc::ChannelArguments args;
+ChannelArguments ServerBuilder::BuildChannelArgs() {
+  ChannelArguments args;
   if (max_receive_message_size_ >= -1) {
     args.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, max_receive_message_size_);
   }
@@ -239,16 +245,19 @@
     args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM,
                 maybe_default_compression_algorithm_.algorithm);
   }
-
   if (resource_quota_ != nullptr) {
     args.SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA, resource_quota_,
                               grpc_resource_quota_arg_vtable());
   }
-
   for (const auto& plugin : plugins_) {
     plugin->UpdateServerBuilder(this);
     plugin->UpdateChannelArguments(&args);
   }
+  return args;
+}
+
+std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
+  ChannelArguments args = BuildChannelArgs();
 
   // == Determine if the server has any syncrhonous methods ==
   bool has_sync_methods = false;
@@ -298,6 +307,10 @@
     }
   }
 
+  if (callback_generic_service_ != nullptr) {
+    has_frequently_polled_cqs = true;
+  }
+
   const bool is_hybrid_server = has_sync_methods && has_frequently_polled_cqs;
 
   if (has_sync_methods) {
@@ -369,6 +382,13 @@
     return nullptr;
   }
 
+#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
+  server->RegisterContextAllocator(std::move(context_allocator_));
+#else
+  server->experimental_registration()->RegisterContextAllocator(
+      std::move(context_allocator_));
+#endif
+
   for (const auto& value : services_) {
     if (!server->RegisterService(value->host.get(), value->service)) {
       return nullptr;
diff --git a/grpc/src/cpp/server/server_callback.cc b/grpc/src/cpp/server/server_callback.cc
index f6b72c0..5b2d328 100644
--- a/grpc/src/cpp/server/server_callback.cc
+++ b/grpc/src/cpp/server/server_callback.cc
@@ -37,7 +37,7 @@
       explicit ClosureWithArg(ServerCallbackCall* call_arg) : call(call_arg) {
         GRPC_CLOSURE_INIT(
             &closure,
-            [](void* void_arg, grpc_error*) {
+            [](void* void_arg, grpc_error_handle) {
               ClosureWithArg* arg = static_cast<ClosureWithArg*>(void_arg);
               arg->call->CallOnDone();
               delete arg;
@@ -66,7 +66,7 @@
           : call(call_arg), reactor(reactor_arg) {
         GRPC_CLOSURE_INIT(
             &closure,
-            [](void* void_arg, grpc_error*) {
+            [](void* void_arg, grpc_error_handle) {
               ClosureWithArg* arg = static_cast<ClosureWithArg*>(void_arg);
               arg->reactor->OnCancel();
               arg->call->MaybeDone();
diff --git a/grpc/src/cpp/server/server_cc.cc b/grpc/src/cpp/server/server_cc.cc
index 2b5486a..a334cdd 100644
--- a/grpc/src/cpp/server/server_cc.cc
+++ b/grpc/src/cpp/server/server_cc.cc
@@ -45,7 +45,9 @@
 #include "absl/memory/memory.h"
 
 #include "src/core/ext/transport/inproc/inproc_transport.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/surface/call.h"
 #include "src/core/lib/surface/completion_queue.h"
@@ -65,6 +67,15 @@
 // max-threads set) to the server builder.
 #define DEFAULT_MAX_SYNC_SERVER_THREADS INT_MAX
 
+// Give a useful status error message if the resource is exhausted specifically
+// because the server threadpool is full.
+const char* kServerThreadpoolExhausted = "Server Threadpool Exhausted";
+
+// Although we might like to give a useful status error message on unimplemented
+// RPCs, it's not always possible since that also would need to be added across
+// languages and isn't actually required by the spec.
+const char* kUnknownRpcMethod = "";
+
 class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
  public:
   ~DefaultGlobalCallbacks() override {}
@@ -88,7 +99,7 @@
   }
 };
 
-class DummyTag : public internal::CompletionQueueTag {
+class PhonyTag : public internal::CompletionQueueTag {
  public:
   bool FinalizeResult(void** /*tag*/, bool* /*status*/) override {
     return true;
@@ -336,199 +347,171 @@
 
 class Server::SyncRequest final : public grpc::internal::CompletionQueueTag {
  public:
-  SyncRequest(grpc::internal::RpcServiceMethod* method, void* method_tag)
-      : method_(method),
-        method_tag_(method_tag),
-        in_flight_(false),
-        has_request_payload_(method->method_type() ==
-                                 grpc::internal::RpcMethod::NORMAL_RPC ||
-                             method->method_type() ==
-                                 grpc::internal::RpcMethod::SERVER_STREAMING),
-        call_details_(nullptr),
-        cq_(nullptr) {
-    grpc_metadata_array_init(&request_metadata_);
+  SyncRequest(Server* server, grpc::internal::RpcServiceMethod* method,
+              grpc_core::Server::RegisteredCallAllocation* data)
+      : SyncRequest(server, method) {
+    CommonSetup(data);
+    data->deadline = &deadline_;
+    data->optional_payload = has_request_payload_ ? &request_payload_ : nullptr;
+  }
+
+  SyncRequest(Server* server, grpc::internal::RpcServiceMethod* method,
+              grpc_core::Server::BatchCallAllocation* data)
+      : SyncRequest(server, method) {
+    CommonSetup(data);
+    call_details_ = new grpc_call_details;
+    grpc_call_details_init(call_details_);
+    data->details = call_details_;
   }
 
   ~SyncRequest() override {
-    if (call_details_) {
+    // The destructor should only cleanup those objects created in the
+    // constructor, since some paths may or may not actually go through the
+    // Run stage where other objects are allocated.
+    if (has_request_payload_ && request_payload_) {
+      grpc_byte_buffer_destroy(request_payload_);
+    }
+    if (call_details_ != nullptr) {
+      grpc_call_details_destroy(call_details_);
       delete call_details_;
     }
     grpc_metadata_array_destroy(&request_metadata_);
-  }
-
-  void SetupRequest() { cq_ = grpc_completion_queue_create_for_pluck(nullptr); }
-
-  void TeardownRequest() {
-    grpc_completion_queue_destroy(cq_);
-    cq_ = nullptr;
-  }
-
-  void Request(grpc_server* server, grpc_completion_queue* notify_cq) {
-    GPR_ASSERT(cq_ && !in_flight_);
-    in_flight_ = true;
-    if (method_tag_) {
-      if (grpc_server_request_registered_call(
-              server, method_tag_, &call_, &deadline_, &request_metadata_,
-              has_request_payload_ ? &request_payload_ : nullptr, cq_,
-              notify_cq, this) != GRPC_CALL_OK) {
-        TeardownRequest();
-        return;
-      }
-    } else {
-      if (!call_details_) {
-        call_details_ = new grpc_call_details;
-        grpc_call_details_init(call_details_);
-      }
-      if (grpc_server_request_call(server, &call_, call_details_,
-                                   &request_metadata_, cq_, notify_cq,
-                                   this) != GRPC_CALL_OK) {
-        TeardownRequest();
-        return;
-      }
-    }
-  }
-
-  void PostShutdownCleanup() {
-    if (call_) {
-      grpc_call_unref(call_);
-      call_ = nullptr;
-    }
-    if (cq_) {
-      grpc_completion_queue_destroy(cq_);
-      cq_ = nullptr;
-    }
+    server_->UnrefWithPossibleNotify();
   }
 
   bool FinalizeResult(void** /*tag*/, bool* status) override {
     if (!*status) {
-      grpc_completion_queue_destroy(cq_);
-      cq_ = nullptr;
+      delete this;
+      return false;
     }
     if (call_details_) {
       deadline_ = call_details_->deadline;
-      grpc_call_details_destroy(call_details_);
-      grpc_call_details_init(call_details_);
     }
     return true;
   }
 
-  // The CallData class represents a call that is "active" as opposed
-  // to just being requested. It wraps and takes ownership of the cq from
-  // the call request
-  class CallData final {
-   public:
-    explicit CallData(Server* server, SyncRequest* mrd)
-        : cq_(mrd->cq_),
-          ctx_(mrd->deadline_, &mrd->request_metadata_),
-          has_request_payload_(mrd->has_request_payload_),
-          request_payload_(has_request_payload_ ? mrd->request_payload_
-                                                : nullptr),
-          request_(nullptr),
-          method_(mrd->method_),
-          call_(
-              mrd->call_, server, &cq_, server->max_receive_message_size(),
-              ctx_.set_server_rpc_info(method_->name(), method_->method_type(),
-                                       server->interceptor_creators_)),
-          server_(server),
-          global_callbacks_(nullptr),
-          resources_(false) {
-      ctx_.set_call(mrd->call_);
-      ctx_.cq_ = &cq_;
-      GPR_ASSERT(mrd->in_flight_);
-      mrd->in_flight_ = false;
-      mrd->request_metadata_.count = 0;
-    }
+  void Run(const std::shared_ptr<GlobalCallbacks>& global_callbacks,
+           bool resources) {
+    ctx_.Init(deadline_, &request_metadata_);
+    wrapped_call_.Init(
+        call_, server_, &cq_, server_->max_receive_message_size(),
+        ctx_->ctx.set_server_rpc_info(method_->name(), method_->method_type(),
+                                      server_->interceptor_creators_));
+    ctx_->ctx.set_call(call_);
+    ctx_->ctx.cq_ = &cq_;
+    request_metadata_.count = 0;
 
-    ~CallData() {
-      if (has_request_payload_ && request_payload_) {
-        grpc_byte_buffer_destroy(request_payload_);
-      }
-    }
+    global_callbacks_ = global_callbacks;
+    resources_ = resources;
 
-    void Run(const std::shared_ptr<GlobalCallbacks>& global_callbacks,
-             bool resources) {
-      global_callbacks_ = global_callbacks;
-      resources_ = resources;
+    interceptor_methods_.SetCall(&*wrapped_call_);
+    interceptor_methods_.SetReverse();
+    // Set interception point for RECV INITIAL METADATA
+    interceptor_methods_.AddInterceptionHookPoint(
+        grpc::experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
+    interceptor_methods_.SetRecvInitialMetadata(&ctx_->ctx.client_metadata_);
 
-      interceptor_methods_.SetCall(&call_);
-      interceptor_methods_.SetReverse();
-      // Set interception point for RECV INITIAL METADATA
+    if (has_request_payload_) {
+      // Set interception point for RECV MESSAGE
+      auto* handler = resources_ ? method_->handler()
+                                 : server_->resource_exhausted_handler_.get();
+      deserialized_request_ = handler->Deserialize(call_, request_payload_,
+                                                   &request_status_, nullptr);
+
+      request_payload_ = nullptr;
       interceptor_methods_.AddInterceptionHookPoint(
-          grpc::experimental::InterceptionHookPoints::
-              POST_RECV_INITIAL_METADATA);
-      interceptor_methods_.SetRecvInitialMetadata(&ctx_.client_metadata_);
-
-      if (has_request_payload_) {
-        // Set interception point for RECV MESSAGE
-        auto* handler = resources_ ? method_->handler()
-                                   : server_->resource_exhausted_handler_.get();
-        request_ = handler->Deserialize(call_.call(), request_payload_,
-                                        &request_status_, nullptr);
-
-        request_payload_ = nullptr;
-        interceptor_methods_.AddInterceptionHookPoint(
-            grpc::experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
-        interceptor_methods_.SetRecvMessage(request_, nullptr);
-      }
-
-      if (interceptor_methods_.RunInterceptors(
-              [this]() { ContinueRunAfterInterception(); })) {
-        ContinueRunAfterInterception();
-      } else {
-        // There were interceptors to be run, so ContinueRunAfterInterception
-        // will be run when interceptors are done.
-      }
+          grpc::experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+      interceptor_methods_.SetRecvMessage(deserialized_request_, nullptr);
     }
 
-    void ContinueRunAfterInterception() {
-      {
-        ctx_.BeginCompletionOp(&call_, nullptr, nullptr);
-        global_callbacks_->PreSynchronousRequest(&ctx_);
-        auto* handler = resources_ ? method_->handler()
-                                   : server_->resource_exhausted_handler_.get();
-        handler->RunHandler(grpc::internal::MethodHandler::HandlerParameter(
-            &call_, &ctx_, request_, request_status_, nullptr, nullptr));
-        request_ = nullptr;
-        global_callbacks_->PostSynchronousRequest(&ctx_);
-
-        cq_.Shutdown();
-
-        grpc::internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag();
-        cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME));
-
-        /* Ensure the cq_ is shutdown */
-        grpc::DummyTag ignored_tag;
-        GPR_ASSERT(cq_.Pluck(&ignored_tag) == false);
-      }
-      delete this;
+    if (interceptor_methods_.RunInterceptors(
+            [this]() { ContinueRunAfterInterception(); })) {
+      ContinueRunAfterInterception();
+    } else {
+      // There were interceptors to be run, so ContinueRunAfterInterception
+      // will be run when interceptors are done.
     }
+  }
 
-   private:
-    grpc::CompletionQueue cq_;
-    grpc::ServerContext ctx_;
-    const bool has_request_payload_;
-    grpc_byte_buffer* request_payload_;
-    void* request_;
-    grpc::Status request_status_;
-    grpc::internal::RpcServiceMethod* const method_;
-    grpc::internal::Call call_;
-    Server* server_;
-    std::shared_ptr<GlobalCallbacks> global_callbacks_;
-    bool resources_;
-    grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_;
-  };
+  void ContinueRunAfterInterception() {
+    ctx_->ctx.BeginCompletionOp(&*wrapped_call_, nullptr, nullptr);
+    global_callbacks_->PreSynchronousRequest(&ctx_->ctx);
+    auto* handler = resources_ ? method_->handler()
+                               : server_->resource_exhausted_handler_.get();
+    handler->RunHandler(grpc::internal::MethodHandler::HandlerParameter(
+        &*wrapped_call_, &ctx_->ctx, deserialized_request_, request_status_,
+        nullptr, nullptr));
+    global_callbacks_->PostSynchronousRequest(&ctx_->ctx);
+
+    cq_.Shutdown();
+
+    grpc::internal::CompletionQueueTag* op_tag = ctx_->ctx.GetCompletionOpTag();
+    cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME));
+
+    // Ensure the cq_ is shutdown
+    grpc::PhonyTag ignored_tag;
+    GPR_ASSERT(cq_.Pluck(&ignored_tag) == false);
+
+    // Cleanup structures allocated during Run/ContinueRunAfterInterception
+    wrapped_call_.Destroy();
+    ctx_.Destroy();
+
+    delete this;
+  }
+
+  // For requests that must be only cleaned up but not actually Run
+  void Cleanup() {
+    cq_.Shutdown();
+    grpc_call_unref(call_);
+    delete this;
+  }
 
  private:
+  SyncRequest(Server* server, grpc::internal::RpcServiceMethod* method)
+      : server_(server),
+        method_(method),
+        has_request_payload_(method->method_type() ==
+                                 grpc::internal::RpcMethod::NORMAL_RPC ||
+                             method->method_type() ==
+                                 grpc::internal::RpcMethod::SERVER_STREAMING),
+        cq_(grpc_completion_queue_create_for_pluck(nullptr)) {}
+
+  template <class CallAllocation>
+  void CommonSetup(CallAllocation* data) {
+    server_->Ref();
+    grpc_metadata_array_init(&request_metadata_);
+    data->tag = static_cast<void*>(this);
+    data->call = &call_;
+    data->initial_metadata = &request_metadata_;
+    data->cq = cq_.cq();
+  }
+
+  Server* const server_;
   grpc::internal::RpcServiceMethod* const method_;
-  void* const method_tag_;
-  bool in_flight_;
   const bool has_request_payload_;
   grpc_call* call_;
-  grpc_call_details* call_details_;
+  grpc_call_details* call_details_ = nullptr;
   gpr_timespec deadline_;
   grpc_metadata_array request_metadata_;
-  grpc_byte_buffer* request_payload_;
-  grpc_completion_queue* cq_;
+  grpc_byte_buffer* request_payload_ = nullptr;
+  grpc::CompletionQueue cq_;
+  grpc::Status request_status_;
+  std::shared_ptr<GlobalCallbacks> global_callbacks_;
+  bool resources_;
+  void* deserialized_request_ = nullptr;
+  grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_;
+
+  // ServerContextWrapper allows ManualConstructor while using a private
+  // contructor of ServerContext via this friend class.
+  struct ServerContextWrapper {
+    ServerContext ctx;
+
+    ServerContextWrapper(gpr_timespec deadline, grpc_metadata_array* arr)
+        : ctx(deadline, arr) {}
+  };
+
+  grpc_core::ManualConstructor<ServerContextWrapper> ctx_;
+  grpc_core::ManualConstructor<internal::Call> wrapped_call_;
 };
 
 template <class ServerContextType>
@@ -552,7 +535,10 @@
                              method->method_type() ==
                                  grpc::internal::RpcMethod::SERVER_STREAMING),
         cq_(cq),
-        tag_(this) {
+        tag_(this),
+        ctx_(server_->context_allocator() != nullptr
+                 ? server_->context_allocator()->NewCallbackServerContext()
+                 : nullptr) {
     CommonSetup(server, data);
     data->deadline = &deadline_;
     data->optional_payload = has_request_payload_ ? &request_payload_ : nullptr;
@@ -567,7 +553,11 @@
         has_request_payload_(false),
         call_details_(new grpc_call_details),
         cq_(cq),
-        tag_(this) {
+        tag_(this),
+        ctx_(server_->context_allocator() != nullptr
+                 ? server_->context_allocator()
+                       ->NewGenericCallbackServerContext()
+                 : nullptr) {
     CommonSetup(server, data);
     grpc_call_details_init(call_details_);
     data->details = call_details_;
@@ -579,6 +569,9 @@
     if (has_request_payload_ && request_payload_) {
       grpc_byte_buffer_destroy(request_payload_);
     }
+    if (ctx_alloc_by_default_ || server_->context_allocator() == nullptr) {
+      default_ctx_.Destroy();
+    }
     server_->UnrefWithPossibleNotify();
   }
 
@@ -631,10 +624,10 @@
       }
 
       // Bind the call, deadline, and metadata from what we got
-      req_->ctx_.set_call(req_->call_);
-      req_->ctx_.cq_ = req_->cq_;
-      req_->ctx_.BindDeadlineAndMetadata(req_->deadline_,
-                                         &req_->request_metadata_);
+      req_->ctx_->set_call(req_->call_);
+      req_->ctx_->cq_ = req_->cq_;
+      req_->ctx_->BindDeadlineAndMetadata(req_->deadline_,
+                                          &req_->request_metadata_);
       req_->request_metadata_.count = 0;
 
       // Create a C++ Call to control the underlying core call
@@ -643,7 +636,7 @@
               grpc::internal::Call(
                   req_->call_, req_->server_, req_->cq_,
                   req_->server_->max_receive_message_size(),
-                  req_->ctx_.set_server_rpc_info(
+                  req_->ctx_->set_server_rpc_info(
                       req_->method_name(),
                       (req_->method_ != nullptr)
                           ? req_->method_->method_type()
@@ -657,7 +650,7 @@
           grpc::experimental::InterceptionHookPoints::
               POST_RECV_INITIAL_METADATA);
       req_->interceptor_methods_.SetRecvInitialMetadata(
-          &req_->ctx_.client_metadata_);
+          &req_->ctx_->client_metadata_);
 
       if (req_->has_request_payload_) {
         // Set interception point for RECV MESSAGE
@@ -683,7 +676,7 @@
                           ? req_->method_->handler()
                           : req_->server_->generic_handler_.get();
       handler->RunHandler(grpc::internal::MethodHandler::HandlerParameter(
-          call_, &req_->ctx_, req_->request_, req_->request_status_,
+          call_, req_->ctx_, req_->request_, req_->request_status_,
           req_->handler_data_, [this] { delete req_; }));
     }
   };
@@ -692,9 +685,16 @@
   void CommonSetup(Server* server, CallAllocation* data) {
     server->Ref();
     grpc_metadata_array_init(&request_metadata_);
-    data->tag = &tag_;
+    data->tag = static_cast<void*>(&tag_);
     data->call = &call_;
     data->initial_metadata = &request_metadata_;
+    if (ctx_ == nullptr) {
+      default_ctx_.Init();
+      ctx_ = &*default_ctx_;
+      ctx_alloc_by_default_ = true;
+    }
+    ctx_->set_context_allocator(server->context_allocator());
+    data->cq = cq_->cq();
   }
 
   Server* const server_;
@@ -709,8 +709,10 @@
   gpr_timespec deadline_;
   grpc_metadata_array request_metadata_;
   grpc::CompletionQueue* const cq_;
+  bool ctx_alloc_by_default_ = false;
   CallbackCallTag tag_;
-  ServerContextType ctx_;
+  ServerContextType* ctx_ = nullptr;
+  grpc_core::ManualConstructor<ServerContextType> default_ctx_;
   grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_;
 };
 
@@ -727,8 +729,8 @@
   if (*status) {
     deadline_ = call_details_->deadline;
     // TODO(yangg) remove the copy here
-    ctx_.method_ = grpc::StringFromCopiedSlice(call_details_->method);
-    ctx_.host_ = grpc::StringFromCopiedSlice(call_details_->host);
+    ctx_->method_ = grpc::StringFromCopiedSlice(call_details_->method);
+    ctx_->host_ = grpc::StringFromCopiedSlice(call_details_->host);
   }
   grpc_slice_unref(call_details_->method);
   grpc_slice_unref(call_details_->host);
@@ -744,7 +746,7 @@
 template <>
 const char* Server::CallbackRequest<
     grpc::GenericCallbackServerContext>::method_name() const {
-  return ctx_.method().c_str();
+  return ctx_->method().c_str();
 }
 
 // Implementation of ThreadManager. Each instance of SyncRequestThreadManager
@@ -783,44 +785,39 @@
   }
 
   void DoWork(void* tag, bool ok, bool resources) override {
+    (void)ok;
     SyncRequest* sync_req = static_cast<SyncRequest*>(tag);
 
-    if (!sync_req) {
-      // No tag. Nothing to work on. This is an unlikley scenario and possibly a
-      // bug in RPC Manager implementation.
-      gpr_log(GPR_ERROR, "Sync server. DoWork() was called with NULL tag");
-      return;
-    }
+    // Under the AllocatingRequestMatcher model we will never see an invalid tag
+    // here.
+    GPR_DEBUG_ASSERT(sync_req != nullptr);
+    GPR_DEBUG_ASSERT(ok);
 
-    if (ok) {
-      // Calldata takes ownership of the completion queue and interceptors
-      // inside sync_req
-      auto* cd = new SyncRequest::CallData(server_, sync_req);
-      // Prepare for the next request
-      if (!IsShutdown()) {
-        sync_req->SetupRequest();  // Create new completion queue for sync_req
-        sync_req->Request(server_->c_server(), server_cq_->cq());
-      }
-
-      GPR_TIMER_SCOPE("cd.Run()", 0);
-      cd->Run(global_callbacks_, resources);
-    }
-    // TODO (sreek) If ok is false here (which it isn't in case of
-    // grpc_request_registered_call), we should still re-queue the request
-    // object
+    GPR_TIMER_SCOPE("sync_req->Run()", 0);
+    sync_req->Run(global_callbacks_, resources);
   }
 
   void AddSyncMethod(grpc::internal::RpcServiceMethod* method, void* tag) {
-    sync_requests_.emplace_back(new SyncRequest(method, tag));
+    server_->server()->core_server->SetRegisteredMethodAllocator(
+        server_cq_->cq(), tag, [this, method] {
+          grpc_core::Server::RegisteredCallAllocation result;
+          new SyncRequest(server_, method, &result);
+          return result;
+        });
+    has_sync_method_ = true;
   }
 
   void AddUnknownSyncMethod() {
-    if (!sync_requests_.empty()) {
+    if (has_sync_method_) {
       unknown_method_ = absl::make_unique<grpc::internal::RpcServiceMethod>(
           "unknown", grpc::internal::RpcMethod::BIDI_STREAMING,
-          new grpc::internal::UnknownMethodHandler);
-      sync_requests_.emplace_back(
-          new SyncRequest(unknown_method_.get(), nullptr));
+          new grpc::internal::UnknownMethodHandler(kUnknownRpcMethod));
+      server_->server()->core_server->SetBatchMethodAllocator(
+          server_cq_->cq(), [this] {
+            grpc_core::Server::BatchCallAllocation result;
+            new SyncRequest(server_, unknown_method_.get(), &result);
+            return result;
+          });
     }
   }
 
@@ -835,27 +832,14 @@
     void* tag;
     bool ok;
     while (server_cq_->Next(&tag, &ok)) {
-      if (ok) {
-        // If a request was pulled off the queue, it means that the thread
-        // handling the request added it to the completion queue after shutdown
-        // was called - because the thread had already started and checked the
-        // shutdown flag before shutdown was called. In this case, we simply
-        // clean it up here, *after* calling wait on all the worker threads, at
-        // which point we are certain no in-flight requests will add more to the
-        // queue. This fixes an intermittent memory leak on shutdown.
-        SyncRequest* sync_req = static_cast<SyncRequest*>(tag);
-        sync_req->PostShutdownCleanup();
-      }
+      // This problem can arise if the server CQ gets a request queued to it
+      // before it gets shutdown but then pulls it after shutdown.
+      static_cast<SyncRequest*>(tag)->Cleanup();
     }
   }
 
   void Start() {
-    if (!sync_requests_.empty()) {
-      for (const auto& value : sync_requests_) {
-        value->SetupRequest();
-        value->Request(server_->c_server(), server_cq_->cq());
-      }
-
+    if (has_sync_method_) {
       Initialize();  // ThreadManager's Initialize()
     }
   }
@@ -864,7 +848,7 @@
   Server* server_;
   grpc::CompletionQueue* server_cq_;
   int cq_timeout_msec_;
-  std::vector<std::unique_ptr<SyncRequest>> sync_requests_;
+  bool has_sync_method_ = false;
   std::unique_ptr<grpc::internal::RpcServiceMethod> unknown_method_;
   std::shared_ptr<Server::GlobalCallbacks> global_callbacks_;
 };
@@ -948,16 +932,23 @@
   {
     grpc::internal::ReleasableMutexLock lock(&mu_);
     if (started_ && !shutdown_) {
-      lock.Unlock();
+      lock.Release();
       Shutdown();
     } else if (!started_) {
       // Shutdown the completion queues
       for (const auto& value : sync_req_mgrs_) {
         value->Shutdown();
       }
-      if (callback_cq_ != nullptr) {
-        callback_cq_->Shutdown();
-        callback_cq_ = nullptr;
+      CompletionQueue* callback_cq =
+          callback_cq_.load(std::memory_order_relaxed);
+      if (callback_cq != nullptr) {
+        if (grpc_iomgr_run_in_background()) {
+          // gRPC-core provides the backing needed for the preferred CQ type
+          callback_cq->Shutdown();
+        } else {
+          CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
+        }
+        callback_cq_.store(nullptr, std::memory_order_release);
       }
     }
   }
@@ -1124,7 +1115,9 @@
     shutdown_done_ = true;
     return;  // no need to wait on CV since done condition already set
   }
-  shutdown_done_cv_.WaitUntil(&mu_, [this] { return shutdown_done_; });
+  grpc::internal::WaitUntil(
+      &shutdown_done_cv_, &mu_,
+      [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) { return shutdown_done_; });
 }
 
 void Server::Start(grpc::ServerCompletionQueue** cqs, size_t num_cqs) {
@@ -1173,13 +1166,27 @@
   }
 #endif
 
+  // If we have a generic service, all unmatched method names go there.
+  // Otherwise, we must provide at least one RPC request for an "unimplemented"
+  // RPC, which covers any RPC for a method name that isn't matched. If we
+  // have a sync service, let it be a sync unimplemented RPC, which must be
+  // registered before server start (to initialize an AllocatingRequestMatcher).
+  // If we have an AllocatingRequestMatcher, we can't also specify other
+  // unimplemented RPCs via explicit async requests, so we won't do so. If we
+  // only have async services, we can specify unimplemented RPCs on each async
+  // CQ so that some user polling thread will move them along as long as some
+  // progress is being made on any RPCs in the system.
+  bool unknown_rpc_needed =
+      !has_async_generic_service_ && !has_callback_generic_service_;
+
+  if (unknown_rpc_needed && !sync_req_mgrs_.empty()) {
+    sync_req_mgrs_[0]->AddUnknownSyncMethod();
+    unknown_rpc_needed = false;
+  }
+
   grpc_server_start(server_);
 
-  if (!has_async_generic_service_ && !has_callback_generic_service_) {
-    for (const auto& value : sync_req_mgrs_) {
-      value->AddUnknownSyncMethod();
-    }
-
+  if (unknown_rpc_needed) {
     for (size_t i = 0; i < num_cqs; i++) {
       if (cqs[i]->IsFrequentlyPolled()) {
         new UnimplementedAsyncRequest(this, cqs[i]);
@@ -1188,6 +1195,7 @@
     if (health_check_cq != nullptr) {
       new UnimplementedAsyncRequest(this, health_check_cq);
     }
+    unknown_rpc_needed = false;
   }
 
   // If this server has any support for synchronous methods (has any sync
@@ -1195,7 +1203,8 @@
   // to deal with the case of thread exhaustion
   if (sync_server_cqs_ != nullptr && !sync_server_cqs_->empty()) {
     resource_exhausted_handler_ =
-        absl::make_unique<grpc::internal::ResourceExhaustedHandler>();
+        absl::make_unique<grpc::internal::ResourceExhaustedHandler>(
+            kServerThreadpoolExhausted);
   }
 
   for (const auto& value : sync_req_mgrs_) {
@@ -1225,7 +1234,7 @@
 
   /// The completion queue to use for server shutdown completion notification
   grpc::CompletionQueue shutdown_cq;
-  grpc::ShutdownTag shutdown_tag;  // Dummy shutdown tag
+  grpc::ShutdownTag shutdown_tag;  // Phony shutdown tag
   grpc_server_shutdown_and_notify(server_, shutdown_cq.cq(), &shutdown_tag);
 
   shutdown_cq.Shutdown();
@@ -1243,6 +1252,9 @@
   // Else in case of SHUTDOWN or GOT_EVENT, it means that the server has
   // successfully shutdown
 
+  // Drop the shutdown ref and wait for all other refs to drop as well.
+  UnrefAndWaitLocked();
+
   // Shutdown all ThreadManagers. This will try to gracefully stop all the
   // threads in the ThreadManagers (once they process any inflight requests)
   for (const auto& value : sync_req_mgrs_) {
@@ -1254,14 +1266,17 @@
     value->Wait();
   }
 
-  // Drop the shutdown ref and wait for all other refs to drop as well.
-  UnrefAndWaitLocked();
-
   // Shutdown the callback CQ. The CQ is owned by its own shutdown tag, so it
   // will delete itself at true shutdown.
-  if (callback_cq_ != nullptr) {
-    callback_cq_->Shutdown();
-    callback_cq_ = nullptr;
+  CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_relaxed);
+  if (callback_cq != nullptr) {
+    if (grpc_iomgr_run_in_background()) {
+      // gRPC-core provides the backing needed for the preferred CQ type
+      callback_cq->Shutdown();
+    } else {
+      CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
+    }
+    callback_cq_.store(nullptr, std::memory_order_release);
   }
 
   // Drain the shutdown queue (if the previous call to AsyncNext() timed out
@@ -1271,7 +1286,7 @@
   }
 
   shutdown_notified_ = true;
-  shutdown_cv_.Broadcast();
+  shutdown_cv_.SignalAll();
 
 #ifndef NDEBUG
   // Unregister this server with the CQs passed into it by the user so that
@@ -1316,8 +1331,9 @@
 Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse(
     UnimplementedAsyncRequest* request)
     : request_(request) {
-  grpc::Status status(grpc::StatusCode::UNIMPLEMENTED, "");
-  grpc::internal::UnknownMethodHandler::FillOps(request_->context(), this);
+  grpc::Status status(grpc::StatusCode::UNIMPLEMENTED, kUnknownRpcMethod);
+  grpc::internal::UnknownMethodHandler::FillOps(request_->context(),
+                                                kUnknownRpcMethod, this);
   request_->stream()->call_.PerformOps(this);
 }
 
@@ -1328,19 +1344,33 @@
 grpc::CompletionQueue* Server::CallbackCQ() {
   // TODO(vjpai): Consider using a single global CQ for the default CQ
   // if there is no explicit per-server CQ registered
-  grpc::internal::MutexLock l(&mu_);
-  if (callback_cq_ != nullptr) {
-    return callback_cq_;
+  CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_acquire);
+  if (callback_cq != nullptr) {
+    return callback_cq;
   }
-  auto* shutdown_callback = new grpc::ShutdownCallback;
-  callback_cq_ = new grpc::CompletionQueue(grpc_completion_queue_attributes{
-      GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
-      shutdown_callback});
+  // The callback_cq_ wasn't already set, so grab a lock and set it up exactly
+  // once for this server.
+  grpc::internal::MutexLock l(&mu_);
+  callback_cq = callback_cq_.load(std::memory_order_relaxed);
+  if (callback_cq != nullptr) {
+    return callback_cq;
+  }
+  if (grpc_iomgr_run_in_background()) {
+    // gRPC-core provides the backing needed for the preferred CQ type
+    auto* shutdown_callback = new grpc::ShutdownCallback;
+    callback_cq = new grpc::CompletionQueue(grpc_completion_queue_attributes{
+        GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
+        shutdown_callback});
 
-  // Transfer ownership of the new cq to its own shutdown callback
-  shutdown_callback->TakeCQ(callback_cq_);
+    // Transfer ownership of the new cq to its own shutdown callback
+    shutdown_callback->TakeCQ(callback_cq);
+  } else {
+    // Otherwise we need to use the alternative CQ variant
+    callback_cq = CompletionQueue::CallbackAlternativeCQ();
+  }
 
-  return callback_cq_;
+  callback_cq_.store(callback_cq, std::memory_order_release);
+  return callback_cq;
 }
 
 }  // namespace grpc
diff --git a/grpc/src/cpp/server/server_context.cc b/grpc/src/cpp/server/server_context.cc
index cb9cf43..2cb014b 100644
--- a/grpc/src/cpp/server/server_context.cc
+++ b/grpc/src/cpp/server/server_context.cc
@@ -28,6 +28,7 @@
 #include <grpc/support/log.h>
 #include <grpcpp/impl/call.h>
 #include <grpcpp/impl/codegen/completion_queue.h>
+#include <grpcpp/impl/grpc_library.h>
 #include <grpcpp/support/server_callback.h>
 #include <grpcpp/support/time.h>
 
@@ -37,6 +38,8 @@
 
 namespace grpc {
 
+static internal::GrpcLibraryInitializer g_gli_initializer;
+
 // CompletionOp
 
 class ServerContextBase::CompletionOp final
@@ -126,7 +129,7 @@
       // Unref can delete this, so do not access anything from this afterward.
       return;
     }
-    /* Start a dummy op so that we can return the tag */
+    /* Start a phony op so that we can return the tag */
     GPR_ASSERT(grpc_call_start_batch(call_.call(), nullptr, 0, core_cq_tag_,
                                      nullptr) == GRPC_CALL_OK);
   }
@@ -233,7 +236,9 @@
 // ServerContextBase body
 
 ServerContextBase::ServerContextBase()
-    : deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)) {}
+    : deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)) {
+  g_gli_initializer.summon();
+}
 
 ServerContextBase::ServerContextBase(gpr_timespec deadline,
                                      grpc_metadata_array* arr)
diff --git a/grpc/src/cpp/server/server_credentials.cc b/grpc/src/cpp/server/server_credentials.cc
index c3b3a8b..36b5a52 100644
--- a/grpc/src/cpp/server/server_credentials.cc
+++ b/grpc/src/cpp/server/server_credentials.cc
@@ -18,8 +18,13 @@
 
 #include <grpcpp/security/server_credentials.h>
 
+#include <grpcpp/impl/grpc_library.h>
+
 namespace grpc {
 
+static internal::GrpcLibraryInitializer g_gli_initializer;
+ServerCredentials::ServerCredentials() { g_gli_initializer.summon(); }
+
 ServerCredentials::~ServerCredentials() {}
 
 }  // namespace grpc
diff --git a/grpc/src/cpp/thread_manager/thread_manager.cc b/grpc/src/cpp/thread_manager/thread_manager.cc
index c8560aa..5155f61 100644
--- a/grpc/src/cpp/thread_manager/thread_manager.cc
+++ b/grpc/src/cpp/thread_manager/thread_manager.cc
@@ -152,7 +152,7 @@
     bool ok;
     WorkStatus work_status = PollForWork(&tag, &ok);
 
-    grpc_core::ReleasableMutexLock lock(&mu_);
+    grpc_core::LockableAndReleasableMutexLock lock(&mu_);
     // Reduce the number of pollers by 1 and check what happened with the poll
     num_pollers_--;
     bool done = false;
@@ -179,7 +179,7 @@
               max_active_threads_sofar_ = num_threads_;
             }
             // Drop lock before spawning thread to avoid contention
-            lock.Unlock();
+            lock.Release();
             WorkerThread* worker = new WorkerThread(this);
             if (worker->created()) {
               worker->Start();
@@ -195,17 +195,17 @@
             // There is still at least some thread polling, so we can go on
             // even though we are below the number of pollers that we would
             // like to have (min_pollers_)
-            lock.Unlock();
+            lock.Release();
           } else {
             // There are no pollers to spare and we couldn't allocate
             // a new thread, so resources are exhausted!
-            lock.Unlock();
+            lock.Release();
             resource_exhausted = true;
           }
         } else {
           // There are a sufficient number of pollers available so we can do
           // the work and continue polling with our existing poller threads
-          lock.Unlock();
+          lock.Release();
         }
         // Lock is always released at this point - do the application work
         // or return resource exhausted if there is new work but we couldn't
diff --git a/grpc/src/cpp/util/error_details.cc b/grpc/src/cpp/util/error_details.cc
index f35a612..0330f01 100644
--- a/grpc/src/cpp/util/error_details.cc
+++ b/grpc/src/cpp/util/error_details.cc
@@ -17,34 +17,3 @@
  */
 
 #include <grpcpp/support/error_details.h>
-
-#include "src/proto/grpc/status/status.pb.h"
-
-namespace grpc {
-
-grpc::Status ExtractErrorDetails(const grpc::Status& from,
-                                 ::google::rpc::Status* to) {
-  if (to == nullptr) {
-    return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "");
-  }
-  if (!to->ParseFromString(from.error_details())) {
-    return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "");
-  }
-  return grpc::Status::OK;
-}
-
-grpc::Status SetErrorDetails(const ::google::rpc::Status& from,
-                             grpc::Status* to) {
-  if (to == nullptr) {
-    return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "");
-  }
-  grpc::StatusCode code = grpc::StatusCode::UNKNOWN;
-  if (from.code() >= grpc::StatusCode::OK &&
-      from.code() <= grpc::StatusCode::UNAUTHENTICATED) {
-    code = static_cast<grpc::StatusCode>(from.code());
-  }
-  *to = grpc::Status(code, from.message(), from.SerializeAsString());
-  return grpc::Status::OK;
-}
-
-}  // namespace grpc
diff --git a/grpc/src/proto/gen_build_yaml.py b/grpc/src/proto/gen_build_yaml.py
index e310d4c..dea444f 100755
--- a/grpc/src/proto/gen_build_yaml.py
+++ b/grpc/src/proto/gen_build_yaml.py
@@ -27,7 +27,8 @@
         with open(proto_filename) as inp:
             for line in inp:
                 imp = re.search(r'import "([^"]*)"', line)
-                if not imp: continue
+                if not imp:
+                    continue
                 imp_proto = imp.group(1)
                 # This indicates an external dependency, which we should handle
                 # differently and not traverse recursively
@@ -40,7 +41,8 @@
                 # revert the change to avoid file error.
                 if imp_proto.startswith('third_party/grpc'):
                     imp_proto = imp_proto[17:]
-                if key not in deps: deps[key] = []
+                if key not in deps:
+                    deps[key] = []
                 deps[key].append(imp_proto[:-6])
                 if is_trans:
                     update_deps(key, imp_proto, deps, deps_external, is_trans,
@@ -57,7 +59,8 @@
     deps_external_trans = {}
     for root, dirs, files in os.walk('src/proto'):
         for f in files:
-            if f[-6:] != '.proto': continue
+            if f[-6:] != '.proto':
+                continue
             look_at = os.path.join(root, f)
             deps_for = look_at[:-6]
             # First level deps
diff --git a/grpc/src/proto/grpc/auth/v1/BUILD b/grpc/src/proto/grpc/auth/v1/BUILD
new file mode 100644
index 0000000..0e487b2
--- /dev/null
+++ b/grpc/src/proto/grpc/auth/v1/BUILD
@@ -0,0 +1,25 @@
+# Copyright 2021 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.
+
+licenses(["notice"])
+
+load("@rules_proto//proto:defs.bzl", "proto_library")
+
+proto_library(
+    name = "authz_policy_proto",
+    srcs = [
+        "authz_policy.proto",
+    ],
+    visibility = ["//visibility:public"],
+)
diff --git a/grpc/src/proto/grpc/auth/v1/authz_policy.proto b/grpc/src/proto/grpc/auth/v1/authz_policy.proto
new file mode 100644
index 0000000..347386f
--- /dev/null
+++ b/grpc/src/proto/grpc/auth/v1/authz_policy.proto
@@ -0,0 +1,122 @@
+// Copyright 2021 The 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.
+
+syntax = "proto3";
+
+package grpc.auth.v1;
+
+// Peer specifies attributes of a peer. Fields in the Peer are ANDed together, once
+// we support multiple fields in the future.
+message Peer {
+  // Optional. A list of peer identities to match for authorization. The principals
+  // are one of, i.e., it matches if one of the principals matches. The field
+  // supports Exact, Prefix, Suffix, and Presence matches.
+  // - Exact match: "abc" will match on value "abc".
+  // - Prefix match: "abc*" will match on value "abc" and "abcd".
+  // - Suffix match: "*abc" will match on value "abc" and "xabc".
+  // - Presence match: "*" will match when the value is not empty.
+  repeated string principals = 1;
+}
+
+// Specification of HTTP header match attributes.
+message Header {
+  // Required. The name of the HTTP header to match. The following headers are *not*
+  // supported: "hop-by-hop" headers (e.g., those listed in "Connection" header),
+  // HTTP/2 pseudo headers (":"-prefixed), the "Host" header, and headers prefixed
+  // with "grpc-".
+  string key = 1;
+
+  // Required. A list of header values to match. The header values are ORed together,
+  // i.e., it matches if one of the values matches. This field supports Exact,
+  // Prefix, Suffix, and Presence match. Multi-valued headers are considered a single
+  // value with commas added between values.
+  // - Exact match: "abc" will match on value "abc".
+  // - Prefix match: "abc*" will match on value "abc" and "abcd".
+  // - Suffix match: "*abc" will match on value "abc" and "xabc".
+  // - Presence match: "*" will match when the value is not empty.
+  repeated string values = 2;
+}
+
+// Request specifies attributes of a request. Fields in the Request are ANDed
+// together.
+message Request {
+  // Optional. A list of paths to match for authorization. This is the fully
+  // qualified name in the form of "/package.service/method". The paths are ORed
+  // together, i.e., it matches if one of the paths matches. This field supports
+  // Exact, Prefix, Suffix, and Presence matches.
+  // - Exact match: "abc" will match on value "abc".
+  // - Prefix match: "abc*" will match on value "abc" and "abcd".
+  // - Suffix match: "*abc" will match on value "abc" and "xabc".
+  // - Presence match: "*" will match when the value is not empty.
+  repeated string paths = 1;
+
+  // Optional. A list of HTTP header key/value pairs to match against, for
+  // potentially advanced use cases. The headers are ANDed together, i.e., it matches
+  // only if *all* the headers match.
+  repeated Header headers = 3;
+}
+
+// Specification of rules.
+message Rule {
+  // Required. The name of an authorization rule.
+  // It is mainly for monitoring and error message generation.
+  string name = 1;
+
+  // Optional. If not set, no checks will be performed against the source. An empty
+  // rule is always matched (i.e., both source and request are empty).
+  Peer source = 2;
+
+  // Optional. If not set, no checks will be performed against the request. An empty
+  // rule is always matched (i.e., both source and request are empty).
+  Request request = 3;
+}
+
+// AuthorizationPolicy defines which principals are permitted to access which
+// resource. Resources are RPC methods scoped by services.
+//
+// In the following yaml policy example, a peer identity from ["admin1", "admin2", "admin3"] 
+// is authorized to access any RPC methods in pkg.service, and peer identity "dev" is 
+// authorized to access the "foo" and "bar" RPC methods.
+//
+// name: example-policy
+// allow_rules:
+// - name: admin-access
+//   source:
+//     principals:
+//     - "spiffe://foo.com/sa/admin1"
+//     - "spiffe://foo.com/sa/admin2"
+//     - "spiffe://foo.com/sa/admin3"
+//   request:
+//     paths: ["/pkg.service/*"]
+// - name: dev-access
+//   source:
+//     principals: ["spiffe://foo.com/sa/dev"]
+//   request:
+//     paths: ["/pkg.service/foo", "/pkg.service/bar"]
+
+message AuthorizationPolicy {
+  // Required. The name of an authorization policy.
+  // It is mainly for monitoring and error message generation.
+  string name = 1;
+
+  // Optional. List of deny rules to match. If a request matches any of the deny
+  // rules, then it will be denied. If none of the deny rules matches or there are
+  // no deny rules, the allow rules will be evaluated.
+  repeated Rule deny_rules = 2;
+
+  // Required. List of allow rules to match. The allow rules will only be evaluated
+  // after the deny rules. If a request matches any of the allow rules, then it will
+  // allowed. If none of the allow rules matches, it will be denied. 
+  repeated Rule allow_rules = 3;
+}
diff --git a/grpc/src/proto/grpc/testing/messages.proto b/grpc/src/proto/grpc/testing/messages.proto
index 5acc2f0..559876e 100644
--- a/grpc/src/proto/grpc/testing/messages.proto
+++ b/grpc/src/proto/grpc/testing/messages.proto
@@ -219,11 +219,27 @@
 // Accumulated stats for RPCs sent by a test client.
 message LoadBalancerAccumulatedStatsResponse {
   // The total number of RPCs have ever issued for each type.
-  map<string, int32> num_rpcs_started_by_method = 1;
+  // Deprecated: use stats_per_method.rpcs_started instead.
+  map<string, int32> num_rpcs_started_by_method = 1 [deprecated = true];
   // The total number of RPCs have ever completed successfully for each type.
-  map<string, int32> num_rpcs_succeeded_by_method = 2;
+  // Deprecated: use stats_per_method.result instead.
+  map<string, int32> num_rpcs_succeeded_by_method = 2 [deprecated = true];
   // The total number of RPCs have ever failed for each type.
-  map<string, int32> num_rpcs_failed_by_method = 3;
+  // Deprecated: use stats_per_method.result instead.
+  map<string, int32> num_rpcs_failed_by_method = 3 [deprecated = true];
+
+  message MethodStats {
+    // The number of RPCs that were started for this method.
+    int32 rpcs_started = 1;
+
+    // The number of RPCs that completed with each status for this method.  The
+    // key is the integral value of a google.rpc.Code; the value is the count.
+    map<int32, int32> result = 2;
+  }
+
+  // Per-method RPC statistics.  The key is the RpcType in string form; e.g.
+  // 'EMPTY_CALL' or 'UNARY_CALL'
+  map<string, MethodStats> stats_per_method = 4;
 }
 
 // Configurations for a test client.
@@ -245,6 +261,9 @@
   repeated RpcType types = 1;
   // The collection of custom metadata to be attached to RPCs sent by the client.
   repeated Metadata metadata = 2;
+  // The deadline to use, in seconds, for all RPCs.  If unset or zero, the
+  // client will use the default from the command-line.
+  int32 timeout_sec = 3;
 }
 
 // Response for updating a test client's configuration.
diff --git a/grpc/src/proto/grpc/testing/xds/cds_for_test.proto b/grpc/src/proto/grpc/testing/xds/cds_for_test.proto
index 8ea198d..3d3c1c1 100644
--- a/grpc/src/proto/grpc/testing/xds/cds_for_test.proto
+++ b/grpc/src/proto/grpc/testing/xds/cds_for_test.proto
@@ -72,6 +72,15 @@
   repeated Thresholds thresholds = 1;
 }
 
+message ClusterConfig {
+  repeated string clusters = 1;
+}
+
+message CustomClusterType {
+  string name = 1;
+  ClusterConfig typed_config = 2;
+}
+
 message Cluster {
   // Refer to :ref:`service discovery type <arch_overview_service_discovery_types>`
   // for an explanation on each type.
@@ -106,6 +115,9 @@
     // The :ref:`service discovery type <arch_overview_service_discovery_types>`
     // to use for resolving the cluster.
     DiscoveryType type = 2;
+
+    // The custom cluster type: aggregate cluster in this case.
+    CustomClusterType cluster_type = 38;
   }
 
   // Only valid when discovery type is EDS.
diff --git a/grpc/src/proto/grpc/testing/xds/v3/BUILD b/grpc/src/proto/grpc/testing/xds/v3/BUILD
index 1bcfa4b..be730de 100644
--- a/grpc/src/proto/grpc/testing/xds/v3/BUILD
+++ b/grpc/src/proto/grpc/testing/xds/v3/BUILD
@@ -15,6 +15,7 @@
 licenses(["notice"])  # Apache v2
 
 load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library")
+load("//bazel:python_rules.bzl", "py_grpc_library", "py_proto_library")
 
 grpc_package(
     name = "xds_v3",
@@ -26,6 +27,7 @@
     srcs = [
         "address.proto",
     ],
+    well_known_protos = True,
 )
 
 grpc_proto_library(
@@ -107,6 +109,10 @@
         "listener.proto",
     ],
     well_known_protos = True,
+    deps = [
+        "address_proto",
+        "base_proto",
+    ],
 )
 
 grpc_proto_library(
@@ -182,6 +188,7 @@
     srcs = [
         "http_connection_manager.proto",
     ],
+    well_known_protos = True,
     deps = [
         "config_source_proto",
         "protocol_proto",
@@ -190,6 +197,13 @@
 )
 
 grpc_proto_library(
+    name = "router_proto",
+    srcs = [
+        "router.proto",
+    ],
+)
+
+grpc_proto_library(
     name = "string_proto",
     srcs = [
         "string.proto",
@@ -201,6 +215,28 @@
 )
 
 grpc_proto_library(
+    name = "aggregate_cluster_proto",
+    srcs = [
+        "aggregate_cluster.proto",
+    ],
+    well_known_protos = True,
+    deps = [
+        "string_proto",
+    ],
+)
+
+grpc_proto_library(
+    name = "fault_common_proto",
+    srcs = [
+        "fault_common.proto",
+    ],
+    well_known_protos = True,
+    deps = [
+        "percent_proto",
+    ],
+)
+
+grpc_proto_library(
     name = "tls_proto",
     srcs = [
         "tls.proto",
@@ -210,3 +246,62 @@
         "string_proto",
     ],
 )
+
+grpc_proto_library(
+    name = "config_dump_proto",
+    srcs = [
+        "config_dump.proto",
+    ],
+    well_known_protos = True,
+)
+
+grpc_proto_library(
+    name = "csds_proto",
+    srcs = [
+        "csds.proto",
+    ],
+    well_known_protos = True,
+    deps = [
+        "base_proto",
+        "config_dump_proto",
+    ],
+)
+
+grpc_proto_library(
+    name = "fault_proto",
+    srcs = [
+        "fault.proto",
+    ],
+    well_known_protos = True,
+    deps = [
+        "fault_common_proto",
+        "percent_proto",
+        "route_proto",
+    ],
+)
+
+py_proto_library(
+    name = "csds_py_pb2",
+    deps = [":_csds_proto_only"],
+)
+
+py_grpc_library(
+    name = "csds_py_pb2_grpc",
+    srcs = [":_csds_proto_only"],
+    deps = [":csds_py_pb2"],
+)
+
+py_proto_library(
+    name = "config_dump_py_pb2",
+    deps = [":_config_dump_proto_only"],
+)
+
+py_proto_library(
+    name = "base_py_pb2",
+    deps = [":_base_proto_only"],
+)
+
+py_proto_library(
+    name = "percent_py_pb2",
+    deps = [":_percent_proto_only"],
+)
diff --git a/grpc/src/proto/grpc/testing/xds/v3/address.proto b/grpc/src/proto/grpc/testing/xds/v3/address.proto
index abea8bf..38592cc 100644
--- a/grpc/src/proto/grpc/testing/xds/v3/address.proto
+++ b/grpc/src/proto/grpc/testing/xds/v3/address.proto
@@ -18,6 +18,8 @@
 
 package envoy.config.core.v3;
 
+import "google/protobuf/wrappers.proto";
+
 // [#protodoc-title: Network addresses]
 
 // [#next-free-field: 7]
@@ -48,3 +50,13 @@
     SocketAddress socket_address = 1;
   }
 }
+
+// CidrRange specifies an IP Address and a prefix length to construct
+// the subnet mask for a `CIDR <https://tools.ietf.org/html/rfc4632>`_ range.
+message CidrRange {
+  // IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``.
+  string address_prefix = 1;
+
+  // Length of prefix, e.g. 0, 32.
+  google.protobuf.UInt32Value prefix_len = 2;
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/ads.proto b/grpc/src/proto/grpc/testing/xds/v3/ads.proto
index aea815d..d576c1d 100644
--- a/grpc/src/proto/grpc/testing/xds/v3/ads.proto
+++ b/grpc/src/proto/grpc/testing/xds/v3/ads.proto
@@ -41,5 +41,5 @@
 
 // [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing
 // services: https://github.com/google/protobuf/issues/4221
-message AdsDummy {
+message AdsPhony {
 }
diff --git a/grpc/src/proto/grpc/testing/xds/v3/aggregate_cluster.proto b/grpc/src/proto/grpc/testing/xds/v3/aggregate_cluster.proto
new file mode 100644
index 0000000..d14ad35
--- /dev/null
+++ b/grpc/src/proto/grpc/testing/xds/v3/aggregate_cluster.proto
@@ -0,0 +1,28 @@
+// Copyright 2020 The 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.
+
+// Local copy of Envoy xDS proto file, used for testing only.
+
+syntax = "proto3";
+
+package envoy.extensions.clusters.aggregate.v3;
+
+// Configuration for the aggregate cluster. See the :ref:`architecture overview
+// <arch_overview_aggregate_cluster>` for more information.
+// [#extension: envoy.clusters.aggregate]
+message ClusterConfig {
+  // Load balancing clusters in aggregate cluster. Clusters are prioritized based on the order they
+  // appear in this list.
+  repeated string clusters = 1;
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/cluster.proto b/grpc/src/proto/grpc/testing/xds/v3/cluster.proto
index c493e86..c04fe20 100644
--- a/grpc/src/proto/grpc/testing/xds/v3/cluster.proto
+++ b/grpc/src/proto/grpc/testing/xds/v3/cluster.proto
@@ -21,6 +21,7 @@
 import "src/proto/grpc/testing/xds/v3/base.proto";
 import "src/proto/grpc/testing/xds/v3/config_source.proto";
 
+import "google/protobuf/any.proto";
 import "google/protobuf/wrappers.proto";
 
 enum RoutingPriority {
@@ -36,6 +37,16 @@
   repeated Thresholds thresholds = 1;
 }
 
+// Extended cluster type.
+message CustomClusterType {
+  // The type of the cluster to instantiate. The name must match a supported cluster type.
+  string name = 1;
+
+  // Cluster specific configuration which depends on the cluster being instantiated.
+  // See the supported cluster for further documentation.
+  google.protobuf.Any typed_config = 2;
+}
+
 // [#protodoc-title: Cluster configuration]
 
 // Configuration for a single upstream cluster.
@@ -134,6 +145,9 @@
     // The :ref:`service discovery type <arch_overview_service_discovery_types>`
     // to use for resolving the cluster.
     DiscoveryType type = 2;
+
+    // The custom cluster type.
+    CustomClusterType cluster_type = 38;
   }
 
   // Configuration to use for EDS updates for the Cluster.
diff --git a/grpc/src/proto/grpc/testing/xds/v3/config_dump.proto b/grpc/src/proto/grpc/testing/xds/v3/config_dump.proto
new file mode 100644
index 0000000..d69b310
--- /dev/null
+++ b/grpc/src/proto/grpc/testing/xds/v3/config_dump.proto
@@ -0,0 +1,284 @@
+// Copyright 2021 The 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.
+
+// Local copy of Envoy xDS proto file, used for testing only.
+
+syntax = "proto3";
+
+package envoy.admin.v3;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/timestamp.proto";
+
+// Resource status from the view of a xDS client, which tells the synchronization
+// status between the xDS client and the xDS server.
+enum ClientResourceStatus {
+  // Resource status is not available/unknown.
+  UNKNOWN = 0;
+
+  // Client requested this resource but hasn't received any update from management
+  // server. The client will not fail requests, but will queue them until update
+  // arrives or the client times out waiting for the resource.
+  REQUESTED = 1;
+
+  // This resource has been requested by the client but has either not been
+  // delivered by the server or was previously delivered by the server and then
+  // subsequently removed from resources provided by the server. For more
+  // information, please refer to the :ref:`"Knowing When a Requested Resource
+  // Does Not Exist" <xds_protocol_resource_not_existed>` section.
+  DOES_NOT_EXIST = 2;
+
+  // Client received this resource and replied with ACK.
+  ACKED = 3;
+
+  // Client received this resource and replied with NACK.
+  NACKED = 4;
+}
+
+message UpdateFailureState {
+  // What the component configuration would have been if the update had succeeded.
+  // This field may not be populated by xDS clients due to storage overhead.
+  google.protobuf.Any failed_configuration = 1;
+
+  // Time of the latest failed update attempt.
+  google.protobuf.Timestamp last_update_attempt = 2;
+
+  // Details about the last failed update attempt.
+  string details = 3;
+
+  // This is the version of the rejected resource.
+  // [#not-implemented-hide:]
+  string version_info = 4;
+}
+
+// Envoy's listener manager fills this message with all currently known listeners. Listener
+// configuration information can be used to recreate an Envoy configuration by populating all
+// listeners as static listeners or by returning them in a LDS response.
+message ListenersConfigDump {
+  // Describes a statically loaded listener.
+  message StaticListener {
+    // The listener config.
+    google.protobuf.Any listener = 1;
+
+    // The timestamp when the Listener was last successfully updated.
+    google.protobuf.Timestamp last_updated = 2;
+  }
+
+  message DynamicListenerState {
+    // This is the per-resource version information. This version is currently taken from the
+    // :ref:`version_info <envoy_api_field_service.discovery.v3.DiscoveryResponse.version_info>` field at the time
+    // that the listener was loaded. In the future, discrete per-listener versions may be supported
+    // by the API.
+    string version_info = 1;
+
+    // The listener config.
+    google.protobuf.Any listener = 2;
+
+    // The timestamp when the Listener was last successfully updated.
+    google.protobuf.Timestamp last_updated = 3;
+  }
+
+  // Describes a dynamically loaded listener via the LDS API.
+  // [#next-free-field: 7]
+  message DynamicListener {
+    // The name or unique id of this listener, pulled from the DynamicListenerState config.
+    string name = 1;
+
+    // The listener state for any active listener by this name.
+    // These are listeners that are available to service data plane traffic.
+    DynamicListenerState active_state = 2;
+
+    // The listener state for any warming listener by this name.
+    // These are listeners that are currently undergoing warming in preparation to service data
+    // plane traffic. Note that if attempting to recreate an Envoy configuration from a
+    // configuration dump, the warming listeners should generally be discarded.
+    DynamicListenerState warming_state = 3;
+
+    // The listener state for any draining listener by this name.
+    // These are listeners that are currently undergoing draining in preparation to stop servicing
+    // data plane traffic. Note that if attempting to recreate an Envoy configuration from a
+    // configuration dump, the draining listeners should generally be discarded.
+    DynamicListenerState draining_state = 4;
+
+    // Set if the last update failed, cleared after the next successful update.
+    // The *error_state* field contains the rejected version of this particular
+    // resource along with the reason and timestamp. For successfully updated or
+    // acknowledged resource, this field should be empty.
+    UpdateFailureState error_state = 5;
+
+    // The client status of this resource.
+    // [#not-implemented-hide:]
+    ClientResourceStatus client_status = 6;
+  }
+
+  // This is the :ref:`version_info <envoy_api_field_service.discovery.v3.DiscoveryResponse.version_info>` in the
+  // last processed LDS discovery response. If there are only static bootstrap listeners, this field
+  // will be "".
+  string version_info = 1;
+
+  // The statically loaded listener configs.
+  repeated StaticListener static_listeners = 2;
+
+  // State for any warming, active, or draining listeners.
+  repeated DynamicListener dynamic_listeners = 3;
+}
+
+// Envoy's cluster manager fills this message with all currently known clusters. Cluster
+// configuration information can be used to recreate an Envoy configuration by populating all
+// clusters as static clusters or by returning them in a CDS response.
+message ClustersConfigDump {
+  // Describes a statically loaded cluster.
+  message StaticCluster {
+    // The cluster config.
+    google.protobuf.Any cluster = 1;
+
+    // The timestamp when the Cluster was last updated.
+    google.protobuf.Timestamp last_updated = 2;
+  }
+
+  // Describes a dynamically loaded cluster via the CDS API.
+  // [#next-free-field: 6]
+  message DynamicCluster {
+    // This is the per-resource version information. This version is currently taken from the
+    // :ref:`version_info <envoy_api_field_service.discovery.v3.DiscoveryResponse.version_info>` field at the time
+    // that the cluster was loaded. In the future, discrete per-cluster versions may be supported by
+    // the API.
+    string version_info = 1;
+
+    // The cluster config.
+    google.protobuf.Any cluster = 2;
+
+    // The timestamp when the Cluster was last updated.
+    google.protobuf.Timestamp last_updated = 3;
+
+    // Set if the last update failed, cleared after the next successful update.
+    // The *error_state* field contains the rejected version of this particular
+    // resource along with the reason and timestamp. For successfully updated or
+    // acknowledged resource, this field should be empty.
+    // [#not-implemented-hide:]
+    UpdateFailureState error_state = 4;
+
+    // The client status of this resource.
+    // [#not-implemented-hide:]
+    ClientResourceStatus client_status = 5;
+  }
+
+  // This is the :ref:`version_info <envoy_api_field_service.discovery.v3.DiscoveryResponse.version_info>` in the
+  // last processed CDS discovery response. If there are only static bootstrap clusters, this field
+  // will be "".
+  string version_info = 1;
+
+  // The statically loaded cluster configs.
+  repeated StaticCluster static_clusters = 2;
+
+  // The dynamically loaded active clusters. These are clusters that are available to service
+  // data plane traffic.
+  repeated DynamicCluster dynamic_active_clusters = 3;
+
+  // The dynamically loaded warming clusters. These are clusters that are currently undergoing
+  // warming in preparation to service data plane traffic. Note that if attempting to recreate an
+  // Envoy configuration from a configuration dump, the warming clusters should generally be
+  // discarded.
+  repeated DynamicCluster dynamic_warming_clusters = 4;
+}
+
+// Envoy's RDS implementation fills this message with all currently loaded routes, as described by
+// their RouteConfiguration objects. Static routes that are either defined in the bootstrap configuration
+// or defined inline while configuring listeners are separated from those configured dynamically via RDS.
+// Route configuration information can be used to recreate an Envoy configuration by populating all routes
+// as static routes or by returning them in RDS responses.
+message RoutesConfigDump {
+  message StaticRouteConfig {
+    // The route config.
+    google.protobuf.Any route_config = 1;
+
+    // The timestamp when the Route was last updated.
+    google.protobuf.Timestamp last_updated = 2;
+  }
+
+  // [#next-free-field: 6]
+  message DynamicRouteConfig {
+    // This is the per-resource version information. This version is currently taken from the
+    // :ref:`version_info <envoy_api_field_service.discovery.v3.DiscoveryResponse.version_info>` field at the time that
+    // the route configuration was loaded.
+    string version_info = 1;
+
+    // The route config.
+    google.protobuf.Any route_config = 2;
+
+    // The timestamp when the Route was last updated.
+    google.protobuf.Timestamp last_updated = 3;
+
+    // Set if the last update failed, cleared after the next successful update.
+    // The *error_state* field contains the rejected version of this particular
+    // resource along with the reason and timestamp. For successfully updated or
+    // acknowledged resource, this field should be empty.
+    // [#not-implemented-hide:]
+    UpdateFailureState error_state = 4;
+
+    // The client status of this resource.
+    // [#not-implemented-hide:]
+    ClientResourceStatus client_status = 5;
+  }
+
+  // The statically loaded route configs.
+  repeated StaticRouteConfig static_route_configs = 2;
+
+  // The dynamically loaded route configs.
+  repeated DynamicRouteConfig dynamic_route_configs = 3;
+}
+
+// Envoy's admin fill this message with all currently known endpoints. Endpoint
+// configuration information can be used to recreate an Envoy configuration by populating all
+// endpoints as static endpoints or by returning them in an EDS response.
+message EndpointsConfigDump {
+  message StaticEndpointConfig {
+    // The endpoint config.
+    google.protobuf.Any endpoint_config = 1;
+
+    // [#not-implemented-hide:] The timestamp when the Endpoint was last updated.
+    google.protobuf.Timestamp last_updated = 2;
+  }
+
+  // [#next-free-field: 6]
+  message DynamicEndpointConfig {
+    // [#not-implemented-hide:] This is the per-resource version information. This version is currently taken from the
+    // :ref:`version_info <envoy_api_field_service.discovery.v3.DiscoveryResponse.version_info>` field at the time that
+    // the endpoint configuration was loaded.
+    string version_info = 1;
+
+    // The endpoint config.
+    google.protobuf.Any endpoint_config = 2;
+
+    // [#not-implemented-hide:] The timestamp when the Endpoint was last updated.
+    google.protobuf.Timestamp last_updated = 3;
+
+    // Set if the last update failed, cleared after the next successful update.
+    // The *error_state* field contains the rejected version of this particular
+    // resource along with the reason and timestamp. For successfully updated or
+    // acknowledged resource, this field should be empty.
+    // [#not-implemented-hide:]
+    UpdateFailureState error_state = 4;
+
+    // The client status of this resource.
+    // [#not-implemented-hide:]
+    ClientResourceStatus client_status = 5;
+  }
+
+  // The statically loaded endpoint configs.
+  repeated StaticEndpointConfig static_endpoint_configs = 2;
+
+  // The dynamically loaded endpoint configs.
+  repeated DynamicEndpointConfig dynamic_endpoint_configs = 3;
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/csds.proto b/grpc/src/proto/grpc/testing/xds/v3/csds.proto
new file mode 100644
index 0000000..bbdfd4e
--- /dev/null
+++ b/grpc/src/proto/grpc/testing/xds/v3/csds.proto
@@ -0,0 +1,89 @@
+// Copyright 2021 The 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.
+
+// Local copy of Envoy xDS proto file, used for testing only.
+
+syntax = "proto3";
+
+package envoy.service.status.v3;
+
+import "src/proto/grpc/testing/xds/v3/config_dump.proto";
+import "src/proto/grpc/testing/xds/v3/base.proto";
+
+
+// CSDS is Client Status Discovery Service. It can be used to get the status of
+// an xDS-compliant client from the management server's point of view. It can
+// also be used to get the current xDS states directly from the client.
+service ClientStatusDiscoveryService {
+  rpc StreamClientStatus(stream ClientStatusRequest) returns (stream ClientStatusResponse) {}
+  rpc FetchClientStatus(ClientStatusRequest) returns (ClientStatusResponse) {}
+}
+
+// Status of a config from a management server view.
+enum ConfigStatus {
+  // Status info is not available/unknown.
+  UNKNOWN = 0;
+
+  // Management server has sent the config to client and received ACK.
+  SYNCED = 1;
+
+  // Config is not sent.
+  NOT_SENT = 2;
+
+  // Management server has sent the config to client but hasn’t received
+  // ACK/NACK.
+  STALE = 3;
+
+  // Management server has sent the config to client but received NACK. The
+  // attached config dump will be the latest config (the rejected one), since
+  // it is the persisted version in the management server.
+  ERROR = 4;
+}
+
+// Request for client status of clients identified by a list of NodeMatchers.
+message ClientStatusRequest {
+  // The node making the csds request.
+  config.core.v3.Node node = 2;
+}
+
+// Detailed config (per xDS) with status.
+// [#next-free-field: 8]
+message PerXdsConfig {
+  // Config status generated by management servers. Will not be present if the
+  // CSDS server is an xDS client.
+  ConfigStatus status = 1;
+
+  oneof per_xds_config {
+    admin.v3.ListenersConfigDump listener_config = 2;
+
+    admin.v3.ClustersConfigDump cluster_config = 3;
+
+    admin.v3.RoutesConfigDump route_config = 4;
+
+    admin.v3.EndpointsConfigDump endpoint_config = 6;
+  }
+}
+
+// All xds configs for a particular client.
+message ClientConfig {
+  // Node for a particular client.
+  config.core.v3.Node node = 1;
+
+  repeated PerXdsConfig xds_config = 2;
+}
+
+message ClientStatusResponse {
+  // Client configs for the clients specified in the ClientStatusRequest.
+  repeated ClientConfig config = 1;
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/fault.proto b/grpc/src/proto/grpc/testing/xds/v3/fault.proto
new file mode 100644
index 0000000..05ec641
--- /dev/null
+++ b/grpc/src/proto/grpc/testing/xds/v3/fault.proto
@@ -0,0 +1,91 @@
+// Copyright 2020 The 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.
+
+// Local copy of Envoy xDS proto file, used for testing only.
+
+syntax = "proto3";
+
+package envoy.extensions.filters.http.fault.v3;
+
+import "src/proto/grpc/testing/xds/v3/fault_common.proto";
+import "src/proto/grpc/testing/xds/v3/route.proto";
+import "src/proto/grpc/testing/xds/v3/percent.proto";
+
+import "google/protobuf/wrappers.proto";
+
+// [#protodoc-title: Fault Injection]
+// Fault Injection :ref:`configuration overview <config_http_filters_fault_injection>`.
+// [#extension: envoy.filters.http.fault]
+
+// [#next-free-field: 6]
+message FaultAbort {
+  // Fault aborts are controlled via an HTTP header (if applicable). See the
+  // :ref:`HTTP fault filter <config_http_filters_fault_injection_http_header>` documentation for
+  // more information.
+  message HeaderAbort {
+  }
+
+  reserved 1;
+
+  oneof error_type {
+    // HTTP status code to use to abort the HTTP request.
+    uint32 http_status = 2;
+
+    // gRPC status code to use to abort the gRPC request.
+    uint32 grpc_status = 5;
+
+    // Fault aborts are controlled via an HTTP header (if applicable).
+    HeaderAbort header_abort = 4;
+  }
+
+  // The percentage of requests/operations/connections that will be aborted with the error code
+  // provided.
+  type.v3.FractionalPercent percentage = 3;
+}
+
+// [#next-free-field: 15]
+message HTTPFault {
+  // If specified, the filter will inject delays based on the values in the
+  // object.
+  common.fault.v3.FaultDelay delay = 1;
+
+  // If specified, the filter will abort requests based on the values in
+  // the object. At least *abort* or *delay* must be specified.
+  FaultAbort abort = 2;
+
+  // Specifies a set of headers that the filter should match on. The fault
+  // injection filter can be applied selectively to requests that match a set of
+  // headers specified in the fault filter config. The chances of actual fault
+  // injection further depend on the value of the :ref:`percentage
+  // <envoy_api_field_extensions.filters.http.fault.v3.FaultAbort.percentage>` field.
+  // The filter will check the request's headers against all the specified
+  // headers in the filter config. A match will happen if all the headers in the
+  // config are present in the request with the same values (or based on
+  // presence if the *value* field is not in the config).
+  repeated config.route.v3.HeaderMatcher headers = 4;
+
+  // The maximum number of faults that can be active at a single time via the configured fault
+  // filter. Note that because this setting can be overridden at the route level, it's possible
+  // for the number of active faults to be greater than this value (if injected via a different
+  // route). If not specified, defaults to unlimited. This setting can be overridden via
+  // `runtime <config_http_filters_fault_injection_runtime>` and any faults that are not injected
+  // due to overflow will be indicated via the `faults_overflow
+  // <config_http_filters_fault_injection_stats>` stat.
+  //
+  // .. attention::
+  //   Like other :ref:`circuit breakers <arch_overview_circuit_break>` in Envoy, this is a fuzzy
+  //   limit. It's possible for the number of active faults to rise slightly above the configured
+  //   amount due to the implementation details.
+  google.protobuf.UInt32Value max_active_faults = 6;
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/fault_common.proto b/grpc/src/proto/grpc/testing/xds/v3/fault_common.proto
new file mode 100644
index 0000000..2c2aedc
--- /dev/null
+++ b/grpc/src/proto/grpc/testing/xds/v3/fault_common.proto
@@ -0,0 +1,49 @@
+// Copyright 2020 The 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.
+
+// Local copy of Envoy xDS proto file, used for testing only.
+
+syntax = "proto3";
+
+package envoy.extensions.filters.common.fault.v3;
+
+import "src/proto/grpc/testing/xds/v3/percent.proto";
+
+import "google/protobuf/duration.proto";
+
+// Delay specification is used to inject latency into the
+// HTTP/gRPC/Mongo/Redis operation or delay proxying of TCP connections.
+message FaultDelay {
+  // Fault delays are controlled via an HTTP header (if applicable). See the
+  // :ref:`HTTP fault filter <config_http_filters_fault_injection_http_header>`
+  // documentation for more information.
+  message HeaderDelay {}
+
+  oneof fault_delay_secifier {
+    // Add a fixed delay before forwarding the operation upstream. See
+    // https://developers.google.com/protocol-buffers/docs/proto3#json for
+    // the JSON/YAML Duration mapping. For HTTP/Mongo/Redis, the specified
+    // delay will be injected before a new request/operation. For TCP
+    // connections, the proxying of the connection upstream will be delayed
+    // for the specified period. This is required if type is FIXED.
+    google.protobuf.Duration fixed_delay = 3;
+
+    // Fault delays are controlled via an HTTP header (if applicable).
+    HeaderDelay header_delay = 5;
+  }
+
+  // The percentage of operations/connections/requests on which the delay will
+  // be injected.
+  type.v3.FractionalPercent percentage = 4;
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/http_connection_manager.proto b/grpc/src/proto/grpc/testing/xds/v3/http_connection_manager.proto
index 786ac0f..7447707 100644
--- a/grpc/src/proto/grpc/testing/xds/v3/http_connection_manager.proto
+++ b/grpc/src/proto/grpc/testing/xds/v3/http_connection_manager.proto
@@ -18,6 +18,8 @@
 
 package envoy.extensions.filters.network.http_connection_manager.v3;
 
+import "google/protobuf/any.proto";
+
 import "src/proto/grpc/testing/xds/v3/config_source.proto";
 import "src/proto/grpc/testing/xds/v3/protocol.proto";
 import "src/proto/grpc/testing/xds/v3/route.proto";
@@ -40,6 +42,11 @@
     ScopedRoutes scoped_routes = 31;
   }
 
+  // A list of individual HTTP filters that make up the filter chain for
+  // requests made to the connection manager. :ref:`Order matters <arch_overview_http_filters_ordering>`
+  // as the filters are processed sequentially as request events happen.
+  repeated HttpFilter http_filters = 5;
+
   // Additional settings for HTTP requests handled by the connection manager. These will be
   // applicable to both HTTP1 and HTTP2 requests.
   config.core.v3.HttpProtocolOptions common_http_protocol_options = 35;
@@ -58,3 +65,18 @@
 
 message ScopedRoutes {
 }
+
+message HttpFilter {
+  // The name of the filter configuration. The name is used as a fallback to
+  // select an extension if the type of the configuration proto is not
+  // sufficient. It also serves as a resource name in ExtensionConfigDS.
+  string name = 1;
+
+  oneof config_type {
+    // Filter specific configuration which depends on the filter being instantiated. See the supported
+    // filters for further documentation.
+    google.protobuf.Any typed_config = 4;
+  }
+
+  bool is_optional = 6;
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/listener.proto b/grpc/src/proto/grpc/testing/xds/v3/listener.proto
index e9160e0..df9ee71 100644
--- a/grpc/src/proto/grpc/testing/xds/v3/listener.proto
+++ b/grpc/src/proto/grpc/testing/xds/v3/listener.proto
@@ -18,7 +18,11 @@
 
 package envoy.config.listener.v3;
 
+import "src/proto/grpc/testing/xds/v3/address.proto";
+import "src/proto/grpc/testing/xds/v3/base.proto";
+
 import "google/protobuf/any.proto";
+import "google/protobuf/wrappers.proto";
 
 // [#protodoc-title: Listener configuration]
 // Listener :ref:`configuration overview <config_listeners>`
@@ -37,6 +41,126 @@
   google.protobuf.Any api_listener = 1;
 }
 
+message Filter {
+  reserved 3;
+
+  // The name of the filter to instantiate. The name must match a
+  // :ref:`supported filter <config_network_filters>`.
+  string name = 1;
+
+  // [#extension-category: envoy.filters.network]
+  oneof config_type {
+    // Filter specific configuration which depends on the filter being
+    // instantiated. See the supported filters for further documentation.
+    google.protobuf.Any typed_config = 4;
+  }
+}
+
+message FilterChainMatch {
+  enum ConnectionSourceType {
+    // Any connection source matches.
+    ANY = 0;
+
+    // Match a connection originating from the same host.
+    SAME_IP_OR_LOOPBACK = 1;
+
+    // Match a connection originating from a different host.
+    EXTERNAL = 2;
+  }
+
+  reserved 1;
+
+  // Optional destination port to consider when use_original_dst is set on the
+  // listener in determining a filter chain match.
+  google.protobuf.UInt32Value destination_port = 8;
+
+  // If non-empty, an IP address and prefix length to match addresses when the
+  // listener is bound to 0.0.0.0/:: or when use_original_dst is specified.
+  repeated core.v3.CidrRange prefix_ranges = 3;
+
+  // Specifies the connection source IP match type. Can be any, local or external network.
+  ConnectionSourceType source_type = 12;
+
+  // The criteria is satisfied if the source IP address of the downstream
+  // connection is contained in at least one of the specified subnets. If the
+  // parameter is not specified or the list is empty, the source IP address is
+  // ignored.
+  repeated core.v3.CidrRange source_prefix_ranges = 6;
+
+  // The criteria is satisfied if the source port of the downstream connection
+  // is contained in at least one of the specified ports. If the parameter is
+  // not specified, the source port is ignored.
+  repeated uint32 source_ports = 7;
+
+  // If non-empty, a list of server names (e.g. SNI for TLS protocol) to consider when determining
+  // a filter chain match. Those values will be compared against the server names of a new
+  // connection, when detected by one of the listener filters.
+  //
+  // The server name will be matched against all wildcard domains, i.e. ``www.example.com``
+  // will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``.
+  //
+  // Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid.
+  //
+  // .. attention::
+  //
+  //   See the :ref:`FAQ entry <faq_how_to_setup_sni>` on how to configure SNI for more
+  //   information.
+  repeated string server_names = 11;
+
+  // If non-empty, a transport protocol to consider when determining a filter chain match.
+  // This value will be compared against the transport protocol of a new connection, when
+  // it's detected by one of the listener filters.
+  //
+  // Suggested values include:
+  //
+  // * ``raw_buffer`` - default, used when no transport protocol is detected,
+  // * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector <config_listener_filters_tls_inspector>`
+  //   when TLS protocol is detected.
+  string transport_protocol = 9;
+
+  // If non-empty, a list of application protocols (e.g. ALPN for TLS protocol) to consider when
+  // determining a filter chain match. Those values will be compared against the application
+  // protocols of a new connection, when detected by one of the listener filters.
+  //
+  // Suggested values include:
+  //
+  // * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector
+  //   <config_listener_filters_tls_inspector>`,
+  // * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector <config_listener_filters_tls_inspector>`
+  //
+  // .. attention::
+  //
+  //   Currently, only :ref:`TLS Inspector <config_listener_filters_tls_inspector>` provides
+  //   application protocol detection based on the requested
+  //   `ALPN <https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation>`_ values.
+  //
+  //   However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet,
+  //   and matching on values other than ``h2`` is going to lead to a lot of false negatives,
+  //   unless all connecting clients are known to use ALPN.
+  repeated string application_protocols = 10;
+}
+
+// A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and
+// various other parameters.
+// [#next-free-field: 10]
+message FilterChain {
+  // The criteria to use when matching a connection to this filter chain.
+  FilterChainMatch filter_chain_match = 1;
+
+  // A list of individual network filters that make up the filter chain for
+  // connections established with the listener. Order matters as the filters are
+  // processed sequentially as connection events happen. Note: If the filter
+  // list is empty, the connection will close by default.
+  repeated Filter filters = 3; 
+
+  // Optional custom transport socket implementation to use for downstream connections.
+  // To setup TLS, set a transport socket with name `tls` and
+  // :ref:`DownstreamTlsContext <envoy_api_msg_extensions.transport_sockets.tls.v3.DownstreamTlsContext>` in the `typed_config`.
+  // If no transport socket configuration is specified, new connections
+  // will be set up with plaintext.
+  core.v3.TransportSocket transport_socket = 6;
+}
+
 // [#next-free-field: 23]
 message Listener {
   // The unique name by which this listener is known. If no name is provided,
@@ -44,6 +168,31 @@
   // updated or removed via :ref:`LDS <config_listeners_lds>` a unique name must be provided.
   string name = 1;
 
+  // The address that the listener should listen on. In general, the address must be unique, though
+  // that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on
+  // Linux as the actual port will be allocated by the OS.
+  core.v3.Address address = 2;
+
+  // A list of filter chains to consider for this listener. The
+  // :ref:`FilterChain <envoy_api_msg_config.listener.v3.FilterChain>` with the most specific
+  // :ref:`FilterChainMatch <envoy_api_msg_config.listener.v3.FilterChainMatch>` criteria is used on a
+  // connection.
+  //
+  // Example using SNI for filter chain selection can be found in the
+  // :ref:`FAQ entry <faq_how_to_setup_sni>`.
+  repeated FilterChain filter_chains = 3;
+
+  // If a connection is redirected using *iptables*, the port on which the proxy
+  // receives it might be different from the original destination address. When this flag is set to
+  // true, the listener hands off redirected connections to the listener associated with the
+  // original destination address. If there is no listener associated with the original destination
+  // address, the connection is handled by the listener that receives it. Defaults to false.
+  google.protobuf.BoolValue use_original_dst = 4; 
+
+  // The default filter chain if none of the filter chain matches. If no default filter chain is supplied,
+  // the connection will be closed. The filter chain match is ignored in this field.
+  FilterChain default_filter_chain = 25;
+
   // Used to represent an API listener, which is used in non-proxy clients. The type of API
   // exposed to the non-proxy application depends on the type of API listener.
   // When this field is set, no other field except for :ref:`name<envoy_api_field_config.listener.v3.Listener.name>`
diff --git a/grpc/src/proto/grpc/testing/xds/v3/route.proto b/grpc/src/proto/grpc/testing/xds/v3/route.proto
index b7fc40b..baeaaf6 100644
--- a/grpc/src/proto/grpc/testing/xds/v3/route.proto
+++ b/grpc/src/proto/grpc/testing/xds/v3/route.proto
@@ -23,6 +23,7 @@
 import "src/proto/grpc/testing/xds/v3/percent.proto";
 import "src/proto/grpc/testing/xds/v3/range.proto";
 
+import "google/protobuf/any.proto";
 import "google/protobuf/duration.proto";
 import "google/protobuf/wrappers.proto";
 
@@ -64,6 +65,13 @@
   // The list of routes that will be matched, in order, for incoming requests.
   // The first route that matches will be used.
   repeated Route routes = 3;
+
+  // The per_filter_config field can be used to provide virtual host-specific
+  // configurations for filters. The key should match the filter name, such as
+  // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter
+  // specific; see the :ref:`HTTP filter documentation <config_http_filters>`
+  // for if and how it is utilized.
+  map<string, google.protobuf.Any> typed_per_filter_config = 15;
 }
 
 // A route is both a specification of how to match a request as well as an indication of what to do
@@ -88,6 +96,13 @@
     // Return a redirect.
     RedirectAction redirect = 3;
   }
+
+  // The typed_per_filter_config field can be used to provide route-specific
+  // configurations for filters. The key should match the filter name, such as
+  // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter
+  // specific; see the :ref:`HTTP filter documentation <config_http_filters>` for
+  // if and how it is utilized.
+  map<string, google.protobuf.Any> typed_per_filter_config = 13;
 }
 
 // Compared to the :ref:`cluster <envoy_api_field_config.route.v3.RouteAction.cluster>` field that specifies a
@@ -108,6 +123,13 @@
     // the choice of an upstream cluster is determined by its weight. The sum of weights across all
     // entries in the clusters array must add up to the total_weight, which defaults to 100.
     google.protobuf.UInt32Value weight = 2;
+
+    // The per_filter_config field can be used to provide weighted cluster-specific
+    // configurations for filters. The key should match the filter name, such as
+    // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter
+    // specific; see the :ref:`HTTP filter documentation <config_http_filters>`
+    // for if and how it is utilized.
+    map<string, google.protobuf.Any> typed_per_filter_config = 10;
   }
 
   // Specifies one or more upstream clusters associated with the route.
@@ -334,3 +356,13 @@
 
 message RedirectAction {
 }
+
+message FilterConfig {
+  // The filter config.
+  google.protobuf.Any config = 1;
+
+  // If true, the filter is optional, meaning that if the client does
+  // not support the specified filter, it may ignore the map entry rather
+  // than rejecting the config.
+  bool is_optional = 2;
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/router.proto b/grpc/src/proto/grpc/testing/xds/v3/router.proto
new file mode 100644
index 0000000..00b11b3
--- /dev/null
+++ b/grpc/src/proto/grpc/testing/xds/v3/router.proto
@@ -0,0 +1,28 @@
+// Copyright 2021 The 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.
+
+// Local copy of Envoy xDS proto file, used for testing only.
+
+syntax = "proto3";
+
+package envoy.extensions.filters.http.router.v3;
+
+// [#protodoc-title: Router]
+// Router :ref:`configuration overview <config_http_filters_router>`.
+// [#extension: envoy.filters.http.router]
+
+// We don't actually use any of the fields in this message, but we need
+// the message itself to signify which filter to use.
+message Router {
+}
diff --git a/grpc/src/proto/grpc/testing/xds/v3/tls.proto b/grpc/src/proto/grpc/testing/xds/v3/tls.proto
index 47db0a0..e9acfb5 100644
--- a/grpc/src/proto/grpc/testing/xds/v3/tls.proto
+++ b/grpc/src/proto/grpc/testing/xds/v3/tls.proto
@@ -20,6 +20,8 @@
 
 import "src/proto/grpc/testing/xds/v3/string.proto";
 
+import "google/protobuf/wrappers.proto";
+
 message CertificateValidationContext {
   // An optional list of Subject Alternative name matchers. If specified, Envoy will verify that the
   // Subject Alternative Name of the presented certificate matches one of the specified matchers.
@@ -53,6 +55,16 @@
   CommonTlsContext common_tls_context = 1;
 }
 
+message DownstreamTlsContext {
+  // Common TLS context settings.
+  CommonTlsContext common_tls_context = 1;
+
+  // If specified, Envoy will reject connections without a valid client
+  // certificate.
+  google.protobuf.BoolValue require_client_certificate = 2;
+}
+
+
 // TLS context shared by both client and server TLS contexts.
 // [#next-free-field: 14]
 message CommonTlsContext {
diff --git a/grpc/src/upb/gen_build_yaml.py b/grpc/src/upb/gen_build_yaml.py
index 71a4886..b556c3d 100755
--- a/grpc/src/upb/gen_build_yaml.py
+++ b/grpc/src/upb/gen_build_yaml.py
@@ -33,27 +33,13 @@
             "third_party/upb/upb/decode.c",
             "third_party/upb/upb/def.c",
             "third_party/upb/upb/encode.c",
-            "third_party/upb/upb/json_decode.c",
-            "third_party/upb/upb/json_encode.c",
             "third_party/upb/upb/msg.c",
             "third_party/upb/upb/reflection.c",
             "third_party/upb/upb/table.c",
             "third_party/upb/upb/text_encode.c",
             "third_party/upb/upb/upb.c",
-            "src/core/ext/upb-generated/google/protobuf/any.upb.c",
             "src/core/ext/upb-generated/google/protobuf/descriptor.upb.c",
-            "src/core/ext/upb-generated/google/protobuf/duration.upb.c",
-            "src/core/ext/upb-generated/google/protobuf/empty.upb.c",
-            "src/core/ext/upb-generated/google/protobuf/struct.upb.c",
-            "src/core/ext/upb-generated/google/protobuf/timestamp.upb.c",
-            "src/core/ext/upb-generated/google/protobuf/wrappers.upb.c",
-            "src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c",
             "src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c",
-            "src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c",
-            "src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c",
-            "src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.c",
-            "src/core/ext/upbdefs-generated/google/protobuf/timestamp.upbdefs.c",
-            "src/core/ext/upbdefs-generated/google/protobuf/wrappers.upbdefs.c",
         ],
         'headers': [
             "third_party/upb/upb/decode_fast.h",
@@ -62,8 +48,6 @@
             "third_party/upb/upb/def.h",
             "third_party/upb/upb/def.hpp",
             "third_party/upb/upb/encode.h",
-            "third_party/upb/upb/json_decode.h",
-            "third_party/upb/upb/json_encode.h",
             "third_party/upb/upb/msg.h",
             "third_party/upb/upb/port_def.inc",
             "third_party/upb/upb/port_undef.inc",
@@ -74,20 +58,8 @@
             "third_party/upb/upb/upb.hpp",
             "third_party/upb/upb/upb.int.h",
             "third_party/upb/third_party/wyhash/wyhash.h",
-            "src/core/ext/upb-generated/google/protobuf/any.upb.h",
             "src/core/ext/upb-generated/google/protobuf/descriptor.upb.h",
-            "src/core/ext/upb-generated/google/protobuf/duration.upb.h",
-            "src/core/ext/upb-generated/google/protobuf/empty.upb.h",
-            "src/core/ext/upb-generated/google/protobuf/struct.upb.h",
-            "src/core/ext/upb-generated/google/protobuf/timestamp.upb.h",
-            "src/core/ext/upb-generated/google/protobuf/wrappers.upb.h",
-            "src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.h",
             "src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.h",
-            "src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.h",
-            "src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.h",
-            "src/core/ext/upbdefs-generated/google/protobuf/struct.upbdefs.h",
-            "src/core/ext/upbdefs-generated/google/protobuf/timestamp.upbdefs.h",
-            "src/core/ext/upbdefs-generated/google/protobuf/wrappers.upbdefs.h",
         ],
         'secure': False,
     }]
diff --git a/grpc/test/core/security/authorization_engine_test.cc b/grpc/test/core/security/authorization_engine_test.cc
deleted file mode 100644
index 4b456a9..0000000
--- a/grpc/test/core/security/authorization_engine_test.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2020 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 "src/core/lib/security/authorization/authorization_engine.h"
-
-#include <gtest/gtest.h>
-
-namespace grpc_core {
-
-class AuthorizationEngineTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    deny_policy_ = envoy_config_rbac_v3_RBAC_new(arena_.ptr());
-    envoy_config_rbac_v3_RBAC_set_action(deny_policy_, 1);
-    allow_policy_ = envoy_config_rbac_v3_RBAC_new(arena_.ptr());
-    envoy_config_rbac_v3_RBAC_set_action(allow_policy_, 0);
-  }
-  upb::Arena arena_;
-  envoy_config_rbac_v3_RBAC* deny_policy_;
-  envoy_config_rbac_v3_RBAC* allow_policy_;
-};
-
-TEST_F(AuthorizationEngineTest, CreateEngineSuccessOnePolicy) {
-  std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
-  EXPECT_NE(engine, nullptr)
-      << "Error: Failed to create an AuthorizationEngine with one policy.";
-}
-
-TEST_F(AuthorizationEngineTest, CreateEngineSuccessTwoPolicies) {
-  std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
-  EXPECT_NE(engine, nullptr)
-      << "Error: Failed to create an AuthorizationEngine with two policies.";
-}
-
-TEST_F(AuthorizationEngineTest, CreateEngineFailNoPolicies) {
-  std::vector<envoy_config_rbac_v3_RBAC*> policies{};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
-  EXPECT_EQ(engine, nullptr)
-      << "Error: Created an AuthorizationEngine without policies.";
-}
-
-TEST_F(AuthorizationEngineTest, CreateEngineFailTooManyPolicies) {
-  std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_,
-                                                   deny_policy_};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
-  EXPECT_EQ(engine, nullptr)
-      << "Error: Created an AuthorizationEngine with more than two policies.";
-}
-
-TEST_F(AuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) {
-  std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_, deny_policy_};
-  std::unique_ptr<AuthorizationEngine> engine =
-      AuthorizationEngine::CreateAuthorizationEngine(policies);
-  EXPECT_EQ(engine, nullptr) << "Error: Created an AuthorizationEngine with "
-                                "policies in the wrong order.";
-}
-
-}  // namespace grpc_core
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/grpc/test/core/security/authorization_matchers_test.cc b/grpc/test/core/security/authorization_matchers_test.cc
new file mode 100644
index 0000000..36b3862
--- /dev/null
+++ b/grpc/test/core/security/authorization_matchers_test.cc
@@ -0,0 +1,420 @@
+// Copyright 2021 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>
+
+#include <list>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "src/core/lib/security/authorization/evaluate_args.h"
+#include "src/core/lib/security/authorization/matchers.h"
+#include "test/core/util/evaluate_args_test_util.h"
+
+namespace grpc_core {
+
+class AuthorizationMatchersTest : public ::testing::Test {
+ protected:
+  EvaluateArgsTestUtil args_;
+};
+
+TEST_F(AuthorizationMatchersTest, AlwaysAuthorizationMatcher) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AlwaysAuthorizationMatcher matcher;
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotAlwaysAuthorizationMatcher) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AlwaysAuthorizationMatcher matcher(/*not_rule=*/true);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, AndAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("foo", "bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/123));
+  AndAuthorizationMatcher matcher(std::move(rules));
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, AndAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("foo", "not_bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/123));
+  AndAuthorizationMatcher matcher(std::move(rules));
+  // Header rule fails. Expected value "bar", got "not_bar" for key "foo".
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotAndAuthorizationMatcher) {
+  args_.AddPairToMetadata(":path", "/expected/foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  StringMatcher string_matcher =
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"/expected/foo",
+                            /*case_sensitive=*/false)
+          .value();
+  std::vector<std::unique_ptr<Rbac::Permission>> ids;
+  ids.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kPath, std::move(string_matcher)));
+  AndAuthorizationMatcher matcher(std::move(ids), /*not_rule=*/true);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, OrAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("foo", "bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderMatcher header_matcher =
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader, header_matcher));
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/456));
+  OrAuthorizationMatcher matcher(std::move(rules));
+  // Matches as header rule matches even though port rule fails.
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, OrAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("foo", "not_bar");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  OrAuthorizationMatcher matcher(std::move(rules));
+  // Header rule fails. Expected value "bar", got "not_bar" for key "foo".
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotOrAuthorizationMatcher) {
+  args_.AddPairToMetadata("foo", "not_bar");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  OrAuthorizationMatcher matcher(std::move(rules), /*not_rule=*/true);
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, HybridAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("foo", "bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> sub_and_rules;
+  sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  std::vector<std::unique_ptr<Rbac::Permission>> sub_or_rules;
+  sub_or_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/123));
+  std::vector<std::unique_ptr<Rbac::Permission>> and_rules;
+  and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kAnd, std::move(sub_and_rules)));
+  and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kOr, std::move(std::move(sub_or_rules))));
+  AndAuthorizationMatcher matcher(std::move(and_rules));
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, HybridAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("foo", "bar");
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> sub_and_rules;
+  sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"absent_key", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"some_value")
+          .value()));
+  std::vector<std::unique_ptr<Rbac::Permission>> sub_or_rules;
+  sub_or_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kDestPort, /*port=*/123));
+  std::vector<std::unique_ptr<Rbac::Permission>> and_rules;
+  and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kAnd, std::move(sub_and_rules)));
+  and_rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kOr, std::move(std::move(sub_or_rules))));
+  AndAuthorizationMatcher matcher(std::move(and_rules));
+  // Fails as "absent_key" header was not present.
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PathAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata(":path", "expected/path");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PathAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"expected/path",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PathAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata(":path", "different/path");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PathAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"expected/path",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotPathAuthorizationMatcher) {
+  args_.AddPairToMetadata(":path", "expected/path");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PathAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact, "expected/path", false)
+          .value(),
+      /*not_rule=*/true);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       PathAuthorizationMatcherFailedMatchMissingPath) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PathAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"expected/path",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, HeaderAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("key123", "foo_xxx");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kPrefix,
+                            /*matcher=*/"foo")
+          .value());
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, HeaderAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("key123", "foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       HeaderAuthorizationMatcherFailedMatchMultivaluedHeader) {
+  args_.AddPairToMetadata("key123", "foo");
+  args_.AddPairToMetadata("key123", "bar");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"foo")
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       HeaderAuthorizationMatcherFailedMatchMissingHeader) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kSuffix,
+                            /*matcher=*/"foo")
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotHeaderAuthorizationMatcher) {
+  args_.AddPairToMetadata("key123", "foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  HeaderAuthorizationMatcher matcher(
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value(),
+      /*not_rule=*/true);
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PortAuthorizationMatcherSuccessfulMatch) {
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PortAuthorizationMatcher matcher(/*port=*/123);
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PortAuthorizationMatcherFailedMatch) {
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PortAuthorizationMatcher matcher(/*port=*/456);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotPortAuthorizationMatcher) {
+  args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  PortAuthorizationMatcher matcher(/*port=*/123, /*not_rule=*/true);
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       AuthenticatedMatcherUnAuthenticatedConnection) {
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"foo.com",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       AuthenticatedMatcherAuthenticatedConnectionMatcherUnset) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest,
+       AuthenticatedMatcherSuccessfulSpiffeIdMatches) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  args_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME,
+                                 "spiffe://foo.abc");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"spiffe://foo.abc",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedSpiffeIdMatches) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  args_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME,
+                                 "spiffe://bar.abc");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"spiffe://foo.abc",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedNothingMatches) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"foo",
+                            /*case_sensitive=*/false)
+          .value());
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, NotAuthenticatedMatcher) {
+  args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  AuthenticatedAuthorizationMatcher matcher(
+      StringMatcher::Create(StringMatcher::Type::kExact, /*matcher=*/"foo",
+                            /*case_sensitive=*/false)
+          .value(),
+      /*not_rule=*/true);
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PolicyAuthorizationMatcherSuccessfulMatch) {
+  args_.AddPairToMetadata("key123", "foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"foo")
+          .value()));
+  PolicyAuthorizationMatcher matcher(Rbac::Policy(
+      Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(rules)),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny)));
+  EXPECT_TRUE(matcher.Matches(args));
+}
+
+TEST_F(AuthorizationMatchersTest, PolicyAuthorizationMatcherFailedMatch) {
+  args_.AddPairToMetadata("key123", "foo");
+  EvaluateArgs args = args_.MakeEvaluateArgs();
+  std::vector<std::unique_ptr<Rbac::Permission>> rules;
+  rules.push_back(absl::make_unique<Rbac::Permission>(
+      Rbac::Permission::RuleType::kHeader,
+      HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"bar")
+          .value()));
+  PolicyAuthorizationMatcher matcher(Rbac::Policy(
+      Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(rules)),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny)));
+  EXPECT_FALSE(matcher.Matches(args));
+}
+
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  grpc_init();
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
+}
diff --git a/grpc/test/core/security/aws_request_signer_test.cc b/grpc/test/core/security/aws_request_signer_test.cc
index e384183..bc5780f 100644
--- a/grpc/test/core/security/aws_request_signer_test.cc
+++ b/grpc/test/core/security/aws_request_signer_test.cc
@@ -65,7 +65,7 @@
 // AWS official example from the developer doc.
 // https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
 TEST(GrpcAwsRequestSignerTest, AWSOfficialExample) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       "AKIDEXAMPLE", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", "", "GET",
       "https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08",
@@ -83,7 +83,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, GetDescribeRegions) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kAmzTestAccessKeyId, kAmzTestSecretAccessKey, kAmzTestToken, "GET",
       "https://"
@@ -100,7 +100,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentity) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kAmzTestAccessKeyId, kAmzTestSecretAccessKey, kAmzTestToken, "POST",
       "https://"
@@ -117,7 +117,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentityNoToken) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kAmzTestAccessKeyId, kAmzTestSecretAccessKey, "", "POST",
       "https://"
@@ -134,7 +134,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, GetHost) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(kBotoTestAccessKeyId,
                                      kBotoTestSecretAccessKey, kBotoTestToken,
                                      "GET", "https://host.foo.com", "us-east-1",
@@ -149,7 +149,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, GetHostDuplicateQueryParam) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "GET",
       "https://host.foo.com/?foo=Zoo&foo=aha", "us-east-1", "",
@@ -164,7 +164,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderKey) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/", "us-east-1", "",
@@ -179,7 +179,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderValue) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/", "us-east-1", "",
@@ -194,7 +194,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, SignPostWithHeader) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/", "us-east-1", "",
@@ -209,7 +209,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, PostWithBodyNoCustomHeaders) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/", "us-east-1", "foo=bar",
@@ -226,7 +226,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, SignPostWithQueryString) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
       "https://host.foo.com/?foo=bar", "us-east-1", "",
@@ -241,7 +241,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, InvalidUrl) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer("access_key_id", "secret_access_key",
                                      "token", "POST", "invalid_url",
                                      "us-east-1", "", {}, &error);
@@ -256,7 +256,7 @@
 }
 
 TEST(GrpcAwsRequestSignerTest, DuplicateRequestDate) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::AwsRequestSigner signer(
       "access_key_id", "secret_access_key", "token", "POST", "invalid_url",
       "us-east-1", "", {{"date", kBotoTestDate}, {"x-amz-date", kAmzTestDate}},
diff --git a/grpc/test/core/security/cel_authorization_engine_test.cc b/grpc/test/core/security/cel_authorization_engine_test.cc
new file mode 100644
index 0000000..4c94a87
--- /dev/null
+++ b/grpc/test/core/security/cel_authorization_engine_test.cc
@@ -0,0 +1,80 @@
+// Copyright 2020 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 "src/core/lib/security/authorization/cel_authorization_engine.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc_core {
+
+class CelAuthorizationEngineTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    deny_policy_ = envoy_config_rbac_v3_RBAC_new(arena_.ptr());
+    envoy_config_rbac_v3_RBAC_set_action(deny_policy_, 1);
+    allow_policy_ = envoy_config_rbac_v3_RBAC_new(arena_.ptr());
+    envoy_config_rbac_v3_RBAC_set_action(allow_policy_, 0);
+  }
+  upb::Arena arena_;
+  envoy_config_rbac_v3_RBAC* deny_policy_;
+  envoy_config_rbac_v3_RBAC* allow_policy_;
+};
+
+TEST_F(CelAuthorizationEngineTest, CreateEngineSuccessOnePolicy) {
+  std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_};
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
+  EXPECT_NE(engine, nullptr)
+      << "Error: Failed to create CelAuthorizationEngine with one policy.";
+}
+
+TEST_F(CelAuthorizationEngineTest, CreateEngineSuccessTwoPolicies) {
+  std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_};
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
+  EXPECT_NE(engine, nullptr)
+      << "Error: Failed to create CelAuthorizationEngine with two policies.";
+}
+
+TEST_F(CelAuthorizationEngineTest, CreateEngineFailNoPolicies) {
+  std::vector<envoy_config_rbac_v3_RBAC*> policies{};
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
+  EXPECT_EQ(engine, nullptr)
+      << "Error: Created CelAuthorizationEngine without policies.";
+}
+
+TEST_F(CelAuthorizationEngineTest, CreateEngineFailTooManyPolicies) {
+  std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_,
+                                                   deny_policy_};
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
+  EXPECT_EQ(engine, nullptr)
+      << "Error: Created CelAuthorizationEngine with more than two policies.";
+}
+
+TEST_F(CelAuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) {
+  std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_, deny_policy_};
+  std::unique_ptr<CelAuthorizationEngine> engine =
+      CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
+  EXPECT_EQ(engine, nullptr) << "Error: Created CelAuthorizationEngine with "
+                                "policies in the wrong order.";
+}
+
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/grpc/test/core/security/credentials_test.cc b/grpc/test/core/security/credentials_test.cc
index 6106f6d..0533247 100644
--- a/grpc/test/core/security/credentials_test.cc
+++ b/grpc/test/core/security/credentials_test.cc
@@ -415,7 +415,7 @@
 } expected_md;
 
 typedef struct {
-  grpc_error* expected_error;
+  grpc_error_handle expected_error;
   const expected_md* expected;
   size_t expected_size;
   grpc_credentials_mdelem_array md_array;
@@ -443,11 +443,11 @@
   }
 }
 
-static void check_request_metadata(void* arg, grpc_error* error) {
+static void check_request_metadata(void* arg, grpc_error_handle error) {
   request_metadata_state* state = static_cast<request_metadata_state*>(arg);
   gpr_log(GPR_INFO, "expected_error: %s",
-          grpc_error_string(state->expected_error));
-  gpr_log(GPR_INFO, "actual_error: %s", grpc_error_string(error));
+          grpc_error_std_string(state->expected_error).c_str());
+  gpr_log(GPR_INFO, "actual_error: %s", grpc_error_std_string(error).c_str());
   if (state->expected_error == GRPC_ERROR_NONE) {
     GPR_ASSERT(error == GRPC_ERROR_NONE);
   } else {
@@ -470,7 +470,7 @@
 }
 
 static request_metadata_state* make_request_metadata_state(
-    grpc_error* expected_error, const expected_md* expected,
+    grpc_error_handle expected_error, const expected_md* expected,
     size_t expected_size) {
   request_metadata_state* state =
       static_cast<request_metadata_state*>(gpr_zalloc(sizeof(*state)));
@@ -487,7 +487,7 @@
 static void run_request_metadata_test(grpc_call_credentials* creds,
                                       grpc_auth_metadata_context auth_md_ctx,
                                       request_metadata_state* state) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (creds->get_request_metadata(&state->pollent, auth_md_ctx,
                                   &state->md_array, &state->on_request_metadata,
                                   &error)) {
@@ -1663,27 +1663,27 @@
   explicit fake_call_creds() : grpc_call_credentials("fake") {
     grpc_slice key = grpc_slice_from_static_string("foo");
     grpc_slice value = grpc_slice_from_static_string("oof");
-    dummy_md_ = grpc_mdelem_from_slices(key, value);
+    phony_md_ = grpc_mdelem_from_slices(key, value);
     grpc_slice_unref(key);
     grpc_slice_unref(value);
   }
 
-  ~fake_call_creds() override { GRPC_MDELEM_UNREF(dummy_md_); }
+  ~fake_call_creds() override { GRPC_MDELEM_UNREF(phony_md_); }
 
-  bool get_request_metadata(grpc_polling_entity* pollent,
-                            grpc_auth_metadata_context context,
+  bool get_request_metadata(grpc_polling_entity* /*pollent*/,
+                            grpc_auth_metadata_context /*context*/,
                             grpc_credentials_mdelem_array* md_array,
-                            grpc_closure* on_request_metadata,
-                            grpc_error** error) override {
-    grpc_credentials_mdelem_array_add(md_array, dummy_md_);
+                            grpc_closure* /*on_request_metadata*/,
+                            grpc_error_handle* /*error*/) override {
+    grpc_credentials_mdelem_array_add(md_array, phony_md_);
     return true;
   }
 
-  void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
-                                   grpc_error* error) override {}
+  void cancel_get_request_metadata(grpc_credentials_mdelem_array* /*md_array*/,
+                                   grpc_error_handle /*error*/) override {}
 
  private:
-  grpc_mdelem dummy_md_;
+  grpc_mdelem phony_md_;
 };
 
 static void test_google_default_creds_not_default(void) {
@@ -1983,7 +1983,7 @@
 
 static void validate_external_account_creds_token_exchage_request(
     const grpc_httpcli_request* request, const char* body, size_t body_size,
-    bool expect_actor_token) {
+    bool /*expect_actor_token*/) {
   // Check that the body is constructed properly.
   GPR_ASSERT(body != nullptr);
   GPR_ASSERT(body_size != 0);
@@ -2021,7 +2021,7 @@
 static void
 validate_external_account_creds_token_exchage_request_with_url_encode(
     const grpc_httpcli_request* request, const char* body, size_t body_size,
-    bool expect_actor_token) {
+    bool /*expect_actor_token*/) {
   // Check that the body is constructed properly.
   GPR_ASSERT(body != nullptr);
   GPR_ASSERT(body_size != 0);
@@ -2051,7 +2051,7 @@
 static void
 validate_external_account_creds_service_account_impersonation_request(
     const grpc_httpcli_request* request, const char* body, size_t body_size,
-    bool expect_actor_token) {
+    bool /*expect_actor_token*/) {
   // Check that the body is constructed properly.
   GPR_ASSERT(body != nullptr);
   GPR_ASSERT(body_size != 0);
@@ -2097,8 +2097,8 @@
 
 static int
 external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token(
-    const grpc_httpcli_request* request, const char* body, size_t body_size,
-    grpc_millis /*deadline*/, grpc_closure* on_done,
+    const grpc_httpcli_request* request, const char* /*body*/,
+    size_t /*body_size*/, grpc_millis /*deadline*/, grpc_closure* on_done,
     grpc_httpcli_response* response) {
   if (strcmp(request->http.path, "/token") == 0) {
     *response = http_response(200,
@@ -2139,10 +2139,13 @@
 
 static void validate_aws_external_account_creds_token_exchage_request(
     const grpc_httpcli_request* request, const char* body, size_t body_size,
-    bool expect_actor_token) {
+    bool /*expect_actor_token*/) {
   // Check that the body is constructed properly.
   GPR_ASSERT(body != nullptr);
   GPR_ASSERT(body_size != 0);
+  // Check that the regional_cred_verification_url got constructed
+  // with the correct AWS Region ("test_regionz" or "test_region").
+  GPR_ASSERT(strstr(body, "regional_cred_verification_url_test_region"));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   std::string get_url_equivalent =
       absl::StrFormat("%s?%s", "https://foo.com:5555/token", body);
@@ -2212,8 +2215,8 @@
 
  protected:
   void RetrieveSubjectToken(
-      HTTPRequestContext* ctx, const Options& options,
-      std::function<void(std::string, grpc_error*)> cb) override {
+      HTTPRequestContext* /*ctx*/, const Options& /*options*/,
+      std::function<void(std::string, grpc_error_handle)> cb) override {
     cb("test_subject_token", GRPC_ERROR_NONE);
   }
 };
@@ -2337,10 +2340,11 @@
   TestExternalAccountCredentials creds(options, {});
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Invalid token url: invalid_token_url.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(&creds, auth_md_ctx, state);
@@ -2371,11 +2375,12 @@
   TestExternalAccountCredentials creds(options, {});
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             external_account_creds_httpcli_post_success);
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Invalid service account impersonation url: "
       "invalid_service_account_impersonation_url.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(&creds, auth_md_ctx, state);
@@ -2407,12 +2412,13 @@
   grpc_httpcli_set_override(
       httpcli_get_should_not_be_called,
       external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token);
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+  grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Missing or invalid access_token in "
       "{\"not_access_token\":\"not_access_token\",\"expires_in\":3599,\"token_"
       "type\":\"Bearer\"}.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(&creds, auth_md_ctx, state);
@@ -2426,7 +2432,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_url_external_account_creds_options_credential_source_format_text,
       &error);
@@ -2463,7 +2469,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_url_external_account_creds_options_credential_source_with_qurey_params_format_text,
       &error);
@@ -2499,7 +2505,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_url_external_account_creds_options_credential_source_format_json,
       &error);
@@ -2532,7 +2538,7 @@
 
 static void
 test_url_external_account_creds_failure_invalid_credential_source_url(void) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_url_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2565,7 +2571,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   char* subject_token_path = write_tmp_jwt_file("test_subject_token");
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       absl::StrFormat(
@@ -2606,7 +2612,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   char* subject_token_path =
       write_tmp_jwt_file("{\"access_token\":\"test_subject_token\"}");
   grpc_core::Json credential_source = grpc_core::Json::Parse(
@@ -2654,7 +2660,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source =
       grpc_core::Json::Parse("{\"file\":\"non_exisiting_file\"}", &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2677,8 +2683,9 @@
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to load file");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(creds.get(), auth_md_ctx, state);
@@ -2692,7 +2699,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   char* subject_token_path = write_tmp_jwt_file("not_a_valid_json_file");
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       absl::StrFormat(
@@ -2727,8 +2734,9 @@
                             httpcli_post_should_not_be_called);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "The content of the file is not a valid json object.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   run_request_metadata_test(creds.get(), auth_md_ctx, state);
@@ -2743,7 +2751,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_aws_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2780,7 +2788,7 @@
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
   gpr_setenv("AWS_REGION", "test_regionz");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_aws_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2811,6 +2819,86 @@
   gpr_unsetenv("AWS_REGION");
 }
 
+static void
+test_aws_external_account_creds_success_path_default_region_env_keys_url(void) {
+  expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
+  grpc_core::ExecCtx exec_ctx;
+  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+                                            nullptr, nullptr};
+  gpr_setenv("AWS_DEFAULT_REGION", "test_regionz");
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  grpc_core::Json credential_source = grpc_core::Json::Parse(
+      valid_aws_external_account_creds_options_credential_source, &error);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  grpc_core::ExternalAccountCredentials::Options options = {
+      "external_account",                 // type;
+      "audience",                         // audience;
+      "subject_token_type",               // subject_token_type;
+      "",                                 // service_account_impersonation_url;
+      "https://foo.com:5555/token",       // token_url;
+      "https://foo.com:5555/token_info",  // token_info_url;
+      credential_source,                  // credential_source;
+      "quota_project_id",                 // quota_project_id;
+      "client_id",                        // client_id;
+      "client_secret",                    // client_secret;
+  };
+  auto creds =
+      grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
+  GPR_ASSERT(creds != nullptr);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
+  request_metadata_state* state =
+      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+  grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
+                            aws_external_account_creds_httpcli_post_success);
+  run_request_metadata_test(creds.get(), auth_md_ctx, state);
+  grpc_core::ExecCtx::Get()->Flush();
+  grpc_httpcli_set_override(nullptr, nullptr);
+  gpr_unsetenv("AWS_DEFAULT_REGION");
+}
+
+static void
+test_aws_external_account_creds_success_path_duplicate_region_env_keys_url(
+    void) {
+  expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
+  grpc_core::ExecCtx exec_ctx;
+  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+                                            nullptr, nullptr};
+  // Make sure that AWS_REGION gets used over AWS_DEFAULT_REGION
+  gpr_setenv("AWS_REGION", "test_regionz");
+  gpr_setenv("AWS_DEFAULT_REGION", "ERROR_REGION");
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  grpc_core::Json credential_source = grpc_core::Json::Parse(
+      valid_aws_external_account_creds_options_credential_source, &error);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  grpc_core::ExternalAccountCredentials::Options options = {
+      "external_account",                 // type;
+      "audience",                         // audience;
+      "subject_token_type",               // subject_token_type;
+      "",                                 // service_account_impersonation_url;
+      "https://foo.com:5555/token",       // token_url;
+      "https://foo.com:5555/token_info",  // token_info_url;
+      credential_source,                  // credential_source;
+      "quota_project_id",                 // quota_project_id;
+      "client_id",                        // client_id;
+      "client_secret",                    // client_secret;
+  };
+  auto creds =
+      grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
+  GPR_ASSERT(creds != nullptr);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
+  request_metadata_state* state =
+      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+  grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
+                            aws_external_account_creds_httpcli_post_success);
+  run_request_metadata_test(creds.get(), auth_md_ctx, state);
+  grpc_core::ExecCtx::Get()->Flush();
+  grpc_httpcli_set_override(nullptr, nullptr);
+  gpr_unsetenv("AWS_REGION");
+  gpr_unsetenv("AWS_DEFAULT_REGION");
+}
+
 static void test_aws_external_account_creds_success_path_region_url_keys_env(
     void) {
   expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
@@ -2820,7 +2908,7 @@
   gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
   gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
   gpr_setenv("AWS_SESSION_TOKEN", "test_token");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_aws_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2863,7 +2951,7 @@
   gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
   gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
   gpr_setenv("AWS_SESSION_TOKEN", "test_token");
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       valid_aws_external_account_creds_options_credential_source, &error);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
@@ -2897,9 +2985,101 @@
   gpr_unsetenv("AWS_SESSION_TOKEN");
 }
 
+static void
+test_aws_external_account_creds_success_path_default_region_env_keys_env(void) {
+  expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
+  grpc_core::ExecCtx exec_ctx;
+  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+                                            nullptr, nullptr};
+  gpr_setenv("AWS_DEFAULT_REGION", "test_regionz");
+  gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
+  gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
+  gpr_setenv("AWS_SESSION_TOKEN", "test_token");
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  grpc_core::Json credential_source = grpc_core::Json::Parse(
+      valid_aws_external_account_creds_options_credential_source, &error);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  grpc_core::ExternalAccountCredentials::Options options = {
+      "external_account",                 // type;
+      "audience",                         // audience;
+      "subject_token_type",               // subject_token_type;
+      "",                                 // service_account_impersonation_url;
+      "https://foo.com:5555/token",       // token_url;
+      "https://foo.com:5555/token_info",  // token_info_url;
+      credential_source,                  // credential_source;
+      "quota_project_id",                 // quota_project_id;
+      "client_id",                        // client_id;
+      "client_secret",                    // client_secret;
+  };
+  auto creds =
+      grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
+  GPR_ASSERT(creds != nullptr);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
+  request_metadata_state* state =
+      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+  grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
+                            aws_external_account_creds_httpcli_post_success);
+  run_request_metadata_test(creds.get(), auth_md_ctx, state);
+  grpc_core::ExecCtx::Get()->Flush();
+  grpc_httpcli_set_override(nullptr, nullptr);
+  gpr_unsetenv("AWS_DEFAULT_REGION");
+  gpr_unsetenv("AWS_ACCESS_KEY_ID");
+  gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
+  gpr_unsetenv("AWS_SESSION_TOKEN");
+}
+
+static void
+test_aws_external_account_creds_success_path_duplicate_region_env_keys_env(
+    void) {
+  expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
+  grpc_core::ExecCtx exec_ctx;
+  grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
+                                            nullptr, nullptr};
+  // Make sure that AWS_REGION gets used over AWS_DEFAULT_REGION
+  gpr_setenv("AWS_REGION", "test_regionz");
+  gpr_setenv("AWS_DEFAULT_REGION", "ERROR_REGION");
+  gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
+  gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
+  gpr_setenv("AWS_SESSION_TOKEN", "test_token");
+  grpc_error_handle error = GRPC_ERROR_NONE;
+  grpc_core::Json credential_source = grpc_core::Json::Parse(
+      valid_aws_external_account_creds_options_credential_source, &error);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  grpc_core::ExternalAccountCredentials::Options options = {
+      "external_account",                 // type;
+      "audience",                         // audience;
+      "subject_token_type",               // subject_token_type;
+      "",                                 // service_account_impersonation_url;
+      "https://foo.com:5555/token",       // token_url;
+      "https://foo.com:5555/token_info",  // token_info_url;
+      credential_source,                  // credential_source;
+      "quota_project_id",                 // quota_project_id;
+      "client_id",                        // client_id;
+      "client_secret",                    // client_secret;
+  };
+  auto creds =
+      grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
+  GPR_ASSERT(creds != nullptr);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
+  GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
+  request_metadata_state* state =
+      make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
+  grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
+                            aws_external_account_creds_httpcli_post_success);
+  run_request_metadata_test(creds.get(), auth_md_ctx, state);
+  grpc_core::ExecCtx::Get()->Flush();
+  grpc_httpcli_set_override(nullptr, nullptr);
+  gpr_unsetenv("AWS_REGION");
+  gpr_unsetenv("AWS_DEFAULT_REGION");
+  gpr_unsetenv("AWS_ACCESS_KEY_ID");
+  gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
+  gpr_unsetenv("AWS_SESSION_TOKEN");
+}
+
 static void test_aws_external_account_creds_failure_unmatched_environment_id(
     void) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id,
       &error);
@@ -2932,7 +3112,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_invalid_region_url,
       &error);
@@ -2956,8 +3136,9 @@
   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Invalid region url: invalid_region_url.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
@@ -2972,7 +3153,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_invalid_url,
       &error);
@@ -2995,8 +3176,9 @@
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid url: invalid_url.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
@@ -3011,7 +3193,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_missing_role_name,
       &error);
@@ -3035,8 +3217,9 @@
   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Missing role name when retrieving signing keys.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
@@ -3053,7 +3236,7 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
                                             nullptr, nullptr};
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   grpc_core::Json credential_source = grpc_core::Json::Parse(
       invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url,
       &error);
@@ -3077,8 +3260,9 @@
   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
   error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
       "Creating aws request signer failed.");
-  grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-      "Error occurred when fetching oauth2 token.", &error, 1);
+  grpc_error_handle expected_error =
+      GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+          "Error occurred when fetching oauth2 token.", &error, 1);
   request_metadata_state* state =
       make_request_metadata_state(expected_error, nullptr, 0);
   grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
@@ -3235,8 +3419,12 @@
   test_file_external_account_creds_failure_invalid_json_content();
   test_aws_external_account_creds_success();
   test_aws_external_account_creds_success_path_region_env_keys_url();
+  test_aws_external_account_creds_success_path_default_region_env_keys_url();
+  test_aws_external_account_creds_success_path_duplicate_region_env_keys_url();
   test_aws_external_account_creds_success_path_region_url_keys_env();
   test_aws_external_account_creds_success_path_region_env_keys_env();
+  test_aws_external_account_creds_success_path_default_region_env_keys_env();
+  test_aws_external_account_creds_success_path_duplicate_region_env_keys_env();
   test_aws_external_account_creds_failure_unmatched_environment_id();
   test_aws_external_account_creds_failure_invalid_region_url();
   test_aws_external_account_creds_failure_invalid_url();
diff --git a/grpc/test/core/security/evaluate_args_test.cc b/grpc/test/core/security/evaluate_args_test.cc
index aa1b436..de98537 100644
--- a/grpc/test/core/security/evaluate_args_test.cc
+++ b/grpc/test/core/security/evaluate_args_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 gRPC authors.
+// Copyright 2021 gRPC authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -17,203 +17,139 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "absl/strings/string_view.h"
-
 #include "src/core/lib/security/authorization/evaluate_args.h"
-#include "test/core/util/eval_args_mock_endpoint.h"
+#include "test/core/util/evaluate_args_test_util.h"
 #include "test/core/util/test_config.h"
 
 namespace grpc_core {
 
 class EvaluateArgsTest : public ::testing::Test {
  protected:
-  void SetUp() override {
-    local_address_ = "255.255.255.255";
-    peer_address_ = "128.128.128.128";
-    local_port_ = 413;
-    peer_port_ = 314;
-    endpoint_ = CreateEvalArgsMockEndpoint(local_address_.c_str(), local_port_,
-                                           peer_address_.c_str(), peer_port_);
-    evaluate_args_ =
-        absl::make_unique<EvaluateArgs>(nullptr, nullptr, endpoint_);
-  }
-  void TearDown() override { grpc_endpoint_destroy(endpoint_); }
-  grpc_endpoint* endpoint_;
-  std::unique_ptr<EvaluateArgs> evaluate_args_;
-  std::string local_address_;
-  std::string peer_address_;
-  int local_port_;
-  int peer_port_;
+  EvaluateArgsTestUtil util_;
 };
 
-TEST_F(EvaluateArgsTest, TestEvaluateArgsLocalAddress) {
-  absl::string_view src_address = evaluate_args_->GetLocalAddress();
-  EXPECT_EQ(src_address, local_address_);
+TEST_F(EvaluateArgsTest, EmptyMetadata) {
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetPath(), nullptr);
+  EXPECT_EQ(args.GetMethod(), nullptr);
+  EXPECT_EQ(args.GetHost(), nullptr);
+  EXPECT_THAT(args.GetHeaders(), ::testing::ElementsAre());
+  EXPECT_EQ(args.GetHeaderValue("some_key", nullptr), absl::nullopt);
 }
 
-TEST_F(EvaluateArgsTest, TestEvaluateArgsLocalPort) {
-  int src_port = evaluate_args_->GetLocalPort();
-  EXPECT_EQ(src_port, local_port_);
+TEST_F(EvaluateArgsTest, GetPathSuccess) {
+  util_.AddPairToMetadata(":path", "/expected/path");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetPath(), "/expected/path");
 }
 
-TEST_F(EvaluateArgsTest, TestEvaluateArgsPeerAddress) {
-  absl::string_view dest_address = evaluate_args_->GetPeerAddress();
-  EXPECT_EQ(dest_address, peer_address_);
+TEST_F(EvaluateArgsTest, GetHostSuccess) {
+  util_.AddPairToMetadata("host", "host123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetHost(), "host123");
 }
 
-TEST_F(EvaluateArgsTest, TestEvaluateArgsPeerPort) {
-  int dest_port = evaluate_args_->GetPeerPort();
-  EXPECT_EQ(dest_port, peer_port_);
+TEST_F(EvaluateArgsTest, GetMethodSuccess) {
+  util_.AddPairToMetadata(":method", "GET");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetMethod(), "GET");
 }
 
-TEST(EvaluateArgsMetadataTest, HandlesNullMetadata) {
-  EvaluateArgs eval_args(nullptr, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetPath(), nullptr);
-  EXPECT_EQ(eval_args.GetMethod(), nullptr);
-  EXPECT_EQ(eval_args.GetHost(), nullptr);
-  EXPECT_THAT(eval_args.GetHeaders(), ::testing::ElementsAre());
+TEST_F(EvaluateArgsTest, GetHeadersSuccess) {
+  util_.AddPairToMetadata("host", "host123");
+  util_.AddPairToMetadata(":path", "/expected/path");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_THAT(args.GetHeaders(),
+              ::testing::UnorderedElementsAre(
+                  ::testing::Pair("host", "host123"),
+                  ::testing::Pair(":path", "/expected/path")));
 }
 
-TEST(EvaluateArgsMetadataTest, HandlesEmptyMetadata) {
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetPath(), nullptr);
-  EXPECT_EQ(eval_args.GetMethod(), nullptr);
-  EXPECT_EQ(eval_args.GetHost(), nullptr);
-  EXPECT_THAT(eval_args.GetHeaders(), ::testing::ElementsAre());
-  grpc_metadata_batch_destroy(&metadata);
+TEST_F(EvaluateArgsTest, GetHeaderValueSuccess) {
+  util_.AddPairToMetadata("key123", "value123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  std::string concatenated_value;
+  absl::optional<absl::string_view> value =
+      args.GetHeaderValue("key123", &concatenated_value);
+  ASSERT_TRUE(value.has_value());
+  EXPECT_EQ(value.value(), "value123");
 }
 
-TEST(EvaluateArgsMetadataTest, GetPathSuccess) {
-  grpc_init();
-  const char* kPath = "/some/path";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_slice fake_val = grpc_slice_intern(grpc_slice_from_static_string(kPath));
-  grpc_mdelem fake_val_md = grpc_mdelem_from_slices(GRPC_MDSTR_PATH, fake_val);
-  grpc_linked_mdelem storage;
-  storage.md = fake_val_md;
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage),
-            GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetPath(), kPath);
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, TestIpv4LocalAddressAndPort) {
+  util_.SetLocalEndpoint("ipv4:255.255.255.255:123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetLocalAddress(), "255.255.255.255");
+  EXPECT_EQ(args.GetLocalPort(), 123);
 }
 
-TEST(EvaluateArgsMetadataTest, GetHostSuccess) {
-  grpc_init();
-  const char* kHost = "host";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_slice fake_val = grpc_slice_intern(grpc_slice_from_static_string(kHost));
-  grpc_mdelem fake_val_md = grpc_mdelem_from_slices(GRPC_MDSTR_HOST, fake_val);
-  grpc_linked_mdelem storage;
-  storage.md = fake_val_md;
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage),
-            GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetHost(), kHost);
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, TestIpv4PeerAddressAndPort) {
+  util_.SetPeerEndpoint("ipv4:128.128.128.128:321");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetPeerAddress(), "128.128.128.128");
+  EXPECT_EQ(args.GetPeerPort(), 321);
 }
 
-TEST(EvaluateArgsMetadataTest, GetMethodSuccess) {
-  grpc_init();
-  const char* kMethod = "GET";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_slice fake_val =
-      grpc_slice_intern(grpc_slice_from_static_string(kMethod));
-  grpc_mdelem fake_val_md =
-      grpc_mdelem_from_slices(GRPC_MDSTR_METHOD, fake_val);
-  grpc_linked_mdelem storage;
-  storage.md = fake_val_md;
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage),
-            GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetMethod(), kMethod);
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, TestIpv6LocalAddressAndPort) {
+  util_.SetLocalEndpoint("ipv6:[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:456");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetLocalAddress(), "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+  EXPECT_EQ(args.GetLocalPort(), 456);
 }
 
-TEST(EvaluateArgsMetadataTest, GetHeadersSuccess) {
-  grpc_init();
-  const char* kPath = "/some/path";
-  const char* kHost = "host";
-  grpc_metadata_batch metadata;
-  grpc_metadata_batch_init(&metadata);
-  grpc_slice fake_path =
-      grpc_slice_intern(grpc_slice_from_static_string(kPath));
-  grpc_mdelem fake_path_md =
-      grpc_mdelem_from_slices(GRPC_MDSTR_PATH, fake_path);
-  grpc_linked_mdelem storage;
-  storage.md = fake_path_md;
-  ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage, GRPC_BATCH_PATH),
-            GRPC_ERROR_NONE);
-  grpc_slice fake_host =
-      grpc_slice_intern(grpc_slice_from_static_string(kHost));
-  grpc_mdelem fake_host_md =
-      grpc_mdelem_from_slices(GRPC_MDSTR_HOST, fake_host);
-  grpc_linked_mdelem storage2;
-  storage2.md = fake_host_md;
-  ASSERT_EQ(
-      grpc_metadata_batch_link_tail(&metadata, &storage2, GRPC_BATCH_HOST),
-      GRPC_ERROR_NONE);
-  EvaluateArgs eval_args(&metadata, nullptr, nullptr);
-  EXPECT_THAT(
-      eval_args.GetHeaders(),
-      ::testing::UnorderedElementsAre(
-          ::testing::Pair(StringViewFromSlice(GRPC_MDSTR_HOST), kHost),
-          ::testing::Pair(StringViewFromSlice(GRPC_MDSTR_PATH), kPath)));
-  grpc_metadata_batch_destroy(&metadata);
-  grpc_shutdown();
+TEST_F(EvaluateArgsTest, TestIpv6PeerAddressAndPort) {
+  util_.SetPeerEndpoint("ipv6:[2001:db8::1]:654");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetPeerAddress(), "2001:db8::1");
+  EXPECT_EQ(args.GetPeerPort(), 654);
 }
 
-TEST(EvaluateArgsAuthContextTest, HandlesNullAuthContext) {
-  EvaluateArgs eval_args(nullptr, nullptr, nullptr);
-  EXPECT_EQ(eval_args.GetSpiffeId(), nullptr);
-  EXPECT_EQ(eval_args.GetCertServerName(), nullptr);
+TEST_F(EvaluateArgsTest, EmptyAuthContext) {
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_TRUE(args.GetTransportSecurityType().empty());
+  EXPECT_TRUE(args.GetSpiffeId().empty());
+  EXPECT_TRUE(args.GetCommonName().empty());
 }
 
-TEST(EvaluateArgsAuthContextTest, HandlesEmptyAuthCtx) {
-  grpc_auth_context auth_context(nullptr);
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetSpiffeId(), nullptr);
-  EXPECT_EQ(eval_args.GetCertServerName(), nullptr);
+TEST_F(EvaluateArgsTest, GetTransportSecurityTypeSuccessOneProperty) {
+  util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 "ssl");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetTransportSecurityType(), "ssl");
 }
 
-TEST(EvaluateArgsAuthContextTest, GetSpiffeIdSuccessOneProperty) {
-  grpc_auth_context auth_context(nullptr);
-  const char* kId = "spiffeid";
-  auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, kId);
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetSpiffeId(), kId);
+TEST_F(EvaluateArgsTest, GetTransportSecurityTypeFailDuplicateProperty) {
+  util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 "type1");
+  util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+                                 "type2");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_TRUE(args.GetTransportSecurityType().empty());
 }
 
-TEST(EvaluateArgsAuthContextTest, GetSpiffeIdFailDuplicateProperty) {
-  grpc_auth_context auth_context(nullptr);
-  auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id1");
-  auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id2");
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetSpiffeId(), nullptr);
+TEST_F(EvaluateArgsTest, GetSpiffeIdSuccessOneProperty) {
+  util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetSpiffeId(), "id123");
 }
 
-TEST(EvaluateArgsAuthContextTest, GetCertServerNameSuccessOneProperty) {
-  grpc_auth_context auth_context(nullptr);
-  const char* kServer = "server";
-  auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, kServer);
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetCertServerName(), kServer);
+TEST_F(EvaluateArgsTest, GetSpiffeIdFailDuplicateProperty) {
+  util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id123");
+  util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id456");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_TRUE(args.GetSpiffeId().empty());
 }
 
-TEST(EvaluateArgsAuthContextTest, GetCertServerNameFailDuplicateProperty) {
-  grpc_auth_context auth_context(nullptr);
-  auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, "server1");
-  auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, "server2");
-  EvaluateArgs eval_args(nullptr, &auth_context, nullptr);
-  EXPECT_EQ(eval_args.GetCertServerName(), nullptr);
+TEST_F(EvaluateArgsTest, GetCommonNameSuccessOneProperty) {
+  util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server123");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_EQ(args.GetCommonName(), "server123");
+}
+
+TEST_F(EvaluateArgsTest, GetCommonNameFailDuplicateProperty) {
+  util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server123");
+  util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server456");
+  EvaluateArgs args = util_.MakeEvaluateArgs();
+  EXPECT_TRUE(args.GetCommonName().empty());
 }
 
 }  // namespace grpc_core
@@ -221,5 +157,8 @@
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  grpc_init();
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
 }
diff --git a/grpc/test/core/security/grpc_authorization_engine_test.cc b/grpc/test/core/security/grpc_authorization_engine_test.cc
new file mode 100644
index 0000000..a2b5e11
--- /dev/null
+++ b/grpc/test/core/security/grpc_authorization_engine_test.cc
@@ -0,0 +1,107 @@
+// Copyright 2021 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>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "src/core/lib/security/authorization/grpc_authorization_engine.h"
+
+namespace grpc_core {
+
+TEST(GrpcAuthorizationEngineTest, AllowEngineWithMatchingPolicy) {
+  Rbac::Policy policy1(
+      Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true));
+  Rbac::Policy policy2((Rbac::Permission(Rbac::Permission::RuleType::kAny)),
+                       (Rbac::Principal(Rbac::Principal::RuleType::kAny)));
+  std::map<std::string, Rbac::Policy> policies;
+  policies["policy1"] = std::move(policy1);
+  policies["policy2"] = std::move(policy2);
+  Rbac rbac(Rbac::Action::kAllow, std::move(policies));
+  GrpcAuthorizationEngine engine(std::move(rbac));
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
+  EXPECT_EQ(decision.matching_policy_name, "policy2");
+}
+
+TEST(GrpcAuthorizationEngineTest, AllowEngineWithNoMatchingPolicy) {
+  Rbac::Policy policy1(
+      Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true));
+  std::map<std::string, Rbac::Policy> policies;
+  policies["policy1"] = std::move(policy1);
+  Rbac rbac(Rbac::Action::kAllow, std::move(policies));
+  GrpcAuthorizationEngine engine(std::move(rbac));
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
+  EXPECT_TRUE(decision.matching_policy_name.empty());
+}
+
+TEST(GrpcAuthorizationEngineTest, AllowEngineWithEmptyPolicies) {
+  GrpcAuthorizationEngine engine(Rbac::Action::kAllow);
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
+  EXPECT_TRUE(decision.matching_policy_name.empty());
+}
+
+TEST(GrpcAuthorizationEngineTest, DenyEngineWithMatchingPolicy) {
+  Rbac::Policy policy1(
+      Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true));
+  Rbac::Policy policy2((Rbac::Permission(Rbac::Permission::RuleType::kAny)),
+                       (Rbac::Principal(Rbac::Principal::RuleType::kAny)));
+  std::map<std::string, Rbac::Policy> policies;
+  policies["policy1"] = std::move(policy1);
+  policies["policy2"] = std::move(policy2);
+  Rbac rbac(Rbac::Action::kDeny, std::move(policies));
+  GrpcAuthorizationEngine engine(std::move(rbac));
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
+  EXPECT_EQ(decision.matching_policy_name, "policy2");
+}
+
+TEST(GrpcAuthorizationEngineTest, DenyEngineWithNoMatchingPolicy) {
+  Rbac::Policy policy1(
+      Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true),
+      Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true));
+  std::map<std::string, Rbac::Policy> policies;
+  policies["policy1"] = std::move(policy1);
+  Rbac rbac(Rbac::Action::kDeny, std::move(policies));
+  GrpcAuthorizationEngine engine(std::move(rbac));
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
+  EXPECT_TRUE(decision.matching_policy_name.empty());
+}
+
+TEST(GrpcAuthorizationEngineTest, DenyEngineWithEmptyPolicies) {
+  GrpcAuthorizationEngine engine(Rbac::Action::kDeny);
+  AuthorizationEngine::Decision decision =
+      engine.Evaluate(EvaluateArgs(nullptr, nullptr));
+  EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
+  EXPECT_TRUE(decision.matching_policy_name.empty());
+}
+
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/grpc/test/core/security/grpc_tls_certificate_distributor_test.cc b/grpc/test/core/security/grpc_tls_certificate_distributor_test.cc
index 9e8efcc..92123a1 100644
--- a/grpc/test/core/security/grpc_tls_certificate_distributor_test.cc
+++ b/grpc/test/core/security/grpc_tls_certificate_distributor_test.cc
@@ -129,8 +129,8 @@
                                              std::move(updated_identity));
     }
 
-    void OnError(grpc_error* root_cert_error,
-                 grpc_error* identity_cert_error) override {
+    void OnError(grpc_error_handle root_cert_error,
+                 grpc_error_handle identity_cert_error) override {
       GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE ||
                  identity_cert_error != GRPC_ERROR_NONE);
       std::string root_error_str;
@@ -562,8 +562,8 @@
 
 TEST_F(GrpcTlsCertificateDistributorTest, SetKeyMaterialsInCallback) {
   distributor_.SetWatchStatusCallback([this](std::string cert_name,
-                                             bool root_being_watched,
-                                             bool identity_being_watched) {
+                                             bool /*root_being_watched*/,
+                                             bool /*identity_being_watched*/) {
     distributor_.SetKeyMaterials(
         cert_name, kRootCert1Contents,
         MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
@@ -913,8 +913,8 @@
 
 TEST_F(GrpcTlsCertificateDistributorTest, SetErrorForCertInCallback) {
   distributor_.SetWatchStatusCallback([this](std::string cert_name,
-                                             bool root_being_watched,
-                                             bool identity_being_watched) {
+                                             bool /*root_being_watched*/,
+                                             bool /*identity_being_watched*/) {
     this->distributor_.SetErrorForCert(
         cert_name, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
         GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
diff --git a/grpc/test/core/security/grpc_tls_certificate_provider_test.cc b/grpc/test/core/security/grpc_tls_certificate_provider_test.cc
index 5055357..9d67556 100644
--- a/grpc/test/core/security/grpc_tls_certificate_provider_test.cc
+++ b/grpc/test/core/security/grpc_tls_certificate_provider_test.cc
@@ -131,8 +131,8 @@
                                              std::move(updated_identity));
     }
 
-    void OnError(grpc_error* root_cert_error,
-                 grpc_error* identity_cert_error) override {
+    void OnError(grpc_error_handle root_cert_error,
+                 grpc_error_handle identity_cert_error) override {
       MutexLock lock(&state_->mu);
       GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE ||
                  identity_cert_error != GRPC_ERROR_NONE);
diff --git a/grpc/test/core/security/grpc_tls_credentials_options_test.cc b/grpc/test/core/security/grpc_tls_credentials_options_test.cc
index 5e9a4e3..c5736ca 100644
--- a/grpc/test/core/security/grpc_tls_credentials_options_test.cc
+++ b/grpc/test/core/security/grpc_tls_credentials_options_test.cc
@@ -69,6 +69,21 @@
   EXPECT_STREQ(error_details.error_details().c_str(), "test error details");
 }
 
+TEST_F(GrpcTlsCredentialsOptionsTest, ClientOptionsOnDefaultRootCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+}
+
 // Tests for StaticDataCertificateProvider.
 TEST_F(GrpcTlsCredentialsOptionsTest,
        ClientOptionsWithStaticDataProviderOnBothCerts) {
@@ -136,6 +151,26 @@
 }
 
 TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithDefaultRootAndStaticDataProviderOnIdentityCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<StaticDataCertificateProvider>(
+      "", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_identity_pair(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
        ServerOptionsWithStaticDataProviderOnBothCerts) {
   auto options = MakeRefCounted<grpc_tls_credentials_options>();
   auto provider = MakeRefCounted<StaticDataCertificateProvider>(
@@ -147,7 +182,7 @@
       GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
   auto credentials = MakeRefCounted<TlsServerCredentials>(options);
   ASSERT_NE(credentials, nullptr);
-  auto connector = credentials->create_security_connector();
+  auto connector = credentials->create_security_connector(nullptr);
   ASSERT_NE(connector, nullptr);
   TlsServerSecurityConnector* tls_connector =
       static_cast<TlsServerSecurityConnector*>(connector.get());
@@ -166,7 +201,7 @@
   options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
   auto credentials = MakeRefCounted<TlsServerCredentials>(options);
   ASSERT_NE(credentials, nullptr);
-  auto connector = credentials->create_security_connector();
+  auto connector = credentials->create_security_connector(nullptr);
   ASSERT_NE(connector, nullptr);
   TlsServerSecurityConnector* tls_connector =
       static_cast<TlsServerSecurityConnector*>(connector.get());
@@ -185,14 +220,14 @@
   options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
   auto credentials = MakeRefCounted<TlsServerCredentials>(options);
   ASSERT_NE(credentials, nullptr);
-  auto connector = credentials->create_security_connector();
+  auto connector = credentials->create_security_connector(nullptr);
   ASSERT_NE(connector, nullptr);
   TlsServerSecurityConnector* tls_connector =
       static_cast<TlsServerSecurityConnector*>(connector.get());
   EXPECT_EQ(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
 }
 
-//// Tests for FileWatcherCertificateProvider.
+// Tests for FileWatcherCertificateProvider.
 TEST_F(GrpcTlsCredentialsOptionsTest,
        ClientOptionsWithCertWatcherProviderOnBothCerts) {
   auto options = MakeRefCounted<grpc_tls_credentials_options>();
@@ -290,7 +325,7 @@
       GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
   auto credentials = MakeRefCounted<TlsServerCredentials>(options);
   ASSERT_NE(credentials, nullptr);
-  auto connector = credentials->create_security_connector();
+  auto connector = credentials->create_security_connector(nullptr);
   ASSERT_NE(connector, nullptr);
   TlsServerSecurityConnector* tls_connector =
       static_cast<TlsServerSecurityConnector*>(connector.get());
@@ -309,7 +344,7 @@
   options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
   auto credentials = MakeRefCounted<TlsServerCredentials>(options);
   ASSERT_NE(credentials, nullptr);
-  auto connector = credentials->create_security_connector();
+  auto connector = credentials->create_security_connector(nullptr);
   ASSERT_NE(connector, nullptr);
   TlsServerSecurityConnector* tls_connector =
       static_cast<TlsServerSecurityConnector*>(connector.get());
@@ -328,7 +363,7 @@
   options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
   auto credentials = MakeRefCounted<TlsServerCredentials>(options);
   ASSERT_NE(credentials, nullptr);
-  auto connector = credentials->create_security_connector();
+  auto connector = credentials->create_security_connector(nullptr);
   ASSERT_NE(connector, nullptr);
   TlsServerSecurityConnector* tls_connector =
       static_cast<TlsServerSecurityConnector*>(connector.get());
@@ -345,7 +380,7 @@
   options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
   auto credentials = MakeRefCounted<TlsServerCredentials>(options);
   ASSERT_NE(credentials, nullptr);
-  auto connector = credentials->create_security_connector();
+  auto connector = credentials->create_security_connector(nullptr);
   ASSERT_NE(connector, nullptr);
   TlsServerSecurityConnector* tls_connector =
       static_cast<TlsServerSecurityConnector*>(connector.get());
@@ -460,6 +495,7 @@
 
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
+  GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, CA_CERT_PATH);
   ::testing::InitGoogleTest(&argc, argv);
   grpc_init();
   int ret = RUN_ALL_TESTS();
diff --git a/grpc/test/core/security/json_token_test.cc b/grpc/test/core/security/json_token_test.cc
index 6b032bb..1ded259 100644
--- a/grpc/test/core/security/json_token_test.cc
+++ b/grpc/test/core/security/json_token_test.cc
@@ -215,11 +215,12 @@
   grpc_slice slice = grpc_base64_decode(b64, 1);
   gpr_free(b64);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(slice));
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   absl::string_view string = grpc_core::StringViewFromSlice(slice);
   Json json = Json::Parse(string, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
     GRPC_ERROR_UNREF(error);
   }
   grpc_slice_unref(slice);
diff --git a/grpc/test/core/security/jwt_verifier_test.cc b/grpc/test/core/security/jwt_verifier_test.cc
index 71178cb..21ed63f 100644
--- a/grpc/test/core/security/jwt_verifier_test.cc
+++ b/grpc/test/core/security/jwt_verifier_test.cc
@@ -207,10 +207,11 @@
 
 static void test_claims_success(void) {
   grpc_jwt_claims* claims;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(claims_without_time_constraint, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
@@ -229,10 +230,11 @@
 
 static void test_expired_claims_failure(void) {
   grpc_jwt_claims* claims;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(expired_claims, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
@@ -257,10 +259,11 @@
 }
 
 static void test_invalid_claims_failure(void) {
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(invalid_claims, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
@@ -270,10 +273,11 @@
 
 static void test_bad_audience_claims_failure(void) {
   grpc_jwt_claims* claims;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(claims_without_time_constraint, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
@@ -287,10 +291,11 @@
 
 static void test_bad_subject_claims_failure(void) {
   grpc_jwt_claims* claims;
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   Json json = Json::Parse(claims_with_bad_subject, &error);
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "JSON parse error: %s",
+            grpc_error_std_string(error).c_str());
   }
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(json.type() == Json::Type::OBJECT);
diff --git a/grpc/test/core/security/matchers_test.cc b/grpc/test/core/security/matchers_test.cc
new file mode 100644
index 0000000..0bacd16
--- /dev/null
+++ b/grpc/test/core/security/matchers_test.cc
@@ -0,0 +1,218 @@
+// Copyright 2021 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 "src/core/lib/matchers/matchers.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc_core {
+
+TEST(StringMatcherTest, ExactMatchCaseSensitive) {
+  auto string_matcher =
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"exact", /*case_sensitive=*/true);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("exact"));
+  EXPECT_FALSE(string_matcher->Match("Exact"));
+  EXPECT_FALSE(string_matcher->Match("exacz"));
+}
+
+TEST(StringMatcherTest, ExactMatchCaseInsensitive) {
+  auto string_matcher =
+      StringMatcher::Create(StringMatcher::Type::kExact,
+                            /*matcher=*/"exact", /*case_sensitive=*/false);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("Exact"));
+  EXPECT_FALSE(string_matcher->Match("Exacz"));
+}
+
+TEST(StringMatcherTest, PrefixMatchCaseSensitive) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kPrefix,
+                                              /*matcher=*/"prefix",
+                                              /*case_sensitive=*/true);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("prefix-test"));
+  EXPECT_FALSE(string_matcher->Match("xx-prefix-test"));
+  EXPECT_FALSE(string_matcher->Match("Prefix-test"));
+  EXPECT_FALSE(string_matcher->Match("pre-test"));
+}
+
+TEST(StringMatcherTest, PrefixMatchCaseInsensitive) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kPrefix,
+                                              /*matcher=*/"prefix",
+                                              /*case_sensitive=*/false);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("PREfix-test"));
+  EXPECT_FALSE(string_matcher->Match("xx-PREfix-test"));
+  EXPECT_FALSE(string_matcher->Match("PRE-test"));
+}
+
+TEST(StringMatcherTest, SuffixMatchCaseSensitive) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSuffix,
+                                              /*matcher=*/"suffix",
+                                              /*case_sensitive=*/true);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("test-suffix"));
+  EXPECT_FALSE(string_matcher->Match("test-Suffix"));
+  EXPECT_FALSE(string_matcher->Match("test-suffix-xx"));
+  EXPECT_FALSE(string_matcher->Match("test-suffiz"));
+}
+
+TEST(StringMatcherTest, SuffixMatchCaseInSensitive) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSuffix,
+                                              /*matcher=*/"suffix",
+                                              /*case_sensitive=*/false);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("Test-SUFFIX"));
+  EXPECT_FALSE(string_matcher->Match("Test-SUFFIX-xx"));
+  EXPECT_FALSE(string_matcher->Match("Test-SUFFIZ"));
+}
+
+TEST(StringMatcherTest, InvalidRegex) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex,
+                                              /*matcher=*/"a[b-a]",
+                                              /*case_sensitive=*/true);
+  EXPECT_FALSE(string_matcher.ok());
+  EXPECT_EQ(string_matcher.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(string_matcher.status().message(),
+            "Invalid regex string specified in matcher.");
+}
+
+TEST(StringMatcherTest, SafeRegexMatchCaseSensitive) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex,
+                                              /*matcher=*/"regex.*",
+                                              /*case_sensitive=*/true);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("regex-test"));
+  EXPECT_FALSE(string_matcher->Match("xx-regex-test"));
+  EXPECT_FALSE(string_matcher->Match("Regex-test"));
+  EXPECT_FALSE(string_matcher->Match("test-regex"));
+}
+
+TEST(StringMatcherTest, SafeRegexMatchCaseInSensitive) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex,
+                                              /*matcher=*/"regex.*",
+                                              /*case_sensitive=*/false);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("regex-test"));
+  EXPECT_TRUE(string_matcher->Match("Regex-test"));
+  EXPECT_FALSE(string_matcher->Match("xx-Regex-test"));
+  EXPECT_FALSE(string_matcher->Match("test-regex"));
+}
+
+TEST(StringMatcherTest, ContainsMatchCaseSensitive) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kContains,
+                                              /*matcher=*/"contains",
+                                              /*case_sensitive=*/true);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("test-contains"));
+  EXPECT_TRUE(string_matcher->Match("test-contains-test"));
+  EXPECT_FALSE(string_matcher->Match("test-Contains"));
+  EXPECT_FALSE(string_matcher->Match("test-containz"));
+}
+
+TEST(StringMatcherTest, ContainsMatchCaseInSensitive) {
+  auto string_matcher = StringMatcher::Create(StringMatcher::Type::kContains,
+                                              /*matcher=*/"contains",
+                                              /*case_sensitive=*/false);
+  ASSERT_TRUE(string_matcher.ok());
+  EXPECT_TRUE(string_matcher->Match("Test-Contains"));
+  EXPECT_TRUE(string_matcher->Match("Test-Contains-Test"));
+  EXPECT_FALSE(string_matcher->Match("Test-Containz"));
+}
+
+TEST(HeaderMatcherTest, StringMatcher) {
+  auto header_matcher =
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"exact");
+  ASSERT_TRUE(header_matcher.ok());
+  EXPECT_TRUE(header_matcher->Match("exact"));
+  EXPECT_FALSE(header_matcher->Match("Exact"));
+  EXPECT_FALSE(header_matcher->Match("exacz"));
+}
+
+TEST(HeaderMatcherTest, StringMatcherWithInvertMatch) {
+  auto header_matcher =
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kExact,
+                            /*matcher=*/"exact",
+                            /*range_start=*/0, /*range_end=*/0,
+                            /*present_match=*/false, /*invert_match=*/true);
+  ASSERT_TRUE(header_matcher.ok());
+  EXPECT_FALSE(header_matcher->Match("exact"));
+  EXPECT_TRUE(header_matcher->Match("Exact"));
+  EXPECT_TRUE(header_matcher->Match("exacz"));
+}
+
+TEST(HeaderMatcherTest, InvalidRegex) {
+  auto header_matcher =
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kSafeRegex,
+                            /*matcher=*/"a[b-a]",
+                            /*range_start=*/0, /*range_end=*/0,
+                            /*present_match=*/false, /*invert_match=*/true);
+  EXPECT_FALSE(header_matcher.ok());
+  EXPECT_EQ(header_matcher.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(header_matcher.status().message(),
+            "Invalid regex string specified in matcher.");
+}
+
+TEST(HeaderMatcherTest, RangeMatcherValidRange) {
+  auto header_matcher =
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kRange,
+                            /*matcher=*/"", /*range_start=*/10,
+                            /*range_end*/ 20);
+  ASSERT_TRUE(header_matcher.ok());
+  EXPECT_TRUE(header_matcher->Match("16"));
+  EXPECT_TRUE(header_matcher->Match("10"));
+  EXPECT_FALSE(header_matcher->Match("3"));
+  EXPECT_FALSE(header_matcher->Match("20"));
+}
+
+TEST(HeaderMatcherTest, RangeMatcherInvalidRange) {
+  auto header_matcher =
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kRange,
+                            /*matcher=*/"", /*range_start=*/20,
+                            /*range_end*/ 10);
+  EXPECT_FALSE(header_matcher.ok());
+  EXPECT_EQ(header_matcher.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(
+      header_matcher.status().message(),
+      "Invalid range specifier specified: end cannot be smaller than start.");
+}
+
+TEST(HeaderMatcherTest, PresentMatcherTrue) {
+  auto header_matcher =
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kPresent,
+                            /*matcher=*/"", /*range_start=*/0,
+                            /*range_end=*/0, /*present_match=*/true);
+  ASSERT_TRUE(header_matcher.ok());
+  EXPECT_TRUE(header_matcher->Match("any_value"));
+  EXPECT_FALSE(header_matcher->Match(absl::nullopt));
+}
+
+TEST(HeaderMatcherTest, PresentMatcherFalse) {
+  auto header_matcher =
+      HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kPresent,
+                            /*matcher=*/"", /*range_start=*/0,
+                            /*range_end=*/0, /*present_match=*/false);
+  ASSERT_TRUE(header_matcher.ok());
+  EXPECT_FALSE(header_matcher->Match("any_value"));
+  EXPECT_TRUE(header_matcher->Match(absl::nullopt));
+}
+
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/grpc/test/core/security/oauth2_utils.cc b/grpc/test/core/security/oauth2_utils.cc
index 0885a1a..536696b 100644
--- a/grpc/test/core/security/oauth2_utils.cc
+++ b/grpc/test/core/security/oauth2_utils.cc
@@ -40,12 +40,13 @@
   grpc_closure closure;
 } oauth2_request;
 
-static void on_oauth2_response(void* arg, grpc_error* error) {
+static void on_oauth2_response(void* arg, grpc_error_handle error) {
   oauth2_request* request = static_cast<oauth2_request*>(arg);
   char* token = nullptr;
   grpc_slice token_slice;
   if (error != GRPC_ERROR_NONE) {
-    gpr_log(GPR_ERROR, "Fetching token failed: %s", grpc_error_string(error));
+    gpr_log(GPR_ERROR, "Fetching token failed: %s",
+            grpc_error_std_string(error).c_str());
   } else {
     GPR_ASSERT(request->md_array.size == 1);
     token_slice = GRPC_MDVALUE(request->md_array.md[0]);
@@ -64,7 +65,7 @@
   gpr_mu_unlock(request->mu);
 }
 
-static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {}
+static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
 
 char* grpc_test_fetch_oauth2_token_with_credentials(
     grpc_call_credentials* creds) {
@@ -86,7 +87,7 @@
   GRPC_CLOSURE_INIT(&request.closure, on_oauth2_response, &request,
                     grpc_schedule_on_exec_ctx);
 
-  grpc_error* error = GRPC_ERROR_NONE;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   if (creds->get_request_metadata(&request.pops, null_ctx, &request.md_array,
                                   &request.closure, &error)) {
     // Synchronous result; invoke callback directly.
diff --git a/grpc/test/core/security/print_google_default_creds_token.cc b/grpc/test/core/security/print_google_default_creds_token.cc
index 398c58c..0d6c7b7 100644
--- a/grpc/test/core/security/print_google_default_creds_token.cc
+++ b/grpc/test/core/security/print_google_default_creds_token.cc
@@ -41,10 +41,11 @@
   grpc_closure on_request_metadata;
 } synchronizer;
 
-static void on_metadata_response(void* arg, grpc_error* error) {
+static void on_metadata_response(void* arg, grpc_error_handle error) {
   synchronizer* sync = static_cast<synchronizer*>(arg);
   if (error != GRPC_ERROR_NONE) {
-    fprintf(stderr, "Fetching token failed: %s\n", grpc_error_string(error));
+    fprintf(stderr, "Fetching token failed: %s\n",
+            grpc_error_std_string(error).c_str());
     fflush(stderr);
   } else {
     char* token;
@@ -70,7 +71,7 @@
   grpc_auth_metadata_context context;
   gpr_cmdline* cl = gpr_cmdline_create("print_google_default_creds_token");
   grpc_pollset* pollset = nullptr;
-  grpc_error* error = nullptr;
+  grpc_error_handle error = GRPC_ERROR_NONE;
   gpr_cmdline_add_string(cl, "service_url",
                          "Service URL for the token request.", &service_url);
   gpr_cmdline_parse(cl, argc, argv);
diff --git a/grpc/test/core/security/rbac_translator_test.cc b/grpc/test/core/security/rbac_translator_test.cc
new file mode 100644
index 0000000..337f471
--- /dev/null
+++ b/grpc/test/core/security/rbac_translator_test.cc
@@ -0,0 +1,809 @@
+// Copyright 2021 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 "src/core/lib/security/authorization/rbac_translator.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace grpc_core {
+
+namespace {
+
+MATCHER_P2(EqualsPrincipalName, expected_matcher_type, expected_matcher_value,
+           "") {
+  return arg->type == Rbac::Principal::RuleType::kPrincipalName &&
+         arg->string_matcher.type() == expected_matcher_type &&
+         arg->string_matcher.string_matcher() == expected_matcher_value;
+}
+
+MATCHER_P2(EqualsPath, expected_matcher_type, expected_matcher_value, "") {
+  return arg->type == Rbac::Permission::RuleType::kPath &&
+         arg->string_matcher.type() == expected_matcher_type &&
+         arg->string_matcher.string_matcher() == expected_matcher_value;
+}
+
+MATCHER_P3(EqualsHeader, expected_name, expected_matcher_type,
+           expected_matcher_value, "") {
+  return arg->type == Rbac::Permission::RuleType::kHeader &&
+         arg->header_matcher.name() == expected_name &&
+         arg->header_matcher.type() == expected_matcher_type &&
+         arg->header_matcher.string_matcher() == expected_matcher_value;
+}
+
+}  // namespace
+
+TEST(GenerateRbacPoliciesTest, InvalidPolicy) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz-policy\",,"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_THAT(
+      std::string(rbac_policies.status().message()),
+      ::testing::StartsWith("Failed to parse SDK authorization policy."));
+}
+
+TEST(GenerateRbacPoliciesTest, MissingAuthorizationPolicyName) {
+  const char* authz_policy = "{}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(), "\"name\" field is not present.");
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectAuthorizationPolicyNameType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": [\"authz_policy\"]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(), "\"name\" is not a string.");
+}
+
+TEST(GenerateRbacPoliciesTest, MissingAllowRules) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz_policy\""
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "\"allow_rules\" is not present.");
+}
+
+TEST(GenerateRbacPoliciesTest, MissingDenyRules) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\""
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  ASSERT_TRUE(rbac_policies.ok());
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
+  EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectAllowRulesType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": {}"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "\"allow_rules\" is not an array.");
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectDenyRulesType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"deny_rules\": 123"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "\"deny_rules\" is not an array.");
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectRuleType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": [\"rule-a\"]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "allow_rules 0: is not an object.");
+}
+
+TEST(GenerateRbacPoliciesTest, MissingRuleNameField) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": [{}]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "allow_rules 0: \"name\" is not present.");
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectRuleNameType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": 123"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "allow_rules 0: \"name\" is not a string.");
+}
+
+TEST(GenerateRbacPoliciesTest, MissingSourceAndRequest) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\""
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  ASSERT_TRUE(rbac_policies.ok());
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_allow_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::Field(&Rbac::Permission::type,
+                                   Rbac::Permission::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::Field(&Rbac::Principal::type,
+                                   Rbac::Principal::RuleType::kAny))))));
+}
+
+TEST(GenerateRbacPoliciesTest, EmptySourceAndRequest) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\","
+      "      \"source\": {},"
+      "      \"request\": {}"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  ASSERT_TRUE(rbac_policies.ok());
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_allow_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::Field(&Rbac::Permission::type,
+                                   Rbac::Permission::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::Field(&Rbac::Principal::type,
+                                   Rbac::Principal::RuleType::kAny))))));
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectSourceType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\","
+      "      \"source\": 111"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "allow_rules 0: \"source\" is not an object.");
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectPrincipalsType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\","
+      "      \"source\": {"
+      "        \"principals\": ["
+      "          \"*\","
+      "          123"
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "allow_rules 0: \"principals\" 1: is not a string.");
+}
+
+TEST(GenerateRbacPoliciesTest, ParseSourceSuccess) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\","
+      "      \"source\": {"
+      "        \"principals\": ["
+      "          \"spiffe://foo.abc\","
+      "          \"spiffe://bar*\","
+      "          \"*baz\","
+      "          \"spiffe://abc.*.com\""
+      "        ]"
+      "      }"
+      "    }"
+      "  ],"
+      "  \"deny_rules\": ["
+      "    {"
+      "      \"name\": \"deny_policy\","
+      "      \"source\": {"
+      "        \"principals\": ["
+      "          \"*\""
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  ASSERT_TRUE(rbac_policies.ok());
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_allow_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::Field(&Rbac::Permission::type,
+                                   Rbac::Permission::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::AllOf(
+                      ::testing::Field(&Rbac::Principal::type,
+                                       Rbac::Principal::RuleType::kAnd),
+                      ::testing::Field(
+                          &Rbac::Principal::principals,
+                          ::testing::ElementsAre(::testing::AllOf(
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Principal::type,
+                                  Rbac::Principal::RuleType::kOr)),
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Principal::principals,
+                                  ::testing::ElementsAre(
+                                      EqualsPrincipalName(
+                                          StringMatcher::Type::kExact,
+                                          "spiffe://foo.abc"),
+                                      EqualsPrincipalName(
+                                          StringMatcher::Type::kPrefix,
+                                          "spiffe://bar"),
+                                      EqualsPrincipalName(
+                                          StringMatcher::Type::kSuffix, "baz"),
+                                      EqualsPrincipalName(
+                                          StringMatcher::Type::kExact,
+                                          "spiffe://abc.*.com")))))))))))));
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
+  EXPECT_THAT(
+      rbac_policies.value().deny_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_deny_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::Field(&Rbac::Permission::type,
+                                   Rbac::Permission::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::AllOf(
+                      ::testing::Field(&Rbac::Principal::type,
+                                       Rbac::Principal::RuleType::kAnd),
+                      ::testing::Field(
+                          &Rbac::Principal::principals,
+                          ::testing::ElementsAre(::testing::AllOf(
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Principal::type,
+                                  Rbac::Principal::RuleType::kOr)),
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Principal::principals,
+                                  ::testing::ElementsAre(EqualsPrincipalName(
+                                      StringMatcher::Type::kPrefix,
+                                      "")))))))))))));
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectRequestType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"deny_rules\": ["
+      "    {"
+      "      \"name\": \"deny_policy\","
+      "      \"request\": 111"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "deny_rules 0: \"request\" is not an object.");
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectPathType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"deny_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\","
+      "      \"request\": {"
+      "        \"paths\": ["
+      "          \"path-a\","
+      "          123"
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "deny_rules 0: \"paths\" 1: is not a string.");
+}
+
+TEST(GenerateRbacPoliciesTest, ParseRequestPathsSuccess) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\","
+      "      \"request\": {"
+      "        \"paths\": ["
+      "          \"*\""
+      "        ]"
+      "      }"
+      "    }"
+      "  ],"
+      "  \"deny_rules\": ["
+      "    {"
+      "      \"name\": \"deny_policy\","
+      "      \"request\": {"
+      "        \"paths\": ["
+      "          \"path-foo\","
+      "          \"path-bar*\","
+      "          \"*baz\""
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  ASSERT_TRUE(rbac_policies.ok());
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
+  EXPECT_THAT(
+      rbac_policies.value().deny_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_deny_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::Field(&Rbac::Principal::type,
+                                   Rbac::Principal::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::AllOf(
+                      ::testing::Field(&Rbac::Permission::type,
+                                       Rbac::Permission::RuleType::kAnd),
+                      ::testing::Field(
+                          &Rbac::Permission::permissions,
+                          ::testing::ElementsAre(::testing::AllOf(
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Permission::type,
+                                  Rbac::Permission::RuleType::kOr)),
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Permission::permissions,
+                                  ::testing::ElementsAre(
+                                      EqualsPath(StringMatcher::Type::kExact,
+                                                 "path-foo"),
+                                      EqualsPath(StringMatcher::Type::kPrefix,
+                                                 "path-bar"),
+                                      EqualsPath(StringMatcher::Type::kSuffix,
+                                                 "baz")))))))))))));
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_allow_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::Field(&Rbac::Principal::type,
+                                   Rbac::Principal::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::AllOf(
+                      ::testing::Field(&Rbac::Permission::type,
+                                       Rbac::Permission::RuleType::kAnd),
+                      ::testing::Field(
+                          &Rbac::Permission::permissions,
+                          ::testing::ElementsAre(::testing::AllOf(
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Permission::type,
+                                  Rbac::Permission::RuleType::kOr)),
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Permission::permissions,
+                                  ::testing::ElementsAre(
+                                      EqualsPath(StringMatcher::Type::kPrefix,
+                                                 "")))))))))))));
+}
+
+TEST(GenerateRbacPoliciesTest, IncorrectHeaderType) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"deny_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\","
+      "      \"request\": {"
+      "        \"headers\": ["
+      "          \"header-a\""
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "deny_rules 0: \"headers\" 0: is not an object.");
+}
+
+TEST(GenerateRbacPoliciesTest, UnsupportedGrpcHeaders) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"deny_rules\": ["
+      "    {"
+      "      \"name\": \"policy\","
+      "      \"request\": {"
+      "        \"headers\": ["
+      "          {"
+      "            \"key\": \"grpc-xxx\","
+      "            \"values\": ["
+      "              \"*\""
+      "            ]"
+      "          }"
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "deny_rules 0: \"headers\" 0: Unsupported \"key\" grpc-xxx.");
+}
+
+TEST(GenerateRbacPoliciesTest, UnsupportedPseudoHeaders) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"policy\","
+      "      \"request\": {"
+      "        \"headers\": ["
+      "          {"
+      "            \"key\": \":method\","
+      "            \"values\": ["
+      "              \"*\""
+      "            ]"
+      "          }"
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "allow_rules 0: \"headers\" 0: Unsupported \"key\" :method.");
+}
+
+TEST(GenerateRbacPoliciesTest, UnsupportedhostHeader) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"deny_rules\": ["
+      "    {"
+      "      \"name\": \"policy\","
+      "      \"request\": {"
+      "        \"headers\": ["
+      "          {"
+      "            \"key\": \"host\","
+      "            \"values\": ["
+      "              \"*\""
+      "            ]"
+      "          }"
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "deny_rules 0: \"headers\" 0: Unsupported \"key\" host.");
+}
+
+TEST(GenerateRbacPoliciesTest, UnsupportedHostHeader) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"policy\","
+      "      \"request\": {"
+      "        \"headers\": ["
+      "          {"
+      "            \"key\": \"Host\","
+      "            \"values\": ["
+      "              \"*\""
+      "            ]"
+      "          }"
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "allow_rules 0: \"headers\" 0: Unsupported \"key\" Host.");
+}
+
+TEST(GenerateRbacPoliciesTest, EmptyHeaderValuesList) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy_1\","
+      "      \"request\": {"
+      "        \"headers\": ["
+      "          {"
+      "            \"key\": \"key-a\","
+      "            \"values\": ["
+      "            ]"
+      "          }"
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
+  EXPECT_EQ(rbac_policies.status().message(),
+            "allow_rules 0: \"headers\" 0: \"values\" list is empty.");
+}
+
+TEST(GenerateRbacPoliciesTest, ParseRequestHeadersSuccess) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy\","
+      "      \"request\": {"
+      "        \"headers\": ["
+      "          {"
+      "            \"key\": \"key-1\","
+      "            \"values\": ["
+      "              \"*\""
+      "            ]"
+      "          },"
+      "          {"
+      "            \"key\": \"key-2\","
+      "            \"values\": ["
+      "              \"foo\","
+      "              \"bar*\","
+      "              \"*baz\""
+      "            ]"
+      "          }"
+      "        ]"
+      "      }"
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  ASSERT_TRUE(rbac_policies.ok());
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
+  EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(::testing::Pair(
+          "authz_allow_policy",
+          ::testing::AllOf(
+              ::testing::Field(
+                  &Rbac::Policy::principals,
+                  ::testing::Field(&Rbac::Principal::type,
+                                   Rbac::Principal::RuleType::kAny)),
+              ::testing::Field(
+                  &Rbac::Policy::permissions,
+                  ::testing::AllOf(
+                      ::testing::Field(&Rbac::Permission::type,
+                                       Rbac::Permission::RuleType::kAnd),
+                      ::testing::Field(
+                          &Rbac::Permission::permissions,
+                          ::testing::ElementsAre(::testing::AllOf(
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Permission::type,
+                                  Rbac::Permission::RuleType::kAnd)),
+                              ::testing::Pointee(::testing::Field(
+                                  &Rbac::Permission::permissions,
+                                  ::testing::ElementsAre(
+                                      ::testing::AllOf(
+                                          ::testing::Pointee(::testing::Field(
+                                              &Rbac::Permission::type,
+                                              Rbac::Permission::RuleType::kOr)),
+                                          ::testing::Pointee(::testing::Field(
+                                              &Rbac::Permission::permissions,
+                                              ::testing::ElementsAre(
+                                                  EqualsHeader(
+                                                      "key-1",
+                                                      HeaderMatcher::Type::
+                                                          kPrefix,
+                                                      ""))))),
+                                      ::testing::AllOf(
+                                          ::testing::Pointee(::testing::Field(
+                                              &Rbac::Permission::type,
+                                              Rbac::Permission::RuleType::kOr)),
+                                          ::testing::Pointee(::testing::Field(
+                                              &Rbac::Permission::permissions,
+                                              ::testing::ElementsAre(
+                                                  EqualsHeader("key-2",
+                                                               HeaderMatcher::
+                                                                   Type::kExact,
+                                                               "foo"),
+                                                  EqualsHeader(
+                                                      "key-2",
+                                                      HeaderMatcher::Type::
+                                                          kPrefix,
+                                                      "bar"),
+                                                  EqualsHeader(
+                                                      "key-2",
+                                                      HeaderMatcher::Type::
+                                                          kSuffix,
+                                                      "baz")))))))))))))))));
+}
+
+TEST(GenerateRbacPoliciesTest, ParseRulesArraySuccess) {
+  const char* authz_policy =
+      "{"
+      "  \"name\": \"authz\","
+      "  \"allow_rules\": ["
+      "    {"
+      "      \"name\": \"allow_policy_1\","
+      "      \"source\": {"
+      "        \"principals\": ["
+      "          \"spiffe://foo.abc\""
+      "        ]"
+      "      },"
+      "      \"request\": {"
+      "        \"paths\": ["
+      "          \"foo\""
+      "        ]"
+      "      }"
+      "    },"
+      "    {"
+      "      \"name\": \"allow_policy_2\""
+      "    }"
+      "  ]"
+      "}";
+  auto rbac_policies = GenerateRbacPolicies(authz_policy);
+  ASSERT_TRUE(rbac_policies.ok());
+  EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny);
+  EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
+  EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow);
+  EXPECT_THAT(
+      rbac_policies.value().allow_policy.policies,
+      ::testing::ElementsAre(
+          ::testing::Pair(
+              "authz_allow_policy_1",
+              ::testing::AllOf(
+                  ::testing::Field(
+                      &Rbac::Policy::permissions,
+                      ::testing::AllOf(
+                          ::testing::Field(&Rbac::Permission::type,
+                                           Rbac::Permission::RuleType::kAnd),
+                          ::testing::Field(
+                              &Rbac::Permission::permissions,
+                              ::testing::ElementsAre(::testing::AllOf(
+                                  ::testing::Pointee(::testing::Field(
+                                      &Rbac::Permission::type,
+                                      Rbac::Permission::RuleType::kOr)),
+                                  ::testing::Pointee(::testing::Field(
+                                      &Rbac::Permission::permissions,
+                                      ::testing::ElementsAre(EqualsPath(
+                                          StringMatcher::Type::kExact,
+                                          "foo"))))))))),
+                  ::testing::Field(
+                      &Rbac::Policy::principals,
+                      ::testing::AllOf(
+                          ::testing::Field(&Rbac::Principal::type,
+                                           Rbac::Principal::RuleType::kAnd),
+                          ::testing::Field(
+                              &Rbac::Principal::principals,
+                              ::testing::ElementsAre(::testing::AllOf(
+                                  ::testing::Pointee(::testing::Field(
+                                      &Rbac::Principal::type,
+                                      Rbac::Principal::RuleType::kOr)),
+                                  ::testing::Pointee(::testing::Field(
+                                      &Rbac::Principal::principals,
+                                      ::testing::ElementsAre(
+                                          EqualsPrincipalName(
+                                              StringMatcher::Type::kExact,
+                                              "spiffe://foo.abc"))))))))))),
+          ::testing::Pair(
+              "authz_allow_policy_2",
+              ::testing::AllOf(
+                  ::testing::Field(
+                      &Rbac::Policy::permissions,
+                      ::testing::Field(&Rbac::Permission::type,
+                                       Rbac::Permission::RuleType::kAny)),
+                  ::testing::Field(
+                      &Rbac::Policy::principals,
+                      ::testing::Field(&Rbac::Principal::type,
+                                       Rbac::Principal::RuleType::kAny))))));
+}
+
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/grpc/test/core/security/secure_endpoint_test.cc b/grpc/test/core/security/secure_endpoint_test.cc
index 50c3694..c5621d9 100644
--- a/grpc/test/core/security/secure_endpoint_test.cc
+++ b/grpc/test/core/security/secure_endpoint_test.cc
@@ -166,7 +166,7 @@
      clean_up},
 };
 
-static void inc_call_ctr(void* arg, grpc_error* /*error*/) {
+static void inc_call_ctr(void* arg, grpc_error_handle /*error*/) {
   ++*static_cast<int*>(arg);
 }
 
@@ -202,7 +202,7 @@
   clean_up();
 }
 
-static void destroy_pollset(void* p, grpc_error* /*error*/) {
+static void destroy_pollset(void* p, grpc_error_handle /*error*/) {
   grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
diff --git a/grpc/test/core/security/security_connector_test.cc b/grpc/test/core/security/security_connector_test.cc
index 2049832..da7f2f0 100644
--- a/grpc/test/core/security/security_connector_test.cc
+++ b/grpc/test/core/security/security_connector_test.cc
@@ -222,6 +222,32 @@
   return 1;
 }
 
+static int check_sans(
+    const grpc_auth_context* ctx, const char* expected_property_name,
+    const std::vector<std::string>& expected_property_values) {
+  grpc_auth_property_iterator it =
+      grpc_auth_context_find_properties_by_name(ctx, expected_property_name);
+  for (const auto& property_value : expected_property_values) {
+    const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
+    if (prop == nullptr) {
+      gpr_log(GPR_ERROR, "Expected value %s not found.",
+              property_value.c_str());
+      return 0;
+    }
+    if (strncmp(prop->value, property_value.c_str(), prop->value_length) != 0) {
+      gpr_log(GPR_ERROR, "Expected peer %s and got %s.", property_value.c_str(),
+              prop->value);
+      return 0;
+    }
+  }
+  if (grpc_auth_property_iterator_next(&it) != nullptr) {
+    gpr_log(GPR_ERROR, "Expected only %zu property values.",
+            expected_property_values.size());
+    return 0;
+  }
+  return 1;
+}
+
 static int check_spiffe_id(const grpc_auth_context* ctx,
                            const char* expected_spiffe_id,
                            bool expect_spiffe_id) {
@@ -444,6 +470,59 @@
   ctx.reset(DEBUG_LOCATION, "test");
 }
 
+static void test_dns_peer_to_auth_context(void) {
+  tsi_peer peer;
+  const std::vector<std::string> expected_dns = {"dns1", "dns2", "dns3"};
+  GPR_ASSERT(tsi_construct_peer(expected_dns.size(), &peer) == TSI_OK);
+  for (size_t i = 0; i < expected_dns.size(); ++i) {
+    GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                   TSI_X509_DNS_PEER_PROPERTY, expected_dns[i].c_str(),
+                   &peer.properties[i]) == TSI_OK);
+  }
+  grpc_core::RefCountedPtr<grpc_auth_context> ctx =
+      grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  GPR_ASSERT(ctx != nullptr);
+  GPR_ASSERT(check_sans(ctx.get(), GRPC_PEER_DNS_PROPERTY_NAME, expected_dns));
+  tsi_peer_destruct(&peer);
+  ctx.reset(DEBUG_LOCATION, "test");
+}
+
+static void test_email_peer_to_auth_context(void) {
+  tsi_peer peer;
+  const std::vector<std::string> expected_emails = {"email1", "email2"};
+  GPR_ASSERT(tsi_construct_peer(expected_emails.size(), &peer) == TSI_OK);
+  for (size_t i = 0; i < expected_emails.size(); ++i) {
+    GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                   TSI_X509_EMAIL_PEER_PROPERTY, expected_emails[i].c_str(),
+                   &peer.properties[i]) == TSI_OK);
+  }
+  grpc_core::RefCountedPtr<grpc_auth_context> ctx =
+      grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  GPR_ASSERT(ctx != nullptr);
+  GPR_ASSERT(
+      check_sans(ctx.get(), GRPC_PEER_EMAIL_PROPERTY_NAME, expected_emails));
+  tsi_peer_destruct(&peer);
+  ctx.reset(DEBUG_LOCATION, "test");
+}
+
+static void test_ip_peer_to_auth_context(void) {
+  tsi_peer peer;
+  const std::vector<std::string> expected_ips = {"128.128.128.128",
+                                                 "255.255.255.255"};
+  GPR_ASSERT(tsi_construct_peer(expected_ips.size(), &peer) == TSI_OK);
+  for (size_t i = 0; i < expected_ips.size(); ++i) {
+    GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                   TSI_X509_IP_PEER_PROPERTY, expected_ips[i].c_str(),
+                   &peer.properties[i]) == TSI_OK);
+  }
+  grpc_core::RefCountedPtr<grpc_auth_context> ctx =
+      grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  GPR_ASSERT(ctx != nullptr);
+  GPR_ASSERT(check_sans(ctx.get(), GRPC_PEER_IP_PROPERTY_NAME, expected_ips));
+  tsi_peer_destruct(&peer);
+  ctx.reset(DEBUG_LOCATION, "test");
+}
+
 static void test_spiffe_id_peer_to_auth_context(void) {
   // Invalid SPIFFE IDs should not be plumbed.
   std::string long_id(2050, 'x');
@@ -558,6 +637,7 @@
   }
   tsi_peer_destruct(&peer);
 }
+
 namespace grpc_core {
 namespace {
 
@@ -637,7 +717,7 @@
   GPR_ASSERT(tsi_construct_string_peer_property("wrong peer property name",
                                                 alpn, strlen(alpn),
                                                 &peer.properties[0]) == TSI_OK);
-  grpc_error* error = grpc_ssl_check_alpn(&peer);
+  grpc_error_handle error = grpc_ssl_check_alpn(&peer);
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   tsi_peer_destruct(&peer);
   GRPC_ERROR_UNREF(error);
@@ -672,6 +752,9 @@
   test_cn_and_one_san_ssl_peer_to_auth_context();
   test_cn_and_multiple_sans_ssl_peer_to_auth_context();
   test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
+  test_dns_peer_to_auth_context();
+  test_email_peer_to_auth_context();
+  test_ip_peer_to_auth_context();
   test_spiffe_id_peer_to_auth_context();
   test_ipv6_address_san();
   test_default_ssl_roots();
diff --git a/grpc/test/core/security/ssl_server_fuzzer.cc b/grpc/test/core/security/ssl_server_fuzzer.cc
index bb5ca72..6401f8e 100644
--- a/grpc/test/core/security/ssl_server_fuzzer.cc
+++ b/grpc/test/core/security/ssl_server_fuzzer.cc
@@ -42,7 +42,7 @@
   bool done_callback_called;
 };
 
-static void on_handshake_done(void* arg, grpc_error* error) {
+static void on_handshake_done(void* arg, grpc_error_handle error) {
   grpc_core::HandshakerArgs* args =
       static_cast<grpc_core::HandshakerArgs*>(arg);
   struct handshake_state* state =
@@ -91,7 +91,7 @@
 
     // Create security connector
     grpc_core::RefCountedPtr<grpc_server_security_connector> sc =
-        creds->create_security_connector();
+        creds->create_security_connector(nullptr);
     GPR_ASSERT(sc != nullptr);
     grpc_millis deadline = GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now();
 
diff --git a/grpc/test/core/security/tls_security_connector_test.cc b/grpc/test/core/security/tls_security_connector_test.cc
index c6f744d..c041fd9 100644
--- a/grpc/test/core/security/tls_security_connector_test.cc
+++ b/grpc/test/core/security/tls_security_connector_test.cc
@@ -146,10 +146,59 @@
   grpc_channel_args_destroy(new_args);
 }
 
-// Note that on client side, we don't have tests watching identity certs only,
-// because in TLS, the trust certs should always be presented. If we don't
-// provide, it will try to load certs from some default system locations, and
-// will hence fail on some systems.
+TEST_F(TlsSecurityConnectorTest,
+       SystemRootsWhenCreateChannelSecurityConnector) {
+  // Create options watching for no certificates.
+  grpc_core::RefCountedPtr<grpc_tls_credentials_options> root_options =
+      grpc_core::MakeRefCounted<grpc_tls_credentials_options>();
+  grpc_core::RefCountedPtr<TlsCredentials> root_credential =
+      grpc_core::MakeRefCounted<TlsCredentials>(root_options);
+  grpc_channel_args* root_new_args = nullptr;
+  grpc_core::RefCountedPtr<grpc_channel_security_connector> root_connector =
+      root_credential->create_security_connector(nullptr, "some_target",
+                                                 nullptr, &root_new_args);
+  EXPECT_NE(root_connector, nullptr);
+  grpc_core::TlsChannelSecurityConnector* tls_root_connector =
+      static_cast<grpc_core::TlsChannelSecurityConnector*>(
+          root_connector.get());
+  EXPECT_NE(tls_root_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  grpc_channel_args_destroy(root_new_args);
+}
+
+TEST_F(TlsSecurityConnectorTest,
+       SystemRootsAndIdentityCertsObtainedWhenCreateChannelSecurityConnector) {
+  grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor =
+      grpc_core::MakeRefCounted<grpc_tls_certificate_distributor>();
+  distributor->SetKeyMaterials(kIdentityCertName, absl::nullopt,
+                               identity_pairs_0_);
+  grpc_core::RefCountedPtr<::grpc_tls_certificate_provider> provider =
+      grpc_core::MakeRefCounted<TlsTestCertificateProvider>(distributor);
+  // Create options only watching for identity certificates.
+  grpc_core::RefCountedPtr<grpc_tls_credentials_options> root_options =
+      grpc_core::MakeRefCounted<grpc_tls_credentials_options>();
+  root_options->set_certificate_provider(provider);
+  root_options->set_watch_identity_pair(true);
+  root_options->set_identity_cert_name(kIdentityCertName);
+  grpc_core::RefCountedPtr<TlsCredentials> root_credential =
+      grpc_core::MakeRefCounted<TlsCredentials>(root_options);
+  grpc_channel_args* root_new_args = nullptr;
+  grpc_core::RefCountedPtr<grpc_channel_security_connector> root_connector =
+      root_credential->create_security_connector(nullptr, "some_target",
+                                                 nullptr, &root_new_args);
+  EXPECT_NE(root_connector, nullptr);
+  grpc_core::TlsChannelSecurityConnector* tls_root_connector =
+      static_cast<grpc_core::TlsChannelSecurityConnector*>(
+          root_connector.get());
+  EXPECT_NE(tls_root_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  EXPECT_EQ(tls_root_connector->KeyCertPairListForTesting(), identity_pairs_0_);
+  // If we have a root update, we shouldn't receive them in security connector,
+  // since we claimed to use default system roots.
+  distributor->SetKeyMaterials(kRootCertName, root_cert_1_, absl::nullopt);
+  EXPECT_NE(tls_root_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  EXPECT_NE(tls_root_connector->RootCertsForTesting(), root_cert_1_);
+  grpc_channel_args_destroy(root_new_args);
+}
+
 TEST_F(TlsSecurityConnectorTest,
        RootCertsObtainedWhenCreateChannelSecurityConnector) {
   grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor =
@@ -303,7 +352,8 @@
   GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
                  TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, target_name,
                  &peer.properties[0]) == TSI_OK);
-  grpc_error* error = grpc_core::internal::TlsCheckHostName(target_name, &peer);
+  grpc_error_handle error =
+      grpc_core::internal::TlsCheckHostName(target_name, &peer);
   tsi_peer_destruct(&peer);
   EXPECT_EQ(error, GRPC_ERROR_NONE);
   GRPC_ERROR_UNREF(error);
@@ -317,7 +367,8 @@
   GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
                  TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, another_name,
                  &peer.properties[0]) == TSI_OK);
-  grpc_error* error = grpc_core::internal::TlsCheckHostName(target_name, &peer);
+  grpc_error_handle error =
+      grpc_core::internal::TlsCheckHostName(target_name, &peer);
   tsi_peer_destruct(&peer);
   EXPECT_NE(error, GRPC_ERROR_NONE);
   GRPC_ERROR_UNREF(error);
@@ -343,7 +394,7 @@
   grpc_core::RefCountedPtr<TlsServerCredentials> credential =
       grpc_core::MakeRefCounted<TlsServerCredentials>(options);
   grpc_core::RefCountedPtr<grpc_server_security_connector> connector =
-      credential->create_security_connector();
+      credential->create_security_connector(nullptr);
   EXPECT_NE(connector, nullptr);
   grpc_core::TlsServerSecurityConnector* tls_connector =
       static_cast<grpc_core::TlsServerSecurityConnector*>(connector.get());
@@ -380,7 +431,7 @@
   grpc_core::RefCountedPtr<TlsServerCredentials> identity_credential =
       grpc_core::MakeRefCounted<TlsServerCredentials>(identity_options);
   grpc_core::RefCountedPtr<grpc_server_security_connector> identity_connector =
-      identity_credential->create_security_connector();
+      identity_credential->create_security_connector(nullptr);
   EXPECT_NE(identity_connector, nullptr);
   grpc_core::TlsServerSecurityConnector* tls_identity_connector =
       static_cast<grpc_core::TlsServerSecurityConnector*>(
@@ -417,7 +468,7 @@
   grpc_core::RefCountedPtr<TlsServerCredentials> credential =
       grpc_core::MakeRefCounted<TlsServerCredentials>(options);
   grpc_core::RefCountedPtr<grpc_server_security_connector> connector =
-      credential->create_security_connector();
+      credential->create_security_connector(nullptr);
   EXPECT_NE(connector, nullptr);
   grpc_core::TlsServerSecurityConnector* tls_connector =
       static_cast<grpc_core::TlsServerSecurityConnector*>(connector.get());
@@ -451,7 +502,7 @@
   grpc_core::RefCountedPtr<TlsServerCredentials> credential =
       grpc_core::MakeRefCounted<TlsServerCredentials>(options);
   grpc_core::RefCountedPtr<grpc_server_security_connector> connector =
-      credential->create_security_connector();
+      credential->create_security_connector(nullptr);
   EXPECT_NE(connector, nullptr);
   grpc_core::TlsServerSecurityConnector* tls_connector =
       static_cast<grpc_core::TlsServerSecurityConnector*>(connector.get());
@@ -495,6 +546,7 @@
 
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
+  GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, CA_CERT_PATH);
   ::testing::InitGoogleTest(&argc, argv);
   grpc_init();
   int ret = RUN_ALL_TESTS();
diff --git a/grpc/test/core/security/xds_credentials_test.cc b/grpc/test/core/security/xds_credentials_test.cc
index 373e905..c055972 100644
--- a/grpc/test/core/security/xds_credentials_test.cc
+++ b/grpc/test/core/security/xds_credentials_test.cc
@@ -29,32 +29,30 @@
 
 namespace {
 
-XdsApi::StringMatcher ExactMatcher(const char* string) {
-  return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::EXACT,
-                               string);
+StringMatcher ExactMatcher(const char* string) {
+  return StringMatcher::Create(StringMatcher::Type::kExact, string).value();
 }
 
-XdsApi::StringMatcher PrefixMatcher(const char* string,
-                                    bool ignore_case = false) {
-  return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::PREFIX,
-                               string, ignore_case);
+StringMatcher PrefixMatcher(const char* string, bool case_sensitive = true) {
+  return StringMatcher::Create(StringMatcher::Type::kPrefix, string,
+                               case_sensitive)
+      .value();
 }
 
-XdsApi::StringMatcher SuffixMatcher(const char* string,
-                                    bool ignore_case = false) {
-  return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::SUFFIX,
-                               string, ignore_case);
+StringMatcher SuffixMatcher(const char* string, bool case_sensitive = true) {
+  return StringMatcher::Create(StringMatcher::Type::kSuffix, string,
+                               case_sensitive)
+      .value();
 }
 
-XdsApi::StringMatcher ContainsMatcher(const char* string,
-                                      bool ignore_case = false) {
-  return XdsApi::StringMatcher(
-      XdsApi::StringMatcher::StringMatcherType::CONTAINS, string, ignore_case);
+StringMatcher ContainsMatcher(const char* string, bool case_sensitive = true) {
+  return StringMatcher::Create(StringMatcher::Type::kContains, string,
+                               case_sensitive)
+      .value();
 }
 
-XdsApi::StringMatcher SafeRegexMatcher(const char* string) {
-  return XdsApi::StringMatcher(
-      XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX, string);
+StringMatcher SafeRegexMatcher(const char* string) {
+  return StringMatcher::Create(StringMatcher::Type::kSafeRegex, string).value();
 }
 
 TEST(XdsSanMatchingTest, EmptySansList) {
@@ -210,15 +208,15 @@
   std::vector<const char*> sans = {"aBc.cOm"};
   EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {PrefixMatcher("AbC", true /* ignore_case */)}));
+      {PrefixMatcher("AbC", false /* case_sensitive */)}));
   sans = {"abc.com"};
   EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {PrefixMatcher("AbC", true /* ignore_case */)}));
+      {PrefixMatcher("AbC", false /* case_sensitive */)}));
   sans = {"xyz.com"};
   EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {PrefixMatcher("AbC", true /* ignore_case */)}));
+      {PrefixMatcher("AbC", false /* case_sensitive */)}));
 }
 
 TEST(XdsSanMatchingTest, SuffixMatch) {
@@ -237,15 +235,15 @@
   std::vector<const char*> sans = {"abc.com"};
   EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {SuffixMatcher(".CoM", true /* ignore_case */)}));
+      {SuffixMatcher(".CoM", false /* case_sensitive */)}));
   sans = {"AbC.cOm"};
   EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {SuffixMatcher(".CoM", true /* ignore_case */)}));
+      {SuffixMatcher(".CoM", false /* case_sensitive */)}));
   sans = {"abc.xyz"};
   EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {SuffixMatcher(".CoM", true /* ignore_case */)}));
+      {SuffixMatcher(".CoM", false /* case_sensitive */)}));
 }
 
 TEST(XdsSanMatchingTest, ContainsMatch) {
@@ -264,19 +262,19 @@
   std::vector<const char*> sans = {"abc.com"};
   EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {ContainsMatcher("AbC", true /* ignore_case */)}));
+      {ContainsMatcher("AbC", false /* case_sensitive */)}));
   sans = {"xyz.abc.com"};
   EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {ContainsMatcher("AbC", true /* ignore_case */)}));
+      {ContainsMatcher("AbC", false /* case_sensitive */)}));
   sans = {"foo.aBc.com"};
   EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {ContainsMatcher("AbC", true /* ignore_case */)}));
+      {ContainsMatcher("AbC", false /* case_sensitive */)}));
   sans = {"foo.Ab.com"};
   EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames(
       sans.data(), sans.size(),
-      {ContainsMatcher("AbC", true /* ignore_case */)}));
+      {ContainsMatcher("AbC", false /* case_sensitive */)}));
 }
 
 TEST(XdsSanMatchingTest, RegexMatch) {
diff --git a/grpc/test/distrib/cpp/run_distrib_test_cmake_aarch64_cross.sh b/grpc/test/distrib/cpp/run_distrib_test_cmake_aarch64_cross.sh
new file mode 100755
index 0000000..4b8b522
--- /dev/null
+++ b/grpc/test/distrib/cpp/run_distrib_test_cmake_aarch64_cross.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+# Copyright 2017 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.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Install openssl (to use instead of boringssl)
+apt-get update && apt-get install -y libssl-dev
+
+# Install CMake 3.16
+apt-get update && apt-get install -y wget
+wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.16.1/cmake-3.16.1-Linux-x86_64.sh
+sh cmake-linux.sh -- --skip-license --prefix=/usr
+rm cmake-linux.sh
+
+# Build and install gRPC for the host architecture.
+# We do this because we need to be able to run protoc and grpc_cpp_plugin
+# while cross-compiling.
+mkdir -p "cmake/build"
+pushd "cmake/build"
+cmake \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DgRPC_INSTALL=ON \
+  -DgRPC_BUILD_TESTS=OFF \
+  -DgRPC_SSL_PROVIDER=package \
+  ../..
+make -j4 install
+popd
+
+# Write a toolchain file to use for cross-compiling.
+cat > /tmp/toolchain.cmake <<'EOT'
+SET(CMAKE_SYSTEM_NAME Linux)
+SET(CMAKE_SYSTEM_PROCESSOR aarch64)
+set(CMAKE_STAGING_PREFIX /tmp/stage)
+set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc-6)
+set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++-6)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+EOT
+
+# Build and install absl (absl won't be installed down below)
+mkdir -p "third_party/abseil-cpp/cmake/build_arm"
+pushd "third_party/abseil-cpp/cmake/build_arm"
+cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/toolchain.cmake \
+      -DCMAKE_BUILD_TYPE=Release \
+      -DCMAKE_INSTALL_PREFIX=/tmp/install \
+      -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \
+      ../..
+make -j4 install
+popd
+
+# Build and install gRPC for ARM.
+# This build will use the host architecture copies of protoc and
+# grpc_cpp_plugin that we built earlier because we installed them
+# to a location in our PATH (/usr/local/bin).
+mkdir -p "cmake/build_arm"
+pushd "cmake/build_arm"
+cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/toolchain.cmake \
+      -DCMAKE_BUILD_TYPE=Release \
+      -DCMAKE_INSTALL_PREFIX=/tmp/install \
+      ../..
+make -j4 install
+popd
+
+# Build helloworld example for ARM.
+# As above, it will find and use protoc and grpc_cpp_plugin
+# for the host architecture.
+mkdir -p "examples/cpp/helloworld/cmake/build_arm"
+pushd "examples/cpp/helloworld/cmake/build_arm"
+cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/toolchain.cmake \
+      -DCMAKE_BUILD_TYPE=Release \
+      -DProtobuf_DIR=/tmp/stage/lib/cmake/protobuf \
+      -DgRPC_DIR=/tmp/stage/lib/cmake/grpc \
+      ../..
+make
+popd
diff --git a/grpc/test/distrib/cpp/run_distrib_test_cmake_module_install.sh b/grpc/test/distrib/cpp/run_distrib_test_cmake_module_install.sh
index 96e63b1..b669b99 100755
--- a/grpc/test/distrib/cpp/run_distrib_test_cmake_module_install.sh
+++ b/grpc/test/distrib/cpp/run_distrib_test_cmake_module_install.sh
@@ -26,6 +26,13 @@
 sh cmake-linux.sh -- --skip-license --prefix=/usr
 rm cmake-linux.sh
 
+# Install absl (absl won't be installed down below)
+mkdir -p "third_party/abseil-cpp/cmake/build"
+pushd "third_party/abseil-cpp/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ../..
+make -j4 install
+popd
+
 # Install gRPC and its dependencies
 mkdir -p "cmake/build"
 pushd "cmake/build"
@@ -33,6 +40,7 @@
   -DCMAKE_BUILD_TYPE=Release \
   -DgRPC_INSTALL=ON \
   -DgRPC_BUILD_TESTS=OFF \
+  -DgRPC_ABSL_PROVIDER=package \
   -DgRPC_SSL_PROVIDER=package \
   ../..
 make -j4 install
diff --git a/grpc/test/distrib/cpp/run_distrib_test_cmake_module_install_pkgconfig.sh b/grpc/test/distrib/cpp/run_distrib_test_cmake_module_install_pkgconfig.sh
index ab61f16..fd08da6 100755
--- a/grpc/test/distrib/cpp/run_distrib_test_cmake_module_install_pkgconfig.sh
+++ b/grpc/test/distrib/cpp/run_distrib_test_cmake_module_install_pkgconfig.sh
@@ -26,6 +26,13 @@
 sh cmake-linux.sh -- --skip-license --prefix=/usr
 rm cmake-linux.sh
 
+# Install absl (absl won't be installed down below)
+mkdir -p "third_party/abseil-cpp/cmake/build"
+pushd "third_party/abseil-cpp/cmake/build"
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ../..
+make -j4 install
+popd
+
 # Install gRPC and its dependencies
 mkdir -p "cmake/build"
 pushd "cmake/build"
@@ -33,6 +40,7 @@
   -DCMAKE_BUILD_TYPE=Release \
   -DgRPC_INSTALL=ON \
   -DgRPC_BUILD_TESTS=OFF \
+  -DgRPC_ABSL_PROVIDER=package \
   -DgRPC_SSL_PROVIDER=package \
   ../..
 make -j4 install
diff --git a/grpc/test/distrib/cpp/run_distrib_test_raspberry_pi.sh b/grpc/test/distrib/cpp/run_distrib_test_raspberry_pi.sh
deleted file mode 100755
index b1a0ba5..0000000
--- a/grpc/test/distrib/cpp/run_distrib_test_raspberry_pi.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/bash
-# Copyright 2017 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.
-
-set -ex
-
-cd "$(dirname "$0")/../../.."
-
-# Install openssl (to use instead of boringssl)
-apt-get update && apt-get install -y libssl-dev
-
-# Install CMake 3.16
-apt-get update && apt-get install -y wget
-wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.16.1/cmake-3.16.1-Linux-x86_64.sh
-sh cmake-linux.sh -- --skip-license --prefix=/usr
-rm cmake-linux.sh
-
-# Build and install gRPC for the host architecture.
-# We do this because we need to be able to run protoc and grpc_cpp_plugin
-# while cross-compiling.
-mkdir -p "cmake/build"
-pushd "cmake/build"
-cmake \
-  -DCMAKE_BUILD_TYPE=Release \
-  -DgRPC_INSTALL=ON \
-  -DgRPC_BUILD_TESTS=OFF \
-  -DgRPC_SSL_PROVIDER=package \
-  ../..
-make -j4 install
-popd
-
-# Download raspberry pi toolchain.
-mkdir -p "/tmp/raspberrypi_root"
-pushd "/tmp/raspberrypi_root"
-git clone https://github.com/raspberrypi/tools raspberrypi-tools
-cd raspberrypi-tools && git checkout 4a335520900ce55e251ac4f420f52bf0b2ab6b1f && cd ..
-
-# Write a toolchain file to use for cross-compiling.
-cat > toolchain.cmake <<'EOT'
-SET(CMAKE_SYSTEM_NAME Linux)
-SET(CMAKE_SYSTEM_PROCESSOR arm)
-set(devel_root /tmp/raspberrypi_root)
-set(CMAKE_STAGING_PREFIX ${devel_root}/stage)
-set(tool_root ${devel_root}/raspberrypi-tools/arm-bcm2708)
-set(CMAKE_SYSROOT ${tool_root}/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot)
-set(CMAKE_C_COMPILER ${tool_root}/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc)
-set(CMAKE_CXX_COMPILER ${tool_root}/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++)
-set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
-set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
-EOT
-popd
-
-# Build and install gRPC for raspberry pi.
-# This build will use the host architecture copies of protoc and
-# grpc_cpp_plugin that we built earlier because we installed them
-# to a location in our PATH (/usr/local/bin).
-mkdir -p "cmake/raspberrypi_build"
-pushd "cmake/raspberrypi_build"
-cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/raspberrypi_root/toolchain.cmake \
-      -DCMAKE_BUILD_TYPE=Release \
-      -DCMAKE_INSTALL_PREFIX=/tmp/raspberrypi_root/grpc_install \
-      ../..
-make -j4 install
-popd
-
-# Build helloworld example for raspberry pi.
-# As above, it will find and use protoc and grpc_cpp_plugin
-# for the host architecture.
-mkdir -p "examples/cpp/helloworld/cmake/raspberrypi_build"
-pushd "examples/cpp/helloworld/cmake/raspberrypi_build"
-cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/raspberrypi_root/toolchain.cmake \
-      -DCMAKE_BUILD_TYPE=Release \
-      -DProtobuf_DIR=/tmp/raspberrypi_root/stage/lib/cmake/protobuf \
-      -DgRPC_DIR=/tmp/raspberrypi_root/stage/lib/cmake/grpc \
-      ../..
-make
-popd
diff --git a/grpc/test/distrib/php/distribtest.php b/grpc/test/distrib/php/distribtest.php
index 236cb09..2dcccd5 100644
--- a/grpc/test/distrib/php/distribtest.php
+++ b/grpc/test/distrib/php/distribtest.php
@@ -23,7 +23,7 @@
 
 $deadline = Grpc\Timeval::infFuture();
 $call = new Grpc\Call($channel,
-                      'dummy_method',
+                      'phony_method',
                       $deadline);
 
 $call->cancel();
diff --git a/grpc/test/distrib/php/run_distrib_test.sh b/grpc/test/distrib/php/run_distrib_test.sh
index a6102f6..0ca30f4 100755
--- a/grpc/test/distrib/php/run_distrib_test.sh
+++ b/grpc/test/distrib/php/run_distrib_test.sh
@@ -20,6 +20,6 @@
 cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
 
 find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
-    xargs pecl install
+    MAKEFLAGS=-j xargs pecl install
 
 php -d extension=grpc.so -d max_execution_time=300 distribtest.php
diff --git a/grpc/test/distrib/php/run_distrib_test_macos.sh b/grpc/test/distrib/php/run_distrib_test_macos.sh
index 8def049..1ec38c6 100755
--- a/grpc/test/distrib/php/run_distrib_test_macos.sh
+++ b/grpc/test/distrib/php/run_distrib_test_macos.sh
@@ -20,6 +20,6 @@
 cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
 
 find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
-    xargs sudo pecl install
+    xargs sudo MAKEFLAGS=-j pecl install
 
 php -d extension=grpc.so -d max_execution_time=300 distribtest.php
diff --git a/grpc/test/distrib/python/distribtest.py b/grpc/test/distrib/python/distribtest.py
index 1144786..0fc2854 100644
--- a/grpc/test/distrib/python/distribtest.py
+++ b/grpc/test/distrib/python/distribtest.py
@@ -18,4 +18,4 @@
 # which is what we are testing here.
 channel = grpc.insecure_channel('localhost:1000')
 del channel
-print 'Success!'
+print('Success!')
diff --git a/grpc/third_party/ABSEIL_MANUAL.md b/grpc/third_party/ABSEIL_MANUAL.md
new file mode 100644
index 0000000..1e510e9
--- /dev/null
+++ b/grpc/third_party/ABSEIL_MANUAL.md
@@ -0,0 +1,32 @@
+# Abseil in gRPC
+
+This document explains how to use Abseil throughout gRPC. Note that this isn't
+supposed to explain general usage of Abseil.
+
+## The version of Abseil
+
+gRPC intends to use the LTS versions of Abseil only because it simplifies
+dependency management. Abseil is being distributed via package distribution
+systems such as vcpkg and cocoapods. If gRPC depends on the certain version
+that aren't registered, gRPC in that system cannot get the right version of
+Abseil when being built, resulting in a build failure.
+Therefore, gRPC will use the LTS version only, preferably the latest one.
+
+## Libraries that are not ready to use
+
+Most of Abseil libraries are okay to use but there are some exceptions
+because they're not going well yet on some of our test machinaries or
+platforms it supports. The following is a list of targets that are NOT
+ready to use.
+
+- `absl/synchronization:*`: This will be ready from the LTS version in 2021.
+- `absl/random`: [WIP](https://github.com/grpc/grpc/pull/23346).
+- `absl/types:variant`: [WIP](https://github.com/grpc/grpc/pull/22961).
+
+## Implemetation only
+
+You can use Abseil in gRPC Core and gRPC C++. But you cannot use it in
+the public interface of gRPC C++ because i) it doesn't gurantee no breaking
+API changes like gRPC C++ does and ii) it may make users change their build
+system to address Abseil.  
+ 
\ No newline at end of file
diff --git a/grpc/third_party/README.md b/grpc/third_party/README.md
index 9bf0483..b93570f 100644
--- a/grpc/third_party/README.md
+++ b/grpc/third_party/README.md
@@ -48,6 +48,14 @@
 
 Updating some dependencies requires extra care.
 
+### Updating third_party/abseil-cpp
+
+- Two additional steps should be done before running `generate_projects.sh` above.
+  - Running `src/abseil-cpp/preprocessed_builds.yaml.gen.py`.
+  - Updating `abseil_version =` scripts in `templates/gRPC-C++.podspec.template` and 
+    `templates/gRPC-Core.podspec.template`.
+- You can see an example of previous [upgrade](https://github.com/grpc/grpc/pull/24270).
+
 ### Updating third_party/boringssl-with-bazel
 
 - Update the `third_party/boringssl-with-bazel` submodule to the latest [`master-with-bazel`](https://github.com/google/boringssl/tree/master-with-bazel) branch
@@ -73,9 +81,9 @@
 
 - Run `tools/buildgen/generate_projects.sh` to regenerate the generated files
     - Because `sha256` in `bazel/grpc_deps.bzl` was left empty, you will get a DEBUG msg like this one:
-```
-Rule 'boringssl' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = "SHA value"
-```
+      ```
+      Rule 'boringssl' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = "SHA value"
+      ```
     - Commit the regenrated files `git commit -m "regenerate files"`
     - Update `bazel/grpc_deps.bzl` with the SHA value shown in the above debug msg. Commit again `git commit -m "Updated sha256"`
 
@@ -97,3 +105,10 @@
 ### Updating third_party/protobuf
 
 See http://go/grpc-third-party-protobuf-update-instructions (internal only)
+
+### Updating third_party/envoy-api
+
+Apart from the above steps, please perform the following two steps to generate the Python `xds-protos` package:
+
+1. Bump the version in the `tools/distrib/python/xds_protos/setup.py`;
+2. Run `tools/distrib/python/xds_protos/build_validate_upload.sh` to upload the built wheel.
diff --git a/grpc/third_party/abseil-cpp/.github/ISSUE_TEMPLATE/config.yml b/grpc/third_party/abseil-cpp/.github/ISSUE_TEMPLATE/config.yml
index 9794ae1..0086358 100644
--- a/grpc/third_party/abseil-cpp/.github/ISSUE_TEMPLATE/config.yml
+++ b/grpc/third_party/abseil-cpp/.github/ISSUE_TEMPLATE/config.yml
@@ -1 +1 @@
-blank_issues_enables: true
+blank_issues_enabled: true
diff --git a/grpc/third_party/abseil-cpp/CMake/AbseilDll.cmake b/grpc/third_party/abseil-cpp/CMake/AbseilDll.cmake
index cf6a8c9..253c73f 100644
--- a/grpc/third_party/abseil-cpp/CMake/AbseilDll.cmake
+++ b/grpc/third_party/abseil-cpp/CMake/AbseilDll.cmake
@@ -1,4 +1,5 @@
 include(CMakeParseArguments)
+include(GNUInstallDirs)
 
 set(ABSL_INTERNAL_DLL_FILES
   "algorithm/algorithm.h"
@@ -10,7 +11,6 @@
   "base/const_init.h"
   "base/dynamic_annotations.h"
   "base/internal/atomic_hook.h"
-  "base/internal/bits.h"
   "base/internal/cycleclock.cc"
   "base/internal/cycleclock.h"
   "base/internal/direct_mmap.h"
@@ -61,6 +61,8 @@
   "base/policy_checks.h"
   "base/port.h"
   "base/thread_annotations.h"
+  "cleanup/cleanup.h"
+  "cleanup/internal/cleanup.h"
   "container/btree_map.h"
   "container/btree_set.h"
   "container/fixed_array.h"
@@ -122,10 +124,15 @@
   "hash/internal/hash.h"
   "hash/internal/hash.cc"
   "hash/internal/spy_hash_state.h"
+  "hash/internal/wyhash.h"
+  "hash/internal/wyhash.cc"
   "memory/memory.h"
   "meta/type_traits.h"
+  "numeric/bits.h"
   "numeric/int128.cc"
   "numeric/int128.h"
+  "numeric/internal/bits.h"
+  "numeric/internal/representation.h"
   "random/bernoulli_distribution.h"
   "random/beta_distribution.h"
   "random/bit_gen_ref.h"
@@ -190,12 +197,18 @@
   "strings/cord.h"
   "strings/escaping.cc"
   "strings/escaping.h"
+  "strings/internal/cord_internal.cc"
   "strings/internal/cord_internal.h"
+  "strings/internal/cord_rep_flat.h"
+  "strings/internal/cord_rep_ring.cc"
+  "strings/internal/cord_rep_ring.h"
+  "strings/internal/cord_rep_ring_reader.h"
   "strings/internal/charconv_bigint.cc"
   "strings/internal/charconv_bigint.h"
   "strings/internal/charconv_parse.cc"
   "strings/internal/charconv_parse.h"
   "strings/internal/stl_type_traits.h"
+  "strings/internal/string_constant.h"
   "strings/match.cc"
   "strings/match.h"
   "strings/numbers.cc"
@@ -250,6 +263,7 @@
   "synchronization/notification.h"
   "synchronization/internal/create_thread_identity.cc"
   "synchronization/internal/create_thread_identity.h"
+  "synchronization/internal/futex.h"
   "synchronization/internal/graphcycles.cc"
   "synchronization/internal/graphcycles.h"
   "synchronization/internal/kernel_timeout.h"
@@ -487,7 +501,7 @@
     abseil_dll
     PUBLIC
       "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
-      $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+      $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
   )
 
   target_compile_options(
@@ -505,8 +519,8 @@
       ${ABSL_CC_LIB_DEFINES}
   )
   install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets
-        RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
-        LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
-        ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
   )
 endfunction()
diff --git a/grpc/third_party/abseil-cpp/CMake/AbseilHelpers.cmake b/grpc/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
index 8b2925c..70eaa4c 100644
--- a/grpc/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
+++ b/grpc/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
@@ -17,7 +17,6 @@
 include(CMakeParseArguments)
 include(AbseilConfigureCopts)
 include(AbseilDll)
-include(AbseilInstallDirs)
 
 # The IDE folder for Abseil that will be used if Abseil is included in a CMake
 # project that sets
@@ -41,7 +40,7 @@
 # LINKOPTS: List of link options
 # PUBLIC: Add this so that this library will be exported under absl::
 # Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal.
-# TESTONLY: When added, this target will only be built if user passes -DABSL_RUN_TESTS=ON to CMake.
+# TESTONLY: When added, this target will only be built if BUILD_TESTING=ON.
 #
 # Note:
 # By default, absl_cc_library will always create a library named absl_${NAME},
@@ -83,7 +82,7 @@
     ${ARGN}
   )
 
-  if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS)
+  if(ABSL_CC_LIB_TESTONLY AND NOT BUILD_TESTING)
     return()
   endif()
 
@@ -104,7 +103,7 @@
     endif()
   endforeach()
 
-  if("${ABSL_CC_SRCS}" STREQUAL "")
+  if(ABSL_CC_SRCS STREQUAL "")
     set(ABSL_CC_LIB_IS_INTERFACE 1)
   else()
     set(ABSL_CC_LIB_IS_INTERFACE 0)
@@ -122,7 +121,11 @@
   # 4. "static"  -- This target does not depend on the DLL and should be built
   #                 statically.
   if (${ABSL_BUILD_DLL})
-    absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
+    if(ABSL_ENABLE_INSTALL)
+      absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
+    else()
+      absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll)
+    endif()
     if (${_in_dll})
       # This target should be replaced by the DLL
       set(_build_type "dll")
@@ -137,8 +140,53 @@
     set(_build_type "static")
   endif()
 
+  # Generate a pkg-config file for every library:
+  if(_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
+    if(NOT ABSL_CC_LIB_TESTONLY)
+      if(absl_VERSION)
+        set(PC_VERSION "${absl_VERSION}")
+      else()
+        set(PC_VERSION "head")
+      endif()
+      foreach(dep ${ABSL_CC_LIB_DEPS})
+        if(${dep} MATCHES "^absl::(.*)")
+	  # Join deps with commas.
+          if(PC_DEPS)
+            set(PC_DEPS "${PC_DEPS},")
+          endif()
+          set(PC_DEPS "${PC_DEPS} absl_${CMAKE_MATCH_1} = ${PC_VERSION}")
+        endif()
+      endforeach()
+      foreach(cflag ${ABSL_CC_LIB_COPTS})
+        if(${cflag} MATCHES "^(-Wno|/wd)")
+          # These flags are needed to suppress warnings that might fire in our headers.
+          set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
+        elseif(${cflag} MATCHES "^(-W|/w[1234eo])")
+          # Don't impose our warnings on others.
+        else()
+          set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
+        endif()
+      endforeach()
+      FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" CONTENT "\
+prefix=${CMAKE_INSTALL_PREFIX}\n\
+exec_prefix=\${prefix}\n\
+libdir=\${prefix}/${CMAKE_INSTALL_LIBDIR}\n\
+includedir=\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}\n\
+\n\
+Name: absl_${_NAME}\n\
+Description: Abseil ${_NAME} library\n\
+URL: https://abseil.io/\n\
+Version: ${PC_VERSION}\n\
+Requires:${PC_DEPS}\n\
+Libs: -L\${libdir} $<JOIN:${ABSL_CC_LIB_LINKOPTS}, > $<$<NOT:$<BOOL:${ABSL_CC_LIB_IS_INTERFACE}>>:-labsl_${_NAME}>\n\
+Cflags: -I\${includedir}${PC_CFLAGS}\n")
+      INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc"
+              DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
+    endif()
+  endif()
+
   if(NOT ABSL_CC_LIB_IS_INTERFACE)
-    if(${_build_type} STREQUAL "dll_dep")
+    if(_build_type STREQUAL "dll_dep")
       # This target depends on the DLL. When adding dependencies to this target,
       # any depended-on-target which is contained inside the DLL is replaced
       # with a dependency on the DLL.
@@ -167,7 +215,7 @@
           "${_gtest_link_define}"
       )
 
-    elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared")
+    elseif(_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
       add_library(${_NAME} "")
       target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
       target_link_libraries(${_NAME}
@@ -190,7 +238,7 @@
     target_include_directories(${_NAME}
       PUBLIC
         "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
-        $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
     )
     target_compile_options(${_NAME}
       PRIVATE ${ABSL_CC_LIB_COPTS})
@@ -215,6 +263,7 @@
     if(ABSL_ENABLE_INSTALL)
       set_target_properties(${_NAME} PROPERTIES
         OUTPUT_NAME "absl_${_NAME}"
+        SOVERSION "2103.0.0"
       )
     endif()
   else()
@@ -223,10 +272,10 @@
     target_include_directories(${_NAME}
       INTERFACE
         "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
-        $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
       )
 
-    if (${_build_type} STREQUAL "dll")
+    if (_build_type STREQUAL "dll")
         set(ABSL_CC_LIB_DEPS abseil_dll)
     endif()
 
@@ -243,9 +292,9 @@
   # installed abseil can't be tested.
   if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
     install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
-          RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
-          LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
-          ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
+          RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+          LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+          ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
     )
   endif()
 
@@ -290,7 +339,7 @@
 #     gtest_main
 # )
 function(absl_cc_test)
-  if(NOT ABSL_RUN_TESTS)
+  if(NOT BUILD_TESTING)
     return()
   endif()
 
diff --git a/grpc/third_party/abseil-cpp/CMake/AbseilInstallDirs.cmake b/grpc/third_party/abseil-cpp/CMake/AbseilInstallDirs.cmake
deleted file mode 100644
index 6fc914b..0000000
--- a/grpc/third_party/abseil-cpp/CMake/AbseilInstallDirs.cmake
+++ /dev/null
@@ -1,20 +0,0 @@
-include(GNUInstallDirs)
-
-# absl_VERSION is only set if we are an LTS release being installed, in which
-# case it may be into a system directory and so we need to make subdirectories
-# for each installed version of Abseil.  This mechanism is implemented in
-# Abseil's internal Copybara (https://github.com/google/copybara) workflows and
-# isn't visible in the CMake buildsystem itself.
-
-if(absl_VERSION)
-  set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}")
-  set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}")
-  set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}")
-  set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/${ABSL_SUBDIR}")
-  set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}")
-else()
-  set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
-  set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
-  set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
-  set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
-endif()
diff --git a/grpc/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in b/grpc/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in
index 994dac0..5769e3a 100644
--- a/grpc/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in
+++ b/grpc/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in
@@ -3,24 +3,12 @@
 project(googletest-external NONE)
 
 include(ExternalProject)
-if(${ABSL_USE_GOOGLETEST_HEAD})
-  ExternalProject_Add(googletest
-    GIT_REPOSITORY    https://github.com/google/googletest.git
-    GIT_TAG           master
-    SOURCE_DIR        "${absl_gtest_src_dir}"
-    BINARY_DIR        "${absl_gtest_build_dir}"
-    CONFIGURE_COMMAND ""
-    BUILD_COMMAND     ""
-    INSTALL_COMMAND   ""
-    TEST_COMMAND      ""
-  )
-else()
-  ExternalProject_Add(googletest
-    SOURCE_DIR        "${absl_gtest_src_dir}"
-    BINARY_DIR        "${absl_gtest_build_dir}"
-    CONFIGURE_COMMAND ""
-    BUILD_COMMAND     ""
-    INSTALL_COMMAND   ""
-    TEST_COMMAND      ""
-  )
-endif()
\ No newline at end of file
+ExternalProject_Add(googletest
+  URL               "${absl_gtest_download_url}"  # May be empty
+  SOURCE_DIR        "${absl_gtest_src_dir}"
+  BINARY_DIR        "${absl_gtest_build_dir}"
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND     ""
+  INSTALL_COMMAND   ""
+  TEST_COMMAND      ""
+)
diff --git a/grpc/third_party/abseil-cpp/CMake/README.md b/grpc/third_party/abseil-cpp/CMake/README.md
index 8f73475..5eee817 100644
--- a/grpc/third_party/abseil-cpp/CMake/README.md
+++ b/grpc/third_party/abseil-cpp/CMake/README.md
@@ -52,7 +52,7 @@
 
 ### Running Abseil Tests with CMake
 
-Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests.  Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run.
+Use the `-DBUILD_TESTING=ON` flag to run Abseil tests.
 
 You will need to provide Abseil with a Googletest dependency.  There are two
 options for how to do this:
@@ -70,7 +70,7 @@
 cd path/to/abseil-cpp
 mkdir build
 cd build
-cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON ..
+cmake -DBUILD_TESTING=ON -DABSL_USE_GOOGLETEST_HEAD=ON ..
 make -j
 ctest
 ```
diff --git a/grpc/third_party/abseil-cpp/CMake/install_test_project/test.sh b/grpc/third_party/abseil-cpp/CMake/install_test_project/test.sh
index 99989b0..a3d3977 100755
--- a/grpc/third_party/abseil-cpp/CMake/install_test_project/test.sh
+++ b/grpc/third_party/abseil-cpp/CMake/install_test_project/test.sh
@@ -13,70 +13,44 @@
 # 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.
-
-# "Unit" and integration tests for Absl CMake installation
-
-# TODO(absl-team): This script isn't fully hermetic because
-# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
-# version of GoogleTest. This means that an upstream change to GoogleTest could
-# break this test. Fix this by allowing this script to pin to a known-good
-# version of GoogleTest.
+#
+# Unit and integration tests for Abseil LTS CMake installation
 
 # Fail on any error. Treat unset variables an error. Print commands as executed.
 set -euox pipefail
 
-install_absl() {
-  pushd "${absl_build_dir}"
-  if [[ "${#}" -eq 1 ]]; then
-    cmake -DCMAKE_INSTALL_PREFIX="${1}" "${absl_dir}"
-  else
-    cmake "${absl_dir}"
-  fi
-  cmake --build . --target install -- -j
-  popd
-}
-
-uninstall_absl() {
-  xargs rm < "${absl_build_dir}"/install_manifest.txt
-  rm -rf "${absl_build_dir}"
-  mkdir -p "${absl_build_dir}"
-}
-
-lts_install=""
-
-while getopts ":l" lts; do
-  case "${lts}" in
-    l )
-      lts_install="true"
-      ;;
-  esac
-done
+source ci/cmake_common.sh
 
 absl_dir=/abseil-cpp
-absl_build_dir=/buildfs/absl-build
+absl_build_dir=/buildfs
 project_dir="${absl_dir}"/CMake/install_test_project
 project_build_dir=/buildfs/project-build
 
-mkdir -p "${absl_build_dir}"
+build_shared_libs="OFF"
+if [ "${LINK_TYPE:-}" = "DYNAMIC" ]; then
+  build_shared_libs="ON"
+fi
+
+# Run the LTS transformations
+./create_lts.py 99998877
+
+# Install Abseil
+pushd "${absl_build_dir}"
+cmake "${absl_dir}" \
+  -DABSL_GOOGLETEST_DOWNLOAD_URL="${ABSL_GOOGLETEST_DOWNLOAD_URL}" \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DBUILD_TESTING=ON \
+  -DBUILD_SHARED_LIBS="${build_shared_libs}"
+make -j $(nproc)
+ctest -j $(nproc)
+make install
+ldconfig
+popd
+
+# Test the project against the installed Abseil
 mkdir -p "${project_build_dir}"
-
-if [[ "${lts_install}" ]]; then
-  install_dir="/usr/local"
-else
-  install_dir="${project_build_dir}"/install
-fi
-mkdir -p "${install_dir}"
-
-# Test build, install, and link against installed abseil
 pushd "${project_build_dir}"
-if [[ "${lts_install}" ]]; then
-  install_absl
-  cmake "${project_dir}"
-else
-  install_absl "${install_dir}"
-  cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}"
-fi
-
+cmake "${project_dir}"
 cmake --build . --target simple
 
 output="$(${project_build_dir}/simple "printme" 2>&1)"
@@ -88,57 +62,35 @@
 
 popd
 
-# Test that we haven't accidentally made absl::abslblah
-pushd "${install_dir}"
-
-# Starting in CMake 3.12 the default install dir is lib$bit_width
-if [[ -d lib64 ]]; then
-  libdir="lib64"
-elif [[ -d lib ]]; then
-  libdir="lib"
-else
-  echo "ls *, */*, */*/*:"
-  ls *
-  ls */*
-  ls */*/*
-  echo "unknown lib dir"
-fi
-
-if [[ "${lts_install}" ]]; then
-  # LTS versions append the date of the release to the subdir.
-  # 9999/99/99 is the dummy date used in the local_lts workflow.
-  absl_subdir="absl_99999999"
-else
-  absl_subdir="absl"
-fi
-
-if ! grep absl::strings "${libdir}/cmake/${absl_subdir}/abslTargets.cmake"; then
-  cat "${libdir}"/cmake/absl/abslTargets.cmake
+if ! grep absl::strings "/usr/local/lib/cmake/absl/abslTargets.cmake"; then
+  cat "/usr/local/lib/cmake/absl/abslTargets.cmake"
   echo "CMake targets named incorrectly"
   exit 1
 fi
 
-uninstall_absl
-popd
+pushd "${HOME}"
+cat > hello-abseil.cc << EOF
+#include <cstdlib>
 
-if [[ ! "${lts_install}" ]]; then
-  # Test that we warn if installed without a prefix or a system prefix
-  output="$(install_absl 2>&1)"
-  if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
-    echo "Install without prefix didn't warn as expected. Output:"
-    echo "${output}"
-    exit 1
-  fi
-  uninstall_absl
+#include "absl/strings/str_format.h"
 
-  output="$(install_absl /usr 2>&1)"
-  if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
-    echo "Install with /usr didn't warn as expected. Output:"
-    echo "${output}"
-    exit 1
-  fi
-  uninstall_absl
+int main(int argc, char **argv) {
+  absl::PrintF("Hello Abseil!\n");
+  return EXIT_SUCCESS;
+}
+EOF
+
+if [ "${LINK_TYPE:-}" != "DYNAMIC" ]; then
+  pc_args=($(pkg-config --cflags --libs --static absl_str_format))
+  g++ -static -o hello-abseil hello-abseil.cc "${pc_args[@]}"
+else
+  pc_args=($(pkg-config --cflags --libs absl_str_format))
+  g++ -o hello-abseil hello-abseil.cc "${pc_args[@]}"
 fi
+hello="$(./hello-abseil)"
+[[ "${hello}" == "Hello Abseil!" ]]
+
+popd
 
 echo "Install test complete!"
 exit 0
diff --git a/grpc/third_party/abseil-cpp/CMakeLists.txt b/grpc/third_party/abseil-cpp/CMakeLists.txt
index f0af6f6..3a73f70 100644
--- a/grpc/third_party/abseil-cpp/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/CMakeLists.txt
@@ -41,7 +41,12 @@
   cmake_policy(SET CMP0077 NEW)
 endif (POLICY CMP0077)
 
-project(absl CXX)
+# Set BUILD_TESTING to OFF by default.
+# This must come before the project() and include(CTest) lines.
+OPTION(BUILD_TESTING "Build tests" OFF)
+
+project(absl LANGUAGES CXX VERSION 20210324)
+include(CTest)
 
 # Output directory is correct by default for most build setups. However, when
 # building Abseil as a DLL, it is important to have the DLL in the same
@@ -51,7 +56,7 @@
 
 # when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp))
 # in the source tree of a project that uses it, install rules are disabled.
-if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
+if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
   option(ABSL_ENABLE_INSTALL "Enable install rule" OFF)
 else()
   option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
@@ -62,8 +67,8 @@
   ${CMAKE_CURRENT_LIST_DIR}/absl/copts
 )
 
-include(AbseilInstallDirs)
 include(CMakePackageConfigHelpers)
+include(GNUInstallDirs)
 include(AbseilDll)
 include(AbseilHelpers)
 
@@ -95,25 +100,28 @@
 option(ABSL_USE_EXTERNAL_GOOGLETEST
   "If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subproject." OFF)
 
-
 option(ABSL_USE_GOOGLETEST_HEAD
-  "If ON, abseil will download HEAD from googletest at config time." OFF)
+  "If ON, abseil will download HEAD from GoogleTest at config time." OFF)
+
+set(ABSL_GOOGLETEST_DOWNLOAD_URL "" CACHE STRING "If set, download GoogleTest from this URL")
 
 set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH
-  "If ABSL_USE_GOOGLETEST_HEAD is OFF, specifies the directory of a local googletest checkout."
+  "If ABSL_USE_GOOGLETEST_HEAD is OFF and ABSL_GOOGLETEST_URL is not set, specifies the directory of a local GoogleTest checkout."
   )
 
-option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
-
-if(${ABSL_RUN_TESTS})
-  # enable CTest.  This will set BUILD_TESTING to ON unless otherwise specified
-  # on the command line
-  include(CTest)
-
+if(BUILD_TESTING)
   ## check targets
   if (NOT ABSL_USE_EXTERNAL_GOOGLETEST)
     set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
-    if(${ABSL_USE_GOOGLETEST_HEAD})
+    if(ABSL_USE_GOOGLETEST_HEAD AND ABSL_GOOGLETEST_DOWNLOAD_URL)
+      message(FATAL_ERROR "Do not set both ABSL_USE_GOOGLETEST_HEAD and ABSL_GOOGLETEST_DOWNLOAD_URL")
+    endif()
+    if(ABSL_USE_GOOGLETEST_HEAD)
+      set(absl_gtest_download_url "https://github.com/google/googletest/archive/master.zip")
+    elseif(ABSL_GOOGLETEST_DOWNLOAD_URL)
+      set(absl_gtest_download_url ${ABSL_GOOGLETEST_DOWNLOAD_URL})
+    endif()
+    if(absl_gtest_download_url)
       set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
     else()
       set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR})
@@ -136,20 +144,21 @@
 add_subdirectory(absl)
 
 if(ABSL_ENABLE_INSTALL)
+  
 
   # install as a subdirectory only
   install(EXPORT ${PROJECT_NAME}Targets
     NAMESPACE absl::
-    DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
   )
 
   configure_package_config_file(
     CMake/abslConfig.cmake.in
     "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
-    INSTALL_DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+    INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
   )
   install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
-    DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
   )
 
   # Abseil only has a version in LTS releases.  This mechanism is accomplished
@@ -162,12 +171,12 @@
     )
 
     install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
-      DESTINATION ${ABSL_INSTALL_CONFIGDIR}
+      DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
     )
   endif()  # absl_VERSION
 
   install(DIRECTORY absl
-    DESTINATION ${ABSL_INSTALL_INCLUDEDIR}
+    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
     FILES_MATCHING
       PATTERN "*.inc"
       PATTERN "*.h"
diff --git a/grpc/third_party/abseil-cpp/LTS.md b/grpc/third_party/abseil-cpp/LTS.md
deleted file mode 100644
index ade8b17..0000000
--- a/grpc/third_party/abseil-cpp/LTS.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Long Term Support (LTS) Branches
-
-This repository contains periodic snapshots of the Abseil codebase that are
-Long Term Support (LTS) branches. An LTS branch allows you to use a known
-version of Abseil without interfering with other projects which may also, in
-turn, use Abseil. (For more information about our releases, see the
-[Abseil Release Management](https://abseil.io/about/releases) guide.)
-
-## LTS Branches
-
-The following lists LTS branches and the dates on which they have been released:
-
-* [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/)
-* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/)
-* [LTS Branch August 8, 2019](https://github.com/abseil/abseil-cpp/tree/lts_2019_08_08/)
-* [LTS Branch February 25, 2020](https://github.com/abseil/abseil-cpp/tree/lts_2020_02_25/)
diff --git a/grpc/third_party/abseil-cpp/README.md b/grpc/third_party/abseil-cpp/README.md
index 85de569..264c4b3 100644
--- a/grpc/third_party/abseil-cpp/README.md
+++ b/grpc/third_party/abseil-cpp/README.md
@@ -9,7 +9,9 @@
 - [About Abseil](#about)
 - [Quickstart](#quickstart)
 - [Building Abseil](#build)
+- [Support](#support)
 - [Codemap](#codemap)
+- [Releases](#releases)
 - [License](#license)
 - [Links](#links)
 
@@ -42,14 +44,22 @@
 <a name="build"></a>
 ## Building Abseil
 
-[Bazel](https://bazel.build) is the official build system for Abseil,
-which is supported on most major platforms (Linux, Windows, macOS, for example)
-and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for
-more information on building Abseil using the Bazel build system.
+[Bazel](https://bazel.build) and [CMake](https://cmake.org/) are the official
+build systems for Abseil.
 
-<a name="cmake"></a>
-If you require CMake support, please check the
-[CMake build instructions](CMake/README.md).
+See the [quickstart](https://abseil.io/docs/cpp/quickstart) for more information
+on building Abseil using the Bazel build system.
+
+If you require CMake support, please check the [CMake build
+instructions](CMake/README.md) and [CMake
+Quickstart](https://abseil.io/docs/cpp/quickstart-cmake).
+
+## Support
+
+Abseil is officially supported on many platforms. See the [Abseil
+platform support
+guide](https://abseil.io/docs/cpp/platforms/platforms) for details on
+supported operating systems, compilers, CPUs, etc.
 
 ## Codemap
 
@@ -62,6 +72,9 @@
 * [`algorithm`](absl/algorithm/)
   <br /> The `algorithm` library contains additions to the C++ `<algorithm>`
   library and container-based versions of such algorithms.
+* [`cleanup`](absl/cleanup/)
+  <br /> The `cleanup` library contains the control-flow-construct-like type
+  `absl::Cleanup` which is used for executing a callback on scope exit.
 * [`container`](absl/container/)
   <br /> The `container` library contains additional STL-style containers,
   including Abseil's unordered "Swiss table" containers.
@@ -79,6 +92,9 @@
   available within C++14 and C++17 versions of the C++ `<type_traits>` library.
 * [`numeric`](absl/numeric/)
   <br /> The `numeric` library contains C++11-compatible 128-bit integers.
+* [`status`](absl/status/)
+  <br /> The `status` contains abstractions for error handling, specifically
+  `absl::Status` and `absl::StatusOr<T>`.
 * [`strings`](absl/strings/)
   <br /> The `strings` library contains a variety of strings routines and
   utilities, including a C++11-compatible version of the C++17
@@ -97,6 +113,15 @@
 * [`utility`](absl/utility/)
   <br /> The `utility` library contains utility and helper code.
 
+## Releases
+
+Abseil recommends users "live-at-head" (update to the latest commit from the
+master branch as often as possible). However, we realize this philosophy doesn't
+work for every project, so we also provide [Long Term Support
+Releases](https://github.com/abseil/abseil-cpp/releases) to which we backport
+fixes for severe bugs. See our [release
+management](https://abseil.io/about/releases) document for more details.
+
 ## License
 
 The Abseil C++ library is licensed under the terms of the Apache
diff --git a/grpc/third_party/abseil-cpp/WORKSPACE b/grpc/third_party/abseil-cpp/WORKSPACE
index 0b53356..258d23b 100644
--- a/grpc/third_party/abseil-cpp/WORKSPACE
+++ b/grpc/third_party/abseil-cpp/WORKSPACE
@@ -20,6 +20,7 @@
 # GoogleTest/GoogleMock framework. Used by most unit-tests.
 http_archive(
     name = "com_google_googletest",
+    # Keep this URL in sync with ABSL_GOOGLETEST_COMMIT in ci/cmake_common.sh.
     urls = ["https://github.com/google/googletest/archive/8567b09290fe402cf01923e2131c5635b8ed851b.zip"],  # 2020-06-12T22:24:28Z
     strip_prefix = "googletest-8567b09290fe402cf01923e2131c5635b8ed851b",
     sha256 = "9a8a166eb6a56c7b3d7b19dc2c946fe4778fd6f21c7a12368ad3b836d8f1be48",
@@ -28,9 +29,9 @@
 # Google benchmark.
 http_archive(
     name = "com_github_google_benchmark",
-    urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"],
-    strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
-    sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
+    urls = ["https://github.com/google/benchmark/archive/bf585a2789e30585b4e3ce6baf11ef2750b54677.zip"],  # 2020-11-26T11:14:03Z
+    strip_prefix = "benchmark-bf585a2789e30585b4e3ce6baf11ef2750b54677",
+    sha256 = "2a778d821997df7d8646c9c59b8edb9a573a6e04c534c01892a40aa524a7b68c",
 )
 
 # C++ rules for Bazel.
diff --git a/grpc/third_party/abseil-cpp/absl/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/BUILD.bazel
index 0b772df..c9d4a2d 100644
--- a/grpc/third_party/abseil-cpp/absl/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/BUILD.bazel
@@ -12,19 +12,32 @@
 # 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.
-#
-
-load(
-    ":compiler_config_setting.bzl",
-    "create_llvm_config",
-)
 
 package(default_visibility = ["//visibility:public"])
 
 licenses(["notice"])
 
-create_llvm_config(
-    name = "llvm_compiler",
+config_setting(
+    name = "clang_compiler",
+    flag_values = {
+        "@bazel_tools//tools/cpp:compiler": "clang",
+    },
+    visibility = [":__subpackages__"],
+)
+
+config_setting(
+    name = "msvc_compiler",
+    flag_values = {
+        "@bazel_tools//tools/cpp:compiler": "msvc-cl",
+    },
+    visibility = [":__subpackages__"],
+)
+
+config_setting(
+    name = "clang-cl_compiler",
+    flag_values = {
+        "@bazel_tools//tools/cpp:compiler": "clang-cl",
+    },
     visibility = [":__subpackages__"],
 )
 
@@ -43,15 +56,6 @@
 )
 
 config_setting(
-    name = "windows",
-    constraint_values = [
-        "@bazel_tools//platforms:x86_64",
-        "@bazel_tools//platforms:windows",
-    ],
-    visibility = [":__subpackages__"],
-)
-
-config_setting(
     name = "ppc",
     values = {
         "cpu": "ppc",
diff --git a/grpc/third_party/abseil-cpp/absl/abseil.podspec.gen.py b/grpc/third_party/abseil-cpp/absl/abseil.podspec.gen.py
index 6aefb79..6375298 100755
--- a/grpc/third_party/abseil-cpp/absl/abseil.podspec.gen.py
+++ b/grpc/third_party/abseil-cpp/absl/abseil.podspec.gen.py
@@ -40,8 +40,8 @@
     'USE_HEADERMAP' => 'NO',
     'ALWAYS_SEARCH_USER_PATHS' => 'NO',
   }
-  s.ios.deployment_target = '7.0'
-  s.osx.deployment_target = '10.9'
+  s.ios.deployment_target = '9.0'
+  s.osx.deployment_target = '10.10'
   s.tvos.deployment_target = '9.0'
   s.watchos.deployment_target = '2.0'
 """
diff --git a/grpc/third_party/abseil-cpp/absl/algorithm/container.h b/grpc/third_party/abseil-cpp/absl/algorithm/container.h
index f0cee94..6398438 100644
--- a/grpc/third_party/abseil-cpp/absl/algorithm/container.h
+++ b/grpc/third_party/abseil-cpp/absl/algorithm/container.h
@@ -90,10 +90,10 @@
 // lookup of std::begin and std::end, i.e.
 //   using std::begin;
 //   using std::end;
-//   std::foo(begin(c), end(c);
+//   std::foo(begin(c), end(c));
 // becomes
 //   std::foo(container_algorithm_internal::begin(c),
-//   container_algorithm_internal::end(c));
+//            container_algorithm_internal::end(c));
 // These are meant for internal use only.
 
 template <typename C>
@@ -188,7 +188,7 @@
 // c_none_of()
 //
 // Container-based version of the <algorithm> `std::none_of()` function to
-// test if no elements in a container fulfil a condition.
+// test if no elements in a container fulfill a condition.
 template <typename C, typename Pred>
 bool c_none_of(const C& c, Pred&& pred) {
   return std::none_of(container_algorithm_internal::c_begin(c),
diff --git a/grpc/third_party/abseil-cpp/absl/base/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/base/BUILD.bazel
index 9d96abe..65ff0dd 100644
--- a/grpc/third_party/abseil-cpp/absl/base/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/base/BUILD.bazel
@@ -160,7 +160,8 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
         "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
@@ -220,7 +221,10 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = select({
-        "//absl:windows": [
+        "//absl:msvc_compiler": [
+            "-DEFAULTLIB:advapi32.lib",
+        ],
+        "//absl:clang-cl_compiler": [
             "-DEFAULTLIB:advapi32.lib",
         ],
         "//absl:wasm": [],
@@ -479,6 +483,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":base",
         ":config",
         ":core_headers",
     ],
@@ -551,7 +556,9 @@
     srcs = ["internal/low_level_alloc_test.cc"],
     copts = ABSL_TEST_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    tags = ["no_test_ios_x86_64"],
+    tags = [
+        "no_test_ios_x86_64",
+    ],
     deps = [
         ":malloc_internal",
         "//absl/container:node_hash_map",
@@ -587,31 +594,6 @@
 )
 
 cc_library(
-    name = "bits",
-    hdrs = ["internal/bits.h"],
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = [
-        "//absl:__subpackages__",
-    ],
-    deps = [
-        ":config",
-        ":core_headers",
-    ],
-)
-
-cc_test(
-    name = "bits_test",
-    size = "small",
-    srcs = ["internal/bits_test.cc"],
-    copts = ABSL_TEST_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = [
-        ":bits",
-        "@com_google_googletest//:gtest_main",
-    ],
-)
-
-cc_library(
     name = "exponential_biased",
     srcs = ["internal/exponential_biased.cc"],
     hdrs = ["internal/exponential_biased.h"],
diff --git a/grpc/third_party/abseil-cpp/absl/base/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/base/CMakeLists.txt
index 9ff5aa2..981b8cc 100644
--- a/grpc/third_party/abseil-cpp/absl/base/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/base/CMakeLists.txt
@@ -418,6 +418,7 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::base
     absl::config
     absl::core_headers
   PUBLIC
@@ -520,30 +521,6 @@
 
 absl_cc_library(
   NAME
-    bits
-  HDRS
-    "internal/bits.h"
-  COPTS
-    ${ABSL_DEFAULT_COPTS}
-  DEPS
-    absl::config
-    absl::core_headers
-)
-
-absl_cc_test(
-  NAME
-    bits_test
-  SRCS
-    "internal/bits_test.cc"
-  COPTS
-    ${ABSL_TEST_COPTS}
-  DEPS
-    absl::bits
-    gtest_main
-)
-
-absl_cc_library(
-  NAME
     exponential_biased
   SRCS
     "internal/exponential_biased.cc"
diff --git a/grpc/third_party/abseil-cpp/absl/base/attributes.h b/grpc/third_party/abseil-cpp/absl/base/attributes.h
index 046fbea..cf2cb55 100644
--- a/grpc/third_party/abseil-cpp/absl/base/attributes.h
+++ b/grpc/third_party/abseil-cpp/absl/base/attributes.h
@@ -18,8 +18,6 @@
 // These macros are used within Abseil and allow the compiler to optimize, where
 // applicable, certain function calls.
 //
-// This file is used for both C and C++!
-//
 // Most macros here are exposing GCC or Clang features, and are stubbed out for
 // other compilers.
 //
@@ -121,7 +119,7 @@
 #if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
 #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
 #define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
-#elif defined(__GNUC__) && !defined(__clang__)
+#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__)
 #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
 #define ABSL_ATTRIBUTE_NO_TAIL_CALL \
   __attribute__((optimize("no-optimize-sibling-calls")))
@@ -607,6 +605,7 @@
 // When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
 // has no effect on diagnostics. In any case this macro has no effect on runtime
 // behavior and performance of code.
+
 #ifdef ABSL_FALLTHROUGH_INTENDED
 #error "ABSL_FALLTHROUGH_INTENDED should not be defined."
 #endif
@@ -645,7 +644,7 @@
 // Every usage of a deprecated entity will trigger a warning when compiled with
 // clang's `-Wdeprecated-declarations` option. This option is turned off by
 // default, but the warnings will be reported by clang-tidy.
-#if defined(__clang__) && __cplusplus >= 201103L
+#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L
 #define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
 #endif
 
@@ -679,4 +678,25 @@
 #define ABSL_CONST_INIT
 #endif  // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
 
+// ABSL_ATTRIBUTE_PURE_FUNCTION
+//
+// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
+// functions. A function is pure if its return value is only a function of its
+// arguments. The pure attribute prohibits a function from modifying the state
+// of the program that is observable by means other than inspecting the
+// function's return value. Declaring such functions with the pure attribute
+// allows the compiler to avoid emitting some calls in repeated invocations of
+// the function with the same argument values.
+//
+// Example:
+//
+//  ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
+#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure)
+#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]]
+#elif ABSL_HAVE_ATTRIBUTE(pure)
+#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure))
+#else
+#define ABSL_ATTRIBUTE_PURE_FUNCTION
+#endif
+
 #endif  // ABSL_BASE_ATTRIBUTES_H_
diff --git a/grpc/third_party/abseil-cpp/absl/base/call_once.h b/grpc/third_party/abseil-cpp/absl/base/call_once.h
index 5b468af..96109f5 100644
--- a/grpc/third_party/abseil-cpp/absl/base/call_once.h
+++ b/grpc/third_party/abseil-cpp/absl/base/call_once.h
@@ -177,15 +177,8 @@
                                   scheduling_mode) == kOnceInit) {
     base_internal::invoke(std::forward<Callable>(fn),
                           std::forward<Args>(args)...);
-    // The call to SpinLockWake below is an optimization, because the waiter
-    // in SpinLockWait is waiting with a short timeout. The atomic load/store
-    // sequence is slightly faster than an atomic exchange:
-    //   old_control = control->exchange(base_internal::kOnceDone,
-    //                                   std::memory_order_release);
-    // We opt for a slightly faster case when there are no waiters, in spite
-    // of longer tail latency when there are waiters.
-    old_control = control->load(std::memory_order_relaxed);
-    control->store(base_internal::kOnceDone, std::memory_order_release);
+    old_control =
+        control->exchange(base_internal::kOnceDone, std::memory_order_release);
     if (old_control == base_internal::kOnceWaiter) {
       base_internal::SpinLockWake(control, true);
     }
diff --git a/grpc/third_party/abseil-cpp/absl/base/config.h b/grpc/third_party/abseil-cpp/absl/base/config.h
index c1d0494..9544996 100644
--- a/grpc/third_party/abseil-cpp/absl/base/config.h
+++ b/grpc/third_party/abseil-cpp/absl/base/config.h
@@ -121,10 +121,16 @@
 #if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
 #define ABSL_NAMESPACE_BEGIN
 #define ABSL_NAMESPACE_END
+#define ABSL_INTERNAL_C_SYMBOL(x) x
 #elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
 #define ABSL_NAMESPACE_BEGIN \
   inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
 #define ABSL_NAMESPACE_END }
+#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v
+#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \
+  ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v)
+#define ABSL_INTERNAL_C_SYMBOL(x) \
+  ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME)
 #else
 #error options.h is misconfigured.
 #endif
@@ -216,6 +222,8 @@
 #if ABSL_INTERNAL_HAS_KEYWORD(__builtin_LINE) && \
     ABSL_INTERNAL_HAS_KEYWORD(__builtin_FILE)
 #define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
+#elif defined(__GNUC__) && __GNUC__ >= 5
+#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
 #endif
 #endif
 
@@ -364,7 +372,7 @@
 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||   \
     defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
     defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
-    defined(__ASYLO__)
+    defined(__ASYLO__) || defined(__myriad2__)
 #define ABSL_HAVE_MMAP 1
 #endif
 
@@ -379,6 +387,15 @@
 #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
 #endif
 
+// ABSL_HAVE_SCHED_GETCPU
+//
+// Checks whether sched_getcpu is available.
+#ifdef ABSL_HAVE_SCHED_GETCPU
+#error ABSL_HAVE_SCHED_GETCPU cannot be directly set
+#elif defined(__linux__)
+#define ABSL_HAVE_SCHED_GETCPU 1
+#endif
+
 // ABSL_HAVE_SCHED_YIELD
 //
 // Checks whether the platform implements sched_yield(2) as defined in
@@ -490,7 +507,7 @@
 #endif
 
 #ifdef __has_include
-#if __has_include(<any>) && __cplusplus >= 201703L && \
+#if __has_include(<any>) && defined(__cplusplus) && __cplusplus >= 201703L && \
     !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
 #define ABSL_HAVE_STD_ANY 1
 #endif
@@ -504,8 +521,8 @@
 #endif
 
 #ifdef __has_include
-#if __has_include(<optional>) && __cplusplus >= 201703L && \
-    !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
+#if __has_include(<optional>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
 #define ABSL_HAVE_STD_OPTIONAL 1
 #endif
 #endif
@@ -518,8 +535,8 @@
 #endif
 
 #ifdef __has_include
-#if __has_include(<variant>) && __cplusplus >= 201703L && \
-    !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
+#if __has_include(<variant>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
 #define ABSL_HAVE_STD_VARIANT 1
 #endif
 #endif
@@ -532,7 +549,8 @@
 #endif
 
 #ifdef __has_include
-#if __has_include(<string_view>) && __cplusplus >= 201703L
+#if __has_include(<string_view>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L
 #define ABSL_HAVE_STD_STRING_VIEW 1
 #endif
 #endif
@@ -544,8 +562,9 @@
 // not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
 // version.
 // TODO(zhangxy): fix tests before enabling aliasing for `std::any`.
-#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
-    ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
+#if defined(_MSC_VER) && _MSC_VER >= 1910 &&         \
+    ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || \
+     (defined(__cplusplus) && __cplusplus > 201402))
 // #define ABSL_HAVE_STD_ANY 1
 #define ABSL_HAVE_STD_OPTIONAL 1
 #define ABSL_HAVE_STD_VARIANT 1
@@ -711,4 +730,13 @@
 #define ABSL_HAVE_ADDRESS_SANITIZER 1
 #endif
 
+// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
+//
+// Class template argument deduction is a language feature added in C++17.
+#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
+#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
+#elif defined(__cpp_deduction_guides)
+#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
+#endif
+
 #endif  // ABSL_BASE_CONFIG_H_
diff --git a/grpc/third_party/abseil-cpp/absl/base/dynamic_annotations.h b/grpc/third_party/abseil-cpp/absl/base/dynamic_annotations.h
index 545f8cb..880cbf6 100644
--- a/grpc/third_party/abseil-cpp/absl/base/dynamic_annotations.h
+++ b/grpc/third_party/abseil-cpp/absl/base/dynamic_annotations.h
@@ -110,6 +110,9 @@
 // Define race annotations.
 
 #if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
+// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are
+// defined by the compiler-based santizer implementation, not by the Abseil
+// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
 
 // -------------------------------------------------------------
 // Annotations that suppress errors. It is usually better to express the
@@ -286,17 +289,22 @@
 // Define IGNORE_READS_BEGIN/_END annotations.
 
 #if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
+// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are
+// defined by the compiler-based implementation, not by the Abseil
+// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
 
 // Request the analysis tool to ignore all reads in the current thread until
 // ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
 // reads, while still checking other reads and all writes.
 // See also ABSL_ANNOTATE_UNPROTECTED_READ.
-#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
-  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()              \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \
+  (__FILE__, __LINE__)
 
 // Stop ignoring reads.
-#define ABSL_ANNOTATE_IGNORE_READS_END() \
-  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+#define ABSL_ANNOTATE_IGNORE_READS_END()              \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \
+  (__FILE__, __LINE__)
 
 // Function prototypes of annotations provided by the compiler-based sanitizer
 // implementation.
@@ -316,16 +324,22 @@
 // TODO(delesley) -- The exclusive lock here ignores writes as well, but
 // allows IGNORE_READS_AND_WRITES to work properly.
 
-#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
-  ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()                          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(                                      \
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \
+  ()
 
-#define ABSL_ANNOTATE_IGNORE_READS_END() \
-  ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
+#define ABSL_ANNOTATE_IGNORE_READS_END()                          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(                                    \
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \
+  ()
 
-ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsBegin()
+ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
+    AbslInternalAnnotateIgnoreReadsBegin)()
     ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
 
-ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsEnd()
+ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
+    AbslInternalAnnotateIgnoreReadsEnd)()
     ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
 
 #else
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/bits.h b/grpc/third_party/abseil-cpp/absl/base/internal/bits.h
deleted file mode 100644
index 81648e2..0000000
--- a/grpc/third_party/abseil-cpp/absl/base/internal/bits.h
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2018 The Abseil 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
-//
-//      https://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 ABSL_BASE_INTERNAL_BITS_H_
-#define ABSL_BASE_INTERNAL_BITS_H_
-
-// This file contains bitwise ops which are implementation details of various
-// absl libraries.
-
-#include <cstdint>
-
-#include "absl/base/config.h"
-
-// Clang on Windows has __builtin_clzll; otherwise we need to use the
-// windows intrinsic functions.
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <intrin.h>
-#if defined(_M_X64)
-#pragma intrinsic(_BitScanReverse64)
-#pragma intrinsic(_BitScanForward64)
-#endif
-#pragma intrinsic(_BitScanReverse)
-#pragma intrinsic(_BitScanForward)
-#endif
-
-#include "absl/base/attributes.h"
-
-#if defined(_MSC_VER) && !defined(__clang__)
-// We can achieve something similar to attribute((always_inline)) with MSVC by
-// using the __forceinline keyword, however this is not perfect. MSVC is
-// much less aggressive about inlining, and even with the __forceinline keyword.
-#define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline
-#else
-// Use default attribute inline.
-#define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE
-#endif
-
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace base_internal {
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
-  int zeroes = 60;
-  if (n >> 32) {
-    zeroes -= 32;
-    n >>= 32;
-  }
-  if (n >> 16) {
-    zeroes -= 16;
-    n >>= 16;
-  }
-  if (n >> 8) {
-    zeroes -= 8;
-    n >>= 8;
-  }
-  if (n >> 4) {
-    zeroes -= 4;
-    n >>= 4;
-  }
-  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
-#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
-  // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  if (_BitScanReverse64(&result, n)) {
-    return 63 - result;
-  }
-  return 64;
-#elif defined(_MSC_VER) && !defined(__clang__)
-  // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  if ((n >> 32) &&
-      _BitScanReverse(&result, static_cast<unsigned long>(n >> 32))) {
-    return 31 - result;
-  }
-  if (_BitScanReverse(&result, static_cast<unsigned long>(n))) {
-    return 63 - result;
-  }
-  return 64;
-#elif defined(__GNUC__) || defined(__clang__)
-  // Use __builtin_clzll, which uses the following instructions:
-  //  x86: bsr
-  //  ARM64: clz
-  //  PPC: cntlzd
-  static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
-                "__builtin_clzll does not take 64-bit arg");
-
-  // Handle 0 as a special case because __builtin_clzll(0) is undefined.
-  if (n == 0) {
-    return 64;
-  }
-  return __builtin_clzll(n);
-#else
-  return CountLeadingZeros64Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
-  int zeroes = 28;
-  if (n >> 16) {
-    zeroes -= 16;
-    n >>= 16;
-  }
-  if (n >> 8) {
-    zeroes -= 8;
-    n >>= 8;
-  }
-  if (n >> 4) {
-    zeroes -= 4;
-    n >>= 4;
-  }
-  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
-#if defined(_MSC_VER) && !defined(__clang__)
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  if (_BitScanReverse(&result, n)) {
-    return 31 - result;
-  }
-  return 32;
-#elif defined(__GNUC__) || defined(__clang__)
-  // Use __builtin_clz, which uses the following instructions:
-  //  x86: bsr
-  //  ARM64: clz
-  //  PPC: cntlzd
-  static_assert(sizeof(int) == sizeof(n),
-                "__builtin_clz does not take 32-bit arg");
-
-  // Handle 0 as a special case because __builtin_clz(0) is undefined.
-  if (n == 0) {
-    return 32;
-  }
-  return __builtin_clz(n);
-#else
-  return CountLeadingZeros32Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
-  int c = 63;
-  n &= ~n + 1;
-  if (n & 0x00000000FFFFFFFF) c -= 32;
-  if (n & 0x0000FFFF0000FFFF) c -= 16;
-  if (n & 0x00FF00FF00FF00FF) c -= 8;
-  if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
-  if (n & 0x3333333333333333) c -= 2;
-  if (n & 0x5555555555555555) c -= 1;
-  return c;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
-#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  _BitScanForward64(&result, n);
-  return result;
-#elif defined(_MSC_VER) && !defined(__clang__)
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  if (static_cast<uint32_t>(n) == 0) {
-    _BitScanForward(&result, static_cast<unsigned long>(n >> 32));
-    return result + 32;
-  }
-  _BitScanForward(&result, static_cast<unsigned long>(n));
-  return result;
-#elif defined(__GNUC__) || defined(__clang__)
-  static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
-                "__builtin_ctzll does not take 64-bit arg");
-  return __builtin_ctzll(n);
-#else
-  return CountTrailingZerosNonZero64Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
-  int c = 31;
-  n &= ~n + 1;
-  if (n & 0x0000FFFF) c -= 16;
-  if (n & 0x00FF00FF) c -= 8;
-  if (n & 0x0F0F0F0F) c -= 4;
-  if (n & 0x33333333) c -= 2;
-  if (n & 0x55555555) c -= 1;
-  return c;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
-#if defined(_MSC_VER) && !defined(__clang__)
-  unsigned long result = 0;  // NOLINT(runtime/int)
-  _BitScanForward(&result, n);
-  return result;
-#elif defined(__GNUC__) || defined(__clang__)
-  static_assert(sizeof(int) == sizeof(n),
-                "__builtin_ctz does not take 32-bit arg");
-  return __builtin_ctz(n);
-#else
-  return CountTrailingZerosNonZero32Slow(n);
-#endif
-}
-
-#undef ABSL_BASE_INTERNAL_FORCEINLINE
-
-}  // namespace base_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_BASE_INTERNAL_BITS_H_
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/bits_test.cc b/grpc/third_party/abseil-cpp/absl/base/internal/bits_test.cc
deleted file mode 100644
index 7855fa6..0000000
--- a/grpc/third_party/abseil-cpp/absl/base/internal/bits_test.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2018 The Abseil 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
-//
-//      https://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 "absl/base/internal/bits.h"
-
-#include "gtest/gtest.h"
-
-namespace {
-
-int CLZ64(uint64_t n) {
-  int fast = absl::base_internal::CountLeadingZeros64(n);
-  int slow = absl::base_internal::CountLeadingZeros64Slow(n);
-  EXPECT_EQ(fast, slow) << n;
-  return fast;
-}
-
-TEST(BitsTest, CountLeadingZeros64) {
-  EXPECT_EQ(64, CLZ64(uint64_t{}));
-  EXPECT_EQ(0, CLZ64(~uint64_t{}));
-
-  for (int index = 0; index < 64; index++) {
-    uint64_t x = static_cast<uint64_t>(1) << index;
-    const auto cnt = 63 - index;
-    ASSERT_EQ(cnt, CLZ64(x)) << index;
-    ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index;
-  }
-}
-
-int CLZ32(uint32_t n) {
-  int fast = absl::base_internal::CountLeadingZeros32(n);
-  int slow = absl::base_internal::CountLeadingZeros32Slow(n);
-  EXPECT_EQ(fast, slow) << n;
-  return fast;
-}
-
-TEST(BitsTest, CountLeadingZeros32) {
-  EXPECT_EQ(32, CLZ32(uint32_t{}));
-  EXPECT_EQ(0, CLZ32(~uint32_t{}));
-
-  for (int index = 0; index < 32; index++) {
-    uint32_t x = static_cast<uint32_t>(1) << index;
-    const auto cnt = 31 - index;
-    ASSERT_EQ(cnt, CLZ32(x)) << index;
-    ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index;
-    ASSERT_EQ(CLZ64(x), CLZ32(x) + 32);
-  }
-}
-
-int CTZ64(uint64_t n) {
-  int fast = absl::base_internal::CountTrailingZerosNonZero64(n);
-  int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n);
-  EXPECT_EQ(fast, slow) << n;
-  return fast;
-}
-
-TEST(BitsTest, CountTrailingZerosNonZero64) {
-  EXPECT_EQ(0, CTZ64(~uint64_t{}));
-
-  for (int index = 0; index < 64; index++) {
-    uint64_t x = static_cast<uint64_t>(1) << index;
-    const auto cnt = index;
-    ASSERT_EQ(cnt, CTZ64(x)) << index;
-    ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index;
-  }
-}
-
-int CTZ32(uint32_t n) {
-  int fast = absl::base_internal::CountTrailingZerosNonZero32(n);
-  int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n);
-  EXPECT_EQ(fast, slow) << n;
-  return fast;
-}
-
-TEST(BitsTest, CountTrailingZerosNonZero32) {
-  EXPECT_EQ(0, CTZ32(~uint32_t{}));
-
-  for (int index = 0; index < 32; index++) {
-    uint32_t x = static_cast<uint32_t>(1) << index;
-    const auto cnt = index;
-    ASSERT_EQ(cnt, CTZ32(x)) << index;
-    ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index;
-  }
-}
-
-
-}  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/direct_mmap.h b/grpc/third_party/abseil-cpp/absl/base/internal/direct_mmap.h
index 16accf0..274054c 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/direct_mmap.h
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/direct_mmap.h
@@ -74,10 +74,13 @@
 inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
                         off64_t offset) noexcept {
 #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
+    defined(__m68k__) || defined(__sh__) ||                                  \
+    (defined(__hppa__) && !defined(__LP64__)) ||                             \
     (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) ||                   \
     (defined(__PPC__) && !defined(__PPC64__)) ||                             \
     (defined(__riscv) && __riscv_xlen == 32) ||                              \
-    (defined(__s390__) && !defined(__s390x__))
+    (defined(__s390__) && !defined(__s390x__)) ||                            \
+    (defined(__sparc__) && !defined(__arch64__))
   // On these architectures, implement mmap with mmap2.
   static int pagesize = 0;
   if (pagesize == 0) {
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/endian.h b/grpc/third_party/abseil-cpp/absl/base/internal/endian.h
index 9677530..dad0e9a 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/endian.h
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/endian.h
@@ -26,6 +26,7 @@
 #endif
 
 #include <cstdint>
+#include "absl/base/casts.h"
 #include "absl/base/config.h"
 #include "absl/base/internal/unaligned_access.h"
 #include "absl/base/port.h"
@@ -173,6 +174,36 @@
 
 #endif /* ENDIAN */
 
+inline uint8_t FromHost(uint8_t x) { return x; }
+inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
+inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
+inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
+inline uint8_t ToHost(uint8_t x) { return x; }
+inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
+inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
+inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
+
+inline int8_t FromHost(int8_t x) { return x; }
+inline int16_t FromHost(int16_t x) {
+  return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t FromHost(int32_t x) {
+  return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t FromHost(int64_t x) {
+  return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
+}
+inline int8_t ToHost(int8_t x) { return x; }
+inline int16_t ToHost(int16_t x) {
+  return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t ToHost(int32_t x) {
+  return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t ToHost(int64_t x) {
+  return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
+}
+
 // Functions to do unaligned loads and stores in little-endian order.
 inline uint16_t Load16(const void *p) {
   return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
@@ -233,6 +264,36 @@
 
 #endif /* ENDIAN */
 
+inline uint8_t FromHost(uint8_t x) { return x; }
+inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
+inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
+inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
+inline uint8_t ToHost(uint8_t x) { return x; }
+inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
+inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
+inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
+
+inline int8_t FromHost(int8_t x) { return x; }
+inline int16_t FromHost(int16_t x) {
+  return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t FromHost(int32_t x) {
+  return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t FromHost(int64_t x) {
+  return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
+}
+inline int8_t ToHost(int8_t x) { return x; }
+inline int16_t ToHost(int16_t x) {
+  return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t ToHost(int32_t x) {
+  return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t ToHost(int64_t x) {
+  return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
+}
+
 // Functions to do unaligned loads and stores in big-endian order.
 inline uint16_t Load16(const void *p) {
   return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc b/grpc/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc
index 90a482d..075583c 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc
@@ -185,7 +185,7 @@
   ABSL_CONST_INIT static ExponentialBiased eb_static;
   EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0));
 
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
   thread_local ExponentialBiased eb_thread;
   EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0));
 #endif
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc b/grpc/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc
index 2f2eaff..31abb88 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc
@@ -21,6 +21,10 @@
 #include <unordered_map>
 #include <utility>
 
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#endif
+
 #include "absl/container/node_hash_map.h"
 
 namespace absl {
@@ -158,5 +162,20 @@
 int main(int argc, char *argv[]) {
   // The actual test runs in the global constructor of `before_main`.
   printf("PASS\n");
+#ifdef __EMSCRIPTEN__
+  // clang-format off
+// This is JS here. Don't try to format it.
+    MAIN_THREAD_EM_ASM({
+      if (ENVIRONMENT_IS_WEB) {
+        if (typeof TEST_FINISH === 'function') {
+          TEST_FINISH($0);
+        } else {
+          console.error('Attempted to exit with status ' + $0);
+          console.error('But TEST_FINSIHED is not a function.');
+        }
+      }
+    }, 0);
+// clang-format on
+#endif
   return 0;
 }
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h b/grpc/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h
index 6ef79fb..9baccc0 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h
@@ -61,6 +61,8 @@
  public:
   // Returns true iff the calling thread may be cooperatively rescheduled.
   static bool ReschedulingIsAllowed();
+  SchedulingGuard(const SchedulingGuard&) = delete;
+  SchedulingGuard& operator=(const SchedulingGuard&) = delete;
 
  private:
   // Disable cooperative rescheduling of the calling thread.  It may still
@@ -101,9 +103,6 @@
   friend class SchedulingHelper;
   friend class SpinLock;
   friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
-
-  SchedulingGuard(const SchedulingGuard&) = delete;
-  SchedulingGuard& operator=(const SchedulingGuard&) = delete;
 };
 
 //------------------------------------------------------------------------------
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/raw_logging.cc b/grpc/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
index ae8754c..074e026 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
@@ -67,28 +67,32 @@
 #undef ABSL_HAVE_RAW_IO
 #endif
 
-// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
-// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
-// selected set of platforms for which we expect not to be able to raw log.
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace raw_logging_internal {
+namespace {
 
-ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
-    absl::raw_logging_internal::LogPrefixHook>
-    log_prefix_hook;
-ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
-    absl::raw_logging_internal::AbortHook>
-    abort_hook;
+// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
+// Explicitly `#error` out when not `ABSL_LOW_LEVEL_WRITE_SUPPORTED`, except for
+// a selected set of platforms for which we expect not to be able to raw log.
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+    absl::base_internal::AtomicHook<LogPrefixHook>
+        log_prefix_hook;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+    absl::base_internal::AtomicHook<AbortHook>
+        abort_hook;
 
 #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
-static const char kTruncated[] = " ... (message truncated)\n";
+constexpr char kTruncated[] = " ... (message truncated)\n";
 
 // sprintf the format to the buffer, adjusting *buf and *size to reflect the
 // consumed bytes, and return whether the message fit without truncation.  If
 // truncation occurred, if possible leave room in the buffer for the message
 // kTruncated[].
-inline static bool VADoRawLog(char** buf, int* size, const char* format,
-                              va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
-inline static bool VADoRawLog(char** buf, int* size,
-                              const char* format, va_list ap) {
+bool VADoRawLog(char** buf, int* size, const char* format, va_list ap)
+    ABSL_PRINTF_ATTRIBUTE(3, 0);
+bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) {
   int n = vsnprintf(*buf, *size, format, ap);
   bool result = true;
   if (n < 0 || n > *size) {
@@ -96,7 +100,7 @@
     if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
       n = *size - sizeof(kTruncated);  // room for truncation message
     } else {
-      n = 0;                           // no room for truncation message
+      n = 0;  // no room for truncation message
     }
   }
   *size -= n;
@@ -105,9 +109,7 @@
 }
 #endif  // ABSL_LOW_LEVEL_WRITE_SUPPORTED
 
-static constexpr int kLogBufSize = 3000;
-
-namespace {
+constexpr int kLogBufSize = 3000;
 
 // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
 // that invoke malloc() and getenv() that might acquire some locks.
@@ -166,7 +168,7 @@
     } else {
       DoRawLog(&buf, &size, "%s", kTruncated);
     }
-    absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
+    SafeWriteToStderr(buffer, strlen(buffer));
   }
 #else
   static_cast<void>(format);
@@ -181,11 +183,18 @@
   }
 }
 
+// Non-formatting version of RawLog().
+//
+// TODO(gfalcon): When string_view no longer depends on base, change this
+// interface to take its message as a string_view instead.
+void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line,
+                        const std::string& message) {
+  RawLog(severity, file, line, "%.*s", static_cast<int>(message.size()),
+         message.data());
+}
+
 }  // namespace
 
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace raw_logging_internal {
 void SafeWriteToStderr(const char *s, size_t len) {
 #if defined(ABSL_HAVE_SYSCALL_WRITE)
   syscall(SYS_write, STDERR_FILENO, s, len);
@@ -201,8 +210,6 @@
 }
 
 void RawLog(absl::LogSeverity severity, const char* file, int line,
-            const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
-void RawLog(absl::LogSeverity severity, const char* file, int line,
             const char* format, ...) {
   va_list ap;
   va_start(ap, format);
@@ -210,15 +217,6 @@
   va_end(ap);
 }
 
-// Non-formatting version of RawLog().
-//
-// TODO(gfalcon): When string_view no longer depends on base, change this
-// interface to take its message as a string_view instead.
-static void DefaultInternalLog(absl::LogSeverity severity, const char* file,
-                               int line, const std::string& message) {
-  RawLog(severity, file, line, "%s", message.c_str());
-}
-
 bool RawLoggingFullySupported() {
 #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
   return true;
@@ -231,6 +229,10 @@
     absl::base_internal::AtomicHook<InternalLogFunction>
         internal_log_function(DefaultInternalLog);
 
+void RegisterLogPrefixHook(LogPrefixHook func) { log_prefix_hook.Store(func); }
+
+void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); }
+
 void RegisterInternalLogFunction(InternalLogFunction func) {
   internal_log_function.Store(func);
 }
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/raw_logging.h b/grpc/third_party/abseil-cpp/absl/base/internal/raw_logging.h
index 2508f3c..2bf7aab 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/raw_logging.h
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/raw_logging.h
@@ -72,12 +72,14 @@
 //
 // The API is a subset of the above: each macro only takes two arguments.  Use
 // StrCat if you need to build a richer message.
-#define ABSL_INTERNAL_LOG(severity, message)                             \
-  do {                                                                   \
-    constexpr const char* absl_raw_logging_internal_filename = __FILE__; \
-    ::absl::raw_logging_internal::internal_log_function(                 \
-        ABSL_RAW_LOGGING_INTERNAL_##severity,                            \
-        absl_raw_logging_internal_filename, __LINE__, message);          \
+#define ABSL_INTERNAL_LOG(severity, message)                                 \
+  do {                                                                       \
+    constexpr const char* absl_raw_logging_internal_filename = __FILE__;     \
+    ::absl::raw_logging_internal::internal_log_function(                     \
+        ABSL_RAW_LOGGING_INTERNAL_##severity,                                \
+        absl_raw_logging_internal_filename, __LINE__, message);              \
+    if (ABSL_RAW_LOGGING_INTERNAL_##severity == ::absl::LogSeverity::kFatal) \
+      ABSL_INTERNAL_UNREACHABLE;                                             \
   } while (0)
 
 #define ABSL_INTERNAL_CHECK(condition, message)                    \
@@ -176,6 +178,14 @@
     InternalLogFunction>
     internal_log_function;
 
+// Registers hooks of the above types.  Only a single hook of each type may be
+// registered.  It is an error to call these functions multiple times with
+// different input arguments.
+//
+// These functions are safe to call at any point during initialization; they do
+// not block or malloc, and are async-signal safe.
+void RegisterLogPrefixHook(LogPrefixHook func);
+void RegisterAbortHook(AbortHook func);
 void RegisterInternalLogFunction(InternalLogFunction func);
 
 }  // namespace raw_logging_internal
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock.cc b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock.cc
index a7d44f3..35c0696 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock.cc
@@ -125,8 +125,9 @@
     // it as having a sleeper.
     if ((lock_value & kWaitTimeMask) == 0) {
       // Here, just "mark" that the thread is going to sleep.  Don't store the
-      // lock wait time in the lock as that will cause the current lock
-      // owner to think it experienced contention.
+      // lock wait time in the lock -- the lock word stores the amount of time
+      // that the current holder waited before acquiring the lock, not the wait
+      // time of any thread currently waiting to acquire it.
       if (lockword_.compare_exchange_strong(
               lock_value, lock_value | kSpinLockSleeper,
               std::memory_order_relaxed, std::memory_order_relaxed)) {
@@ -140,6 +141,14 @@
         // this thread obtains the lock.
         lock_value = TryLockInternal(lock_value, wait_cycles);
         continue;   // Skip the delay at the end of the loop.
+      } else if ((lock_value & kWaitTimeMask) == 0) {
+        // The lock is still held, without a waiter being marked, but something
+        // else about the lock word changed, causing our CAS to fail. For
+        // example, a new lock holder may have acquired the lock with
+        // kSpinLockDisabledScheduling set, whereas the previous holder had not
+        // set that flag. In this case, attempt again to mark ourselves as a
+        // waiter.
+        continue;
       }
     }
 
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock.h b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock.h
index e6ac9e6..c73b5e0 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock.h
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock.h
@@ -15,11 +15,8 @@
 //
 
 //  Most users requiring mutual exclusion should use Mutex.
-//  SpinLock is provided for use in three situations:
+//  SpinLock is provided for use in two situations:
 //   - for use in code that Mutex itself depends on
-//   - to get a faster fast-path release under low contention (without an
-//     atomic read-modify-write) In return, SpinLock has worse behaviour under
-//     contention, which is why Mutex is preferred in most situations.
 //   - for async signal safety (see below)
 
 // SpinLock is async signal safe.  If a spinlock is used within a signal
@@ -140,8 +137,20 @@
   //
   // bit[0] encodes whether a lock is being held.
   // bit[1] encodes whether a lock uses cooperative scheduling.
-  // bit[2] encodes whether a lock disables scheduling.
+  // bit[2] encodes whether the current lock holder disabled scheduling when
+  //        acquiring the lock. Only set when kSpinLockHeld is also set.
   // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
+  //        This is set by the lock holder to indicate how long it waited on
+  //        the lock before eventually acquiring it. The number of cycles is
+  //        encoded as a 29-bit unsigned int, or in the case that the current
+  //        holder did not wait but another waiter is queued, the LSB
+  //        (kSpinLockSleeper) is set. The implementation does not explicitly
+  //        track the number of queued waiters beyond this. It must always be
+  //        assumed that waiters may exist if the current holder was required to
+  //        queue.
+  //
+  // Invariant: if the lock is not held, the value is either 0 or
+  // kSpinLockCooperative.
   static constexpr uint32_t kSpinLockHeld = 1;
   static constexpr uint32_t kSpinLockCooperative = 2;
   static constexpr uint32_t kSpinLockDisabledScheduling = 4;
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc
index bc46894..7b0cada 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc
@@ -20,7 +20,7 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
     std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
     int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
   // In Akaros, one must take care not to call anything that could cause a
@@ -29,7 +29,7 @@
   // arbitrary code.
 }
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
     std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
 
 }  // extern "C"
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc
index e31c6ed..202f7cd 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc
@@ -56,7 +56,7 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
     std::atomic<uint32_t> *w, uint32_t value, int loop,
     absl::base_internal::SchedulingMode) {
   absl::base_internal::ErrnoSaver errno_saver;
@@ -66,8 +66,8 @@
   syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
 }
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
-                                                  bool all) {
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
+    std::atomic<uint32_t> *w, bool all) {
   syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0);
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc
index fcd21b1..4f6f887 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc
@@ -25,7 +25,7 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
     std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
     absl::base_internal::SchedulingMode /* mode */) {
   absl::base_internal::ErrnoSaver errno_saver;
@@ -40,7 +40,7 @@
   }
 }
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
     std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
 
 }  // extern "C"
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h
index 169bc74..579bd09 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h
@@ -43,18 +43,16 @@
                       const SpinLockWaitTransition trans[],
                       SchedulingMode scheduling_mode);
 
-// If possible, wake some thread that has called SpinLockDelay(w, ...). If
-// "all" is true, wake all such threads.  This call is a hint, and on some
-// systems it may be a no-op; threads calling SpinLockDelay() will always wake
-// eventually even if SpinLockWake() is never called.
+// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all`
+// is true, wake all such threads. On some systems, this may be a no-op; on
+// those systems, threads calling SpinLockDelay() will always wake eventually
+// even if SpinLockWake() is never called.
 void SpinLockWake(std::atomic<uint32_t> *w, bool all);
 
 // Wait for an appropriate spin delay on iteration "loop" of a
 // spin loop on location *w, whose previously observed value was "value".
 // SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
-// or may wait for a delay that can be truncated by a call to SpinLockWake(w).
-// In all cases, it must return in bounded time even if SpinLockWake() is not
-// called.
+// or may wait for a call to SpinLockWake(w).
 void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
                    base_internal::SchedulingMode scheduling_mode);
 
@@ -73,21 +71,23 @@
 // By changing our extension points to be extern "C", we dodge this
 // check.
 extern "C" {
-void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, bool all);
-void AbslInternalSpinLockDelay(
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t> *w,
+                                                      bool all);
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
     std::atomic<uint32_t> *w, uint32_t value, int loop,
     absl::base_internal::SchedulingMode scheduling_mode);
 }
 
 inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w,
                                               bool all) {
-  AbslInternalSpinLockWake(w, all);
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all);
 }
 
 inline void absl::base_internal::SpinLockDelay(
     std::atomic<uint32_t> *w, uint32_t value, int loop,
     absl::base_internal::SchedulingMode scheduling_mode) {
-  AbslInternalSpinLockDelay(w, value, loop, scheduling_mode);
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)
+  (w, value, loop, scheduling_mode);
 }
 
 #endif  // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc
index 78654b5..9d22481 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc
@@ -20,9 +20,9 @@
 
 extern "C" {
 
-void AbslInternalSpinLockDelay(std::atomic<uint32_t>* /* lock_word */,
-                               uint32_t /* value */, int loop,
-                               absl::base_internal::SchedulingMode /* mode */) {
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
+    std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
+    absl::base_internal::SchedulingMode /* mode */) {
   if (loop == 0) {
   } else if (loop == 1) {
     Sleep(0);
@@ -31,7 +31,7 @@
   }
 }
 
-void AbslInternalSpinLockWake(std::atomic<uint32_t>* /* lock_word */,
-                              bool /* all */) {}
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
+    std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
 
 }  // extern "C"
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/strerror.cc b/grpc/third_party/abseil-cpp/absl/base/internal/strerror.cc
index d66ba12..0d6226f 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/strerror.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/strerror.cc
@@ -51,7 +51,6 @@
 }
 
 std::string StrErrorInternal(int errnum) {
-  absl::base_internal::ErrnoSaver errno_saver;
   char buf[100];
   const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
   if (*str == '\0') {
@@ -76,6 +75,7 @@
 }  // namespace
 
 std::string StrError(int errnum) {
+  absl::base_internal::ErrnoSaver errno_saver;
   static const auto* table = NewStrErrorTable();
   if (errnum >= 0 && errnum < static_cast<int>(table->size())) {
     return (*table)[errnum];
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/strerror_test.cc b/grpc/third_party/abseil-cpp/absl/base/internal/strerror_test.cc
index a53da97..e32d5b5 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/strerror_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/strerror_test.cc
@@ -62,12 +62,14 @@
       ++counter;
       errno = ERANGE;
       const std::string value = absl::base_internal::StrError(i);
+      // EXPECT_* could change errno. Stash it first.
+      int check_err = errno;
+      EXPECT_THAT(check_err, Eq(ERANGE));
       // Only the GNU implementation is guaranteed to provide the
       // string "Unknown error nnn". POSIX doesn't say anything.
       if (!absl::StartsWith(value, "Unknown error ")) {
-        EXPECT_THAT(absl::base_internal::StrError(i), Eq(expected_strings[i]));
+        EXPECT_THAT(value, Eq(expected_strings[i]));
       }
-      EXPECT_THAT(errno, Eq(ERANGE));
     }
   };
 
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/sysinfo.cc b/grpc/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
index 349d926..4a3b205 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
@@ -426,7 +426,7 @@
 // userspace construct) to avoid unnecessary system calls. Without this caching,
 // it can take roughly 98ns, while it takes roughly 1ns with this caching.
 pid_t GetCachedTID() {
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
   static thread_local pid_t thread_id = GetTID();
   return thread_id;
 #else
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc b/grpc/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc
index fa8b88b..5f9e45f 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc
@@ -37,17 +37,28 @@
       << "NumCPUs() should not have the default value of 0";
 }
 
+// Ensure that NominalCPUFrequency returns a reasonable value, or 1.00 on
+// platforms where the CPU frequency is not available through sysfs.
+//
+// POWER is particularly problematic here; some Linux kernels expose the CPU
+// frequency, while others do not. Since we can't predict a priori what a given
+// machine is going to do, just disable this test on POWER on Linux.
+#if !(defined(__linux) && (defined(__ppc64__) || defined(__PPC64__)))
 TEST(SysinfoTest, NominalCPUFrequency) {
-#if !(defined(__aarch64__) && defined(__linux__)) && !defined(__EMSCRIPTEN__)
-  EXPECT_GE(NominalCPUFrequency(), 1000.0)
-      << "NominalCPUFrequency() did not return a reasonable value";
-#else
-  // Aarch64 cannot read the CPU frequency from sysfs, so we get back 1.0.
-  // Emscripten does not have a sysfs to read from at all.
+  // Linux only exposes the CPU frequency on certain architectures, and
+  // Emscripten doesn't expose it at all.
+#if defined(__linux__) &&                                                  \
+        (defined(__aarch64__) || defined(__hppa__) || defined(__mips__) || \
+         defined(__riscv) || defined(__s390x__)) ||                        \
+    defined(__EMSCRIPTEN__)
   EXPECT_EQ(NominalCPUFrequency(), 1.0)
       << "CPU frequency detection was fixed! Please update unittest.";
+#else
+  EXPECT_GE(NominalCPUFrequency(), 1000.0)
+      << "NominalCPUFrequency() did not return a reasonable value";
 #endif
 }
+#endif
 
 TEST(SysinfoTest, GetTID) {
   EXPECT_EQ(GetTID(), GetTID());  // Basic compile and equality test.
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/thread_identity.cc b/grpc/third_party/abseil-cpp/absl/base/internal/thread_identity.cc
index d63a04a..6ea010e 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/thread_identity.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/thread_identity.cc
@@ -23,6 +23,7 @@
 #include <cassert>
 #include <memory>
 
+#include "absl/base/attributes.h"
 #include "absl/base/call_once.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/spinlock.h"
@@ -53,9 +54,11 @@
 // exist within a process (via dlopen() or similar), references to
 // thread_identity_ptr from each instance of the code will refer to
 // *different* instances of this ptr.
-#ifdef __GNUC__
+// Apple platforms have the visibility attribute, but issue a compile warning
+// that protected visibility is unsupported.
+#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
 __attribute__((visibility("protected")))
-#endif  // __GNUC__
+#endif  // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
 #if ABSL_PER_THREAD_TLS
 // Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
 ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/thread_identity.h b/grpc/third_party/abseil-cpp/absl/base/internal/thread_identity.h
index ceb109b..9ee651a 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/thread_identity.h
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/thread_identity.h
@@ -32,6 +32,7 @@
 
 #include "absl/base/config.h"
 #include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/optimization.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -69,30 +70,28 @@
                          // is using this PerThreadSynch as a terminator.  Its
                          // skip field must not be filled in because the loop
                          // might then skip over the terminator.
-
-  // The wait parameters of the current wait.  waitp is null if the
-  // thread is not waiting. Transitions from null to non-null must
-  // occur before the enqueue commit point (state = kQueued in
-  // Enqueue() and CondVarEnqueue()). Transitions from non-null to
-  // null must occur after the wait is finished (state = kAvailable in
-  // Mutex::Block() and CondVar::WaitCommon()). This field may be
-  // changed only by the thread that describes this PerThreadSynch.  A
-  // special case is Fer(), which calls Enqueue() on another thread,
-  // but with an identical SynchWaitParams pointer, thus leaving the
-  // pointer unchanged.
-  SynchWaitParams *waitp;
-
-  bool suppress_fatal_errors;  // If true, try to proceed even in the face of
-                               // broken invariants.  This is used within fatal
-                               // signal handlers to improve the chances of
-                               // debug logging information being output
-                               // successfully.
-
-  intptr_t readers;     // Number of readers in mutex.
-  int priority;         // Priority of thread (updated every so often).
-
-  // When priority will next be read (cycles).
-  int64_t next_priority_read_cycles;
+  bool wake;             // This thread is to be woken from a Mutex.
+  // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
+  // waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
+  //
+  // The value of "x->cond_waiter" is meaningless if "x" is not on a
+  // Mutex waiter list.
+  bool cond_waiter;
+  bool maybe_unlocking;  // Valid at head of Mutex waiter queue;
+                         // true if UnlockSlow could be searching
+                         // for a waiter to wake.  Used for an optimization
+                         // in Enqueue().  true is always a valid value.
+                         // Can be reset to false when the unlocker or any
+                         // writer releases the lock, or a reader fully
+                         // releases the lock.  It may not be set to false
+                         // by a reader that decrements the count to
+                         // non-zero. protected by mutex spinlock
+  bool suppress_fatal_errors;  // If true, try to proceed even in the face
+                               // of broken invariants.  This is used within
+                               // fatal signal handlers to improve the
+                               // chances of debug logging information being
+                               // output successfully.
+  int priority;                // Priority of thread (updated every so often).
 
   // State values:
   //   kAvailable: This PerThreadSynch is available.
@@ -111,30 +110,30 @@
   };
   std::atomic<State> state;
 
-  bool maybe_unlocking;  // Valid at head of Mutex waiter queue;
-                         // true if UnlockSlow could be searching
-                         // for a waiter to wake.  Used for an optimization
-                         // in Enqueue().  true is always a valid value.
-                         // Can be reset to false when the unlocker or any
-                         // writer releases the lock, or a reader fully releases
-                         // the lock.  It may not be set to false by a reader
-                         // that decrements the count to non-zero.
-                         // protected by mutex spinlock
+  // The wait parameters of the current wait.  waitp is null if the
+  // thread is not waiting. Transitions from null to non-null must
+  // occur before the enqueue commit point (state = kQueued in
+  // Enqueue() and CondVarEnqueue()). Transitions from non-null to
+  // null must occur after the wait is finished (state = kAvailable in
+  // Mutex::Block() and CondVar::WaitCommon()). This field may be
+  // changed only by the thread that describes this PerThreadSynch.  A
+  // special case is Fer(), which calls Enqueue() on another thread,
+  // but with an identical SynchWaitParams pointer, thus leaving the
+  // pointer unchanged.
+  SynchWaitParams* waitp;
 
-  bool wake;  // This thread is to be woken from a Mutex.
+  intptr_t readers;     // Number of readers in mutex.
 
-  // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
-  // waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
-  //
-  // The value of "x->cond_waiter" is meaningless if "x" is not on a
-  // Mutex waiter list.
-  bool cond_waiter;
+  // When priority will next be read (cycles).
+  int64_t next_priority_read_cycles;
 
   // Locks held; used during deadlock detection.
   // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
   SynchLocksHeld *all_locks;
 };
 
+// The instances of this class are allocated in NewThreadIdentity() with an
+// alignment of PerThreadSynch::kAlignment.
 struct ThreadIdentity {
   // Must be the first member.  The Mutex implementation requires that
   // the PerThreadSynch object associated with each thread is
@@ -144,7 +143,7 @@
 
   // Private: Reserved for absl::synchronization_internal::Waiter.
   struct WaiterState {
-    char data[128];
+    alignas(void*) char data[128];
   } waiter_state;
 
   // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
@@ -212,7 +211,9 @@
 #define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
 #elif defined(_WIN32) && !defined(__MINGW32__)
 #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
-#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
+#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) &&        \
     (__GOOGLE_GRTE_VERSION__ >= 20140228L)
 // Support for async-safe TLS was specifically added in GRTEv4.  It's not
 // present in the upstream eglibc.
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc b/grpc/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc
index c055f75..c260ff1 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc
@@ -18,6 +18,7 @@
 #include <functional>
 #include <new>
 #include <stdexcept>
+
 #include "absl/base/config.h"
 #include "absl/base/internal/raw_logging.h"
 
@@ -25,83 +26,186 @@
 ABSL_NAMESPACE_BEGIN
 namespace base_internal {
 
+// NOTE: The various STL exception throwing functions are placed within the
+// #ifdef blocks so the symbols aren't exposed on platforms that don't support
+// them, such as the Android NDK. For example, ANGLE fails to link when building
+// within AOSP without them, since the STL functions don't exist.
 namespace {
+#ifdef ABSL_HAVE_EXCEPTIONS
 template <typename T>
 [[noreturn]] void Throw(const T& error) {
-#ifdef ABSL_HAVE_EXCEPTIONS
   throw error;
-#else
-  ABSL_RAW_LOG(FATAL, "%s", error.what());
-  std::abort();
-#endif
 }
+#endif
 }  // namespace
 
 void ThrowStdLogicError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::logic_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdLogicError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::logic_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 void ThrowStdInvalidArgument(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::invalid_argument(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdInvalidArgument(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::invalid_argument(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdDomainError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::domain_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdDomainError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::domain_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdLengthError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::length_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdLengthError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::length_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdOutOfRange(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::out_of_range(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdOutOfRange(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::out_of_range(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdRuntimeError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::runtime_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdRuntimeError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::runtime_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdRangeError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::range_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdRangeError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::range_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdOverflowError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::overflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdOverflowError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::overflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
 void ThrowStdUnderflowError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::underflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
 }
 void ThrowStdUnderflowError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
   Throw(std::underflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
 }
 
-void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
+void ThrowStdBadFunctionCall() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::bad_function_call());
+#else
+  std::abort();
+#endif
+}
 
-void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
+void ThrowStdBadAlloc() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::bad_alloc());
+#else
+  std::abort();
+#endif
+}
 
 }  // namespace base_internal
 ABSL_NAMESPACE_END
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/unaligned_access.h b/grpc/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
index dd5250d..093dd9b 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
@@ -31,80 +31,6 @@
 // The unaligned API is C++ only.  The declarations use C++ features
 // (namespaces, inline) which are absent or incompatible in C.
 #if defined(__cplusplus)
-
-#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
-    defined(ABSL_HAVE_THREAD_SANITIZER) || defined(ABSL_HAVE_MEMORY_SANITIZER)
-// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
-// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
-// will miss a bug if 08 is the first unaddressable byte.
-// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
-// miss a race between this access and some other accesses to 08.
-// MemorySanitizer will correctly propagate the shadow on unaligned stores
-// and correctly report bugs on unaligned loads, but it may not properly
-// update and report the origin of the uninitialized memory.
-// For all three tools, replacing an unaligned access with a tool-specific
-// callback solves the problem.
-
-// Make sure uint16_t/uint32_t/uint64_t are defined.
-#include <stdint.h>
-
-extern "C" {
-uint16_t __sanitizer_unaligned_load16(const void *p);
-uint32_t __sanitizer_unaligned_load32(const void *p);
-uint64_t __sanitizer_unaligned_load64(const void *p);
-void __sanitizer_unaligned_store16(void *p, uint16_t v);
-void __sanitizer_unaligned_store32(void *p, uint32_t v);
-void __sanitizer_unaligned_store64(void *p, uint64_t v);
-}  // extern "C"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace base_internal {
-
-inline uint16_t UnalignedLoad16(const void *p) {
-  return __sanitizer_unaligned_load16(p);
-}
-
-inline uint32_t UnalignedLoad32(const void *p) {
-  return __sanitizer_unaligned_load32(p);
-}
-
-inline uint64_t UnalignedLoad64(const void *p) {
-  return __sanitizer_unaligned_load64(p);
-}
-
-inline void UnalignedStore16(void *p, uint16_t v) {
-  __sanitizer_unaligned_store16(p, v);
-}
-
-inline void UnalignedStore32(void *p, uint32_t v) {
-  __sanitizer_unaligned_store32(p, v);
-}
-
-inline void UnalignedStore64(void *p, uint64_t v) {
-  __sanitizer_unaligned_store64(p, v);
-}
-
-}  // namespace base_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
-  (absl::base_internal::UnalignedLoad16(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
-  (absl::base_internal::UnalignedLoad32(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
-  (absl::base_internal::UnalignedLoad64(_p))
-
-#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
-  (absl::base_internal::UnalignedStore16(_p, _val))
-#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
-  (absl::base_internal::UnalignedStore32(_p, _val))
-#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
-  (absl::base_internal::UnalignedStore64(_p, _val))
-
-#else
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace base_internal {
@@ -151,8 +77,6 @@
 #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
   (absl::base_internal::UnalignedStore64(_p, _val))
 
-#endif
-
 #endif  // defined(__cplusplus), end of unaligned API
 
 #endif  // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
diff --git a/grpc/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc b/grpc/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc
index f1e7bbe..1545288 100644
--- a/grpc/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc
@@ -123,9 +123,7 @@
 
 #pragma intrinsic(__rdtsc)
 
-int64_t UnscaledCycleClock::Now() {
-  return __rdtsc();
-}
+int64_t UnscaledCycleClock::Now() { return __rdtsc(); }
 
 double UnscaledCycleClock::Frequency() {
   return base_internal::NominalCPUFrequency();
diff --git a/grpc/third_party/abseil-cpp/absl/base/log_severity.h b/grpc/third_party/abseil-cpp/absl/base/log_severity.h
index 65a3b16..2236422 100644
--- a/grpc/third_party/abseil-cpp/absl/base/log_severity.h
+++ b/grpc/third_party/abseil-cpp/absl/base/log_severity.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
-#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
+#ifndef ABSL_BASE_LOG_SEVERITY_H_
+#define ABSL_BASE_LOG_SEVERITY_H_
 
 #include <array>
 #include <ostream>
@@ -36,7 +36,7 @@
 // such values to a defined severity level, however in some cases values other
 // than the defined levels are useful for comparison.
 //
-// Exmaple:
+// Example:
 //
 //   // Effectively disables all logging:
 //   SetMinLogLevel(static_cast<absl::LogSeverity>(100));
@@ -118,4 +118,4 @@
 ABSL_NAMESPACE_END
 }  // namespace absl
 
-#endif  // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
+#endif  // ABSL_BASE_LOG_SEVERITY_H_
diff --git a/grpc/third_party/abseil-cpp/absl/base/macros.h b/grpc/third_party/abseil-cpp/absl/base/macros.h
index 02dd9ff..3e085a9 100644
--- a/grpc/third_party/abseil-cpp/absl/base/macros.h
+++ b/grpc/third_party/abseil-cpp/absl/base/macros.h
@@ -144,4 +144,15 @@
 #define ABSL_INTERNAL_RETHROW do {} while (false)
 #endif  // ABSL_HAVE_EXCEPTIONS
 
+// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement.  A program which
+// reaches one has undefined behavior, and the compiler may optimize
+// accordingly.
+#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_UNREACHABLE __assume(0)
+#else
+#define ABSL_INTERNAL_UNREACHABLE
+#endif
+
 #endif  // ABSL_BASE_MACROS_H_
diff --git a/grpc/third_party/abseil-cpp/absl/base/optimization.h b/grpc/third_party/abseil-cpp/absl/base/optimization.h
index 2e31376..d090be1 100644
--- a/grpc/third_party/abseil-cpp/absl/base/optimization.h
+++ b/grpc/third_party/abseil-cpp/absl/base/optimization.h
@@ -22,13 +22,15 @@
 #ifndef ABSL_BASE_OPTIMIZATION_H_
 #define ABSL_BASE_OPTIMIZATION_H_
 
+#include <assert.h>
+
 #include "absl/base/config.h"
 
 // ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
 //
-// Instructs the compiler to avoid optimizing tail-call recursion. Use of this
-// macro is useful when you wish to preserve the existing function order within
-// a stack trace for logging, debugging, or profiling purposes.
+// Instructs the compiler to avoid optimizing tail-call recursion. This macro is
+// useful when you wish to preserve the existing function order within a stack
+// trace for logging, debugging, or profiling purposes.
 //
 // Example:
 //
@@ -104,9 +106,10 @@
 // Cacheline aligning objects properly allows constructive memory sharing and
 // prevents destructive (or "false") memory sharing.
 //
-// NOTE: this macro should be replaced with usage of `alignas()` using
+// NOTE: callers should replace uses of this macro with `alignas()` using
 // `std::hardware_constructive_interference_size` and/or
-// `std::hardware_destructive_interference_size` when available within C++17.
+// `std::hardware_destructive_interference_size` when C++17 becomes available to
+// them.
 //
 // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
 // for more information.
@@ -179,7 +182,7 @@
 #endif
 
 // ABSL_INTERNAL_ASSUME(cond)
-// Informs the compiler than a condition is always true and that it can assume
+// Informs the compiler that a condition is always true and that it can assume
 // it to be true for optimization purposes. The call has undefined behavior if
 // the condition is false.
 // In !NDEBUG mode, the condition is checked with an assert().
@@ -216,7 +219,7 @@
 // This macro forces small unique name on a static file level symbols like
 // static local variables or static functions. This is intended to be used in
 // macro definitions to optimize the cost of generated code. Do NOT use it on
-// symbols exported from translation unit since it may casue a link time
+// symbols exported from translation unit since it may cause a link time
 // conflict.
 //
 // Example:
diff --git a/grpc/third_party/abseil-cpp/absl/base/options.h b/grpc/third_party/abseil-cpp/absl/base/options.h
index 6a0fb07..eca879a 100644
--- a/grpc/third_party/abseil-cpp/absl/base/options.h
+++ b/grpc/third_party/abseil-cpp/absl/base/options.h
@@ -206,7 +206,7 @@
 // allowed.
 
 #define ABSL_OPTION_USE_INLINE_NAMESPACE 1
-#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_2020_09_23
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20210324
 
 // ABSL_OPTION_HARDENED
 //
diff --git a/grpc/third_party/abseil-cpp/absl/base/port.h b/grpc/third_party/abseil-cpp/absl/base/port.h
index 6c28068..5bc4d6c 100644
--- a/grpc/third_party/abseil-cpp/absl/base/port.h
+++ b/grpc/third_party/abseil-cpp/absl/base/port.h
@@ -14,7 +14,6 @@
 //
 // This files is a forwarding header for other headers containing various
 // portability macros and functions.
-// This file is used for both C and C++!
 
 #ifndef ABSL_BASE_PORT_H_
 #define ABSL_BASE_PORT_H_
diff --git a/grpc/third_party/abseil-cpp/absl/base/spinlock_test_common.cc b/grpc/third_party/abseil-cpp/absl/base/spinlock_test_common.cc
index dee266e..2b572c5 100644
--- a/grpc/third_party/abseil-cpp/absl/base/spinlock_test_common.cc
+++ b/grpc/third_party/abseil-cpp/absl/base/spinlock_test_common.cc
@@ -92,6 +92,7 @@
 
 static void ThreadedTest(SpinLock* spinlock) {
   std::vector<std::thread> threads;
+  threads.reserve(kNumThreads);
   for (int i = 0; i < kNumThreads; ++i) {
     threads.push_back(std::thread(TestFunction, i, spinlock));
   }
diff --git a/grpc/third_party/abseil-cpp/absl/base/thread_annotations.h b/grpc/third_party/abseil-cpp/absl/base/thread_annotations.h
index e23fff1..9695f6d 100644
--- a/grpc/third_party/abseil-cpp/absl/base/thread_annotations.h
+++ b/grpc/third_party/abseil-cpp/absl/base/thread_annotations.h
@@ -317,7 +317,7 @@
 
 // Takes a reference to a guarded data member, and returns an unguarded
 // reference.
-// Do not used this function directly, use ABSL_TS_UNCHECKED_READ instead.
+// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead.
 template <typename T>
 inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
   return v;
diff --git a/grpc/third_party/abseil-cpp/absl/cleanup/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/cleanup/BUILD.bazel
new file mode 100644
index 0000000..5cca898
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/cleanup/BUILD.bazel
@@ -0,0 +1,66 @@
+# Copyright 2021 The Abseil 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
+#
+#      https://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.
+
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load(
+    "//absl:copts/configure_copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_DEFAULT_LINKOPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+cc_library(
+    name = "cleanup_internal",
+    hdrs = ["internal/cleanup.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:base_internal",
+        "//absl/base:core_headers",
+        "//absl/utility",
+    ],
+)
+
+cc_library(
+    name = "cleanup",
+    hdrs = [
+        "cleanup.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":cleanup_internal",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "cleanup_test",
+    size = "small",
+    srcs = [
+        "cleanup_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":cleanup",
+        "//absl/base:config",
+        "//absl/utility",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/grpc/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt
new file mode 100644
index 0000000..a2dd78a
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt
@@ -0,0 +1,55 @@
+# Copyright 2021 The Abseil 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
+#
+#      https://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.
+
+absl_cc_library(
+  NAME
+    cleanup_internal
+  HDRS
+    "internal/cleanup.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::base_internal
+    absl::core_headers
+    absl::utility
+  PUBLIC
+)
+
+absl_cc_library(
+  NAME
+    cleanup
+  HDRS
+    "cleanup.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::cleanup_internal
+    absl::config
+    absl::core_headers
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    cleanup_test
+  SRCS
+    "cleanup_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::cleanup
+    absl::config
+    absl::utility
+    gmock_main
+)
diff --git a/grpc/third_party/abseil-cpp/absl/cleanup/cleanup.h b/grpc/third_party/abseil-cpp/absl/cleanup/cleanup.h
new file mode 100644
index 0000000..61b53d5
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/cleanup/cleanup.h
@@ -0,0 +1,140 @@
+// Copyright 2021 The Abseil 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
+//
+//      https://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.
+//
+// -----------------------------------------------------------------------------
+// File: cleanup.h
+// -----------------------------------------------------------------------------
+//
+// `absl::Cleanup` implements the scope guard idiom, invoking the contained
+// callback's `operator()() &&` on scope exit.
+//
+// Example:
+//
+// ```
+//   absl::Status CopyGoodData(const char* source_path, const char* sink_path) {
+//     FILE* source_file = fopen(source_path, "r");
+//     if (source_file == nullptr) {
+//       return absl::NotFoundError("No source file");  // No cleanups execute
+//     }
+//
+//     // C++17 style cleanup using class template argument deduction
+//     absl::Cleanup source_closer = [source_file] { fclose(source_file); };
+//
+//     FILE* sink_file = fopen(sink_path, "w");
+//     if (sink_file == nullptr) {
+//       return absl::NotFoundError("No sink file");  // First cleanup executes
+//     }
+//
+//     // C++11 style cleanup using the factory function
+//     auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); });
+//
+//     Data data;
+//     while (ReadData(source_file, &data)) {
+//       if (!data.IsGood()) {
+//         absl::Status result = absl::FailedPreconditionError("Read bad data");
+//         return result;  // Both cleanups execute
+//       }
+//       SaveData(sink_file, &data);
+//     }
+//
+//     return absl::OkStatus();  // Both cleanups execute
+//   }
+// ```
+//
+// Methods:
+//
+// `std::move(cleanup).Cancel()` will prevent the callback from executing.
+//
+// `std::move(cleanup).Invoke()` will execute the callback early, before
+// destruction, and prevent the callback from executing in the destructor.
+//
+// Usage:
+//
+// `absl::Cleanup` is not an interface type. It is only intended to be used
+// within the body of a function. It is not a value type and instead models a
+// control flow construct. Check out `defer` in Golang for something similar.
+
+#ifndef ABSL_CLEANUP_CLEANUP_H_
+#define ABSL_CLEANUP_CLEANUP_H_
+
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+#include "absl/cleanup/internal/cleanup.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <typename Arg, typename Callback = void()>
+class ABSL_MUST_USE_RESULT Cleanup final {
+  static_assert(cleanup_internal::WasDeduced<Arg>(),
+                "Explicit template parameters are not supported.");
+
+  static_assert(cleanup_internal::ReturnsVoid<Callback>(),
+                "Callbacks that return values are not supported.");
+
+ public:
+  Cleanup(Callback callback)  // NOLINT
+      : storage_(std::move(callback), /* is_callback_engaged = */ true) {}
+
+  Cleanup(Cleanup&& other) = default;
+
+  void Cancel() && {
+    ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
+    storage_.DisengageCallback();
+  }
+
+  void Invoke() && {
+    ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
+    storage_.DisengageCallback();
+    storage_.InvokeCallback();
+  }
+
+  ~Cleanup() {
+    if (storage_.IsCallbackEngaged()) {
+      storage_.InvokeCallback();
+    }
+  }
+
+ private:
+  cleanup_internal::Storage<Callback> storage_;
+};
+
+// `absl::Cleanup c = /* callback */;`
+//
+// C++17 type deduction API for creating an instance of `absl::Cleanup`
+#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
+template <typename Callback>
+Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
+#endif  // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
+
+// `auto c = absl::MakeCleanup(/* callback */);`
+//
+// C++11 type deduction API for creating an instance of `absl::Cleanup`
+template <typename... Args, typename Callback>
+absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback) {
+  static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(),
+                "Explicit template parameters are not supported.");
+
+  static_assert(cleanup_internal::ReturnsVoid<Callback>(),
+                "Callbacks that return values are not supported.");
+
+  return {std::move(callback)};
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CLEANUP_CLEANUP_H_
diff --git a/grpc/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc b/grpc/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc
new file mode 100644
index 0000000..792595d
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc
@@ -0,0 +1,267 @@
+// Copyright 2021 The Abseil 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
+//
+//      https://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 "absl/cleanup/cleanup.h"
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+namespace {
+
+using Tag = absl::cleanup_internal::Tag;
+
+template <typename Type1, typename Type2>
+constexpr bool IsSame() {
+  return (std::is_same<Type1, Type2>::value);
+}
+
+struct IdentityFactory {
+  template <typename Callback>
+  static Callback AsCallback(Callback callback) {
+    return Callback(std::move(callback));
+  }
+};
+
+// `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to
+// represent users that make their own move-only callback types outside of
+// `std::function` and lambda literals.
+class FunctorClass {
+  using Callback = std::function<void()>;
+
+ public:
+  explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {}
+
+  FunctorClass(FunctorClass&& other)
+      : callback_(absl::exchange(other.callback_, Callback())) {}
+
+  FunctorClass(const FunctorClass&) = delete;
+
+  FunctorClass& operator=(const FunctorClass&) = delete;
+
+  FunctorClass& operator=(FunctorClass&&) = delete;
+
+  void operator()() const& = delete;
+
+  void operator()() && {
+    ASSERT_TRUE(callback_);
+    callback_();
+    callback_ = nullptr;
+  }
+
+ private:
+  Callback callback_;
+};
+
+struct FunctorClassFactory {
+  template <typename Callback>
+  static FunctorClass AsCallback(Callback callback) {
+    return FunctorClass(std::move(callback));
+  }
+};
+
+struct StdFunctionFactory {
+  template <typename Callback>
+  static std::function<void()> AsCallback(Callback callback) {
+    return std::function<void()>(std::move(callback));
+  }
+};
+
+using CleanupTestParams =
+    ::testing::Types<IdentityFactory, FunctorClassFactory, StdFunctionFactory>;
+template <typename>
+struct CleanupTest : public ::testing::Test {};
+TYPED_TEST_SUITE(CleanupTest, CleanupTestParams);
+
+bool fn_ptr_called = false;
+void FnPtrFunction() { fn_ptr_called = true; }
+
+TYPED_TEST(CleanupTest, FactoryProducesCorrectType) {
+  {
+    auto callback = TypeParam::AsCallback([] {});
+    auto cleanup = absl::MakeCleanup(std::move(callback));
+
+    static_assert(
+        IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
+        "");
+  }
+
+  {
+    auto cleanup = absl::MakeCleanup(&FnPtrFunction);
+
+    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
+                  "");
+  }
+
+  {
+    auto cleanup = absl::MakeCleanup(FnPtrFunction);
+
+    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
+                  "");
+  }
+}
+
+#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
+TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
+  {
+    auto callback = TypeParam::AsCallback([] {});
+    absl::Cleanup cleanup = std::move(callback);
+
+    static_assert(
+        IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
+        "");
+  }
+
+  {
+    absl::Cleanup cleanup = &FnPtrFunction;
+
+    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
+                  "");
+  }
+
+  {
+    absl::Cleanup cleanup = FnPtrFunction;
+
+    static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
+                  "");
+  }
+}
+
+TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
+  {
+    auto callback = IdentityFactory::AsCallback([] {});
+    auto factory_cleanup = absl::MakeCleanup(callback);
+    absl::Cleanup deduction_cleanup = callback;
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+
+  {
+    auto factory_cleanup =
+        absl::MakeCleanup(FunctorClassFactory::AsCallback([] {}));
+    absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {});
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+
+  {
+    auto factory_cleanup =
+        absl::MakeCleanup(StdFunctionFactory::AsCallback([] {}));
+    absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {});
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+
+  {
+    auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction);
+    absl::Cleanup deduction_cleanup = &FnPtrFunction;
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+
+  {
+    auto factory_cleanup = absl::MakeCleanup(FnPtrFunction);
+    absl::Cleanup deduction_cleanup = FnPtrFunction;
+
+    static_assert(
+        IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
+  }
+}
+#endif  // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
+
+TYPED_TEST(CleanupTest, BasicUsage) {
+  bool called = false;
+
+  {
+    auto cleanup =
+        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
+    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
+  }
+
+  EXPECT_TRUE(called);  // Destructor should invoke the callback
+}
+
+TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) {
+  fn_ptr_called = false;
+
+  {
+    auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction));
+    EXPECT_FALSE(fn_ptr_called);  // Constructor shouldn't invoke the callback
+  }
+
+  EXPECT_TRUE(fn_ptr_called);  // Destructor should invoke the callback
+}
+
+TYPED_TEST(CleanupTest, Cancel) {
+  bool called = false;
+
+  {
+    auto cleanup =
+        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
+    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
+
+    std::move(cleanup).Cancel();
+    EXPECT_FALSE(called);  // Cancel shouldn't invoke the callback
+  }
+
+  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
+}
+
+TYPED_TEST(CleanupTest, Invoke) {
+  bool called = false;
+
+  {
+    auto cleanup =
+        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
+    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
+
+    std::move(cleanup).Invoke();
+    EXPECT_TRUE(called);  // Invoke should invoke the callback
+
+    called = false;  // Reset tracker before destructor runs
+  }
+
+  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
+}
+
+TYPED_TEST(CleanupTest, Move) {
+  bool called = false;
+
+  {
+    auto moved_from_cleanup =
+        absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
+    EXPECT_FALSE(called);  // Constructor shouldn't invoke the callback
+
+    {
+      auto moved_to_cleanup = std::move(moved_from_cleanup);
+      EXPECT_FALSE(called);  // Move shouldn't invoke the callback
+    }
+
+    EXPECT_TRUE(called);  // Destructor should invoke the callback
+
+    called = false;  // Reset tracker before destructor runs
+  }
+
+  EXPECT_FALSE(called);  // Destructor shouldn't invoke the callback
+}
+
+}  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h b/grpc/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h
new file mode 100644
index 0000000..b4c4073
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h
@@ -0,0 +1,81 @@
+// Copyright 2021 The Abseil 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
+//
+//      https://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 ABSL_CLEANUP_INTERNAL_CLEANUP_H_
+#define ABSL_CLEANUP_INTERNAL_CLEANUP_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace cleanup_internal {
+
+struct Tag {};
+
+template <typename Arg, typename... Args>
+constexpr bool WasDeduced() {
+  return (std::is_same<cleanup_internal::Tag, Arg>::value) &&
+         (sizeof...(Args) == 0);
+}
+
+template <typename Callback>
+constexpr bool ReturnsVoid() {
+  return (std::is_same<base_internal::invoke_result_t<Callback>, void>::value);
+}
+
+template <typename Callback>
+class Storage {
+ public:
+  Storage() = delete;
+
+  Storage(Callback callback, bool is_callback_engaged)
+      : callback_(std::move(callback)),
+        is_callback_engaged_(is_callback_engaged) {}
+
+  Storage(Storage&& other)
+      : callback_(std::move(other.callback_)),
+        is_callback_engaged_(
+            absl::exchange(other.is_callback_engaged_, false)) {}
+
+  Storage(const Storage& other) = delete;
+
+  Storage& operator=(Storage&& other) = delete;
+
+  Storage& operator=(const Storage& other) = delete;
+
+  bool IsCallbackEngaged() const { return is_callback_engaged_; }
+
+  void DisengageCallback() { is_callback_engaged_ = false; }
+
+  void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS {
+    std::move(callback_)();
+  }
+
+ private:
+  Callback callback_;
+  bool is_callback_engaged_;
+};
+
+}  // namespace cleanup_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CLEANUP_INTERNAL_CLEANUP_H_
diff --git a/grpc/third_party/abseil-cpp/absl/compiler_config_setting.bzl b/grpc/third_party/abseil-cpp/absl/compiler_config_setting.bzl
deleted file mode 100644
index 6696229..0000000
--- a/grpc/third_party/abseil-cpp/absl/compiler_config_setting.bzl
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright 2018 The Abseil 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
-#
-#      https://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.
-
-"""Creates config_setting that allows selecting based on 'compiler' value."""
-
-def create_llvm_config(name, visibility):
-    # The "do_not_use_tools_cpp_compiler_present" attribute exists to
-    # distinguish between older versions of Bazel that do not support
-    # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
-    # In the future, the only way to select on the compiler will be through
-    # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
-    # be removed.
-    if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
-        native.config_setting(
-            name = name,
-            flag_values = {
-                "@bazel_tools//tools/cpp:compiler": "llvm",
-            },
-            visibility = visibility,
-        )
-    else:
-        native.config_setting(
-            name = name,
-            values = {"compiler": "llvm"},
-            visibility = visibility,
-        )
diff --git a/grpc/third_party/abseil-cpp/absl/container/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/container/BUILD.bazel
index 8e72ad0..f22fdc6 100644
--- a/grpc/third_party/abseil-cpp/absl/container/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/container/BUILD.bazel
@@ -599,12 +599,12 @@
         ":hashtablez_sampler",
         ":have_sse",
         ":layout",
-        "//absl/base:bits",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
         "//absl/memory",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/utility",
     ],
 )
@@ -630,6 +630,45 @@
     ],
 )
 
+cc_binary(
+    name = "raw_hash_set_benchmark",
+    testonly = 1,
+    srcs = ["internal/raw_hash_set_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":hash_function_defaults",
+        ":raw_hash_set",
+        "//absl/base:raw_logging_internal",
+        "//absl/strings:str_format",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_binary(
+    name = "raw_hash_set_probe_benchmark",
+    testonly = 1,
+    srcs = ["internal/raw_hash_set_probe_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = select({
+        "//conditions:default": [],
+    }) + ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":flat_hash_map",
+        ":hash_function_defaults",
+        ":hashtable_debug",
+        ":raw_hash_set",
+        "//absl/random",
+        "//absl/random:distributions",
+        "//absl/strings",
+        "//absl/strings:str_format",
+    ],
+)
+
 cc_test(
     name = "raw_hash_set_allocator_test",
     size = "small",
@@ -677,6 +716,22 @@
     ],
 )
 
+cc_binary(
+    name = "layout_benchmark",
+    testonly = 1,
+    srcs = ["internal/layout_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":layout",
+        "//absl/base:core_headers",
+        "//absl/base:raw_logging_internal",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
 cc_library(
     name = "tracked",
     testonly = 1,
diff --git a/grpc/third_party/abseil-cpp/absl/container/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/container/CMakeLists.txt
index eb202c4..2d7d0e6 100644
--- a/grpc/third_party/abseil-cpp/absl/container/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/container/CMakeLists.txt
@@ -14,15 +14,6 @@
 # limitations under the License.
 #
 
-# This is deprecated and will be removed in the future.  It also doesn't do
-# anything anyways.  Prefer to use the library associated with the API you are
-# using.
-absl_cc_library(
-  NAME
-    container
-  PUBLIC
-)
-
 absl_cc_library(
   NAME
     btree
diff --git a/grpc/third_party/abseil-cpp/absl/container/btree_benchmark.cc b/grpc/third_party/abseil-cpp/absl/container/btree_benchmark.cc
index 4679867..65b6790 100644
--- a/grpc/third_party/abseil-cpp/absl/container/btree_benchmark.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/btree_benchmark.cc
@@ -26,6 +26,7 @@
 #include <unordered_set>
 #include <vector>
 
+#include "benchmark/benchmark.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/container/btree_map.h"
 #include "absl/container/btree_set.h"
@@ -39,7 +40,6 @@
 #include "absl/strings/cord.h"
 #include "absl/strings/str_format.h"
 #include "absl/time/time.h"
-#include "benchmark/benchmark.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -101,39 +101,6 @@
   BM_InsertImpl<T>(state, true);
 }
 
-// container::insert sometimes returns a pair<iterator, bool> and sometimes
-// returns an iterator (for multi- containers).
-template <typename Iter>
-Iter GetIterFromInsert(const std::pair<Iter, bool>& pair) {
-  return pair.first;
-}
-template <typename Iter>
-Iter GetIterFromInsert(const Iter iter) {
-  return iter;
-}
-
-// Benchmark insertion of values into a container at the end.
-template <typename T>
-void BM_InsertEnd(benchmark::State& state) {
-  using V = typename remove_pair_const<typename T::value_type>::type;
-  typename KeyOfValue<typename T::key_type, V>::type key_of_value;
-
-  T container;
-  const int kSize = 10000;
-  for (int i = 0; i < kSize; ++i) {
-    container.insert(Generator<V>(kSize)(i));
-  }
-  V v = Generator<V>(kSize)(kSize - 1);
-  typename T::key_type k = key_of_value(v);
-
-  auto it = container.find(k);
-  while (state.KeepRunning()) {
-    // Repeatedly removing then adding v.
-    container.erase(it);
-    it = GetIterFromInsert(container.insert(v));
-  }
-}
-
 // Benchmark inserting the first few elements in a container. In b-tree, this is
 // when the root node grows.
 template <typename T>
@@ -513,7 +480,6 @@
 #define MY_BENCHMARK3(type)               \
   MY_BENCHMARK4(type, Insert);            \
   MY_BENCHMARK4(type, InsertSorted);      \
-  MY_BENCHMARK4(type, InsertEnd);         \
   MY_BENCHMARK4(type, InsertSmall);       \
   MY_BENCHMARK4(type, Lookup);            \
   MY_BENCHMARK4(type, FullLookup);        \
diff --git a/grpc/third_party/abseil-cpp/absl/container/btree_map.h b/grpc/third_party/abseil-cpp/absl/container/btree_map.h
index abc09b0..ea49d44 100644
--- a/grpc/third_party/abseil-cpp/absl/container/btree_map.h
+++ b/grpc/third_party/abseil-cpp/absl/container/btree_map.h
@@ -384,9 +384,8 @@
 
   // btree_map::equal_range()
   //
-  // Returns a closed range [first, last], defined by a `std::pair` of two
-  // iterators, containing all elements with the passed key in the
-  // `btree_map`.
+  // Returns a half-open range [first, last), defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the `btree_map`.
   using Base::equal_range;
 
   // btree_map::find()
@@ -709,7 +708,7 @@
 
   // btree_multimap::equal_range()
   //
-  // Returns a closed range [first, last], defined by a `std::pair` of two
+  // Returns a half-open range [first, last), defined by a `std::pair` of two
   // iterators, containing all elements with the passed key in the
   // `btree_multimap`.
   using Base::equal_range;
diff --git a/grpc/third_party/abseil-cpp/absl/container/btree_test.cc b/grpc/third_party/abseil-cpp/absl/container/btree_test.cc
index 1bfa0c2..74337df 100644
--- a/grpc/third_party/abseil-cpp/absl/container/btree_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/btree_test.cc
@@ -55,6 +55,7 @@
 using ::testing::IsEmpty;
 using ::testing::IsNull;
 using ::testing::Pair;
+using ::testing::SizeIs;
 
 template <typename T, typename U>
 void CheckPairEquals(const T &x, const U &y) {
@@ -1182,6 +1183,103 @@
   EXPECT_EQ(1, tmap.size());
 }
 
+}  // namespace
+
+class BtreeNodePeer {
+ public:
+  // Yields the size of a leaf node with a specific number of values.
+  template <typename ValueType>
+  constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) {
+    return btree_node<
+        set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>,
+                   /*TargetNodeSize=*/256,  // This parameter isn't used here.
+                   /*Multi=*/false>>::SizeWithNSlots(target_values_per_node);
+  }
+
+  // Yields the number of slots in a (non-root) leaf node for this btree.
+  template <typename Btree>
+  constexpr static size_t GetNumSlotsPerNode() {
+    return btree_node<typename Btree::params_type>::kNodeSlots;
+  }
+
+  template <typename Btree>
+  constexpr static size_t GetMaxFieldType() {
+    return std::numeric_limits<
+        typename btree_node<typename Btree::params_type>::field_type>::max();
+  }
+
+  template <typename Btree>
+  constexpr static bool UsesLinearNodeSearch() {
+    return btree_node<typename Btree::params_type>::use_linear_search::value;
+  }
+};
+
+namespace {
+
+class BtreeMapTest : public ::testing::Test {
+ public:
+  struct Key {};
+  struct Cmp {
+    template <typename T>
+    bool operator()(T, T) const {
+      return false;
+    }
+  };
+
+  struct KeyLin {
+    using absl_btree_prefer_linear_node_search = std::true_type;
+  };
+  struct CmpLin : Cmp {
+    using absl_btree_prefer_linear_node_search = std::true_type;
+  };
+
+  struct KeyBin {
+    using absl_btree_prefer_linear_node_search = std::false_type;
+  };
+  struct CmpBin : Cmp {
+    using absl_btree_prefer_linear_node_search = std::false_type;
+  };
+
+  template <typename K, typename C>
+  static bool IsLinear() {
+    return BtreeNodePeer::UsesLinearNodeSearch<absl::btree_map<K, int, C>>();
+  }
+};
+
+TEST_F(BtreeMapTest, TestLinearSearchPreferredForKeyLinearViaAlias) {
+  // Test requesting linear search by directly exporting an alias.
+  EXPECT_FALSE((IsLinear<Key, Cmp>()));
+  EXPECT_TRUE((IsLinear<KeyLin, Cmp>()));
+  EXPECT_TRUE((IsLinear<Key, CmpLin>()));
+  EXPECT_TRUE((IsLinear<KeyLin, CmpLin>()));
+}
+
+TEST_F(BtreeMapTest, LinearChoiceTree) {
+  // Cmp has precedence, and is forcing binary
+  EXPECT_FALSE((IsLinear<Key, CmpBin>()));
+  EXPECT_FALSE((IsLinear<KeyLin, CmpBin>()));
+  EXPECT_FALSE((IsLinear<KeyBin, CmpBin>()));
+  EXPECT_FALSE((IsLinear<int, CmpBin>()));
+  EXPECT_FALSE((IsLinear<std::string, CmpBin>()));
+  // Cmp has precedence, and is forcing linear
+  EXPECT_TRUE((IsLinear<Key, CmpLin>()));
+  EXPECT_TRUE((IsLinear<KeyLin, CmpLin>()));
+  EXPECT_TRUE((IsLinear<KeyBin, CmpLin>()));
+  EXPECT_TRUE((IsLinear<int, CmpLin>()));
+  EXPECT_TRUE((IsLinear<std::string, CmpLin>()));
+  // Cmp has no preference, Key determines linear vs binary.
+  EXPECT_FALSE((IsLinear<Key, Cmp>()));
+  EXPECT_TRUE((IsLinear<KeyLin, Cmp>()));
+  EXPECT_FALSE((IsLinear<KeyBin, Cmp>()));
+  // arithmetic key w/ std::less or std::greater: linear
+  EXPECT_TRUE((IsLinear<int, std::less<int>>()));
+  EXPECT_TRUE((IsLinear<double, std::greater<double>>()));
+  // arithmetic key w/ custom compare: binary
+  EXPECT_FALSE((IsLinear<int, Cmp>()));
+  // non-arithmetic key: binary
+  EXPECT_FALSE((IsLinear<std::string, std::less<std::string>>()));
+}
+
 TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) {
   absl::btree_map<std::string, std::unique_ptr<std::string>> m;
 
@@ -1327,34 +1425,6 @@
   EXPECT_EQ(tracker.swaps(), 0);
 }
 
-}  // namespace
-
-class BtreeNodePeer {
- public:
-  // Yields the size of a leaf node with a specific number of values.
-  template <typename ValueType>
-  constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) {
-    return btree_node<
-        set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>,
-                   /*TargetNodeSize=*/256,  // This parameter isn't used here.
-                   /*Multi=*/false>>::SizeWithNValues(target_values_per_node);
-  }
-
-  // Yields the number of values in a (non-root) leaf node for this set.
-  template <typename Set>
-  constexpr static size_t GetNumValuesPerNode() {
-    return btree_node<typename Set::params_type>::kNodeValues;
-  }
-
-  template <typename Set>
-  constexpr static size_t GetMaxFieldType() {
-    return std::numeric_limits<
-        typename btree_node<typename Set::params_type>::field_type>::max();
-  }
-};
-
-namespace {
-
 // A btree set with a specific number of values per node.
 template <typename Key, int TargetValuesPerNode, typename Cmp = std::less<Key>>
 class SizedBtreeSet
@@ -1388,7 +1458,7 @@
 TEST(Btree, MovesComparisonsCopiesSwapsTracking) {
   InstanceTracker tracker;
   // Note: this is minimum number of values per node.
-  SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3> set3;
+  SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/4> set4;
   // Note: this is the default number of values per node for a set of int32s
   // (with 64-bit pointers).
   SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61> set61;
@@ -1399,28 +1469,28 @@
   std::vector<int> values =
       GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23);
 
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3);
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61);
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set4)>(), 4);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
   if (sizeof(void *) == 8) {
-    EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(),
-              BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>());
+    EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
+              BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>());
   }
 
   // Test key insertion/deletion in random order.
-  ExpectOperationCounts(45281, 132551, values, &tracker, &set3);
+  ExpectOperationCounts(56540, 134212, values, &tracker, &set4);
   ExpectOperationCounts(386718, 129807, values, &tracker, &set61);
   ExpectOperationCounts(586761, 130310, values, &tracker, &set100);
 
   // Test key insertion/deletion in sorted order.
   std::sort(values.begin(), values.end());
-  ExpectOperationCounts(26638, 92134, values, &tracker, &set3);
+  ExpectOperationCounts(24972, 85563, values, &tracker, &set4);
   ExpectOperationCounts(20208, 87757, values, &tracker, &set61);
   ExpectOperationCounts(20124, 96583, values, &tracker, &set100);
 
   // Test key insertion/deletion in reverse sorted order.
   std::reverse(values.begin(), values.end());
-  ExpectOperationCounts(49951, 119325, values, &tracker, &set3);
+  ExpectOperationCounts(54949, 127531, values, &tracker, &set4);
   ExpectOperationCounts(338813, 118266, values, &tracker, &set61);
   ExpectOperationCounts(534529, 125279, values, &tracker, &set100);
 }
@@ -1437,9 +1507,9 @@
 TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) {
   InstanceTracker tracker;
   // Note: this is minimum number of values per node.
-  SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3,
+  SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/4,
                 MovableOnlyInstanceThreeWayCompare>
-      set3;
+      set4;
   // Note: this is the default number of values per node for a set of int32s
   // (with 64-bit pointers).
   SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61,
@@ -1454,28 +1524,28 @@
   std::vector<int> values =
       GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23);
 
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3);
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61);
-  EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set4)>(), 4);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
+  EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
   if (sizeof(void *) == 8) {
-    EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(),
-              BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>());
+    EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
+              BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>());
   }
 
   // Test key insertion/deletion in random order.
-  ExpectOperationCounts(45281, 122560, values, &tracker, &set3);
+  ExpectOperationCounts(56540, 124221, values, &tracker, &set4);
   ExpectOperationCounts(386718, 119816, values, &tracker, &set61);
   ExpectOperationCounts(586761, 120319, values, &tracker, &set100);
 
   // Test key insertion/deletion in sorted order.
   std::sort(values.begin(), values.end());
-  ExpectOperationCounts(26638, 92134, values, &tracker, &set3);
+  ExpectOperationCounts(24972, 85563, values, &tracker, &set4);
   ExpectOperationCounts(20208, 87757, values, &tracker, &set61);
   ExpectOperationCounts(20124, 96583, values, &tracker, &set100);
 
   // Test key insertion/deletion in reverse sorted order.
   std::reverse(values.begin(), values.end());
-  ExpectOperationCounts(49951, 109326, values, &tracker, &set3);
+  ExpectOperationCounts(54949, 117532, values, &tracker, &set4);
   ExpectOperationCounts(338813, 108267, values, &tracker, &set61);
   ExpectOperationCounts(534529, 115280, values, &tracker, &set100);
 }
@@ -1968,6 +2038,30 @@
   EXPECT_EQ(res, ++other.begin());
 }
 
+TEST(Btree, ExtractMultiMapEquivalentKeys) {
+  // Note: using string keys means a three-way comparator.
+  absl::btree_multimap<std::string, int> map;
+  for (int i = 0; i < 100; ++i) {
+    for (int j = 0; j < 100; ++j) {
+      map.insert({absl::StrCat(i), j});
+    }
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    const std::string key = absl::StrCat(i);
+    auto node_handle = map.extract(key);
+    EXPECT_EQ(node_handle.key(), key);
+    EXPECT_EQ(node_handle.mapped(), 0) << i;
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    const std::string key = absl::StrCat(i);
+    auto node_handle = map.extract(key);
+    EXPECT_EQ(node_handle.key(), key);
+    EXPECT_EQ(node_handle.mapped(), 1) << i;
+  }
+}
+
 // For multisets, insert with hint also affects correctness because we need to
 // insert immediately before the hint if possible.
 struct InsertMultiHintData {
@@ -2109,6 +2203,31 @@
                                Pair(4, 1), Pair(4, 4), Pair(5, 5)));
 }
 
+TEST(Btree, MergeIntoSetMovableOnly) {
+  absl::btree_set<MovableOnlyInstance> src;
+  src.insert(MovableOnlyInstance(1));
+  absl::btree_multiset<MovableOnlyInstance> dst1;
+  dst1.insert(MovableOnlyInstance(2));
+  absl::btree_set<MovableOnlyInstance> dst2;
+
+  // Test merge into multiset.
+  dst1.merge(src);
+
+  EXPECT_TRUE(src.empty());
+  // ElementsAre/ElementsAreArray don't work with move-only types.
+  ASSERT_THAT(dst1, SizeIs(2));
+  EXPECT_EQ(*dst1.begin(), MovableOnlyInstance(1));
+  EXPECT_EQ(*std::next(dst1.begin()), MovableOnlyInstance(2));
+
+  // Test merge into set.
+  dst2.merge(dst1);
+
+  EXPECT_TRUE(dst1.empty());
+  ASSERT_THAT(dst2, SizeIs(2));
+  EXPECT_EQ(*dst2.begin(), MovableOnlyInstance(1));
+  EXPECT_EQ(*std::next(dst2.begin()), MovableOnlyInstance(2));
+}
+
 struct KeyCompareToWeakOrdering {
   template <typename T>
   absl::weak_ordering operator()(const T &a, const T &b) const {
@@ -2585,6 +2704,12 @@
   int i2;
 };
 
+bool operator==(const MultiKey a, const MultiKey b) {
+  return a.i1 == b.i1 && a.i2 == b.i2;
+}
+
+// A heterogeneous comparator that has different equivalence classes for
+// different lookup types.
 struct MultiKeyComp {
   using is_transparent = void;
   bool operator()(const MultiKey a, const MultiKey b) const {
@@ -2595,11 +2720,36 @@
   bool operator()(const MultiKey a, const int b) const { return a.i1 < b; }
 };
 
-// Test that when there's a heterogeneous comparator that behaves differently
-// for some heterogeneous operators, we get equal_range() right.
-TEST(Btree, MultiKeyEqualRange) {
-  absl::btree_set<MultiKey, MultiKeyComp> set;
+// A heterogeneous, three-way comparator that has different equivalence classes
+// for different lookup types.
+struct MultiKeyThreeWayComp {
+  using is_transparent = void;
+  absl::weak_ordering operator()(const MultiKey a, const MultiKey b) const {
+    if (a.i1 < b.i1) return absl::weak_ordering::less;
+    if (a.i1 > b.i1) return absl::weak_ordering::greater;
+    if (a.i2 < b.i2) return absl::weak_ordering::less;
+    if (a.i2 > b.i2) return absl::weak_ordering::greater;
+    return absl::weak_ordering::equivalent;
+  }
+  absl::weak_ordering operator()(const int a, const MultiKey b) const {
+    if (a < b.i1) return absl::weak_ordering::less;
+    if (a > b.i1) return absl::weak_ordering::greater;
+    return absl::weak_ordering::equivalent;
+  }
+  absl::weak_ordering operator()(const MultiKey a, const int b) const {
+    if (a.i1 < b) return absl::weak_ordering::less;
+    if (a.i1 > b) return absl::weak_ordering::greater;
+    return absl::weak_ordering::equivalent;
+  }
+};
 
+template <typename Compare>
+class BtreeMultiKeyTest : public ::testing::Test {};
+using MultiKeyComps = ::testing::Types<MultiKeyComp, MultiKeyThreeWayComp>;
+TYPED_TEST_SUITE(BtreeMultiKeyTest, MultiKeyComps);
+
+TYPED_TEST(BtreeMultiKeyTest, EqualRange) {
+  absl::btree_set<MultiKey, TypeParam> set;
   for (int i = 0; i < 100; ++i) {
     for (int j = 0; j < 100; ++j) {
       set.insert({i, j});
@@ -2609,11 +2759,140 @@
   for (int i = 0; i < 100; ++i) {
     auto equal_range = set.equal_range(i);
     EXPECT_EQ(equal_range.first->i1, i);
-    EXPECT_EQ(equal_range.first->i2, 0);
+    EXPECT_EQ(equal_range.first->i2, 0) << i;
     EXPECT_EQ(std::distance(equal_range.first, equal_range.second), 100) << i;
   }
 }
 
+TYPED_TEST(BtreeMultiKeyTest, Extract) {
+  absl::btree_set<MultiKey, TypeParam> set;
+  for (int i = 0; i < 100; ++i) {
+    for (int j = 0; j < 100; ++j) {
+      set.insert({i, j});
+    }
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    auto node_handle = set.extract(i);
+    EXPECT_EQ(node_handle.value().i1, i);
+    EXPECT_EQ(node_handle.value().i2, 0) << i;
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    auto node_handle = set.extract(i);
+    EXPECT_EQ(node_handle.value().i1, i);
+    EXPECT_EQ(node_handle.value().i2, 1) << i;
+  }
+}
+
+TYPED_TEST(BtreeMultiKeyTest, Erase) {
+  absl::btree_set<MultiKey, TypeParam> set = {
+      {1, 1}, {2, 1}, {2, 2}, {3, 1}};
+  EXPECT_EQ(set.erase(2), 2);
+  EXPECT_THAT(set, ElementsAre(MultiKey{1, 1}, MultiKey{3, 1}));
+}
+
+TYPED_TEST(BtreeMultiKeyTest, Count) {
+  const absl::btree_set<MultiKey, TypeParam> set = {
+      {1, 1}, {2, 1}, {2, 2}, {3, 1}};
+  EXPECT_EQ(set.count(2), 2);
+}
+
+TEST(Btree, AllocConstructor) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used = 0;
+  Alloc alloc(&bytes_used);
+  Set set(alloc);
+
+  set.insert({1, 2, 3});
+
+  EXPECT_THAT(set, ElementsAre(1, 2, 3));
+  EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocInitializerListConstructor) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used = 0;
+  Alloc alloc(&bytes_used);
+  Set set({1, 2, 3}, alloc);
+
+  EXPECT_THAT(set, ElementsAre(1, 2, 3));
+  EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocRangeConstructor) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used = 0;
+  Alloc alloc(&bytes_used);
+  std::vector<int> v = {1, 2, 3};
+  Set set(v.begin(), v.end(), alloc);
+
+  EXPECT_THAT(set, ElementsAre(1, 2, 3));
+  EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocCopyConstructor) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used1 = 0;
+  Alloc alloc1(&bytes_used1);
+  Set set1(alloc1);
+
+  set1.insert({1, 2, 3});
+
+  int64_t bytes_used2 = 0;
+  Alloc alloc2(&bytes_used2);
+  Set set2(set1, alloc2);
+
+  EXPECT_THAT(set1, ElementsAre(1, 2, 3));
+  EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+  EXPECT_GT(bytes_used1, set1.size() * sizeof(int));
+  EXPECT_EQ(bytes_used1, bytes_used2);
+}
+
+TEST(Btree, AllocMoveConstructor_SameAlloc) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used = 0;
+  Alloc alloc(&bytes_used);
+  Set set1(alloc);
+
+  set1.insert({1, 2, 3});
+
+  const int64_t original_bytes_used = bytes_used;
+  EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
+
+  Set set2(std::move(set1), alloc);
+
+  EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+  EXPECT_EQ(bytes_used, original_bytes_used);
+}
+
+TEST(Btree, AllocMoveConstructor_DifferentAlloc) {
+  using Alloc = CountingAllocator<int>;
+  using Set = absl::btree_set<int, std::less<int>, Alloc>;
+  int64_t bytes_used1 = 0;
+  Alloc alloc1(&bytes_used1);
+  Set set1(alloc1);
+
+  set1.insert({1, 2, 3});
+
+  const int64_t original_bytes_used = bytes_used1;
+  EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
+
+  int64_t bytes_used2 = 0;
+  Alloc alloc2(&bytes_used2);
+  Set set2(std::move(set1), alloc2);
+
+  EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+  // We didn't free these bytes allocated by `set1` yet.
+  EXPECT_EQ(bytes_used1, original_bytes_used);
+  EXPECT_EQ(bytes_used2, original_bytes_used);
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/grpc/third_party/abseil-cpp/absl/container/fixed_array.h b/grpc/third_party/abseil-cpp/absl/container/fixed_array.h
index c8fe8d9..fcb3e54 100644
--- a/grpc/third_party/abseil-cpp/absl/container/fixed_array.h
+++ b/grpc/third_party/abseil-cpp/absl/container/fixed_array.h
@@ -232,8 +232,8 @@
 
   // FixedArray::at
   //
-  // Bounds-checked access.  Returns a reference to the ith element of the
-  // fiexed array, or throws std::out_of_range
+  // Bounds-checked access.  Returns a reference to the ith element of the fixed
+  // array, or throws std::out_of_range
   reference at(size_type i) {
     if (ABSL_PREDICT_FALSE(i >= size())) {
       base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
diff --git a/grpc/third_party/abseil-cpp/absl/container/flat_hash_set.h b/grpc/third_party/abseil-cpp/absl/container/flat_hash_set.h
index 81e145a..6b89da6 100644
--- a/grpc/third_party/abseil-cpp/absl/container/flat_hash_set.h
+++ b/grpc/third_party/abseil-cpp/absl/container/flat_hash_set.h
@@ -324,7 +324,7 @@
 
   // flat_hash_set::merge()
   //
-  // Extracts elements from a given `source` flat hash map into this
+  // Extracts elements from a given `source` flat hash set into this
   // `flat_hash_set`. If the destination `flat_hash_set` already contains an
   // element with an equivalent key, that element is not extracted.
   using Base::merge;
diff --git a/grpc/third_party/abseil-cpp/absl/container/inlined_vector.h b/grpc/third_party/abseil-cpp/absl/container/inlined_vector.h
index 90bb96e..7c18234 100644
--- a/grpc/third_party/abseil-cpp/absl/container/inlined_vector.h
+++ b/grpc/third_party/abseil-cpp/absl/container/inlined_vector.h
@@ -167,11 +167,13 @@
   // Creates an inlined vector by copying the contents of `other` using `alloc`.
   InlinedVector(const InlinedVector& other, const allocator_type& alloc)
       : storage_(alloc) {
-    if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) {
+    if (other.empty()) {
+      // Empty; nothing to do.
+    } else if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) {
+      // Memcpy-able and do not need allocation.
       storage_.MemcpyFrom(other.storage_);
     } else {
-      storage_.Initialize(IteratorValueAdapter<const_pointer>(other.data()),
-                          other.size());
+      storage_.InitFrom(other.storage_);
     }
   }
 
diff --git a/grpc/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc b/grpc/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
index b8dafe9..e256fad 100644
--- a/grpc/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
@@ -534,6 +534,28 @@
 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType);
 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType);
 
+// Measure cost of copy-constructor+destructor.
+void BM_CopyTrivial(benchmark::State& state) {
+  const int n = state.range(0);
+  InlVec<int64_t> src(n);
+  for (auto s : state) {
+    InlVec<int64_t> copy(src);
+    benchmark::DoNotOptimize(copy);
+  }
+}
+BENCHMARK(BM_CopyTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize);
+
+// Measure cost of copy-constructor+destructor.
+void BM_CopyNonTrivial(benchmark::State& state) {
+  const int n = state.range(0);
+  InlVec<InlVec<int64_t>> src(n);
+  for (auto s : state) {
+    InlVec<InlVec<int64_t>> copy(src);
+    benchmark::DoNotOptimize(copy);
+  }
+}
+BENCHMARK(BM_CopyNonTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize);
+
 template <typename T, size_t FromSize, size_t ToSize>
 void BM_AssignSizeRef(benchmark::State& state) {
   auto size = ToSize;
diff --git a/grpc/third_party/abseil-cpp/absl/container/inlined_vector_test.cc b/grpc/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
index 415c60d..98aff33 100644
--- a/grpc/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/inlined_vector_test.cc
@@ -736,22 +736,26 @@
   // In particular, ensure that std::allocator doesn't cost anything to store.
   // The union should be absorbing some of the allocation bookkeeping overhead
   // in the larger vectors, leaving only the size_ field as overhead.
-  EXPECT_EQ(2 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 1>) - 1 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 2>) - 2 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 3>) - 3 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 4>) - 4 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 5>) - 5 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 6>) - 6 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 7>) - 7 * sizeof(int*));
-  EXPECT_EQ(1 * sizeof(int*),
-            sizeof(absl::InlinedVector<int*, 8>) - 8 * sizeof(int*));
+
+  struct T { void* val; };
+  size_t expected_overhead = sizeof(T);
+
+  EXPECT_EQ((2 * expected_overhead),
+            sizeof(absl::InlinedVector<T, 1>) - sizeof(T[1]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 2>) - sizeof(T[2]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 3>) - sizeof(T[3]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 4>) - sizeof(T[4]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 5>) - sizeof(T[5]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 6>) - sizeof(T[6]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 7>) - sizeof(T[7]));
+  EXPECT_EQ(expected_overhead,
+            sizeof(absl::InlinedVector<T, 8>) - sizeof(T[8]));
 }
 
 TEST(IntVec, Clear) {
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/btree.h b/grpc/third_party/abseil-cpp/absl/container/internal/btree.h
index 002ccc1..0bb3836 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/btree.h
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/btree.h
@@ -182,15 +182,44 @@
   using type = StringBtreeDefaultGreater;
 };
 
+// Detects an 'absl_btree_prefer_linear_node_search' member. This is
+// a protocol used as an opt-in or opt-out of linear search.
+//
+//  For example, this would be useful for key types that wrap an integer
+//  and define their own cheap operator<(). For example:
+//
+//   class K {
+//    public:
+//     using absl_btree_prefer_linear_node_search = std::true_type;
+//     ...
+//    private:
+//     friend bool operator<(K a, K b) { return a.k_ < b.k_; }
+//     int k_;
+//   };
+//
+//   btree_map<K, V> m;  // Uses linear search
+//
+// If T has the preference tag, then it has a preference.
+// Btree will use the tag's truth value.
+template <typename T, typename = void>
+struct has_linear_node_search_preference : std::false_type {};
+template <typename T, typename = void>
+struct prefers_linear_node_search : std::false_type {};
+template <typename T>
+struct has_linear_node_search_preference<
+    T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+    : std::true_type {};
+template <typename T>
+struct prefers_linear_node_search<
+    T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+    : T::absl_btree_prefer_linear_node_search {};
+
 template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
           bool Multi, typename SlotPolicy>
 struct common_params {
   // If Compare is a common comparator for a string-like type, then we adapt it
   // to use heterogeneous lookup and to be a key-compare-to comparator.
   using key_compare = typename key_compare_to_adapter<Compare>::type;
-  // True when key_compare has been adapted to StringBtreeDefault{Less,Greater}.
-  using is_key_compare_adapted =
-      absl::negation<std::is_same<key_compare, Compare>>;
   // A type which indicates if we have a key-compare-to functor or a plain old
   // key-compare functor.
   using is_key_compare_to = btree_is_key_compare_to<key_compare, Key>;
@@ -200,9 +229,6 @@
   using size_type = std::make_signed<size_t>::type;
   using difference_type = ptrdiff_t;
 
-  // True if this is a multiset or multimap.
-  using is_multi_container = std::integral_constant<bool, Multi>;
-
   using slot_policy = SlotPolicy;
   using slot_type = typename slot_policy::slot_type;
   using value_type = typename slot_policy::value_type;
@@ -212,6 +238,23 @@
   using reference = value_type &;
   using const_reference = const value_type &;
 
+  // For the given lookup key type, returns whether we can have multiple
+  // equivalent keys in the btree. If this is a multi-container, then we can.
+  // Otherwise, we can have multiple equivalent keys only if all of the
+  // following conditions are met:
+  // - The comparator is transparent.
+  // - The lookup key type is not the same as key_type.
+  // - The comparator is not a StringBtreeDefault{Less,Greater} comparator
+  //   that we know has the same equivalence classes for all lookup types.
+  template <typename LookupKey>
+  constexpr static bool can_have_multiple_equivalent_keys() {
+    return Multi ||
+           (IsTransparent<key_compare>::value &&
+            !std::is_same<LookupKey, Key>::value &&
+            !std::is_same<key_compare, StringBtreeDefaultLess>::value &&
+            !std::is_same<key_compare, StringBtreeDefaultGreater>::value);
+  }
+
   enum {
     kTargetNodeSize = TargetNodeSize,
 
@@ -391,6 +434,10 @@
 // useful information.
 template <typename V>
 struct SearchResult<V, false> {
+  SearchResult() {}
+  explicit SearchResult(V value) : value(value) {}
+  SearchResult(V value, MatchKind /*match*/) : value(value) {}
+
   V value;
 
   static constexpr bool HasMatch() { return false; }
@@ -403,7 +450,6 @@
 template <typename Params>
 class btree_node {
   using is_key_compare_to = typename Params::is_key_compare_to;
-  using is_multi_container = typename Params::is_multi_container;
   using field_type = typename Params::node_count_type;
   using allocator_type = typename Params::allocator_type;
   using slot_type = typename Params::slot_type;
@@ -421,15 +467,22 @@
   using difference_type = typename Params::difference_type;
 
   // Btree decides whether to use linear node search as follows:
+  //   - If the comparator expresses a preference, use that.
+  //   - If the key expresses a preference, use that.
   //   - If the key is arithmetic and the comparator is std::less or
   //     std::greater, choose linear.
   //   - Otherwise, choose binary.
   // TODO(ezb): Might make sense to add condition(s) based on node-size.
   using use_linear_search = std::integral_constant<
       bool,
-                std::is_arithmetic<key_type>::value &&
-                    (std::is_same<std::less<key_type>, key_compare>::value ||
-                     std::is_same<std::greater<key_type>, key_compare>::value)>;
+      has_linear_node_search_preference<key_compare>::value
+          ? prefers_linear_node_search<key_compare>::value
+          : has_linear_node_search_preference<key_type>::value
+                ? prefers_linear_node_search<key_type>::value
+                : std::is_arithmetic<key_type>::value &&
+                      (std::is_same<std::less<key_type>, key_compare>::value ||
+                       std::is_same<std::greater<key_type>,
+                                    key_compare>::value)>;
 
   // This class is organized by gtl::Layout as if it had the following
   // structure:
@@ -446,23 +499,23 @@
   //   // is the same as the count of values.
   //   field_type finish;
   //   // The maximum number of values the node can hold. This is an integer in
-  //   // [1, kNodeValues] for root leaf nodes, kNodeValues for non-root leaf
+  //   // [1, kNodeSlots] for root leaf nodes, kNodeSlots for non-root leaf
   //   // nodes, and kInternalNodeMaxCount (as a sentinel value) for internal
-  //   // nodes (even though there are still kNodeValues values in the node).
+  //   // nodes (even though there are still kNodeSlots values in the node).
   //   // TODO(ezb): make max_count use only 4 bits and record log2(capacity)
   //   // to free extra bits for is_root, etc.
   //   field_type max_count;
   //
   //   // The array of values. The capacity is `max_count` for leaf nodes and
-  //   // kNodeValues for internal nodes. Only the values in
+  //   // kNodeSlots for internal nodes. Only the values in
   //   // [start, finish) have been initialized and are valid.
   //   slot_type values[max_count];
   //
   //   // The array of child pointers. The keys in children[i] are all less
   //   // than key(i). The keys in children[i + 1] are all greater than key(i).
-  //   // There are 0 children for leaf nodes and kNodeValues + 1 children for
+  //   // There are 0 children for leaf nodes and kNodeSlots + 1 children for
   //   // internal nodes.
-  //   btree_node *children[kNodeValues + 1];
+  //   btree_node *children[kNodeSlots + 1];
   //
   // This class is only constructed by EmptyNodeType. Normally, pointers to the
   // layout above are allocated, cast to btree_node*, and de-allocated within
@@ -484,57 +537,62 @@
  private:
   using layout_type = absl::container_internal::Layout<btree_node *, field_type,
                                                        slot_type, btree_node *>;
-  constexpr static size_type SizeWithNValues(size_type n) {
+  constexpr static size_type SizeWithNSlots(size_type n) {
     return layout_type(/*parent*/ 1,
                        /*position, start, finish, max_count*/ 4,
-                       /*values*/ n,
+                       /*slots*/ n,
                        /*children*/ 0)
         .AllocSize();
   }
   // A lower bound for the overhead of fields other than values in a leaf node.
   constexpr static size_type MinimumOverhead() {
-    return SizeWithNValues(1) - sizeof(value_type);
+    return SizeWithNSlots(1) - sizeof(value_type);
   }
 
   // Compute how many values we can fit onto a leaf node taking into account
   // padding.
-  constexpr static size_type NodeTargetValues(const int begin, const int end) {
+  constexpr static size_type NodeTargetSlots(const int begin, const int end) {
     return begin == end ? begin
-                        : SizeWithNValues((begin + end) / 2 + 1) >
+                        : SizeWithNSlots((begin + end) / 2 + 1) >
                                   params_type::kTargetNodeSize
-                              ? NodeTargetValues(begin, (begin + end) / 2)
-                              : NodeTargetValues((begin + end) / 2 + 1, end);
+                              ? NodeTargetSlots(begin, (begin + end) / 2)
+                              : NodeTargetSlots((begin + end) / 2 + 1, end);
   }
 
   enum {
     kTargetNodeSize = params_type::kTargetNodeSize,
-    kNodeTargetValues = NodeTargetValues(0, params_type::kTargetNodeSize),
+    kNodeTargetSlots = NodeTargetSlots(0, params_type::kTargetNodeSize),
 
-    // We need a minimum of 3 values per internal node in order to perform
+    // We need a minimum of 3 slots per internal node in order to perform
     // splitting (1 value for the two nodes involved in the split and 1 value
-    // propagated to the parent as the delimiter for the split).
-    kNodeValues = kNodeTargetValues >= 3 ? kNodeTargetValues : 3,
+    // propagated to the parent as the delimiter for the split). For performance
+    // reasons, we don't allow 3 slots-per-node due to bad worst case occupancy
+    // of 1/3 (for a node, not a b-tree).
+    kMinNodeSlots = 4,
+
+    kNodeSlots =
+        kNodeTargetSlots >= kMinNodeSlots ? kNodeTargetSlots : kMinNodeSlots,
 
     // The node is internal (i.e. is not a leaf node) if and only if `max_count`
     // has this value.
     kInternalNodeMaxCount = 0,
   };
 
-  // Leaves can have less than kNodeValues values.
-  constexpr static layout_type LeafLayout(const int max_values = kNodeValues) {
+  // Leaves can have less than kNodeSlots values.
+  constexpr static layout_type LeafLayout(const int slot_count = kNodeSlots) {
     return layout_type(/*parent*/ 1,
                        /*position, start, finish, max_count*/ 4,
-                       /*values*/ max_values,
+                       /*slots*/ slot_count,
                        /*children*/ 0);
   }
   constexpr static layout_type InternalLayout() {
     return layout_type(/*parent*/ 1,
                        /*position, start, finish, max_count*/ 4,
-                       /*values*/ kNodeValues,
-                       /*children*/ kNodeValues + 1);
+                       /*slots*/ kNodeSlots,
+                       /*children*/ kNodeSlots + 1);
   }
-  constexpr static size_type LeafSize(const int max_values = kNodeValues) {
-    return LeafLayout(max_values).AllocSize();
+  constexpr static size_type LeafSize(const int slot_count = kNodeSlots) {
+    return LeafLayout(slot_count).AllocSize();
   }
   constexpr static size_type InternalSize() {
     return InternalLayout().AllocSize();
@@ -591,10 +649,10 @@
   }
   field_type max_count() const {
     // Internal nodes have max_count==kInternalNodeMaxCount.
-    // Leaf nodes have max_count in [1, kNodeValues].
+    // Leaf nodes have max_count in [1, kNodeSlots].
     const field_type max_count = GetField<1>()[3];
     return max_count == field_type{kInternalNodeMaxCount}
-               ? field_type{kNodeValues}
+               ? field_type{kNodeSlots}
                : max_count;
   }
 
@@ -672,7 +730,7 @@
       }
       ++s;
     }
-    return {s};
+    return SearchResult<int, false>{s};
   }
 
   // Returns the position of the first value whose key is not less than k using
@@ -707,7 +765,7 @@
         e = mid;
       }
     }
-    return {s};
+    return SearchResult<int, false>{s};
   }
 
   // Returns the position of the first value whose key is not less than k using
@@ -716,7 +774,7 @@
   SearchResult<int, true> binary_search_impl(
       const K &k, int s, int e, const CompareTo &comp,
       std::true_type /* IsCompareTo */) const {
-    if (is_multi_container::value) {
+    if (params_type::template can_have_multiple_equivalent_keys<K>()) {
       MatchKind exact_match = MatchKind::kNe;
       while (s != e) {
         const int mid = (s + e) >> 1;
@@ -727,14 +785,14 @@
           e = mid;
           if (c == 0) {
             // Need to return the first value whose key is not less than k,
-            // which requires continuing the binary search if this is a
-            // multi-container.
+            // which requires continuing the binary search if there could be
+            // multiple equivalent keys.
             exact_match = MatchKind::kEq;
           }
         }
       }
       return {s, exact_match};
-    } else {  // Not a multi-container.
+    } else {  // Can't have multiple equivalent keys.
       while (s != e) {
         const int mid = (s + e) >> 1;
         const absl::weak_ordering c = comp(key(mid), k);
@@ -784,12 +842,12 @@
         start_slot(), max_count * sizeof(slot_type));
   }
   void init_internal(btree_node *parent) {
-    init_leaf(parent, kNodeValues);
+    init_leaf(parent, kNodeSlots);
     // Set `max_count` to a sentinel value to indicate that this node is
     // internal.
     set_max_count(kInternalNodeMaxCount);
     absl::container_internal::SanitizerPoisonMemoryRegion(
-        &mutable_child(start()), (kNodeValues + 1) * sizeof(btree_node *));
+        &mutable_child(start()), (kNodeSlots + 1) * sizeof(btree_node *));
   }
 
   static void deallocate(const size_type size, btree_node *node,
@@ -800,12 +858,6 @@
   // Deletes a node and all of its children.
   static void clear_and_delete(btree_node *node, allocator_type *alloc);
 
- public:
-  // Exposed only for tests.
-  static bool testonly_uses_linear_node_search() {
-    return use_linear_search::value;
-  }
-
  private:
   template <typename... Args>
   void value_init(const field_type i, allocator_type *alloc, Args &&... args) {
@@ -873,6 +925,7 @@
   using key_type = typename Node::key_type;
   using size_type = typename Node::size_type;
   using params_type = typename Node::params_type;
+  using is_map_container = typename params_type::is_map_container;
 
   using node_type = Node;
   using normal_node = typename std::remove_const<Node>::type;
@@ -884,7 +937,7 @@
   using slot_type = typename params_type::slot_type;
 
   using iterator =
-      btree_iterator<normal_node, normal_reference, normal_pointer>;
+     btree_iterator<normal_node, normal_reference, normal_pointer>;
   using const_iterator =
       btree_iterator<const_node, const_reference, const_pointer>;
 
@@ -901,20 +954,19 @@
   btree_iterator(Node *n, int p) : node(n), position(p) {}
 
   // NOTE: this SFINAE allows for implicit conversions from iterator to
-  // const_iterator, but it specifically avoids defining copy constructors so
-  // that btree_iterator can be trivially copyable. This is for performance and
-  // binary size reasons.
+  // const_iterator, but it specifically avoids hiding the copy constructor so
+  // that the trivial one will be used when possible.
   template <typename N, typename R, typename P,
             absl::enable_if_t<
                 std::is_same<btree_iterator<N, R, P>, iterator>::value &&
                     std::is_same<btree_iterator, const_iterator>::value,
                 int> = 0>
-  btree_iterator(const btree_iterator<N, R, P> &other)  // NOLINT
+  btree_iterator(const btree_iterator<N, R, P> other)  // NOLINT
       : node(other.node), position(other.position) {}
 
  private:
   // This SFINAE allows explicit conversions from const_iterator to
-  // iterator, but also avoids defining a copy constructor.
+  // iterator, but also avoids hiding the copy constructor.
   // NOTE: the const_cast is safe because this constructor is only called by
   // non-const methods and the container owns the nodes.
   template <typename N, typename R, typename P,
@@ -922,7 +974,7 @@
                 std::is_same<btree_iterator<N, R, P>, const_iterator>::value &&
                     std::is_same<btree_iterator, iterator>::value,
                 int> = 0>
-  explicit btree_iterator(const btree_iterator<N, R, P> &other)
+  explicit btree_iterator(const btree_iterator<N, R, P> other)
       : node(const_cast<node_type *>(other.node)), position(other.position) {}
 
   // Increment/decrement the iterator.
@@ -985,6 +1037,8 @@
   }
 
  private:
+  friend iterator;
+  friend const_iterator;
   template <typename Params>
   friend class btree;
   template <typename Tree>
@@ -995,8 +1049,6 @@
   friend class btree_map_container;
   template <typename Tree>
   friend class btree_multiset_container;
-  template <typename N, typename R, typename P>
-  friend struct btree_iterator;
   template <typename TreeType, typename CheckerType>
   friend class base_checker;
 
@@ -1017,8 +1069,6 @@
   using is_key_compare_to = typename Params::is_key_compare_to;
   using init_type = typename Params::init_type;
   using field_type = typename node_type::field_type;
-  using is_multi_container = typename Params::is_multi_container;
-  using is_key_compare_adapted = typename Params::is_key_compare_adapted;
 
   // We use a static empty node for the root/leftmost/rightmost of empty btrees
   // in order to avoid branching in begin()/end().
@@ -1054,8 +1104,8 @@
   }
 
   enum : uint32_t {
-    kNodeValues = node_type::kNodeValues,
-    kMinNodeValues = kNodeValues / 2,
+    kNodeSlots = node_type::kNodeSlots,
+    kMinNodeValues = kNodeSlots / 2,
   };
 
   struct node_stats {
@@ -1085,7 +1135,8 @@
   using const_reference = typename Params::const_reference;
   using pointer = typename Params::pointer;
   using const_pointer = typename Params::const_pointer;
-  using iterator = btree_iterator<node_type, reference, pointer>;
+  using iterator =
+      typename btree_iterator<node_type, reference, pointer>::iterator;
   using const_iterator = typename iterator::const_iterator;
   using reverse_iterator = std::reverse_iterator<iterator>;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
@@ -1098,28 +1149,46 @@
  private:
   // For use in copy_or_move_values_in_order.
   const value_type &maybe_move_from_iterator(const_iterator it) { return *it; }
-  value_type &&maybe_move_from_iterator(iterator it) { return std::move(*it); }
+  value_type &&maybe_move_from_iterator(iterator it) {
+    // This is a destructive operation on the other container so it's safe for
+    // us to const_cast and move from the keys here even if it's a set.
+    return std::move(const_cast<value_type &>(*it));
+  }
 
   // Copies or moves (depending on the template parameter) the values in
   // other into this btree in their order in other. This btree must be empty
   // before this method is called. This method is used in copy construction,
   // copy assignment, and move assignment.
   template <typename Btree>
-  void copy_or_move_values_in_order(Btree *other);
+  void copy_or_move_values_in_order(Btree &other);
 
   // Validates that various assumptions/requirements are true at compile time.
   constexpr static bool static_assert_validation();
 
  public:
-  btree(const key_compare &comp, const allocator_type &alloc);
+  btree(const key_compare &comp, const allocator_type &alloc)
+      : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
 
-  btree(const btree &other);
+  btree(const btree &other) : btree(other, other.allocator()) {}
+  btree(const btree &other, const allocator_type &alloc)
+      : btree(other.key_comp(), alloc) {
+    copy_or_move_values_in_order(other);
+  }
   btree(btree &&other) noexcept
       : root_(std::move(other.root_)),
         rightmost_(absl::exchange(other.rightmost_, EmptyNode())),
         size_(absl::exchange(other.size_, 0)) {
     other.mutable_root() = EmptyNode();
   }
+  btree(btree &&other, const allocator_type &alloc)
+      : btree(other.key_comp(), alloc) {
+    if (alloc == other.allocator()) {
+      swap(other);
+    } else {
+      // Move values from `other` one at a time when allocators are different.
+      copy_or_move_values_in_order(other);
+    }
+  }
 
   ~btree() {
     // Put static_asserts in destructor to avoid triggering them before the type
@@ -1147,17 +1216,22 @@
     return const_reverse_iterator(begin());
   }
 
-  // Finds the first element whose key is not less than key.
+  // Finds the first element whose key is not less than `key`.
   template <typename K>
   iterator lower_bound(const K &key) {
-    return internal_end(internal_lower_bound(key));
+    return internal_end(internal_lower_bound(key).value);
   }
   template <typename K>
   const_iterator lower_bound(const K &key) const {
-    return internal_end(internal_lower_bound(key));
+    return internal_end(internal_lower_bound(key).value);
   }
 
-  // Finds the first element whose key is greater than key.
+  // Finds the first element whose key is not less than `key` and also returns
+  // whether that element is equal to `key`.
+  template <typename K>
+  std::pair<iterator, bool> lower_bound_equal(const K &key) const;
+
+  // Finds the first element whose key is greater than `key`.
   template <typename K>
   iterator upper_bound(const K &key) {
     return internal_end(internal_upper_bound(key));
@@ -1239,18 +1313,8 @@
   // to the element after the last erased element.
   std::pair<size_type, iterator> erase_range(iterator begin, iterator end);
 
-  // Erases the specified key from the btree. Returns 1 if an element was
-  // erased and 0 otherwise.
-  template <typename K>
-  size_type erase_unique(const K &key);
-
-  // Erases all of the entries matching the specified key from the
-  // btree. Returns the number of elements erased.
-  template <typename K>
-  size_type erase_multi(const K &key);
-
-  // Finds the iterator corresponding to a key or returns end() if the key is
-  // not present.
+  // Finds an element with key equivalent to `key` or returns `end()` if `key`
+  // is not present.
   template <typename K>
   iterator find(const K &key) {
     return internal_end(internal_find(key));
@@ -1260,23 +1324,6 @@
     return internal_end(internal_find(key));
   }
 
-  // Returns a count of the number of times the key appears in the btree.
-  template <typename K>
-  size_type count_unique(const K &key) const {
-    const iterator begin = internal_find(key);
-    if (begin.node == nullptr) {
-      // The key doesn't exist in the tree.
-      return 0;
-    }
-    return 1;
-  }
-  // Returns a count of the number of times the key appears in the btree.
-  template <typename K>
-  size_type count_multi(const K &key) const {
-    const auto range = equal_range(key);
-    return std::distance(range.first, range.second);
-  }
-
   // Clear the btree, deleting all of the values it contains.
   void clear();
 
@@ -1339,12 +1386,14 @@
     }
   }
 
-  // The average number of bytes used per value stored in the btree.
+  // The average number of bytes used per value stored in the btree assuming
+  // random insertion order.
   static double average_bytes_per_value() {
-    // Returns the number of bytes per value on a leaf node that is 75%
-    // full. Experimentally, this matches up nicely with the computed number of
-    // bytes per value in trees that had their values inserted in random order.
-    return node_type::LeafSize() / (kNodeValues * 0.75);
+    // The expected number of values per node with random insertion order is the
+    // average of the maximum and minimum numbers of values per node.
+    const double expected_values_per_node =
+        (kNodeSlots + kMinNodeValues) / 2.0;
+    return node_type::LeafSize() / expected_values_per_node;
   }
 
   // The fullness of the btree. Computed as the number of elements in the btree
@@ -1354,7 +1403,7 @@
   // Returns 0 for empty trees.
   double fullness() const {
     if (empty()) return 0.0;
-    return static_cast<double>(size()) / (nodes() * kNodeValues);
+    return static_cast<double>(size()) / (nodes() * kNodeSlots);
   }
   // The overhead of the btree structure in bytes per node. Computed as the
   // total number of bytes used by the btree minus the number of bytes used for
@@ -1404,7 +1453,7 @@
   }
   node_type *new_leaf_node(node_type *parent) {
     node_type *n = allocate(node_type::LeafSize());
-    n->init_leaf(parent, kNodeValues);
+    n->init_leaf(parent, kNodeSlots);
     return n;
   }
   node_type *new_leaf_root_node(const int max_count) {
@@ -1453,28 +1502,19 @@
   static IterType internal_last(IterType iter);
 
   // Returns an iterator pointing to the leaf position at which key would
-  // reside in the tree. We provide 2 versions of internal_locate. The first
-  // version uses a less-than comparator and is incapable of distinguishing when
-  // there is an exact match. The second version is for the key-compare-to
-  // specialization and distinguishes exact matches. The key-compare-to
-  // specialization allows the caller to avoid a subsequent comparison to
-  // determine if an exact match was made, which is important for keys with
-  // expensive comparison, such as strings.
+  // reside in the tree, unless there is an exact match - in which case, the
+  // result may not be on a leaf. When there's a three-way comparator, we can
+  // return whether there was an exact match. This allows the caller to avoid a
+  // subsequent comparison to determine if an exact match was made, which is
+  // important for keys with expensive comparison, such as strings.
   template <typename K>
   SearchResult<iterator, is_key_compare_to::value> internal_locate(
       const K &key) const;
 
-  template <typename K>
-  SearchResult<iterator, false> internal_locate_impl(
-      const K &key, std::false_type /* IsCompareTo */) const;
-
-  template <typename K>
-  SearchResult<iterator, true> internal_locate_impl(
-      const K &key, std::true_type /* IsCompareTo */) const;
-
   // Internal routine which implements lower_bound().
   template <typename K>
-  iterator internal_lower_bound(const K &key) const;
+  SearchResult<iterator, is_key_compare_to::value> internal_lower_bound(
+      const K &key) const;
 
   // Internal routine which implements upper_bound().
   template <typename K>
@@ -1503,13 +1543,6 @@
     return res;
   }
 
- public:
-  // Exposed only for tests.
-  static bool testonly_uses_linear_node_search() {
-    return node_type::testonly_uses_linear_node_search();
-  }
-
- private:
   // We use compressed tuple in order to save space because key_compare and
   // allocator_type are usually empty.
   absl::container_internal::CompressedTuple<key_compare, allocator_type,
@@ -1665,7 +1698,7 @@
 void btree_node<P>::split(const int insert_position, btree_node *dest,
                           allocator_type *alloc) {
   assert(dest->count() == 0);
-  assert(max_count() == kNodeValues);
+  assert(max_count() == kNodeSlots);
 
   // We bias the split based on the position being inserted. If we're
   // inserting at the beginning of the left node then bias the split to put
@@ -1673,7 +1706,7 @@
   // right node then bias the split to put more values on the left node.
   if (insert_position == start()) {
     dest->set_finish(dest->start() + finish() - 1);
-  } else if (insert_position == kNodeValues) {
+  } else if (insert_position == kNodeSlots) {
     dest->set_finish(dest->start());
   } else {
     dest->set_finish(dest->start() + count() / 2);
@@ -1744,7 +1777,7 @@
 
   // Navigate to the leftmost leaf under node, and then delete upwards.
   while (!node->leaf()) node = node->start_child();
-  // Use `int` because `pos` needs to be able to hold `kNodeValues+1`, which
+  // Use `int` because `pos` needs to be able to hold `kNodeSlots+1`, which
   // isn't guaranteed to be a valid `field_type`.
   int pos = node->position();
   btree_node *parent = node->parent();
@@ -1832,7 +1865,7 @@
 // btree methods
 template <typename P>
 template <typename Btree>
-void btree<P>::copy_or_move_values_in_order(Btree *other) {
+void btree<P>::copy_or_move_values_in_order(Btree &other) {
   static_assert(std::is_same<btree, Btree>::value ||
                     std::is_same<const btree, Btree>::value,
                 "Btree type must be same or const.");
@@ -1840,11 +1873,11 @@
 
   // We can avoid key comparisons because we know the order of the
   // values is the same order we'll store them in.
-  auto iter = other->begin();
-  if (iter == other->end()) return;
+  auto iter = other.begin();
+  if (iter == other.end()) return;
   insert_multi(maybe_move_from_iterator(iter));
   ++iter;
-  for (; iter != other->end(); ++iter) {
+  for (; iter != other.end(); ++iter) {
     // If the btree is not empty, we can just insert the new value at the end
     // of the tree.
     internal_emplace(end(), maybe_move_from_iterator(iter));
@@ -1863,7 +1896,7 @@
   // Note: We assert that kTargetValues, which is computed from
   // Params::kTargetNodeSize, must fit the node_type::field_type.
   static_assert(
-      kNodeValues < (1 << (8 * sizeof(typename node_type::field_type))),
+      kNodeSlots < (1 << (8 * sizeof(typename node_type::field_type))),
       "target node size too large");
 
   // Verify that key_compare returns an absl::{weak,strong}_ordering or bool.
@@ -1883,31 +1916,29 @@
 }
 
 template <typename P>
-btree<P>::btree(const key_compare &comp, const allocator_type &alloc)
-    : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
-
-template <typename P>
-btree<P>::btree(const btree &other)
-    : btree(other.key_comp(), other.allocator()) {
-  copy_or_move_values_in_order(&other);
+template <typename K>
+auto btree<P>::lower_bound_equal(const K &key) const
+    -> std::pair<iterator, bool> {
+  const SearchResult<iterator, is_key_compare_to::value> res =
+      internal_lower_bound(key);
+  const iterator lower = iterator(internal_end(res.value));
+  const bool equal = res.HasMatch()
+                         ? res.IsEq()
+                         : lower != end() && !compare_keys(key, lower.key());
+  return {lower, equal};
 }
 
 template <typename P>
 template <typename K>
 auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> {
-  const iterator lower = lower_bound(key);
-  // TODO(ezb): we should be able to avoid this comparison when there's a
-  // three-way comparator.
-  if (lower == end() || compare_keys(key, lower.key())) return {lower, lower};
+  const std::pair<iterator, bool> lower_and_equal = lower_bound_equal(key);
+  const iterator lower = lower_and_equal.first;
+  if (!lower_and_equal.second) {
+    return {lower, lower};
+  }
 
   const iterator next = std::next(lower);
-  // When the comparator is heterogeneous, we can't assume that comparison with
-  // non-`key_type` will be equivalent to `key_type` comparisons so there
-  // could be multiple equivalent keys even in a unique-container. But for
-  // heterogeneous comparisons from the default string adapted comparators, we
-  // don't need to worry about this.
-  if (!is_multi_container::value &&
-      (std::is_same<K, key_type>::value || is_key_compare_adapted::value)) {
+  if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
     // The next iterator after lower must point to a key greater than `key`.
     // Note: if this assert fails, then it may indicate that the comparator does
     // not meet the equivalence requirements for Compare
@@ -1918,7 +1949,7 @@
   // Try once more to avoid the call to upper_bound() if there's only one
   // equivalent key. This should prevent all calls to upper_bound() in cases of
   // unique-containers with heterogeneous comparators in which all comparison
-  // operators are equivalent.
+  // operators have the same equivalence classes.
   if (next == end() || compare_keys(key, next.key())) return {lower, next};
 
   // In this case, we need to call upper_bound() to avoid worst case O(N)
@@ -1934,8 +1965,8 @@
     mutable_root() = rightmost_ = new_leaf_root_node(1);
   }
 
-  auto res = internal_locate(key);
-  iterator &iter = res.value;
+  SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
+  iterator iter = res.value;
 
   if (res.HasMatch()) {
     if (res.IsEq()) {
@@ -2049,7 +2080,7 @@
       *mutable_allocator() = other.allocator();
     }
 
-    copy_or_move_values_in_order(&other);
+    copy_or_move_values_in_order(other);
   }
   return *this;
 }
@@ -2079,7 +2110,7 @@
         // comparator while moving the values so we can't swap the key
         // comparators.
         *mutable_key_comp() = other.key_comp();
-        copy_or_move_values_in_order(&other);
+        copy_or_move_values_in_order(other);
       }
     }
   }
@@ -2203,31 +2234,6 @@
 }
 
 template <typename P>
-template <typename K>
-auto btree<P>::erase_unique(const K &key) -> size_type {
-  const iterator iter = internal_find(key);
-  if (iter.node == nullptr) {
-    // The key doesn't exist in the tree, return nothing done.
-    return 0;
-  }
-  erase(iter);
-  return 1;
-}
-
-template <typename P>
-template <typename K>
-auto btree<P>::erase_multi(const K &key) -> size_type {
-  const iterator begin = internal_lower_bound(key);
-  if (begin.node == nullptr) {
-    // The key doesn't exist in the tree, return nothing done.
-    return 0;
-  }
-  // Delete all of the keys between begin and upper_bound(key).
-  const iterator end = internal_end(internal_upper_bound(key));
-  return erase_range(begin, end).first;
-}
-
-template <typename P>
 void btree<P>::clear() {
   if (!empty()) {
     node_type::clear_and_delete(root(), mutable_allocator());
@@ -2271,7 +2277,7 @@
   node_type *&node = iter->node;
   int &insert_position = iter->position;
   assert(node->count() == node->max_count());
-  assert(kNodeValues == node->max_count());
+  assert(kNodeSlots == node->max_count());
 
   // First try to make room on the node by rebalancing.
   node_type *parent = node->parent();
@@ -2279,17 +2285,17 @@
     if (node->position() > parent->start()) {
       // Try rebalancing with our left sibling.
       node_type *left = parent->child(node->position() - 1);
-      assert(left->max_count() == kNodeValues);
-      if (left->count() < kNodeValues) {
+      assert(left->max_count() == kNodeSlots);
+      if (left->count() < kNodeSlots) {
         // We bias rebalancing based on the position being inserted. If we're
         // inserting at the end of the right node then we bias rebalancing to
         // fill up the left node.
-        int to_move = (kNodeValues - left->count()) /
-                      (1 + (insert_position < kNodeValues));
+        int to_move = (kNodeSlots - left->count()) /
+                      (1 + (insert_position < static_cast<int>(kNodeSlots)));
         to_move = (std::max)(1, to_move);
 
         if (insert_position - to_move >= node->start() ||
-            left->count() + to_move < kNodeValues) {
+            left->count() + to_move < static_cast<int>(kNodeSlots)) {
           left->rebalance_right_to_left(to_move, node, mutable_allocator());
 
           assert(node->max_count() - node->count() == to_move);
@@ -2308,17 +2314,17 @@
     if (node->position() < parent->finish()) {
       // Try rebalancing with our right sibling.
       node_type *right = parent->child(node->position() + 1);
-      assert(right->max_count() == kNodeValues);
-      if (right->count() < kNodeValues) {
+      assert(right->max_count() == kNodeSlots);
+      if (right->count() < kNodeSlots) {
         // We bias rebalancing based on the position being inserted. If we're
         // inserting at the beginning of the left node then we bias rebalancing
         // to fill up the right node.
-        int to_move = (kNodeValues - right->count()) /
+        int to_move = (static_cast<int>(kNodeSlots) - right->count()) /
                       (1 + (insert_position > node->start()));
         to_move = (std::max)(1, to_move);
 
         if (insert_position <= node->finish() - to_move ||
-            right->count() + to_move < kNodeValues) {
+            right->count() + to_move < static_cast<int>(kNodeSlots)) {
           node->rebalance_left_to_right(to_move, right, mutable_allocator());
 
           if (insert_position > node->finish()) {
@@ -2334,8 +2340,8 @@
 
     // Rebalancing failed, make sure there is room on the parent node for a new
     // value.
-    assert(parent->max_count() == kNodeValues);
-    if (parent->count() == kNodeValues) {
+    assert(parent->max_count() == kNodeSlots);
+    if (parent->count() == kNodeSlots) {
       iterator parent_iter(node->parent(), node->position());
       rebalance_or_split(&parent_iter);
     }
@@ -2380,8 +2386,8 @@
   if (iter->node->position() > parent->start()) {
     // Try merging with our left sibling.
     node_type *left = parent->child(iter->node->position() - 1);
-    assert(left->max_count() == kNodeValues);
-    if (1 + left->count() + iter->node->count() <= kNodeValues) {
+    assert(left->max_count() == kNodeSlots);
+    if (1U + left->count() + iter->node->count() <= kNodeSlots) {
       iter->position += 1 + left->count();
       merge_nodes(left, iter->node);
       iter->node = left;
@@ -2391,8 +2397,8 @@
   if (iter->node->position() < parent->finish()) {
     // Try merging with our right sibling.
     node_type *right = parent->child(iter->node->position() + 1);
-    assert(right->max_count() == kNodeValues);
-    if (1 + iter->node->count() + right->count() <= kNodeValues) {
+    assert(right->max_count() == kNodeSlots);
+    if (1U + iter->node->count() + right->count() <= kNodeSlots) {
       merge_nodes(iter->node, right);
       return true;
     }
@@ -2473,12 +2479,12 @@
   allocator_type *alloc = mutable_allocator();
   if (iter.node->count() == max_count) {
     // Make room in the leaf for the new item.
-    if (max_count < kNodeValues) {
+    if (max_count < kNodeSlots) {
       // Insertion into the root where the root is smaller than the full node
       // size. Simply grow the size of the root node.
       assert(iter.node == root());
       iter.node =
-          new_leaf_root_node((std::min<int>)(kNodeValues, 2 * max_count));
+          new_leaf_root_node((std::min<int>)(kNodeSlots, 2 * max_count));
       // Transfer the values from the old root to the new root.
       node_type *old_root = root();
       node_type *new_root = iter.node;
@@ -2501,61 +2507,51 @@
 template <typename K>
 inline auto btree<P>::internal_locate(const K &key) const
     -> SearchResult<iterator, is_key_compare_to::value> {
-  return internal_locate_impl(key, is_key_compare_to());
-}
-
-template <typename P>
-template <typename K>
-inline auto btree<P>::internal_locate_impl(
-    const K &key, std::false_type /* IsCompareTo */) const
-    -> SearchResult<iterator, false> {
   iterator iter(const_cast<node_type *>(root()));
   for (;;) {
-    iter.position = iter.node->lower_bound(key, key_comp()).value;
-    // NOTE: we don't need to walk all the way down the tree if the keys are
-    // equal, but determining equality would require doing an extra comparison
-    // on each node on the way down, and we will need to go all the way to the
-    // leaf node in the expected case.
-    if (iter.node->leaf()) {
-      break;
-    }
-    iter.node = iter.node->child(iter.position);
-  }
-  return {iter};
-}
-
-template <typename P>
-template <typename K>
-inline auto btree<P>::internal_locate_impl(
-    const K &key, std::true_type /* IsCompareTo */) const
-    -> SearchResult<iterator, true> {
-  iterator iter(const_cast<node_type *>(root()));
-  for (;;) {
-    SearchResult<int, true> res = iter.node->lower_bound(key, key_comp());
+    SearchResult<int, is_key_compare_to::value> res =
+        iter.node->lower_bound(key, key_comp());
     iter.position = res.value;
-    if (res.match == MatchKind::kEq) {
+    if (res.IsEq()) {
       return {iter, MatchKind::kEq};
     }
+    // Note: in the non-key-compare-to case, we don't need to walk all the way
+    // down the tree if the keys are equal, but determining equality would
+    // require doing an extra comparison on each node on the way down, and we
+    // will need to go all the way to the leaf node in the expected case.
     if (iter.node->leaf()) {
       break;
     }
     iter.node = iter.node->child(iter.position);
   }
+  // Note: in the non-key-compare-to case, the key may actually be equivalent
+  // here (and the MatchKind::kNe is ignored).
   return {iter, MatchKind::kNe};
 }
 
 template <typename P>
 template <typename K>
-auto btree<P>::internal_lower_bound(const K &key) const -> iterator {
+auto btree<P>::internal_lower_bound(const K &key) const
+    -> SearchResult<iterator, is_key_compare_to::value> {
+  if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
+    SearchResult<iterator, is_key_compare_to::value> ret = internal_locate(key);
+    ret.value = internal_last(ret.value);
+    return ret;
+  }
   iterator iter(const_cast<node_type *>(root()));
+  SearchResult<int, is_key_compare_to::value> res;
+  bool seen_eq = false;
   for (;;) {
-    iter.position = iter.node->lower_bound(key, key_comp()).value;
+    res = iter.node->lower_bound(key, key_comp());
+    iter.position = res.value;
     if (iter.node->leaf()) {
       break;
     }
+    seen_eq = seen_eq || res.IsEq();
     iter.node = iter.node->child(iter.position);
   }
-  return internal_last(iter);
+  if (res.IsEq()) return {iter, MatchKind::kEq};
+  return {internal_last(iter), seen_eq ? MatchKind::kEq : MatchKind::kNe};
 }
 
 template <typename P>
@@ -2575,7 +2571,7 @@
 template <typename P>
 template <typename K>
 auto btree<P>::internal_find(const K &key) const -> iterator {
-  auto res = internal_locate(key);
+  SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
   if (res.HasMatch()) {
     if (res.IsEq()) {
       return res.value;
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/btree_container.h b/grpc/third_party/abseil-cpp/absl/container/internal/btree_container.h
index 137614f..03be708 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/btree_container.h
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/btree_container.h
@@ -23,6 +23,7 @@
 #include "absl/base/internal/throw_delegate.h"
 #include "absl/container/internal/btree.h"  // IWYU pragma: export
 #include "absl/container/internal/common.h"
+#include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
 
 namespace absl {
@@ -68,8 +69,21 @@
   explicit btree_container(const key_compare &comp,
                            const allocator_type &alloc = allocator_type())
       : tree_(comp, alloc) {}
-  btree_container(const btree_container &other) = default;
-  btree_container(btree_container &&other) noexcept = default;
+  explicit btree_container(const allocator_type &alloc)
+      : tree_(key_compare(), alloc) {}
+
+  btree_container(const btree_container &other)
+      : btree_container(other, absl::allocator_traits<allocator_type>::
+                                   select_on_container_copy_construction(
+                                       other.get_allocator())) {}
+  btree_container(const btree_container &other, const allocator_type &alloc)
+      : tree_(other.tree_, alloc) {}
+
+  btree_container(btree_container &&other) noexcept(
+      std::is_nothrow_move_constructible<Tree>::value) = default;
+  btree_container(btree_container &&other, const allocator_type &alloc)
+      : tree_(std::move(other.tree_), alloc) {}
+
   btree_container &operator=(const btree_container &other) = default;
   btree_container &operator=(btree_container &&other) noexcept(
       std::is_nothrow_move_assignable<Tree>::value) = default;
@@ -90,6 +104,11 @@
 
   // Lookup routines.
   template <typename K = key_type>
+  size_type count(const key_arg<K> &key) const {
+    auto equal_range = this->equal_range(key);
+    return std::distance(equal_range.first, equal_range.second);
+  }
+  template <typename K = key_type>
   iterator find(const key_arg<K> &key) {
     return tree_.find(key);
   }
@@ -138,6 +157,11 @@
   iterator erase(const_iterator first, const_iterator last) {
     return tree_.erase_range(iterator(first), iterator(last)).second;
   }
+  template <typename K = key_type>
+  size_type erase(const key_arg<K> &key) {
+    auto equal_range = this->equal_range(key);
+    return tree_.erase_range(equal_range.first, equal_range.second).first;
+  }
 
   // Extract routines.
   node_type extract(iterator position) {
@@ -151,7 +175,6 @@
     return extract(iterator(position));
   }
 
- public:
   // Utility routines.
   void clear() { tree_.clear(); }
   void swap(btree_container &other) { tree_.swap(other.tree_); }
@@ -235,7 +258,7 @@
   using super_type::super_type;
   btree_set_container() {}
 
-  // Range constructor.
+  // Range constructors.
   template <class InputIterator>
   btree_set_container(InputIterator b, InputIterator e,
                       const key_compare &comp = key_compare(),
@@ -243,18 +266,19 @@
       : super_type(comp, alloc) {
     insert(b, e);
   }
+  template <class InputIterator>
+  btree_set_container(InputIterator b, InputIterator e,
+                      const allocator_type &alloc)
+      : btree_set_container(b, e, key_compare(), alloc) {}
 
-  // Initializer list constructor.
+  // Initializer list constructors.
   btree_set_container(std::initializer_list<init_type> init,
                       const key_compare &comp = key_compare(),
                       const allocator_type &alloc = allocator_type())
       : btree_set_container(init.begin(), init.end(), comp, alloc) {}
-
-  // Lookup routines.
-  template <typename K = key_type>
-  size_type count(const key_arg<K> &key) const {
-    return this->tree_.count_unique(key);
-  }
+  btree_set_container(std::initializer_list<init_type> init,
+                      const allocator_type &alloc)
+      : btree_set_container(init.begin(), init.end(), alloc) {}
 
   // Insertion routines.
   std::pair<iterator, bool> insert(const value_type &v) {
@@ -313,20 +337,13 @@
     return res.first;
   }
 
-  // Deletion routines.
-  // TODO(ezb): we should support heterogeneous comparators that have different
-  // behavior for K!=key_type.
-  template <typename K = key_type>
-  size_type erase(const key_arg<K> &key) {
-    return this->tree_.erase_unique(key);
-  }
-  using super_type::erase;
-
   // Node extraction routines.
   template <typename K = key_type>
   node_type extract(const key_arg<K> &key) {
-    auto it = this->find(key);
-    return it == this->end() ? node_type() : extract(it);
+    const std::pair<iterator, bool> lower_and_equal =
+        this->tree_.lower_bound_equal(key);
+    return lower_and_equal.second ? extract(lower_and_equal.first)
+                                  : node_type();
   }
   using super_type::extract;
 
@@ -344,7 +361,7 @@
           int> = 0>
   void merge(btree_container<T> &src) {  // NOLINT
     for (auto src_it = src.begin(); src_it != src.end();) {
-      if (insert(std::move(*src_it)).second) {
+      if (insert(std::move(params_type::element(src_it.slot()))).second) {
         src_it = src.erase(src_it);
       } else {
         ++src_it;
@@ -371,6 +388,7 @@
 class btree_map_container : public btree_set_container<Tree> {
   using super_type = btree_set_container<Tree>;
   using params_type = typename Tree::params_type;
+  friend class BtreeNodePeer;
 
  private:
   template <class K>
@@ -535,7 +553,7 @@
   using super_type::super_type;
   btree_multiset_container() {}
 
-  // Range constructor.
+  // Range constructors.
   template <class InputIterator>
   btree_multiset_container(InputIterator b, InputIterator e,
                            const key_compare &comp = key_compare(),
@@ -543,18 +561,19 @@
       : super_type(comp, alloc) {
     insert(b, e);
   }
+  template <class InputIterator>
+  btree_multiset_container(InputIterator b, InputIterator e,
+                           const allocator_type &alloc)
+      : btree_multiset_container(b, e, key_compare(), alloc) {}
 
-  // Initializer list constructor.
+  // Initializer list constructors.
   btree_multiset_container(std::initializer_list<init_type> init,
                            const key_compare &comp = key_compare(),
                            const allocator_type &alloc = allocator_type())
       : btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
-
-  // Lookup routines.
-  template <typename K = key_type>
-  size_type count(const key_arg<K> &key) const {
-    return this->tree_.count_multi(key);
-  }
+  btree_multiset_container(std::initializer_list<init_type> init,
+                           const allocator_type &alloc)
+      : btree_multiset_container(init.begin(), init.end(), alloc) {}
 
   // Insertion routines.
   iterator insert(const value_type &v) { return this->tree_.insert_multi(v); }
@@ -600,18 +619,13 @@
     return res;
   }
 
-  // Deletion routines.
-  template <typename K = key_type>
-  size_type erase(const key_arg<K> &key) {
-    return this->tree_.erase_multi(key);
-  }
-  using super_type::erase;
-
   // Node extraction routines.
   template <typename K = key_type>
   node_type extract(const key_arg<K> &key) {
-    auto it = this->find(key);
-    return it == this->end() ? node_type() : extract(it);
+    const std::pair<iterator, bool> lower_and_equal =
+        this->tree_.lower_bound_equal(key);
+    return lower_and_equal.second ? extract(lower_and_equal.first)
+                                  : node_type();
   }
   using super_type::extract;
 
@@ -627,8 +641,9 @@
                            typename T::params_type::is_map_container>>::value,
           int> = 0>
   void merge(btree_container<T> &src) {  // NOLINT
-    insert(std::make_move_iterator(src.begin()),
-           std::make_move_iterator(src.end()));
+    for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it) {
+      insert(std::move(params_type::element(src_it.slot())));
+    }
     src.clear();
   }
 
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h b/grpc/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h
index 02bfd03..5ebe164 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h
@@ -257,7 +257,7 @@
 
   template <int I>
   ElemT<I>& get() & {
-    return internal_compressed_tuple::Storage<ElemT<I>, I>::get();
+    return StorageT<I>::get();
   }
 
   template <int I>
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc b/grpc/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc
index 6a7fcd2..fb9c4dd 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc
@@ -166,7 +166,7 @@
 }
 
 TEST(DecomposeValue, Decomposable) {
-  auto f = [](const int& x, int&& y) {
+  auto f = [](const int& x, int&& y) {  // NOLINT
     EXPECT_EQ(&x, &y);
     EXPECT_EQ(42, x);
     return 'A';
@@ -200,7 +200,8 @@
 }
 
 TEST(DecomposePair, Decomposable) {
-  auto f = [](const int& x, std::piecewise_construct_t, std::tuple<int&&> k,
+  auto f = [](const int& x,  // NOLINT
+              std::piecewise_construct_t, std::tuple<int&&> k,
               std::tuple<double>&& v) {
     EXPECT_EQ(&x, &std::get<0>(k));
     EXPECT_EQ(42, x);
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc b/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc
index e4484fb..5a29bed 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc
@@ -72,6 +72,7 @@
   total_probe_length.store(0, std::memory_order_relaxed);
   hashes_bitwise_or.store(0, std::memory_order_relaxed);
   hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
+  hashes_bitwise_xor.store(0, std::memory_order_relaxed);
 
   create_time = absl::Now();
   // The inliner makes hardcoded skip_count difficult (especially when combined
@@ -180,7 +181,9 @@
   if (ABSL_PREDICT_TRUE(state == kDontForce)) return false;
 
   if (state == kUninitialized) {
-    state = AbslContainerInternalSampleEverything() ? kForce : kDontForce;
+    state = ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)()
+                ? kForce
+                : kDontForce;
     global_state.store(state, std::memory_order_relaxed);
   }
   return state == kForce;
@@ -235,6 +238,7 @@
 
   info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed);
   info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed);
+  info->hashes_bitwise_xor.fetch_xor(hash, std::memory_order_relaxed);
   info->max_probe_length.store(
       std::max(info->max_probe_length.load(std::memory_order_relaxed),
                probe_length),
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h b/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
index 394348d..85685f7 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h
@@ -78,6 +78,7 @@
   std::atomic<size_t> total_probe_length;
   std::atomic<size_t> hashes_bitwise_or;
   std::atomic<size_t> hashes_bitwise_and;
+  std::atomic<size_t> hashes_bitwise_xor;
 
   // `HashtablezSampler` maintains intrusive linked lists for all samples.  See
   // comments on `HashtablezSampler::all_` for details on these.  `init_mu`
@@ -312,7 +313,7 @@
 // initialization of static storage duration objects.
 // The definition of this constant is weak, which allows us to inject a
 // different value for it at link time.
-extern "C" bool AbslContainerInternalSampleEverything();
+extern "C" bool ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)();
 
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
index 78b9d36..ed35a7e 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
@@ -21,7 +21,8 @@
 namespace container_internal {
 
 // See hashtablez_sampler.h for details.
-extern "C" ABSL_ATTRIBUTE_WEAK bool AbslContainerInternalSampleEverything() {
+extern "C" ABSL_ATTRIBUTE_WEAK bool ABSL_INTERNAL_C_SYMBOL(
+    AbslContainerInternalSampleEverything)() {
   return false;
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc b/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc
index 8d10a1e..5f4c83b 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc
@@ -89,6 +89,7 @@
   EXPECT_EQ(info.total_probe_length.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
+  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
   EXPECT_GE(info.create_time, test_start);
 
   info.capacity.store(1, std::memory_order_relaxed);
@@ -98,6 +99,7 @@
   info.total_probe_length.store(1, std::memory_order_relaxed);
   info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
   info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
+  info.hashes_bitwise_xor.store(1, std::memory_order_relaxed);
   info.create_time = test_start - absl::Hours(20);
 
   info.PrepareForSampling();
@@ -109,6 +111,7 @@
   EXPECT_EQ(info.total_probe_length.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
+  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
   EXPECT_GE(info.create_time, test_start);
 }
 
@@ -133,14 +136,17 @@
   EXPECT_EQ(info.max_probe_length.load(), 6);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00);
+  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x0000FF00);
   RecordInsertSlow(&info, 0x000FF000, 4 * kProbeLength);
   EXPECT_EQ(info.max_probe_length.load(), 6);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00);
+  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x000F0F00);
   RecordInsertSlow(&info, 0x00FF0000, 12 * kProbeLength);
   EXPECT_EQ(info.max_probe_length.load(), 12);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00);
+  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x00F00F00);
 }
 
 TEST(HashtablezInfoTest, RecordErase) {
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/inlined_vector.h b/grpc/third_party/abseil-cpp/absl/container/internal/inlined_vector.h
index 4d80b72..b8aec45 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/inlined_vector.h
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/inlined_vector.h
@@ -33,6 +33,12 @@
 ABSL_NAMESPACE_BEGIN
 namespace inlined_vector_internal {
 
+// GCC does not deal very well with the below code
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
 template <typename Iterator>
 using IsAtLeastForwardIterator = std::is_convertible<
     typename std::iterator_traits<Iterator>::iterator_category,
@@ -75,6 +81,23 @@
   }
 }
 
+// If kUseMemcpy is true, memcpy(dst, src, n); else do nothing.
+// Useful to avoid compiler warnings when memcpy() is used for T values
+// that are not trivially copyable in non-reachable code.
+template <bool kUseMemcpy>
+inline void MemcpyIfAllowed(void* dst, const void* src, size_t n);
+
+// memcpy when allowed.
+template <>
+inline void MemcpyIfAllowed<true>(void* dst, const void* src, size_t n) {
+  memcpy(dst, src, n);
+}
+
+// Do nothing for types that are not memcpy-able. This function is only
+// called from non-reachable branches.
+template <>
+inline void MemcpyIfAllowed<false>(void*, const void*, size_t) {}
+
 template <typename AllocatorType, typename Pointer, typename ValueAdapter,
           typename SizeType>
 void ConstructElements(AllocatorType* alloc_ptr, Pointer construct_first,
@@ -298,14 +321,20 @@
   // Storage Constructors and Destructor
   // ---------------------------------------------------------------------------
 
-  Storage() : metadata_() {}
+  Storage() : metadata_(allocator_type(), /* size and is_allocated */ 0) {}
 
-  explicit Storage(const allocator_type& alloc) : metadata_(alloc, {}) {}
+  explicit Storage(const allocator_type& alloc)
+      : metadata_(alloc, /* size and is_allocated */ 0) {}
 
   ~Storage() {
-    pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
-    inlined_vector_internal::DestroyElements(GetAllocPtr(), data, GetSize());
-    DeallocateIfAllocated();
+    if (GetSizeAndIsAllocated() == 0) {
+      // Empty and not allocated; nothing to do.
+    } else if (IsMemcpyOk::value) {
+      // No destructors need to be run; just deallocate if necessary.
+      DeallocateIfAllocated();
+    } else {
+      DestroyContents();
+    }
   }
 
   // ---------------------------------------------------------------------------
@@ -363,6 +392,8 @@
   // Storage Member Mutators
   // ---------------------------------------------------------------------------
 
+  ABSL_ATTRIBUTE_NOINLINE void InitFrom(const Storage& other);
+
   template <typename ValueAdapter>
   void Initialize(ValueAdapter values, size_type new_size);
 
@@ -445,6 +476,8 @@
   }
 
  private:
+  ABSL_ATTRIBUTE_NOINLINE void DestroyContents();
+
   using Metadata =
       container_internal::CompressedTuple<allocator_type, size_type>;
 
@@ -462,11 +495,48 @@
     Inlined inlined;
   };
 
+  template <typename... Args>
+  ABSL_ATTRIBUTE_NOINLINE reference EmplaceBackSlow(Args&&... args);
+
   Metadata metadata_;
   Data data_;
 };
 
 template <typename T, size_t N, typename A>
+void Storage<T, N, A>::DestroyContents() {
+  pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), data, GetSize());
+  DeallocateIfAllocated();
+}
+
+template <typename T, size_t N, typename A>
+void Storage<T, N, A>::InitFrom(const Storage& other) {
+  const auto n = other.GetSize();
+  assert(n > 0);  // Empty sources handled handled in caller.
+  const_pointer src;
+  pointer dst;
+  if (!other.GetIsAllocated()) {
+    dst = GetInlinedData();
+    src = other.GetInlinedData();
+  } else {
+    // Because this is only called from the `InlinedVector` constructors, it's
+    // safe to take on the allocation with size `0`. If `ConstructElements(...)`
+    // throws, deallocation will be automatically handled by `~Storage()`.
+    size_type new_capacity = ComputeCapacity(GetInlinedCapacity(), n);
+    dst = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity);
+    SetAllocatedData(dst, new_capacity);
+    src = other.GetAllocatedData();
+  }
+  if (IsMemcpyOk::value) {
+    MemcpyIfAllowed<IsMemcpyOk::value>(dst, src, sizeof(dst[0]) * n);
+  } else {
+    auto values = IteratorValueAdapter<const_pointer>(src);
+    inlined_vector_internal::ConstructElements(GetAllocPtr(), dst, &values, n);
+  }
+  GetSizeAndIsAllocated() = other.GetSizeAndIsAllocated();
+}
+
+template <typename T, size_t N, typename A>
 template <typename ValueAdapter>
 auto Storage<T, N, A>::Initialize(ValueAdapter values, size_type new_size)
     -> void {
@@ -542,48 +612,42 @@
 template <typename ValueAdapter>
 auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void {
   StorageView storage_view = MakeStorageView();
-
-  IteratorValueAdapter<MoveIterator> move_values(
-      MoveIterator(storage_view.data));
-
-  AllocationTransaction allocation_tx(GetAllocPtr());
-  ConstructionTransaction construction_tx(GetAllocPtr());
-
-  absl::Span<value_type> construct_loop;
-  absl::Span<value_type> move_construct_loop;
-  absl::Span<value_type> destroy_loop;
-
-  if (new_size > storage_view.capacity) {
+  auto* const base = storage_view.data;
+  const size_type size = storage_view.size;
+  auto* alloc = GetAllocPtr();
+  if (new_size <= size) {
+    // Destroy extra old elements.
+    inlined_vector_internal::DestroyElements(alloc, base + new_size,
+                                             size - new_size);
+  } else if (new_size <= storage_view.capacity) {
+    // Construct new elements in place.
+    inlined_vector_internal::ConstructElements(alloc, base + size, &values,
+                                               new_size - size);
+  } else {
+    // Steps:
+    //  a. Allocate new backing store.
+    //  b. Construct new elements in new backing store.
+    //  c. Move existing elements from old backing store to now.
+    //  d. Destroy all elements in old backing store.
+    // Use transactional wrappers for the first two steps so we can roll
+    // back if necessary due to exceptions.
+    AllocationTransaction allocation_tx(alloc);
     size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
     pointer new_data = allocation_tx.Allocate(new_capacity);
-    construct_loop = {new_data + storage_view.size,
-                      new_size - storage_view.size};
-    move_construct_loop = {new_data, storage_view.size};
-    destroy_loop = {storage_view.data, storage_view.size};
-  } else if (new_size > storage_view.size) {
-    construct_loop = {storage_view.data + storage_view.size,
-                      new_size - storage_view.size};
-  } else {
-    destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
-  }
 
-  construction_tx.Construct(construct_loop.data(), &values,
-                            construct_loop.size());
+    ConstructionTransaction construction_tx(alloc);
+    construction_tx.Construct(new_data + size, &values, new_size - size);
 
-  inlined_vector_internal::ConstructElements(
-      GetAllocPtr(), move_construct_loop.data(), &move_values,
-      move_construct_loop.size());
+    IteratorValueAdapter<MoveIterator> move_values((MoveIterator(base)));
+    inlined_vector_internal::ConstructElements(alloc, new_data, &move_values,
+                                               size);
 
-  inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
-                                           destroy_loop.size());
-
-  construction_tx.Commit();
-  if (allocation_tx.DidAllocate()) {
+    inlined_vector_internal::DestroyElements(alloc, base, size);
+    construction_tx.Commit();
     DeallocateIfAllocated();
     AcquireAllocatedData(&allocation_tx);
     SetIsAllocated();
   }
-
   SetSize(new_size);
 }
 
@@ -684,44 +748,50 @@
 template <typename... Args>
 auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> reference {
   StorageView storage_view = MakeStorageView();
+  const auto n = storage_view.size;
+  if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) {
+    // Fast path; new element fits.
+    pointer last_ptr = storage_view.data + n;
+    AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
+                               std::forward<Args>(args)...);
+    AddSize(1);
+    return *last_ptr;
+  }
+  // TODO(b/173712035): Annotate with musttail attribute to prevent regression.
+  return EmplaceBackSlow(std::forward<Args>(args)...);
+}
 
+template <typename T, size_t N, typename A>
+template <typename... Args>
+auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> reference {
+  StorageView storage_view = MakeStorageView();
   AllocationTransaction allocation_tx(GetAllocPtr());
-
   IteratorValueAdapter<MoveIterator> move_values(
       MoveIterator(storage_view.data));
-
-  pointer construct_data;
-  if (storage_view.size == storage_view.capacity) {
-    size_type new_capacity = NextCapacity(storage_view.capacity);
-    construct_data = allocation_tx.Allocate(new_capacity);
-  } else {
-    construct_data = storage_view.data;
-  }
-
+  size_type new_capacity = NextCapacity(storage_view.capacity);
+  pointer construct_data = allocation_tx.Allocate(new_capacity);
   pointer last_ptr = construct_data + storage_view.size;
 
+  // Construct new element.
   AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
                              std::forward<Args>(args)...);
-
-  if (allocation_tx.DidAllocate()) {
-    ABSL_INTERNAL_TRY {
-      inlined_vector_internal::ConstructElements(
-          GetAllocPtr(), allocation_tx.GetData(), &move_values,
-          storage_view.size);
-    }
-    ABSL_INTERNAL_CATCH_ANY {
-      AllocatorTraits::destroy(*GetAllocPtr(), last_ptr);
-      ABSL_INTERNAL_RETHROW;
-    }
-
-    inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
-                                             storage_view.size);
-
-    DeallocateIfAllocated();
-    AcquireAllocatedData(&allocation_tx);
-    SetIsAllocated();
+  // Move elements from old backing store to new backing store.
+  ABSL_INTERNAL_TRY {
+    inlined_vector_internal::ConstructElements(
+        GetAllocPtr(), allocation_tx.GetData(), &move_values,
+        storage_view.size);
   }
+  ABSL_INTERNAL_CATCH_ANY {
+    AllocatorTraits::destroy(*GetAllocPtr(), last_ptr);
+    ABSL_INTERNAL_RETHROW;
+  }
+  // Destroy elements in old backing store.
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+                                           storage_view.size);
 
+  DeallocateIfAllocated();
+  AcquireAllocatedData(&allocation_tx);
+  SetIsAllocated();
   AddSize(1);
   return *last_ptr;
 }
@@ -885,6 +955,11 @@
   swap(*GetAllocPtr(), *other_storage_ptr->GetAllocPtr());
 }
 
+// End ignore "maybe-uninitialized"
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
 }  // namespace inlined_vector_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/layout.h b/grpc/third_party/abseil-cpp/absl/container/internal/layout.h
index 2336783..a59a243 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/layout.h
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/layout.h
@@ -404,7 +404,7 @@
   constexpr size_t Offset() const {
     static_assert(N < NumOffsets, "Index out of bounds");
     return adl_barrier::Align(
-        Offset<N - 1>() + SizeOf<ElementType<N - 1>>() * size_[N - 1],
+        Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],
         ElementAlignment<N>::value);
   }
 
@@ -597,7 +597,7 @@
   constexpr size_t AllocSize() const {
     static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
     return Offset<NumTypes - 1>() +
-           SizeOf<ElementType<NumTypes - 1>>() * size_[NumTypes - 1];
+        SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];
   }
 
   // If built with --config=asan, poisons padding bytes (if any) in the
@@ -621,7 +621,7 @@
     // The `if` is an optimization. It doesn't affect the observable behaviour.
     if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
       size_t start =
-          Offset<N - 1>() + SizeOf<ElementType<N - 1>>() * size_[N - 1];
+          Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1];
       ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
     }
 #endif
@@ -645,7 +645,7 @@
   // produce "unsigned*" where another produces "unsigned int *".
   std::string DebugString() const {
     const auto offsets = Offsets();
-    const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>()...};
+    const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...};
     const std::string types[] = {
         adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
     std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/layout_benchmark.cc b/grpc/third_party/abseil-cpp/absl/container/internal/layout_benchmark.cc
new file mode 100644
index 0000000..d8636e8
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/layout_benchmark.cc
@@ -0,0 +1,122 @@
+// Copyright 2018 The Abseil 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
+//
+//      https://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.
+//
+// Every benchmark should have the same performance as the corresponding
+// headroom benchmark.
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/internal/layout.h"
+#include "benchmark/benchmark.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+using ::benchmark::DoNotOptimize;
+
+using Int128 = int64_t[2];
+
+// This benchmark provides the upper bound on performance for BM_OffsetConstant.
+template <size_t Offset, class... Ts>
+void BM_OffsetConstantHeadroom(benchmark::State& state) {
+  for (auto _ : state) {
+    DoNotOptimize(Offset);
+  }
+}
+
+template <size_t Offset, class... Ts>
+void BM_OffsetConstant(benchmark::State& state) {
+  using L = Layout<Ts...>;
+  ABSL_RAW_CHECK(L::Partial(3, 5, 7).template Offset<3>() == Offset,
+                 "Invalid offset");
+  for (auto _ : state) {
+    DoNotOptimize(L::Partial(3, 5, 7).template Offset<3>());
+  }
+}
+
+template <class... Ts>
+size_t VariableOffset(size_t n, size_t m, size_t k);
+
+template <>
+size_t VariableOffset<int8_t, int16_t, int32_t, Int128>(size_t n, size_t m,
+                                                        size_t k) {
+  auto Align = [](size_t n, size_t m) { return (n + m - 1) & ~(m - 1); };
+  return Align(Align(Align(n * 1, 2) + m * 2, 4) + k * 4, 8);
+}
+
+template <>
+size_t VariableOffset<Int128, int32_t, int16_t, int8_t>(size_t n, size_t m,
+                                                        size_t k) {
+  // No alignment is necessary.
+  return n * 16 + m * 4 + k * 2;
+}
+
+// This benchmark provides the upper bound on performance for BM_OffsetVariable.
+template <size_t Offset, class... Ts>
+void BM_OffsetVariableHeadroom(benchmark::State& state) {
+  size_t n = 3;
+  size_t m = 5;
+  size_t k = 7;
+  ABSL_RAW_CHECK(VariableOffset<Ts...>(n, m, k) == Offset, "Invalid offset");
+  for (auto _ : state) {
+    DoNotOptimize(n);
+    DoNotOptimize(m);
+    DoNotOptimize(k);
+    DoNotOptimize(VariableOffset<Ts...>(n, m, k));
+  }
+}
+
+template <size_t Offset, class... Ts>
+void BM_OffsetVariable(benchmark::State& state) {
+  using L = Layout<Ts...>;
+  size_t n = 3;
+  size_t m = 5;
+  size_t k = 7;
+  ABSL_RAW_CHECK(L::Partial(n, m, k).template Offset<3>() == Offset,
+                 "Inavlid offset");
+  for (auto _ : state) {
+    DoNotOptimize(n);
+    DoNotOptimize(m);
+    DoNotOptimize(k);
+    DoNotOptimize(L::Partial(n, m, k).template Offset<3>());
+  }
+}
+
+// Run all benchmarks in two modes:
+//
+//   Layout with padding: int8_t[3], int16_t[5], int32_t[7], Int128[?].
+//   Layout without padding: Int128[3], int32_t[5], int16_t[7], int8_t[?].
+
+#define OFFSET_BENCHMARK(NAME, OFFSET, T1, T2, T3, T4) \
+  auto& NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4 =  \
+      NAME<OFFSET, T1, T2, T3, T4>;                    \
+  BENCHMARK(NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4)
+
+OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 48, int8_t, int16_t, int32_t,
+                 Int128);
+OFFSET_BENCHMARK(BM_OffsetConstant, 48, int8_t, int16_t, int32_t, Int128);
+OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 82, Int128, int32_t, int16_t,
+                 int8_t);
+OFFSET_BENCHMARK(BM_OffsetConstant, 82, Int128, int32_t, int16_t, int8_t);
+OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 48, int8_t, int16_t, int32_t,
+                 Int128);
+OFFSET_BENCHMARK(BM_OffsetVariable, 48, int8_t, int16_t, int32_t, Int128);
+OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 82, Int128, int32_t, int16_t,
+                 int8_t);
+OFFSET_BENCHMARK(BM_OffsetVariable, 82, Int128, int32_t, int16_t, int8_t);
+}  // namespace
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/layout_test.cc b/grpc/third_party/abseil-cpp/absl/container/internal/layout_test.cc
index 757272f..1d7158f 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/layout_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/layout_test.cc
@@ -128,8 +128,10 @@
   {
     using L = Layout<int32_t, int32_t>;
     SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>();
-    SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial())::ElementTypes>();
-    SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial(0))::ElementTypes>();
+    SameType<std::tuple<int32_t, int32_t>,
+             decltype(L::Partial())::ElementTypes>();
+    SameType<std::tuple<int32_t, int32_t>,
+             decltype(L::Partial(0))::ElementTypes>();
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
@@ -368,18 +370,21 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p))));
   }
   {
     using L = Layout<int32_t, int32_t>;
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
-    EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
     EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
     EXPECT_EQ(12,
-              Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
+    EXPECT_EQ(
+        12, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p))));
     EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p))));
   }
@@ -387,39 +392,44 @@
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p))));
-    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p))));
-    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
+    EXPECT_EQ(
+        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
     EXPECT_EQ(8,
               Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
     EXPECT_EQ(
-        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
+        4,
+        Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(
         8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(
@@ -428,7 +438,8 @@
         24,
         Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(
-        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
+        8,
+        Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p))));
@@ -439,75 +450,78 @@
   alignas(max_align_t) const unsigned char p[100] = {};
   {
     using L = Layout<int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p))));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
-    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+        0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
+        0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
+                                 L::Partial(0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         0,
         Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
+                                 L::Partial(1, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         8,
         Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
+    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
+                                 L::Partial(5, 3).Pointer<int32_t>(p))));
     EXPECT_EQ(
         24,
         Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(0, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
+                                 L::Partial(0, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<const Int128*>(
                                  L::Partial(0, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        4,
-        Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(1, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
+                                 L::Partial(1, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(8, Distance(p, Type<const Int128*>(
                                  L::Partial(1, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(24, Distance(p, Type<const Int128*>(
                                   L::Partial(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        8,
-        Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
+                                 L::Partial(5, 3, 1).Pointer<int32_t>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
   }
 }
 
@@ -548,15 +562,18 @@
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p))));
@@ -568,48 +585,61 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p))));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(8,
               Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(
         24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
@@ -790,67 +820,72 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
   }
   {
     using L = Layout<int32_t, int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
     EXPECT_EQ(
         12,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
-    EXPECT_EQ(12,
-              Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        12, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+               p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
     EXPECT_EQ(
         0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        8,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+               p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+            p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
@@ -864,7 +899,8 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         4,
         Distance(
@@ -878,7 +914,8 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(
@@ -890,12 +927,14 @@
             p,
             Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
+        0,
+        Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
     EXPECT_EQ(
-        8, Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
+        8,
+        Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
   }
 }
 
@@ -906,98 +945,94 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
+        0,
+        Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
-            Type<Span<const int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(
-            p,
-            Type<Span<const int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        8,
-        Distance(
-            p,
-            Type<Span<const int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
+            Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
-            Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+            Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p))
+        Distance(p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p))
                         .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(0, 0).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p))
+                        .data()));
+    EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(1, 0).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p))
+                        .data()));
+    EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(5, 3).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(0, 0, 0).Slice<int8_t>(p))
+                                 .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(0, 0, 0).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>(
                                  L::Partial(0, 0, 0).Slice<Int128>(p))
                                  .data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p,
-            Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p))
-                        .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(1, 0, 0).Slice<int8_t>(p))
+                                 .data()));
+    EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(1, 0, 0).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>(
                                  L::Partial(1, 0, 0).Slice<Int128>(p))
                                  .data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p,
-            Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(5, 3, 1).Slice<int8_t>(p))
+                                 .data()));
     EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>(
                                   L::Partial(5, 3, 1).Slice<Int128>(p))
                                   .data()));
-    EXPECT_EQ(
-        8,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p))
-                        .data()));
+    EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(5, 3, 1).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
+        Distance(p,
+                 Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p,
                  Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        8, Distance(
-               p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
+        8,
+        Distance(
+            p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
   }
 }
 
@@ -1005,18 +1040,19 @@
   alignas(max_align_t) unsigned char p[100];
   {
     using L = Layout<int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data()));
   }
   {
     using L = Layout<int32_t, int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
     EXPECT_EQ(
         12,
         Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
@@ -1025,55 +1061,63 @@
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        4, Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        8, Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
+        Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
     EXPECT_EQ(
         0, Distance(
                p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        4,
-        Distance(p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
+        4, Distance(
+               p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
     EXPECT_EQ(
         8, Distance(
                p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24, Distance(
                 p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
     EXPECT_EQ(
-        8,
-        Distance(p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
+        8, Distance(
+               p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(24,
               Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
-    EXPECT_EQ(8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
+    EXPECT_EQ(8,
+              Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
   }
 }
 
@@ -1082,66 +1126,84 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4, Distance(
-               p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        8, Distance(
-               p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
+            p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(
+            p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(
+            p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
             Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         4,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         8,
         Distance(
             p,
             Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(
@@ -1150,14 +1212,16 @@
     EXPECT_EQ(
         8,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
+            p,
+            Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
+        8,
+        Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
   }
 }
 
@@ -1256,17 +1320,17 @@
   }
   {
     const auto x = L::Partial(1, 2, 3);
-    EXPECT_THAT(
-        (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
-        Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
-              IsSameSlice(x.Slice<2>(p))));
+    EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
+                    x.Slices(p))),
+                Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
+                      IsSameSlice(x.Slice<2>(p))));
   }
   {
     const L x(1, 2, 3);
-    EXPECT_THAT(
-        (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
-        Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
-              IsSameSlice(x.Slice<2>(p))));
+    EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
+                    x.Slices(p))),
+                Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
+                      IsSameSlice(x.Slice<2>(p))));
   }
 }
 
@@ -1398,7 +1462,8 @@
               x.DebugString());
   }
   {
-    constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
+    constexpr auto x =
+        Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
     EXPECT_EQ(
         "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
         "@16" +
@@ -1406,7 +1471,8 @@
         x.DebugString());
   }
   {
-    constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
+    constexpr auto x =
+        Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
     EXPECT_EQ(
         "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
         "@16" +
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc
index 919ac07..bfef071 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc
@@ -27,7 +27,7 @@
 
 // Returns "random" seed.
 inline size_t RandomSeed() {
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
   static thread_local size_t counter = 0;
   size_t value = ++counter;
 #else   // ABSL_HAVE_THREAD_LOCAL
@@ -43,6 +43,19 @@
   return (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6;
 }
 
+void ConvertDeletedToEmptyAndFullToDeleted(
+    ctrl_t* ctrl, size_t capacity) {
+  assert(ctrl[capacity] == kSentinel);
+  assert(IsValidCapacity(capacity));
+  for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) {
+    Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
+  }
+  // Copy the cloned ctrl bytes.
+  std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth);
+  ctrl[capacity] = kSentinel;
+}
+
+
 }  // namespace container_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
index ec13a2f..8615de8 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h
@@ -102,7 +102,6 @@
 #include <type_traits>
 #include <utility>
 
-#include "absl/base/internal/bits.h"
 #include "absl/base/internal/endian.h"
 #include "absl/base/optimization.h"
 #include "absl/base/port.h"
@@ -116,6 +115,7 @@
 #include "absl/container/internal/layout.h"
 #include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
 #include "absl/utility/utility.h"
 
 namespace absl {
@@ -189,18 +189,9 @@
 }
 
 template <typename T>
-int TrailingZeros(T x) {
-  return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64(
-                              static_cast<uint64_t>(x))
-                        : base_internal::CountTrailingZerosNonZero32(
-                              static_cast<uint32_t>(x));
-}
-
-template <typename T>
-int LeadingZeros(T x) {
-  return sizeof(T) == 8
-             ? base_internal::CountLeadingZeros64(static_cast<uint64_t>(x))
-             : base_internal::CountLeadingZeros32(static_cast<uint32_t>(x));
+uint32_t TrailingZeros(T x) {
+  ABSL_INTERNAL_ASSUME(x != 0);
+  return countr_zero(x);
 }
 
 // An abstraction over a bitmask. It provides an easy way to iterate through the
@@ -230,26 +221,24 @@
   }
   explicit operator bool() const { return mask_ != 0; }
   int operator*() const { return LowestBitSet(); }
-  int LowestBitSet() const {
+  uint32_t LowestBitSet() const {
     return container_internal::TrailingZeros(mask_) >> Shift;
   }
-  int HighestBitSet() const {
-    return (sizeof(T) * CHAR_BIT - container_internal::LeadingZeros(mask_) -
-            1) >>
-           Shift;
+  uint32_t HighestBitSet() const {
+    return static_cast<uint32_t>((bit_width(mask_) - 1) >> Shift);
   }
 
   BitMask begin() const { return *this; }
   BitMask end() const { return BitMask(0); }
 
-  int TrailingZeros() const {
+  uint32_t TrailingZeros() const {
     return container_internal::TrailingZeros(mask_) >> Shift;
   }
 
-  int LeadingZeros() const {
+  uint32_t LeadingZeros() const {
     constexpr int total_significant_bits = SignificantBits << Shift;
     constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits;
-    return container_internal::LeadingZeros(mask_ << extra_bits) >> Shift;
+    return countl_zero(mask_ << extra_bits) >> Shift;
   }
 
  private:
@@ -380,8 +369,8 @@
   // Returns the number of trailing empty or deleted elements in the group.
   uint32_t CountLeadingEmptyOrDeleted() const {
     auto special = _mm_set1_epi8(kSentinel);
-    return TrailingZeros(
-        _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1);
+    return TrailingZeros(static_cast<uint32_t>(
+        _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1));
   }
 
   void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
@@ -472,25 +461,23 @@
 //   DELETED -> EMPTY
 //   EMPTY -> EMPTY
 //   FULL -> DELETED
-inline void ConvertDeletedToEmptyAndFullToDeleted(
-    ctrl_t* ctrl, size_t capacity) {
-  assert(ctrl[capacity] == kSentinel);
-  assert(IsValidCapacity(capacity));
-  for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) {
-    Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
-  }
-  // Copy the cloned ctrl bytes.
-  std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth);
-  ctrl[capacity] = kSentinel;
-}
+void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity);
 
 // Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1.
 inline size_t NormalizeCapacity(size_t n) {
-  return n ? ~size_t{} >> LeadingZeros(n) : 1;
+  return n ? ~size_t{} >> countl_zero(n) : 1;
 }
 
-// We use 7/8th as maximum load factor.
-// For 16-wide groups, that gives an average of two empty slots per group.
+// General notes on capacity/growth methods below:
+// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
+//   average of two empty slots per group.
+// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity.
+// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we
+//   never need to probe (the whole table fits in one group) so we don't need a
+//   load factor less than 1.
+
+// Given `capacity` of the table, returns the size (i.e. number of full slots)
+// at which we should grow the capacity.
 inline size_t CapacityToGrowth(size_t capacity) {
   assert(IsValidCapacity(capacity));
   // `capacity*7/8`
@@ -501,7 +488,7 @@
   return capacity - capacity / 8;
 }
 // From desired "growth" to a lowerbound of the necessary capacity.
-// Might not be a valid one and required NormalizeCapacity().
+// Might not be a valid one and requires NormalizeCapacity().
 inline size_t GrowthToLowerboundCapacity(size_t growth) {
   // `growth*8/7`
   if (Group::kWidth == 8 && growth == 7) {
@@ -523,6 +510,64 @@
                         "been erased, or the table might have rehashed.");
 }
 
+struct FindInfo {
+  size_t offset;
+  size_t probe_length;
+};
+
+// The representation of the object has two modes:
+//  - small: For capacities < kWidth-1
+//  - large: For the rest.
+//
+// Differences:
+//  - In small mode we are able to use the whole capacity. The extra control
+//  bytes give us at least one "empty" control byte to stop the iteration.
+//  This is important to make 1 a valid capacity.
+//
+//  - In small mode only the first `capacity()` control bytes after the
+//  sentinel are valid. The rest contain dummy kEmpty values that do not
+//  represent a real slot. This is important to take into account on
+//  find_first_non_full(), where we never try ShouldInsertBackwards() for
+//  small tables.
+inline bool is_small(size_t capacity) { return capacity < Group::kWidth - 1; }
+
+inline probe_seq<Group::kWidth> probe(ctrl_t* ctrl, size_t hash,
+                                      size_t capacity) {
+  return probe_seq<Group::kWidth>(H1(hash, ctrl), capacity);
+}
+
+// Probes the raw_hash_set with the probe sequence for hash and returns the
+// pointer to the first empty or deleted slot.
+// NOTE: this function must work with tables having both kEmpty and kDelete
+// in one group. Such tables appears during drop_deletes_without_resize.
+//
+// This function is very useful when insertions happen and:
+// - the input is already a set
+// - there are enough slots
+// - the element with the hash is not in the table
+inline FindInfo find_first_non_full(ctrl_t* ctrl, size_t hash,
+                                    size_t capacity) {
+  auto seq = probe(ctrl, hash, capacity);
+  while (true) {
+    Group g{ctrl + seq.offset()};
+    auto mask = g.MatchEmptyOrDeleted();
+    if (mask) {
+#if !defined(NDEBUG)
+      // We want to add entropy even when ASLR is not enabled.
+      // In debug build we will randomly insert in either the front or back of
+      // the group.
+      // TODO(kfm,sbenza): revisit after we do unconditional mixing
+      if (!is_small(capacity) && ShouldInsertBackwards(hash, ctrl)) {
+        return {seq.offset(mask.HighestBitSet()), seq.index()};
+      }
+#endif
+      return {seq.offset(mask.LowestBitSet()), seq.index()};
+    }
+    seq.next();
+    assert(seq.index() < capacity && "full table!");
+  }
+}
+
 // Policy: a policy defines how to perform different operations on
 // the slots of the hashtable (see hash_policy_traits.h for the full interface
 // of policy).
@@ -747,10 +792,10 @@
   explicit raw_hash_set(size_t bucket_count, const hasher& hash = hasher(),
                         const key_equal& eq = key_equal(),
                         const allocator_type& alloc = allocator_type())
-      : ctrl_(EmptyGroup()), settings_(0, hash, eq, alloc) {
+      : ctrl_(EmptyGroup()),
+        settings_(0, HashtablezInfoHandle(), hash, eq, alloc) {
     if (bucket_count) {
       capacity_ = NormalizeCapacity(bucket_count);
-      reset_growth_left();
       initialize_slots();
     }
   }
@@ -856,10 +901,10 @@
     // than a full `insert`.
     for (const auto& v : that) {
       const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v);
-      auto target = find_first_non_full(hash);
+      auto target = find_first_non_full(ctrl_, hash, capacity_);
       set_ctrl(target.offset, H2(hash));
       emplace_at(target.offset, v);
-      infoz_.RecordInsert(hash, target.probe_length);
+      infoz().RecordInsert(hash, target.probe_length);
     }
     size_ = that.size();
     growth_left() -= that.size();
@@ -873,28 +918,27 @@
         slots_(absl::exchange(that.slots_, nullptr)),
         size_(absl::exchange(that.size_, 0)),
         capacity_(absl::exchange(that.capacity_, 0)),
-        infoz_(absl::exchange(that.infoz_, HashtablezInfoHandle())),
         // Hash, equality and allocator are copied instead of moved because
         // `that` must be left valid. If Hash is std::function<Key>, moving it
         // would create a nullptr functor that cannot be called.
-        settings_(that.settings_) {
-    // growth_left was copied above, reset the one from `that`.
-    that.growth_left() = 0;
-  }
+        settings_(absl::exchange(that.growth_left(), 0),
+                  absl::exchange(that.infoz(), HashtablezInfoHandle()),
+                  that.hash_ref(), that.eq_ref(), that.alloc_ref()) {}
 
   raw_hash_set(raw_hash_set&& that, const allocator_type& a)
       : ctrl_(EmptyGroup()),
         slots_(nullptr),
         size_(0),
         capacity_(0),
-        settings_(0, that.hash_ref(), that.eq_ref(), a) {
+        settings_(0, HashtablezInfoHandle(), that.hash_ref(), that.eq_ref(),
+                  a) {
     if (a == that.alloc_ref()) {
       std::swap(ctrl_, that.ctrl_);
       std::swap(slots_, that.slots_);
       std::swap(size_, that.size_);
       std::swap(capacity_, that.capacity_);
       std::swap(growth_left(), that.growth_left());
-      std::swap(infoz_, that.infoz_);
+      std::swap(infoz(), that.infoz());
     } else {
       reserve(that.size());
       // Note: this will copy elements of dense_set and unordered_set instead of
@@ -965,7 +1009,7 @@
       reset_growth_left();
     }
     assert(empty());
-    infoz_.RecordStorageChanged(0, capacity_);
+    infoz().RecordStorageChanged(0, capacity_);
   }
 
   // This overload kicks in when the argument is an rvalue of insertable and
@@ -1038,7 +1082,7 @@
 
   template <class InputIt>
   void insert(InputIt first, InputIt last) {
-    for (; first != last; ++first) insert(*first);
+    for (; first != last; ++first) emplace(*first);
   }
 
   template <class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
@@ -1065,7 +1109,9 @@
   }
 
   iterator insert(const_iterator, node_type&& node) {
-    return insert(std::move(node)).first;
+    auto res = insert(std::move(node));
+    node = std::move(res.node);
+    return res.position;
   }
 
   // This overload kicks in if we can deduce the key from args. This enables us
@@ -1255,7 +1301,7 @@
     swap(growth_left(), that.growth_left());
     swap(hash_ref(), that.hash_ref());
     swap(eq_ref(), that.eq_ref());
-    swap(infoz_, that.infoz_);
+    swap(infoz(), that.infoz());
     SwapAlloc(alloc_ref(), that.alloc_ref(),
               typename AllocTraits::propagate_on_container_swap{});
   }
@@ -1264,7 +1310,7 @@
     if (n == 0 && capacity_ == 0) return;
     if (n == 0 && size_ == 0) {
       destroy_slots();
-      infoz_.RecordStorageChanged(0, 0);
+      infoz().RecordStorageChanged(0, 0);
       return;
     }
     // bitor is a faster way of doing `max` here. We will round up to the next
@@ -1276,7 +1322,12 @@
     }
   }
 
-  void reserve(size_t n) { rehash(GrowthToLowerboundCapacity(n)); }
+  void reserve(size_t n) {
+    size_t m = GrowthToLowerboundCapacity(n);
+    if (m > capacity_) {
+      resize(NormalizeCapacity(m));
+    }
+  }
 
   // Extension API: support for heterogeneous keys.
   //
@@ -1301,7 +1352,7 @@
   void prefetch(const key_arg<K>& key) const {
     (void)key;
 #if defined(__GNUC__)
-    auto seq = probe(hash_ref()(key));
+    auto seq = probe(ctrl_, hash_ref()(key), capacity_);
     __builtin_prefetch(static_cast<const void*>(ctrl_ + seq.offset()));
     __builtin_prefetch(static_cast<const void*>(slots_ + seq.offset()));
 #endif  // __GNUC__
@@ -1316,7 +1367,7 @@
   // called heterogeneous key support.
   template <class K = key_type>
   iterator find(const key_arg<K>& key, size_t hash) {
-    auto seq = probe(hash);
+    auto seq = probe(ctrl_, hash, capacity_);
     while (true) {
       Group g{ctrl_ + seq.offset()};
       for (int i : g.Match(H2(hash))) {
@@ -1477,7 +1528,7 @@
 
     set_ctrl(index, was_never_full ? kEmpty : kDeleted);
     growth_left() += was_never_full;
-    infoz_.RecordErase();
+    infoz().RecordErase();
   }
 
   void initialize_slots() {
@@ -1494,7 +1545,7 @@
     // bound more carefully.
     if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value &&
         slots_ == nullptr) {
-      infoz_ = Sample();
+      infoz() = Sample();
     }
 
     auto layout = MakeLayout(capacity_);
@@ -1504,7 +1555,7 @@
     slots_ = layout.template Pointer<1>(mem);
     reset_ctrl();
     reset_growth_left();
-    infoz_.RecordStorageChanged(size_, capacity_);
+    infoz().RecordStorageChanged(size_, capacity_);
   }
 
   void destroy_slots() {
@@ -1538,7 +1589,7 @@
       if (IsFull(old_ctrl[i])) {
         size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
                                           PolicyTraits::element(old_slots + i));
-        auto target = find_first_non_full(hash);
+        auto target = find_first_non_full(ctrl_, hash, capacity_);
         size_t new_i = target.offset;
         total_probe_length += target.probe_length;
         set_ctrl(new_i, H2(hash));
@@ -1552,12 +1603,12 @@
       Deallocate<Layout::Alignment()>(&alloc_ref(), old_ctrl,
                                       layout.AllocSize());
     }
-    infoz_.RecordRehash(total_probe_length);
+    infoz().RecordRehash(total_probe_length);
   }
 
   void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE {
     assert(IsValidCapacity(capacity_));
-    assert(!is_small());
+    assert(!is_small(capacity_));
     // Algorithm:
     // - mark all DELETED slots as EMPTY
     // - mark all FULL slots as DELETED
@@ -1582,7 +1633,7 @@
       if (!IsDeleted(ctrl_[i])) continue;
       size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
                                         PolicyTraits::element(slots_ + i));
-      auto target = find_first_non_full(hash);
+      auto target = find_first_non_full(ctrl_, hash, capacity_);
       size_t new_i = target.offset;
       total_probe_length += target.probe_length;
 
@@ -1590,7 +1641,8 @@
       // If they do, we don't need to move the object as it falls already in the
       // best probe we can.
       const auto probe_index = [&](size_t pos) {
-        return ((pos - probe(hash).offset()) & capacity_) / Group::kWidth;
+        return ((pos - probe(ctrl_, hash, capacity_).offset()) & capacity_) /
+               Group::kWidth;
       };
 
       // Element doesn't move.
@@ -1617,7 +1669,7 @@
       }
     }
     reset_growth_left();
-    infoz_.RecordRehash(total_probe_length);
+    infoz().RecordRehash(total_probe_length);
   }
 
   void rehash_and_grow_if_necessary() {
@@ -1634,7 +1686,7 @@
 
   bool has_element(const value_type& elem) const {
     size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, elem);
-    auto seq = probe(hash);
+    auto seq = probe(ctrl_, hash, capacity_);
     while (true) {
       Group g{ctrl_ + seq.offset()};
       for (int i : g.Match(H2(hash))) {
@@ -1649,41 +1701,6 @@
     return false;
   }
 
-  // Probes the raw_hash_set with the probe sequence for hash and returns the
-  // pointer to the first empty or deleted slot.
-  // NOTE: this function must work with tables having both kEmpty and kDelete
-  // in one group. Such tables appears during drop_deletes_without_resize.
-  //
-  // This function is very useful when insertions happen and:
-  // - the input is already a set
-  // - there are enough slots
-  // - the element with the hash is not in the table
-  struct FindInfo {
-    size_t offset;
-    size_t probe_length;
-  };
-  FindInfo find_first_non_full(size_t hash) {
-    auto seq = probe(hash);
-    while (true) {
-      Group g{ctrl_ + seq.offset()};
-      auto mask = g.MatchEmptyOrDeleted();
-      if (mask) {
-#if !defined(NDEBUG)
-        // We want to add entropy even when ASLR is not enabled.
-        // In debug build we will randomly insert in either the front or back of
-        // the group.
-        // TODO(kfm,sbenza): revisit after we do unconditional mixing
-        if (!is_small() && ShouldInsertBackwards(hash, ctrl_)) {
-          return {seq.offset(mask.HighestBitSet()), seq.index()};
-        }
-#endif
-        return {seq.offset(mask.LowestBitSet()), seq.index()};
-      }
-      seq.next();
-      assert(seq.index() < capacity_ && "full table!");
-    }
-  }
-
   // TODO(alkis): Optimize this assuming *this and that don't overlap.
   raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) {
     raw_hash_set tmp(std::move(that));
@@ -1700,7 +1717,7 @@
   template <class K>
   std::pair<size_t, bool> find_or_prepare_insert(const K& key) {
     auto hash = hash_ref()(key);
-    auto seq = probe(hash);
+    auto seq = probe(ctrl_, hash, capacity_);
     while (true) {
       Group g{ctrl_ + seq.offset()};
       for (int i : g.Match(H2(hash))) {
@@ -1717,16 +1734,16 @@
   }
 
   size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE {
-    auto target = find_first_non_full(hash);
+    auto target = find_first_non_full(ctrl_, hash, capacity_);
     if (ABSL_PREDICT_FALSE(growth_left() == 0 &&
                            !IsDeleted(ctrl_[target.offset]))) {
       rehash_and_grow_if_necessary();
-      target = find_first_non_full(hash);
+      target = find_first_non_full(ctrl_, hash, capacity_);
     }
     ++size_;
     growth_left() -= IsEmpty(ctrl_[target.offset]);
     set_ctrl(target.offset, H2(hash));
-    infoz_.RecordInsert(hash, target.probe_length);
+    infoz().RecordInsert(hash, target.probe_length);
     return target.offset;
   }
 
@@ -1754,10 +1771,6 @@
  private:
   friend struct RawHashSetTestOnlyAccess;
 
-  probe_seq<Group::kWidth> probe(size_t hash) const {
-    return probe_seq<Group::kWidth>(H1(hash, ctrl_), capacity_);
-  }
-
   // Reset all ctrl bytes back to kEmpty, except the sentinel.
   void reset_ctrl() {
     std::memset(ctrl_, kEmpty, capacity_ + Group::kWidth);
@@ -1787,29 +1800,15 @@
 
   size_t& growth_left() { return settings_.template get<0>(); }
 
-  // The representation of the object has two modes:
-  //  - small: For capacities < kWidth-1
-  //  - large: For the rest.
-  //
-  // Differences:
-  //  - In small mode we are able to use the whole capacity. The extra control
-  //  bytes give us at least one "empty" control byte to stop the iteration.
-  //  This is important to make 1 a valid capacity.
-  //
-  //  - In small mode only the first `capacity()` control bytes after the
-  //  sentinel are valid. The rest contain dummy kEmpty values that do not
-  //  represent a real slot. This is important to take into account on
-  //  find_first_non_full(), where we never try ShouldInsertBackwards() for
-  //  small tables.
-  bool is_small() const { return capacity_ < Group::kWidth - 1; }
+  HashtablezInfoHandle& infoz() { return settings_.template get<1>(); }
 
-  hasher& hash_ref() { return settings_.template get<1>(); }
-  const hasher& hash_ref() const { return settings_.template get<1>(); }
-  key_equal& eq_ref() { return settings_.template get<2>(); }
-  const key_equal& eq_ref() const { return settings_.template get<2>(); }
-  allocator_type& alloc_ref() { return settings_.template get<3>(); }
+  hasher& hash_ref() { return settings_.template get<2>(); }
+  const hasher& hash_ref() const { return settings_.template get<2>(); }
+  key_equal& eq_ref() { return settings_.template get<3>(); }
+  const key_equal& eq_ref() const { return settings_.template get<3>(); }
+  allocator_type& alloc_ref() { return settings_.template get<4>(); }
   const allocator_type& alloc_ref() const {
-    return settings_.template get<3>();
+    return settings_.template get<4>();
   }
 
   // TODO(alkis): Investigate removing some of these fields:
@@ -1819,10 +1818,11 @@
   slot_type* slots_ = nullptr;     // [capacity * slot_type]
   size_t size_ = 0;                // number of full slots
   size_t capacity_ = 0;            // total number of slots
-  HashtablezInfoHandle infoz_;
-  absl::container_internal::CompressedTuple<size_t /* growth_left */, hasher,
+  absl::container_internal::CompressedTuple<size_t /* growth_left */,
+                                            HashtablezInfoHandle, hasher,
                                             key_equal, allocator_type>
-      settings_{0, hasher{}, key_equal{}, allocator_type{}};
+      settings_{0, HashtablezInfoHandle{}, hasher{}, key_equal{},
+                allocator_type{}};
 };
 
 // Erases all elements that satisfy the predicate `pred` from the container `c`.
@@ -1846,7 +1846,7 @@
                              const typename Set::key_type& key) {
     size_t num_probes = 0;
     size_t hash = set.hash_ref()(key);
-    auto seq = set.probe(hash);
+    auto seq = probe(set.ctrl_, hash, set.capacity_);
     while (true) {
       container_internal::Group g{set.ctrl_ + seq.offset()};
       for (int i : g.Match(container_internal::H2(hash))) {
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc
index 1a03608..e73f53f 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -466,6 +466,9 @@
   size_t id_ = std::numeric_limits<size_t>::max();
 };
 
+// This doesn't compile with GCC 5.4 and 5.5 due to a bug in noexcept handing.
+#if !defined(__GNUC__) || __GNUC__ != 5 || (__GNUC_MINOR__ != 4 && \
+    __GNUC_MINOR__ != 5)
 TEST(NoPropagateOn, Swap) {
   using PA = PAlloc<char>;
   using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
@@ -475,6 +478,7 @@
   EXPECT_EQ(t1.get_allocator(), PA(1));
   EXPECT_EQ(t2.get_allocator(), PA(2));
 }
+#endif
 
 TEST(NoPropagateOn, CopyConstruct) {
   using PA = PAlloc<char>;
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc
new file mode 100644
index 0000000..f9be2c5
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc
@@ -0,0 +1,396 @@
+// Copyright 2018 The Abseil 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
+//
+//      https://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 "absl/container/internal/raw_hash_set.h"
+
+#include <numeric>
+#include <random>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/internal/hash_function_defaults.h"
+#include "absl/strings/str_format.h"
+#include "benchmark/benchmark.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+struct RawHashSetTestOnlyAccess {
+  template <typename C>
+  static auto GetSlots(const C& c) -> decltype(c.slots_) {
+    return c.slots_;
+  }
+};
+
+namespace {
+
+struct IntPolicy {
+  using slot_type = int64_t;
+  using key_type = int64_t;
+  using init_type = int64_t;
+
+  static void construct(void*, int64_t* slot, int64_t v) { *slot = v; }
+  static void destroy(void*, int64_t*) {}
+  static void transfer(void*, int64_t* new_slot, int64_t* old_slot) {
+    *new_slot = *old_slot;
+  }
+
+  static int64_t& element(slot_type* slot) { return *slot; }
+
+  template <class F>
+  static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) {
+    return std::forward<F>(f)(x, x);
+  }
+};
+
+class StringPolicy {
+  template <class F, class K, class V,
+            class = typename std::enable_if<
+                std::is_convertible<const K&, absl::string_view>::value>::type>
+  decltype(std::declval<F>()(
+      std::declval<const absl::string_view&>(), std::piecewise_construct,
+      std::declval<std::tuple<K>>(),
+      std::declval<V>())) static apply_impl(F&& f,
+                                            std::pair<std::tuple<K>, V> p) {
+    const absl::string_view& key = std::get<0>(p.first);
+    return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
+                              std::move(p.second));
+  }
+
+ public:
+  struct slot_type {
+    struct ctor {};
+
+    template <class... Ts>
+    slot_type(ctor, Ts&&... ts) : pair(std::forward<Ts>(ts)...) {}
+
+    std::pair<std::string, std::string> pair;
+  };
+
+  using key_type = std::string;
+  using init_type = std::pair<std::string, std::string>;
+
+  template <class allocator_type, class... Args>
+  static void construct(allocator_type* alloc, slot_type* slot, Args... args) {
+    std::allocator_traits<allocator_type>::construct(
+        *alloc, slot, typename slot_type::ctor(), std::forward<Args>(args)...);
+  }
+
+  template <class allocator_type>
+  static void destroy(allocator_type* alloc, slot_type* slot) {
+    std::allocator_traits<allocator_type>::destroy(*alloc, slot);
+  }
+
+  template <class allocator_type>
+  static void transfer(allocator_type* alloc, slot_type* new_slot,
+                       slot_type* old_slot) {
+    construct(alloc, new_slot, std::move(old_slot->pair));
+    destroy(alloc, old_slot);
+  }
+
+  static std::pair<std::string, std::string>& element(slot_type* slot) {
+    return slot->pair;
+  }
+
+  template <class F, class... Args>
+  static auto apply(F&& f, Args&&... args)
+      -> decltype(apply_impl(std::forward<F>(f),
+                             PairArgs(std::forward<Args>(args)...))) {
+    return apply_impl(std::forward<F>(f),
+                      PairArgs(std::forward<Args>(args)...));
+  }
+};
+
+struct StringHash : container_internal::hash_default_hash<absl::string_view> {
+  using is_transparent = void;
+};
+struct StringEq : std::equal_to<absl::string_view> {
+  using is_transparent = void;
+};
+
+struct StringTable
+    : raw_hash_set<StringPolicy, StringHash, StringEq, std::allocator<int>> {
+  using Base = typename StringTable::raw_hash_set;
+  StringTable() {}
+  using Base::Base;
+};
+
+struct IntTable
+    : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
+                   std::equal_to<int64_t>, std::allocator<int64_t>> {
+  using Base = typename IntTable::raw_hash_set;
+  IntTable() {}
+  using Base::Base;
+};
+
+struct string_generator {
+  template <class RNG>
+  std::string operator()(RNG& rng) const {
+    std::string res;
+    res.resize(12);
+    std::uniform_int_distribution<uint32_t> printable_ascii(0x20, 0x7E);
+    std::generate(res.begin(), res.end(), [&] { return printable_ascii(rng); });
+    return res;
+  }
+
+  size_t size;
+};
+
+// Model a cache in steady state.
+//
+// On a table of size N, keep deleting the LRU entry and add a random one.
+void BM_CacheInSteadyState(benchmark::State& state) {
+  std::random_device rd;
+  std::mt19937 rng(rd());
+  string_generator gen{12};
+  StringTable t;
+  std::deque<std::string> keys;
+  while (t.size() < state.range(0)) {
+    auto x = t.emplace(gen(rng), gen(rng));
+    if (x.second) keys.push_back(x.first->first);
+  }
+  ABSL_RAW_CHECK(state.range(0) >= 10, "");
+  while (state.KeepRunning()) {
+    // Some cache hits.
+    std::deque<std::string>::const_iterator it;
+    for (int i = 0; i != 90; ++i) {
+      if (i % 10 == 0) it = keys.end();
+      ::benchmark::DoNotOptimize(t.find(*--it));
+    }
+    // Some cache misses.
+    for (int i = 0; i != 10; ++i) ::benchmark::DoNotOptimize(t.find(gen(rng)));
+    ABSL_RAW_CHECK(t.erase(keys.front()), keys.front().c_str());
+    keys.pop_front();
+    while (true) {
+      auto x = t.emplace(gen(rng), gen(rng));
+      if (x.second) {
+        keys.push_back(x.first->first);
+        break;
+      }
+    }
+  }
+  state.SetItemsProcessed(state.iterations());
+  state.SetLabel(absl::StrFormat("load_factor=%.2f", t.load_factor()));
+}
+
+template <typename Benchmark>
+void CacheInSteadyStateArgs(Benchmark* bm) {
+  // The default.
+  const float max_load_factor = 0.875;
+  // When the cache is at the steady state, the probe sequence will equal
+  // capacity if there is no reclamation of deleted slots. Pick a number large
+  // enough to make the benchmark slow for that case.
+  const size_t capacity = 1 << 10;
+
+  // Check N data points to cover load factors in [0.4, 0.8).
+  const size_t kNumPoints = 10;
+  for (size_t i = 0; i != kNumPoints; ++i)
+    bm->Arg(std::ceil(
+        capacity * (max_load_factor + i * max_load_factor / kNumPoints) / 2));
+}
+BENCHMARK(BM_CacheInSteadyState)->Apply(CacheInSteadyStateArgs);
+
+void BM_EndComparison(benchmark::State& state) {
+  std::random_device rd;
+  std::mt19937 rng(rd());
+  string_generator gen{12};
+  StringTable t;
+  while (t.size() < state.range(0)) {
+    t.emplace(gen(rng), gen(rng));
+  }
+
+  for (auto _ : state) {
+    for (auto it = t.begin(); it != t.end(); ++it) {
+      benchmark::DoNotOptimize(it);
+      benchmark::DoNotOptimize(t);
+      benchmark::DoNotOptimize(it != t.end());
+    }
+  }
+}
+BENCHMARK(BM_EndComparison)->Arg(400);
+
+void BM_CopyCtor(benchmark::State& state) {
+  std::random_device rd;
+  std::mt19937 rng(rd());
+  IntTable t;
+  std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
+
+  while (t.size() < state.range(0)) {
+    t.emplace(dist(rng));
+  }
+
+  for (auto _ : state) {
+    IntTable t2 = t;
+    benchmark::DoNotOptimize(t2);
+  }
+}
+BENCHMARK(BM_CopyCtor)->Range(128, 4096);
+
+void BM_CopyAssign(benchmark::State& state) {
+  std::random_device rd;
+  std::mt19937 rng(rd());
+  IntTable t;
+  std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
+  while (t.size() < state.range(0)) {
+    t.emplace(dist(rng));
+  }
+
+  IntTable t2;
+  for (auto _ : state) {
+    t2 = t;
+    benchmark::DoNotOptimize(t2);
+  }
+}
+BENCHMARK(BM_CopyAssign)->Range(128, 4096);
+
+void BM_NoOpReserveIntTable(benchmark::State& state) {
+  IntTable t;
+  t.reserve(100000);
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(t);
+    t.reserve(100000);
+  }
+}
+BENCHMARK(BM_NoOpReserveIntTable);
+
+void BM_NoOpReserveStringTable(benchmark::State& state) {
+  StringTable t;
+  t.reserve(100000);
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(t);
+    t.reserve(100000);
+  }
+}
+BENCHMARK(BM_NoOpReserveStringTable);
+
+void BM_ReserveIntTable(benchmark::State& state) {
+  int reserve_size = state.range(0);
+  for (auto _ : state) {
+    state.PauseTiming();
+    IntTable t;
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(t);
+    t.reserve(reserve_size);
+  }
+}
+BENCHMARK(BM_ReserveIntTable)->Range(128, 4096);
+
+void BM_ReserveStringTable(benchmark::State& state) {
+  int reserve_size = state.range(0);
+  for (auto _ : state) {
+    state.PauseTiming();
+    StringTable t;
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(t);
+    t.reserve(reserve_size);
+  }
+}
+BENCHMARK(BM_ReserveStringTable)->Range(128, 4096);
+
+void BM_Group_Match(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -4);
+  Group g{group.data()};
+  h2_t h = 1;
+  for (auto _ : state) {
+    ::benchmark::DoNotOptimize(h);
+    ::benchmark::DoNotOptimize(g.Match(h));
+  }
+}
+BENCHMARK(BM_Group_Match);
+
+void BM_Group_MatchEmpty(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -4);
+  Group g{group.data()};
+  for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmpty());
+}
+BENCHMARK(BM_Group_MatchEmpty);
+
+void BM_Group_MatchEmptyOrDeleted(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -4);
+  Group g{group.data()};
+  for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_MatchEmptyOrDeleted);
+
+void BM_Group_CountLeadingEmptyOrDeleted(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -2);
+  Group g{group.data()};
+  for (auto _ : state)
+    ::benchmark::DoNotOptimize(g.CountLeadingEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_CountLeadingEmptyOrDeleted);
+
+void BM_Group_MatchFirstEmptyOrDeleted(benchmark::State& state) {
+  std::array<ctrl_t, Group::kWidth> group;
+  std::iota(group.begin(), group.end(), -2);
+  Group g{group.data()};
+  for (auto _ : state) ::benchmark::DoNotOptimize(*g.MatchEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_MatchFirstEmptyOrDeleted);
+
+void BM_DropDeletes(benchmark::State& state) {
+  constexpr size_t capacity = (1 << 20) - 1;
+  std::vector<ctrl_t> ctrl(capacity + 1 + Group::kWidth);
+  ctrl[capacity] = kSentinel;
+  std::vector<ctrl_t> pattern = {kEmpty, 2, kDeleted, 2, kEmpty, 1, kDeleted};
+  for (size_t i = 0; i != capacity; ++i) {
+    ctrl[i] = pattern[i % pattern.size()];
+  }
+  while (state.KeepRunning()) {
+    state.PauseTiming();
+    std::vector<ctrl_t> ctrl_copy = ctrl;
+    state.ResumeTiming();
+    ConvertDeletedToEmptyAndFullToDeleted(ctrl_copy.data(), capacity);
+    ::benchmark::DoNotOptimize(ctrl_copy[capacity]);
+  }
+}
+BENCHMARK(BM_DropDeletes);
+
+}  // namespace
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// These methods are here to make it easy to examine the assembly for targeted
+// parts of the API.
+auto CodegenAbslRawHashSetInt64Find(absl::container_internal::IntTable* table,
+                                    int64_t key) -> decltype(table->find(key)) {
+  return table->find(key);
+}
+
+bool CodegenAbslRawHashSetInt64FindNeEnd(
+    absl::container_internal::IntTable* table, int64_t key) {
+  return table->find(key) != table->end();
+}
+
+bool CodegenAbslRawHashSetInt64Contains(
+    absl::container_internal::IntTable* table, int64_t key) {
+  return table->contains(key);
+}
+
+void CodegenAbslRawHashSetInt64Iterate(
+    absl::container_internal::IntTable* table) {
+  for (auto x : *table) benchmark::DoNotOptimize(x);
+}
+
+int odr =
+    (::benchmark::DoNotOptimize(std::make_tuple(
+         &CodegenAbslRawHashSetInt64Find, &CodegenAbslRawHashSetInt64FindNeEnd,
+         &CodegenAbslRawHashSetInt64Contains,
+         &CodegenAbslRawHashSetInt64Iterate)),
+     1);
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc
new file mode 100644
index 0000000..7169a2e
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc
@@ -0,0 +1,590 @@
+// Copyright 2018 The Abseil 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
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Generates probe length statistics for many combinations of key types and key
+// distributions, all using the default hash function for swisstable.
+
+#include <memory>
+#include <regex>  // NOLINT
+#include <vector>
+
+#include "absl/container/flat_hash_map.h"
+#include "absl/container/internal/hash_function_defaults.h"
+#include "absl/container/internal/hashtable_debug.h"
+#include "absl/container/internal/raw_hash_set.h"
+#include "absl/random/distributions.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+enum class OutputStyle { kRegular, kBenchmark };
+
+// The --benchmark command line flag.
+// This is populated from main().
+// When run in "benchmark" mode, we have different output. This allows
+// A/B comparisons with tools like `benchy`.
+absl::string_view benchmarks;
+
+OutputStyle output() {
+  return !benchmarks.empty() ? OutputStyle::kBenchmark : OutputStyle::kRegular;
+}
+
+template <class T>
+struct Policy {
+  using slot_type = T;
+  using key_type = T;
+  using init_type = T;
+
+  template <class allocator_type, class Arg>
+  static void construct(allocator_type* alloc, slot_type* slot,
+                        const Arg& arg) {
+    std::allocator_traits<allocator_type>::construct(*alloc, slot, arg);
+  }
+
+  template <class allocator_type>
+  static void destroy(allocator_type* alloc, slot_type* slot) {
+    std::allocator_traits<allocator_type>::destroy(*alloc, slot);
+  }
+
+  static slot_type& element(slot_type* slot) { return *slot; }
+
+  template <class F, class... Args>
+  static auto apply(F&& f, const slot_type& arg)
+      -> decltype(std::forward<F>(f)(arg, arg)) {
+    return std::forward<F>(f)(arg, arg);
+  }
+};
+
+absl::BitGen& GlobalBitGen() {
+  static auto* value = new absl::BitGen;
+  return *value;
+}
+
+// Keeps a pool of allocations and randomly gives one out.
+// This introduces more randomization to the addresses given to swisstable and
+// should help smooth out this factor from probe length calculation.
+template <class T>
+class RandomizedAllocator {
+ public:
+  using value_type = T;
+
+  RandomizedAllocator() = default;
+  template <typename U>
+  RandomizedAllocator(RandomizedAllocator<U>) {}  // NOLINT
+
+  static T* allocate(size_t n) {
+    auto& pointers = GetPointers(n);
+    // Fill the pool
+    while (pointers.size() < kRandomPool) {
+      pointers.push_back(std::allocator<T>{}.allocate(n));
+    }
+
+    // Choose a random one.
+    size_t i = absl::Uniform<size_t>(GlobalBitGen(), 0, pointers.size());
+    T* result = pointers[i];
+    pointers[i] = pointers.back();
+    pointers.pop_back();
+    return result;
+  }
+
+  static void deallocate(T* p, size_t n) {
+    // Just put it back on the pool. No need to release the memory.
+    GetPointers(n).push_back(p);
+  }
+
+ private:
+  // We keep at least kRandomPool allocations for each size.
+  static constexpr size_t kRandomPool = 20;
+
+  static std::vector<T*>& GetPointers(size_t n) {
+    static auto* m = new absl::flat_hash_map<size_t, std::vector<T*>>();
+    return (*m)[n];
+  }
+};
+
+template <class T>
+struct DefaultHash {
+  using type = absl::container_internal::hash_default_hash<T>;
+};
+
+template <class T>
+using DefaultHashT = typename DefaultHash<T>::type;
+
+template <class T>
+struct Table : absl::container_internal::raw_hash_set<
+                   Policy<T>, DefaultHashT<T>,
+                   absl::container_internal::hash_default_eq<T>,
+                   RandomizedAllocator<T>> {};
+
+struct LoadSizes {
+  size_t min_load;
+  size_t max_load;
+};
+
+LoadSizes GetMinMaxLoadSizes() {
+  static const auto sizes = [] {
+    Table<int> t;
+
+    // First, fill enough to have a good distribution.
+    constexpr size_t kMinSize = 10000;
+    while (t.size() < kMinSize) t.insert(t.size());
+
+    const auto reach_min_load_factor = [&] {
+      const double lf = t.load_factor();
+      while (lf <= t.load_factor()) t.insert(t.size());
+    };
+
+    // Then, insert until we reach min load factor.
+    reach_min_load_factor();
+    const size_t min_load_size = t.size();
+
+    // Keep going until we hit min load factor again, then go back one.
+    t.insert(t.size());
+    reach_min_load_factor();
+
+    return LoadSizes{min_load_size, t.size() - 1};
+  }();
+  return sizes;
+}
+
+struct Ratios {
+  double min_load;
+  double avg_load;
+  double max_load;
+};
+
+// See absl/container/internal/hashtable_debug.h for details on
+// probe length calculation.
+template <class ElemFn>
+Ratios CollectMeanProbeLengths() {
+  const auto min_max_sizes = GetMinMaxLoadSizes();
+
+  ElemFn elem;
+  using Key = decltype(elem());
+  Table<Key> t;
+
+  Ratios result;
+  while (t.size() < min_max_sizes.min_load) t.insert(elem());
+  result.min_load =
+      absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+  while (t.size() < (min_max_sizes.min_load + min_max_sizes.max_load) / 2)
+    t.insert(elem());
+  result.avg_load =
+      absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+  while (t.size() < min_max_sizes.max_load) t.insert(elem());
+  result.max_load =
+      absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+  return result;
+}
+
+template <int Align>
+uintptr_t PointerForAlignment() {
+  alignas(Align) static constexpr uintptr_t kInitPointer = 0;
+  return reinterpret_cast<uintptr_t>(&kInitPointer);
+}
+
+// This incomplete type is used for testing hash of pointers of different
+// alignments.
+// NOTE: We are generating invalid pointer values on the fly with
+// reinterpret_cast. There are not "safely derived" pointers so using them is
+// technically UB. It is unlikely to be a problem, though.
+template <int Align>
+struct Ptr;
+
+template <int Align>
+Ptr<Align>* MakePtr(uintptr_t v) {
+  if (sizeof(v) == 8) {
+    constexpr int kCopyBits = 16;
+    // Ensure high bits are all the same.
+    v = static_cast<uintptr_t>(static_cast<intptr_t>(v << kCopyBits) >>
+                               kCopyBits);
+  }
+  return reinterpret_cast<Ptr<Align>*>(v);
+}
+
+struct IntIdentity {
+  uint64_t i;
+  friend bool operator==(IntIdentity a, IntIdentity b) { return a.i == b.i; }
+  IntIdentity operator++(int) { return IntIdentity{i++}; }
+};
+
+template <int Align>
+struct PtrIdentity {
+  explicit PtrIdentity(uintptr_t val = PointerForAlignment<Align>()) : i(val) {}
+  uintptr_t i;
+  friend bool operator==(PtrIdentity a, PtrIdentity b) { return a.i == b.i; }
+  PtrIdentity operator++(int) {
+    PtrIdentity p(i);
+    i += Align;
+    return p;
+  }
+};
+
+constexpr char kStringFormat[] = "/path/to/file/name-%07d-of-9999999.txt";
+
+template <bool small>
+struct String {
+  std::string value;
+  static std::string Make(uint32_t v) {
+    return {small ? absl::StrCat(v) : absl::StrFormat(kStringFormat, v)};
+  }
+};
+
+template <>
+struct DefaultHash<IntIdentity> {
+  struct type {
+    size_t operator()(IntIdentity t) const { return t.i; }
+  };
+};
+
+template <int Align>
+struct DefaultHash<PtrIdentity<Align>> {
+  struct type {
+    size_t operator()(PtrIdentity<Align> t) const { return t.i; }
+  };
+};
+
+template <class T>
+struct Sequential {
+  T operator()() const { return current++; }
+  mutable T current{};
+};
+
+template <int Align>
+struct Sequential<Ptr<Align>*> {
+  Ptr<Align>* operator()() const {
+    auto* result = MakePtr<Align>(current);
+    current += Align;
+    return result;
+  }
+  mutable uintptr_t current = PointerForAlignment<Align>();
+};
+
+
+template <bool small>
+struct Sequential<String<small>> {
+  std::string operator()() const { return String<small>::Make(current++); }
+  mutable uint32_t current = 0;
+};
+
+template <class T, class U>
+struct Sequential<std::pair<T, U>> {
+  mutable Sequential<T> tseq;
+  mutable Sequential<U> useq;
+
+  using RealT = decltype(tseq());
+  using RealU = decltype(useq());
+
+  mutable std::vector<RealT> ts;
+  mutable std::vector<RealU> us;
+  mutable size_t ti = 0, ui = 0;
+
+  std::pair<RealT, RealU> operator()() const {
+    std::pair<RealT, RealU> value{get_t(), get_u()};
+    if (ti == 0) {
+      ti = ui + 1;
+      ui = 0;
+    } else {
+      --ti;
+      ++ui;
+    }
+    return value;
+  }
+
+  RealT get_t() const {
+    while (ti >= ts.size()) ts.push_back(tseq());
+    return ts[ti];
+  }
+
+  RealU get_u() const {
+    while (ui >= us.size()) us.push_back(useq());
+    return us[ui];
+  }
+};
+
+template <class T, int percent_skip>
+struct AlmostSequential {
+  mutable Sequential<T> current;
+
+  auto operator()() const -> decltype(current()) {
+    while (absl::Uniform(GlobalBitGen(), 0.0, 1.0) <= percent_skip / 100.)
+      current();
+    return current();
+  }
+};
+
+struct Uniform {
+  template <typename T>
+  T operator()(T) const {
+    return absl::Uniform<T>(absl::IntervalClosed, GlobalBitGen(), T{0}, ~T{0});
+  }
+};
+
+struct Gaussian {
+  template <typename T>
+  T operator()(T) const {
+    double d;
+    do {
+      d = absl::Gaussian<double>(GlobalBitGen(), 1e6, 1e4);
+    } while (d <= 0 || d > std::numeric_limits<T>::max() / 2);
+    return static_cast<T>(d);
+  }
+};
+
+struct Zipf {
+  template <typename T>
+  T operator()(T) const {
+    return absl::Zipf<T>(GlobalBitGen(), std::numeric_limits<T>::max(), 1.6);
+  }
+};
+
+template <class T, class Dist>
+struct Random {
+  T operator()() const { return Dist{}(T{}); }
+};
+
+template <class Dist, int Align>
+struct Random<Ptr<Align>*, Dist> {
+  Ptr<Align>* operator()() const {
+    return MakePtr<Align>(Random<uintptr_t, Dist>{}() * Align);
+  }
+};
+
+template <class Dist>
+struct Random<IntIdentity, Dist> {
+  IntIdentity operator()() const {
+    return IntIdentity{Random<uint64_t, Dist>{}()};
+  }
+};
+
+template <class Dist, int Align>
+struct Random<PtrIdentity<Align>, Dist> {
+  PtrIdentity<Align> operator()() const {
+    return PtrIdentity<Align>{Random<uintptr_t, Dist>{}() * Align};
+  }
+};
+
+template <class Dist, bool small>
+struct Random<String<small>, Dist> {
+  std::string operator()() const {
+    return String<small>::Make(Random<uint32_t, Dist>{}());
+  }
+};
+
+template <class T, class U, class Dist>
+struct Random<std::pair<T, U>, Dist> {
+  auto operator()() const
+      -> decltype(std::make_pair(Random<T, Dist>{}(), Random<U, Dist>{}())) {
+    return std::make_pair(Random<T, Dist>{}(), Random<U, Dist>{}());
+  }
+};
+
+template <typename>
+std::string Name();
+
+std::string Name(uint32_t*) { return "u32"; }
+std::string Name(uint64_t*) { return "u64"; }
+std::string Name(IntIdentity*) { return "IntIdentity"; }
+
+template <int Align>
+std::string Name(Ptr<Align>**) {
+  return absl::StrCat("Ptr", Align);
+}
+
+template <int Align>
+std::string Name(PtrIdentity<Align>*) {
+  return absl::StrCat("PtrIdentity", Align);
+}
+
+template <bool small>
+std::string Name(String<small>*) {
+  return small ? "StrS" : "StrL";
+}
+
+template <class T, class U>
+std::string Name(std::pair<T, U>*) {
+  if (output() == OutputStyle::kBenchmark)
+    return absl::StrCat("P_", Name<T>(), "_", Name<U>());
+  return absl::StrCat("P<", Name<T>(), ",", Name<U>(), ">");
+}
+
+template <class T>
+std::string Name(Sequential<T>*) {
+  return "Sequential";
+}
+
+template <class T, int P>
+std::string Name(AlmostSequential<T, P>*) {
+  return absl::StrCat("AlmostSeq_", P);
+}
+
+template <class T>
+std::string Name(Random<T, Uniform>*) {
+  return "UnifRand";
+}
+
+template <class T>
+std::string Name(Random<T, Gaussian>*) {
+  return "GausRand";
+}
+
+template <class T>
+std::string Name(Random<T, Zipf>*) {
+  return "ZipfRand";
+}
+
+template <typename T>
+std::string Name() {
+  return Name(static_cast<T*>(nullptr));
+}
+
+constexpr int kNameWidth = 15;
+constexpr int kDistWidth = 16;
+
+bool CanRunBenchmark(absl::string_view name) {
+  static std::regex* const filter = []() -> std::regex* {
+    return benchmarks.empty() || benchmarks == "all"
+               ? nullptr
+               : new std::regex(std::string(benchmarks));
+  }();
+  return filter == nullptr || std::regex_search(std::string(name), *filter);
+}
+
+struct Result {
+  std::string name;
+  std::string dist_name;
+  Ratios ratios;
+};
+
+template <typename T, typename Dist>
+void RunForTypeAndDistribution(std::vector<Result>& results) {
+  std::string name = absl::StrCat(Name<T>(), "/", Name<Dist>());
+  // We have to check against all three names (min/avg/max) before we run it.
+  // If any of them is enabled, we run it.
+  if (!CanRunBenchmark(absl::StrCat(name, "/min")) &&
+      !CanRunBenchmark(absl::StrCat(name, "/avg")) &&
+      !CanRunBenchmark(absl::StrCat(name, "/max"))) {
+    return;
+  }
+  results.push_back({Name<T>(), Name<Dist>(), CollectMeanProbeLengths<Dist>()});
+}
+
+template <class T>
+void RunForType(std::vector<Result>& results) {
+  RunForTypeAndDistribution<T, Sequential<T>>(results);
+  RunForTypeAndDistribution<T, AlmostSequential<T, 20>>(results);
+  RunForTypeAndDistribution<T, AlmostSequential<T, 50>>(results);
+  RunForTypeAndDistribution<T, Random<T, Uniform>>(results);
+#ifdef NDEBUG
+  // Disable these in non-opt mode because they take too long.
+  RunForTypeAndDistribution<T, Random<T, Gaussian>>(results);
+  RunForTypeAndDistribution<T, Random<T, Zipf>>(results);
+#endif  // NDEBUG
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  // Parse the benchmark flags. Ignore all of them except the regex pattern.
+  for (int i = 1; i < argc; ++i) {
+    absl::string_view arg = argv[i];
+    const auto next = [&] { return argv[std::min(i + 1, argc - 1)]; };
+
+    if (absl::ConsumePrefix(&arg, "--benchmark_filter")) {
+      if (arg == "") {
+        // --benchmark_filter X
+        benchmarks = next();
+      } else if (absl::ConsumePrefix(&arg, "=")) {
+        // --benchmark_filter=X
+        benchmarks = arg;
+      }
+    }
+
+    // Any --benchmark flag turns on the mode.
+    if (absl::ConsumePrefix(&arg, "--benchmark")) {
+      if (benchmarks.empty()) benchmarks="all";
+    }
+  }
+
+  std::vector<Result> results;
+  RunForType<uint64_t>(results);
+  RunForType<IntIdentity>(results);
+  RunForType<Ptr<8>*>(results);
+  RunForType<Ptr<16>*>(results);
+  RunForType<Ptr<32>*>(results);
+  RunForType<Ptr<64>*>(results);
+  RunForType<PtrIdentity<8>>(results);
+  RunForType<PtrIdentity<16>>(results);
+  RunForType<PtrIdentity<32>>(results);
+  RunForType<PtrIdentity<64>>(results);
+  RunForType<std::pair<uint32_t, uint32_t>>(results);
+  RunForType<String<true>>(results);
+  RunForType<String<false>>(results);
+  RunForType<std::pair<uint64_t, String<true>>>(results);
+  RunForType<std::pair<String<true>, uint64_t>>(results);
+  RunForType<std::pair<uint64_t, String<false>>>(results);
+  RunForType<std::pair<String<false>, uint64_t>>(results);
+
+  switch (output()) {
+    case OutputStyle::kRegular:
+      absl::PrintF("%-*s%-*s       Min       Avg       Max\n%s\n", kNameWidth,
+                   "Type", kDistWidth, "Distribution",
+                   std::string(kNameWidth + kDistWidth + 10 * 3, '-'));
+      for (const auto& result : results) {
+        absl::PrintF("%-*s%-*s  %8.4f  %8.4f  %8.4f\n", kNameWidth, result.name,
+                     kDistWidth, result.dist_name, result.ratios.min_load,
+                     result.ratios.avg_load, result.ratios.max_load);
+      }
+      break;
+    case OutputStyle::kBenchmark: {
+      absl::PrintF("{\n");
+      absl::PrintF("  \"benchmarks\": [\n");
+      absl::string_view comma;
+      for (const auto& result : results) {
+        auto print = [&](absl::string_view stat, double Ratios::*val) {
+          std::string name =
+              absl::StrCat(result.name, "/", result.dist_name, "/", stat);
+          // Check the regex again. We might had have enabled only one of the
+          // stats for the benchmark.
+          if (!CanRunBenchmark(name)) return;
+          absl::PrintF("    %s{\n", comma);
+          absl::PrintF("      \"cpu_time\": %f,\n", 1e9 * result.ratios.*val);
+          absl::PrintF("      \"real_time\": %f,\n", 1e9 * result.ratios.*val);
+          absl::PrintF("      \"iterations\": 1,\n");
+          absl::PrintF("      \"name\": \"%s\",\n", name);
+          absl::PrintF("      \"time_unit\": \"ns\"\n");
+          absl::PrintF("    }\n");
+          comma = ",";
+        };
+        print("min", &Ratios::min_load);
+        print("avg", &Ratios::avg_load);
+        print("max", &Ratios::max_load);
+      }
+      absl::PrintF("  ],\n");
+      absl::PrintF("  \"context\": {\n");
+      absl::PrintF("  }\n");
+      absl::PrintF("}\n");
+      break;
+    }
+  }
+
+  return 0;
+}
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
index f5ae83c..7dac65a 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
@@ -14,6 +14,7 @@
 
 #include "absl/container/internal/raw_hash_set.h"
 
+#include <atomic>
 #include <cmath>
 #include <cstdint>
 #include <deque>
@@ -22,6 +23,8 @@
 #include <numeric>
 #include <random>
 #include <string>
+#include <unordered_map>
+#include <unordered_set>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -48,11 +51,10 @@
 
 namespace {
 
-using ::testing::DoubleNear;
 using ::testing::ElementsAre;
+using ::testing::Eq;
 using ::testing::Ge;
 using ::testing::Lt;
-using ::testing::Optional;
 using ::testing::Pair;
 using ::testing::UnorderedElementsAre;
 
@@ -75,8 +77,14 @@
   for (size_t growth = 0; growth < 10000; ++growth) {
     SCOPED_TRACE(growth);
     size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth));
-    // The capacity is large enough for `growth`
+    // The capacity is large enough for `growth`.
     EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
+    // For (capacity+1) < kWidth, growth should equal capacity.
+    if (capacity + 1 < Group::kWidth) {
+      EXPECT_THAT(CapacityToGrowth(capacity), Eq(capacity));
+    } else {
+      EXPECT_THAT(CapacityToGrowth(capacity), Lt(capacity));
+    }
     if (growth != 0 && capacity > 1) {
       // There is no smaller capacity that works.
       EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth));
@@ -250,25 +258,43 @@
   }
 }
 
-struct IntPolicy {
-  using slot_type = int64_t;
-  using key_type = int64_t;
-  using init_type = int64_t;
+template <class T>
+struct ValuePolicy {
+  using slot_type = T;
+  using key_type = T;
+  using init_type = T;
 
-  static void construct(void*, int64_t* slot, int64_t v) { *slot = v; }
-  static void destroy(void*, int64_t*) {}
-  static void transfer(void*, int64_t* new_slot, int64_t* old_slot) {
-    *new_slot = *old_slot;
+  template <class Allocator, class... Args>
+  static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
+    absl::allocator_traits<Allocator>::construct(*alloc, slot,
+                                                 std::forward<Args>(args)...);
   }
 
-  static int64_t& element(slot_type* slot) { return *slot; }
+  template <class Allocator>
+  static void destroy(Allocator* alloc, slot_type* slot) {
+    absl::allocator_traits<Allocator>::destroy(*alloc, slot);
+  }
 
-  template <class F>
-  static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) {
-    return std::forward<F>(f)(x, x);
+  template <class Allocator>
+  static void transfer(Allocator* alloc, slot_type* new_slot,
+                       slot_type* old_slot) {
+    construct(alloc, new_slot, std::move(*old_slot));
+    destroy(alloc, old_slot);
+  }
+
+  static T& element(slot_type* slot) { return *slot; }
+
+  template <class F, class... Args>
+  static decltype(absl::container_internal::DecomposeValue(
+      std::declval<F>(), std::declval<Args>()...))
+  apply(F&& f, Args&&... args) {
+    return absl::container_internal::DecomposeValue(
+        std::forward<F>(f), std::forward<Args>(args)...);
   }
 };
 
+using IntPolicy = ValuePolicy<int64_t>;
+
 class StringPolicy {
   template <class F, class K, class V,
             class = typename std::enable_if<
@@ -393,6 +419,13 @@
     size_t growth_left;
     void* infoz;
   };
+  struct MockTableInfozDisabled {
+    void* ctrl;
+    void* slots;
+    size_t size;
+    size_t capacity;
+    size_t growth_left;
+  };
   struct StatelessHash {
     size_t operator()(absl::string_view) const { return 0; }
   };
@@ -400,17 +433,27 @@
     size_t dummy;
   };
 
-  EXPECT_EQ(
-      sizeof(MockTable),
-      sizeof(
-          raw_hash_set<StringPolicy, StatelessHash,
-                       std::equal_to<absl::string_view>, std::allocator<int>>));
+  if (std::is_empty<HashtablezInfoHandle>::value) {
+    EXPECT_EQ(sizeof(MockTableInfozDisabled),
+              sizeof(raw_hash_set<StringPolicy, StatelessHash,
+                                  std::equal_to<absl::string_view>,
+                                  std::allocator<int>>));
 
-  EXPECT_EQ(
-      sizeof(MockTable) + sizeof(StatefulHash),
-      sizeof(
-          raw_hash_set<StringPolicy, StatefulHash,
-                       std::equal_to<absl::string_view>, std::allocator<int>>));
+    EXPECT_EQ(sizeof(MockTableInfozDisabled) + sizeof(StatefulHash),
+              sizeof(raw_hash_set<StringPolicy, StatefulHash,
+                                  std::equal_to<absl::string_view>,
+                                  std::allocator<int>>));
+  } else {
+    EXPECT_EQ(sizeof(MockTable),
+              sizeof(raw_hash_set<StringPolicy, StatelessHash,
+                                  std::equal_to<absl::string_view>,
+                                  std::allocator<int>>));
+
+    EXPECT_EQ(sizeof(MockTable) + sizeof(StatefulHash),
+              sizeof(raw_hash_set<StringPolicy, StatefulHash,
+                                  std::equal_to<absl::string_view>,
+                                  std::allocator<int>>));
+  }
 }
 
 TEST(Table, Empty) {
@@ -847,7 +890,8 @@
 std::vector<int64_t> CollectBadMergeKeys(size_t N) {
   static constexpr int kGroupSize = Group::kWidth - 1;
 
-  auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector<int64_t> {
+  auto topk_range = [](size_t b, size_t e,
+                       IntTable* t) -> std::vector<int64_t> {
     for (size_t i = b; i != e; ++i) {
       t->emplace(i);
     }
@@ -1001,8 +1045,8 @@
 // 1. Create new table and reserve it to keys.size() * 2
 // 2. Insert all keys xored with seed
 // 3. Collect ProbeStats from final table.
-ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector<int64_t>& keys,
-                                                size_t num_iters) {
+ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
+    const std::vector<int64_t>& keys, size_t num_iters) {
   const size_t reserve_size = keys.size() * 2;
 
   ProbeStats stats;
@@ -1656,6 +1700,38 @@
   EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0")));
 }
 
+TEST(Table, IteratorEmplaceConstructibleRequirement) {
+  struct Value {
+    explicit Value(absl::string_view view) : value(view) {}
+    std::string value;
+
+    bool operator==(const Value& other) const { return value == other.value; }
+  };
+  struct H {
+    size_t operator()(const Value& v) const {
+      return absl::Hash<std::string>{}(v.value);
+    }
+  };
+
+  struct Table : raw_hash_set<ValuePolicy<Value>, H, std::equal_to<Value>,
+                              std::allocator<Value>> {
+    using Base = typename Table::raw_hash_set;
+    using Base::Base;
+  };
+
+  std::string input[3]{"A", "B", "C"};
+
+  Table t(std::begin(input), std::end(input));
+  EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"}));
+
+  input[0] = "D";
+  input[1] = "E";
+  input[2] = "F";
+  t.insert(std::begin(input), std::end(input));
+  EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"},
+                                      Value{"D"}, Value{"E"}, Value{"F"}));
+}
+
 TEST(Nodes, EmptyNodeType) {
   using node_type = StringTable::node_type;
   node_type n;
@@ -1710,6 +1786,26 @@
   EXPECT_FALSE(node);
 }
 
+TEST(Nodes, HintInsert) {
+  IntTable t = {1, 2, 3};
+  auto node = t.extract(1);
+  EXPECT_THAT(t, UnorderedElementsAre(2, 3));
+  auto it = t.insert(t.begin(), std::move(node));
+  EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
+  EXPECT_EQ(*it, 1);
+  EXPECT_FALSE(node);
+
+  node = t.extract(2);
+  EXPECT_THAT(t, UnorderedElementsAre(1, 3));
+  // reinsert 2 to make the next insert fail.
+  t.insert(2);
+  EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
+  it = t.insert(t.begin(), std::move(node));
+  EXPECT_EQ(*it, 2);
+  // The node was not emptied by the insert call.
+  EXPECT_TRUE(node);
+}
+
 IntTable MakeSimpleTable(size_t size) {
   IntTable t;
   while (t.size() < size) t.insert(t.size());
@@ -1804,18 +1900,34 @@
 
   auto& sampler = HashtablezSampler::Global();
   size_t start_size = 0;
-  start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; });
+  std::unordered_set<const HashtablezInfo*> preexisting_info;
+  start_size += sampler.Iterate([&](const HashtablezInfo& info) {
+    preexisting_info.insert(&info);
+    ++start_size;
+  });
 
   std::vector<IntTable> tables;
   for (int i = 0; i < 1000000; ++i) {
     tables.emplace_back();
     tables.back().insert(1);
+    tables.back().insert(i % 5);
   }
   size_t end_size = 0;
-  end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; });
+  std::unordered_map<size_t, int> observed_checksums;
+  end_size += sampler.Iterate([&](const HashtablezInfo& info) {
+    if (preexisting_info.count(&info) == 0) {
+      observed_checksums[info.hashes_bitwise_xor.load(
+          std::memory_order_relaxed)]++;
+    }
+    ++end_size;
+  });
 
   EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
               0.01, 0.005);
+  EXPECT_EQ(observed_checksums.size(), 5);
+  for (const auto& [_, count] : observed_checksums) {
+    EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.2, 0.05);
+  }
 }
 #endif  // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
 
diff --git a/grpc/third_party/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h b/grpc/third_party/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h
index 76ee95e..3f90ad7 100644
--- a/grpc/third_party/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h
+++ b/grpc/third_party/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h
@@ -16,6 +16,7 @@
 #define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
 
 #include <algorithm>
+#include <unordered_map>
 #include <vector>
 
 #include "gmock/gmock.h"
diff --git a/grpc/third_party/abseil-cpp/absl/container/node_hash_set.h b/grpc/third_party/abseil-cpp/absl/container/node_hash_set.h
index 56ce3b6..93b15f4 100644
--- a/grpc/third_party/abseil-cpp/absl/container/node_hash_set.h
+++ b/grpc/third_party/abseil-cpp/absl/container/node_hash_set.h
@@ -18,7 +18,7 @@
 //
 // An `absl::node_hash_set<T>` is an unordered associative container designed to
 // be a more efficient replacement for `std::unordered_set`. Like
-// `unordered_set`, search, insertion, and deletion of map elements can be done
+// `unordered_set`, search, insertion, and deletion of set elements can be done
 // as an `O(1)` operation. However, `node_hash_set` (and other unordered
 // associative containers known as the collection of Abseil "Swiss tables")
 // contain other optimizations that result in both memory and computation
@@ -60,7 +60,7 @@
 // following notable differences:
 //
 // * Supports heterogeneous lookup, through `find()`, `operator[]()` and
-//   `insert()`, provided that the map is provided a compatible heterogeneous
+//   `insert()`, provided that the set is provided a compatible heterogeneous
 //   hashing function and equality operator.
 // * Contains a `capacity()` member function indicating the number of element
 //   slots (open, deleted, and empty) within the hash set.
@@ -76,13 +76,13 @@
 // Example:
 //
 //   // Create a node hash set of three strings
-//   absl::node_hash_map<std::string, std::string> ducks =
+//   absl::node_hash_set<std::string> ducks =
 //     {"huey", "dewey", "louie"};
 //
-//  // Insert a new element into the node hash map
-//  ducks.insert("donald"};
+//  // Insert a new element into the node hash set
+//  ducks.insert("donald");
 //
-//  // Force a rehash of the node hash map
+//  // Force a rehash of the node hash set
 //  ducks.rehash(0);
 //
 //  // See if "dewey" is present
@@ -100,7 +100,7 @@
  public:
   // Constructors and Assignment Operators
   //
-  // A node_hash_set supports the same overload set as `std::unordered_map`
+  // A node_hash_set supports the same overload set as `std::unordered_set`
   // for construction and assignment:
   //
   // *  Default constructor
@@ -167,7 +167,7 @@
   // available within the `node_hash_set`.
   //
   // NOTE: this member function is particular to `absl::node_hash_set` and is
-  // not provided in the `std::unordered_map` API.
+  // not provided in the `std::unordered_set` API.
   using Base::capacity;
 
   // node_hash_set::empty()
@@ -208,7 +208,7 @@
   //   `void`.
   //
   //   NOTE: this return behavior is different than that of STL containers in
-  //   general and `std::unordered_map` in particular.
+  //   general and `std::unordered_set` in particular.
   //
   // iterator erase(const_iterator first, const_iterator last):
   //
@@ -314,7 +314,7 @@
 
   // node_hash_set::merge()
   //
-  // Extracts elements from a given `source` flat hash map into this
+  // Extracts elements from a given `source` node hash set into this
   // `node_hash_set`. If the destination `node_hash_set` already contains an
   // element with an equivalent key, that element is not extracted.
   using Base::merge;
@@ -322,15 +322,15 @@
   // node_hash_set::swap(node_hash_set& other)
   //
   // Exchanges the contents of this `node_hash_set` with those of the `other`
-  // flat hash map, avoiding invocation of any move, copy, or swap operations on
+  // node hash set, avoiding invocation of any move, copy, or swap operations on
   // individual elements.
   //
   // All iterators and references on the `node_hash_set` remain valid, excepting
   // for the past-the-end iterator, which is invalidated.
   //
-  // `swap()` requires that the flat hash set's hashing and key equivalence
+  // `swap()` requires that the node hash set's hashing and key equivalence
   // functions be Swappable, and are exchaged using unqualified calls to
-  // non-member `swap()`. If the map's allocator has
+  // non-member `swap()`. If the set's allocator has
   // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
   // set to `true`, the allocators are also exchanged using an unqualified call
   // to non-member `swap()`; otherwise, the allocators are not swapped.
@@ -385,14 +385,14 @@
   // node_hash_set::bucket_count()
   //
   // Returns the number of "buckets" within the `node_hash_set`. Note that
-  // because a flat hash map contains all elements within its internal storage,
+  // because a node hash set contains all elements within its internal storage,
   // this value simply equals the current capacity of the `node_hash_set`.
   using Base::bucket_count;
 
   // node_hash_set::load_factor()
   //
   // Returns the current load factor of the `node_hash_set` (the average number
-  // of slots occupied with a value within the hash map).
+  // of slots occupied with a value within the hash set).
   using Base::load_factor;
 
   // node_hash_set::max_load_factor()
diff --git a/grpc/third_party/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake b/grpc/third_party/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake
index acd46d0..9cd6fd1 100644
--- a/grpc/third_party/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake
+++ b/grpc/third_party/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake
@@ -12,16 +12,16 @@
   set(ABSL_BUILD_DLL FALSE)
 endif()
 
-if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64|amd64|AMD64")
+if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
   if (MSVC)
     set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}")
   else()
     set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}")
   endif()
-elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm.*|aarch64")
-  if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64")
+  if (CMAKE_SIZEOF_VOID_P STREQUAL "8")
     set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM64_FLAGS}")
-  elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
+  elseif(CMAKE_SIZEOF_VOID_P STREQUAL "4")
     set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM32_FLAGS}")
   else()
     message(WARNING "Value of CMAKE_SIZEOF_VOID_P (${CMAKE_SIZEOF_VOID_P}) is not supported.")
@@ -32,20 +32,19 @@
 endif()
 
 
-if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
   set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}")
   set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}")
-elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
   # MATCHES so we get both Clang and AppleClang
   if(MSVC)
     # clang-cl is half MSVC, half LLVM
     set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}")
     set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}")
-    set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
   else()
     set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
     set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}")
-    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+    if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
       # AppleClang doesn't have lsan
       # https://developer.apple.com/documentation/code_diagnostics
       if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
@@ -54,7 +53,7 @@
       endif()
     endif()
   endif()
-elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
   set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}")
   set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}")
   set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
diff --git a/grpc/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake b/grpc/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake
index 97bd283..51742c9 100644
--- a/grpc/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake
+++ b/grpc/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake
@@ -5,47 +5,6 @@
 
 list(APPEND ABSL_CLANG_CL_FLAGS
     "/W3"
-    "-Wno-c++98-compat-pedantic"
-    "-Wno-conversion"
-    "-Wno-covered-switch-default"
-    "-Wno-deprecated"
-    "-Wno-disabled-macro-expansion"
-    "-Wno-double-promotion"
-    "-Wno-comma"
-    "-Wno-extra-semi"
-    "-Wno-extra-semi-stmt"
-    "-Wno-packed"
-    "-Wno-padded"
-    "-Wno-sign-compare"
-    "-Wno-float-conversion"
-    "-Wno-float-equal"
-    "-Wno-format-nonliteral"
-    "-Wno-gcc-compat"
-    "-Wno-global-constructors"
-    "-Wno-exit-time-destructors"
-    "-Wno-non-modular-include-in-module"
-    "-Wno-old-style-cast"
-    "-Wno-range-loop-analysis"
-    "-Wno-reserved-id-macro"
-    "-Wno-shorten-64-to-32"
-    "-Wno-switch-enum"
-    "-Wno-thread-safety-negative"
-    "-Wno-unknown-warning-option"
-    "-Wno-unreachable-code"
-    "-Wno-unused-macros"
-    "-Wno-weak-vtables"
-    "-Wno-zero-as-null-pointer-constant"
-    "-Wbitfield-enum-conversion"
-    "-Wbool-conversion"
-    "-Wconstant-conversion"
-    "-Wenum-conversion"
-    "-Wint-conversion"
-    "-Wliteral-conversion"
-    "-Wnon-literal-null-conversion"
-    "-Wnull-conversion"
-    "-Wobjc-literal-conversion"
-    "-Wno-sign-conversion"
-    "-Wstring-conversion"
     "/DNOMINMAX"
     "/DWIN32_LEAN_AND_MEAN"
     "/D_CRT_SECURE_NO_WARNINGS"
@@ -78,6 +37,7 @@
     "-Wextra"
     "-Wcast-qual"
     "-Wconversion-null"
+    "-Wformat-security"
     "-Wmissing-declarations"
     "-Woverlength-strings"
     "-Wpointer-arith"
@@ -87,8 +47,6 @@
     "-Wvarargs"
     "-Wvla"
     "-Wwrite-strings"
-    "-Wno-missing-field-initializers"
-    "-Wno-sign-compare"
     "-DNOMINMAX"
 )
 
@@ -105,48 +63,36 @@
 list(APPEND ABSL_LLVM_FLAGS
     "-Wall"
     "-Wextra"
-    "-Weverything"
-    "-Wno-c++98-compat-pedantic"
-    "-Wno-conversion"
-    "-Wno-covered-switch-default"
-    "-Wno-deprecated"
-    "-Wno-disabled-macro-expansion"
-    "-Wno-double-promotion"
-    "-Wno-comma"
-    "-Wno-extra-semi"
-    "-Wno-extra-semi-stmt"
-    "-Wno-packed"
-    "-Wno-padded"
-    "-Wno-sign-compare"
-    "-Wno-float-conversion"
-    "-Wno-float-equal"
-    "-Wno-format-nonliteral"
-    "-Wno-gcc-compat"
-    "-Wno-global-constructors"
-    "-Wno-exit-time-destructors"
-    "-Wno-non-modular-include-in-module"
-    "-Wno-old-style-cast"
-    "-Wno-range-loop-analysis"
-    "-Wno-reserved-id-macro"
-    "-Wno-shorten-64-to-32"
-    "-Wno-switch-enum"
-    "-Wno-thread-safety-negative"
-    "-Wno-unknown-warning-option"
-    "-Wno-unreachable-code"
-    "-Wno-unused-macros"
-    "-Wno-weak-vtables"
-    "-Wno-zero-as-null-pointer-constant"
-    "-Wbitfield-enum-conversion"
-    "-Wbool-conversion"
-    "-Wconstant-conversion"
-    "-Wenum-conversion"
-    "-Wint-conversion"
+    "-Wcast-qual"
+    "-Wconversion"
+    "-Wfloat-overflow-conversion"
+    "-Wfloat-zero-conversion"
+    "-Wfor-loop-analysis"
+    "-Wformat-security"
+    "-Wgnu-redeclared-enum"
+    "-Winfinite-recursion"
     "-Wliteral-conversion"
-    "-Wnon-literal-null-conversion"
-    "-Wnull-conversion"
-    "-Wobjc-literal-conversion"
-    "-Wno-sign-conversion"
+    "-Wmissing-declarations"
+    "-Woverlength-strings"
+    "-Wpointer-arith"
+    "-Wself-assign"
+    "-Wshadow"
     "-Wstring-conversion"
+    "-Wtautological-overlap-compare"
+    "-Wundef"
+    "-Wuninitialized"
+    "-Wunreachable-code"
+    "-Wunused-comparison"
+    "-Wunused-local-typedefs"
+    "-Wunused-result"
+    "-Wvla"
+    "-Wwrite-strings"
+    "-Wno-float-conversion"
+    "-Wno-implicit-float-conversion"
+    "-Wno-implicit-int-float-conversion"
+    "-Wno-implicit-int-conversion"
+    "-Wno-shorten-64-to-32"
+    "-Wno-sign-conversion"
     "-DNOMINMAX"
 )
 
diff --git a/grpc/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl b/grpc/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl
index bcdd61e..6707488 100644
--- a/grpc/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl
+++ b/grpc/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl
@@ -6,47 +6,6 @@
 
 ABSL_CLANG_CL_FLAGS = [
     "/W3",
-    "-Wno-c++98-compat-pedantic",
-    "-Wno-conversion",
-    "-Wno-covered-switch-default",
-    "-Wno-deprecated",
-    "-Wno-disabled-macro-expansion",
-    "-Wno-double-promotion",
-    "-Wno-comma",
-    "-Wno-extra-semi",
-    "-Wno-extra-semi-stmt",
-    "-Wno-packed",
-    "-Wno-padded",
-    "-Wno-sign-compare",
-    "-Wno-float-conversion",
-    "-Wno-float-equal",
-    "-Wno-format-nonliteral",
-    "-Wno-gcc-compat",
-    "-Wno-global-constructors",
-    "-Wno-exit-time-destructors",
-    "-Wno-non-modular-include-in-module",
-    "-Wno-old-style-cast",
-    "-Wno-range-loop-analysis",
-    "-Wno-reserved-id-macro",
-    "-Wno-shorten-64-to-32",
-    "-Wno-switch-enum",
-    "-Wno-thread-safety-negative",
-    "-Wno-unknown-warning-option",
-    "-Wno-unreachable-code",
-    "-Wno-unused-macros",
-    "-Wno-weak-vtables",
-    "-Wno-zero-as-null-pointer-constant",
-    "-Wbitfield-enum-conversion",
-    "-Wbool-conversion",
-    "-Wconstant-conversion",
-    "-Wenum-conversion",
-    "-Wint-conversion",
-    "-Wliteral-conversion",
-    "-Wnon-literal-null-conversion",
-    "-Wnull-conversion",
-    "-Wobjc-literal-conversion",
-    "-Wno-sign-conversion",
-    "-Wstring-conversion",
     "/DNOMINMAX",
     "/DWIN32_LEAN_AND_MEAN",
     "/D_CRT_SECURE_NO_WARNINGS",
@@ -79,6 +38,7 @@
     "-Wextra",
     "-Wcast-qual",
     "-Wconversion-null",
+    "-Wformat-security",
     "-Wmissing-declarations",
     "-Woverlength-strings",
     "-Wpointer-arith",
@@ -88,8 +48,6 @@
     "-Wvarargs",
     "-Wvla",
     "-Wwrite-strings",
-    "-Wno-missing-field-initializers",
-    "-Wno-sign-compare",
     "-DNOMINMAX",
 ]
 
@@ -106,48 +64,36 @@
 ABSL_LLVM_FLAGS = [
     "-Wall",
     "-Wextra",
-    "-Weverything",
-    "-Wno-c++98-compat-pedantic",
-    "-Wno-conversion",
-    "-Wno-covered-switch-default",
-    "-Wno-deprecated",
-    "-Wno-disabled-macro-expansion",
-    "-Wno-double-promotion",
-    "-Wno-comma",
-    "-Wno-extra-semi",
-    "-Wno-extra-semi-stmt",
-    "-Wno-packed",
-    "-Wno-padded",
-    "-Wno-sign-compare",
-    "-Wno-float-conversion",
-    "-Wno-float-equal",
-    "-Wno-format-nonliteral",
-    "-Wno-gcc-compat",
-    "-Wno-global-constructors",
-    "-Wno-exit-time-destructors",
-    "-Wno-non-modular-include-in-module",
-    "-Wno-old-style-cast",
-    "-Wno-range-loop-analysis",
-    "-Wno-reserved-id-macro",
-    "-Wno-shorten-64-to-32",
-    "-Wno-switch-enum",
-    "-Wno-thread-safety-negative",
-    "-Wno-unknown-warning-option",
-    "-Wno-unreachable-code",
-    "-Wno-unused-macros",
-    "-Wno-weak-vtables",
-    "-Wno-zero-as-null-pointer-constant",
-    "-Wbitfield-enum-conversion",
-    "-Wbool-conversion",
-    "-Wconstant-conversion",
-    "-Wenum-conversion",
-    "-Wint-conversion",
+    "-Wcast-qual",
+    "-Wconversion",
+    "-Wfloat-overflow-conversion",
+    "-Wfloat-zero-conversion",
+    "-Wfor-loop-analysis",
+    "-Wformat-security",
+    "-Wgnu-redeclared-enum",
+    "-Winfinite-recursion",
     "-Wliteral-conversion",
-    "-Wnon-literal-null-conversion",
-    "-Wnull-conversion",
-    "-Wobjc-literal-conversion",
-    "-Wno-sign-conversion",
+    "-Wmissing-declarations",
+    "-Woverlength-strings",
+    "-Wpointer-arith",
+    "-Wself-assign",
+    "-Wshadow",
     "-Wstring-conversion",
+    "-Wtautological-overlap-compare",
+    "-Wundef",
+    "-Wuninitialized",
+    "-Wunreachable-code",
+    "-Wunused-comparison",
+    "-Wunused-local-typedefs",
+    "-Wunused-result",
+    "-Wvla",
+    "-Wwrite-strings",
+    "-Wno-float-conversion",
+    "-Wno-implicit-float-conversion",
+    "-Wno-implicit-int-float-conversion",
+    "-Wno-implicit-int-conversion",
+    "-Wno-shorten-64-to-32",
+    "-Wno-sign-conversion",
     "-DNOMINMAX",
 ]
 
diff --git a/grpc/third_party/abseil-cpp/absl/copts/configure_copts.bzl b/grpc/third_party/abseil-cpp/absl/copts/configure_copts.bzl
index ff9a5ea..669a906 100644
--- a/grpc/third_party/abseil-cpp/absl/copts/configure_copts.bzl
+++ b/grpc/third_party/abseil-cpp/absl/copts/configure_copts.bzl
@@ -22,21 +22,21 @@
 )
 
 ABSL_DEFAULT_COPTS = select({
-    "//absl:windows": ABSL_MSVC_FLAGS,
-    "//absl:llvm_compiler": ABSL_LLVM_FLAGS,
+    "//absl:msvc_compiler": ABSL_MSVC_FLAGS,
+    "//absl:clang-cl_compiler": ABSL_CLANG_CL_FLAGS,
+    "//absl:clang_compiler": ABSL_LLVM_FLAGS,
     "//conditions:default": ABSL_GCC_FLAGS,
 })
 
-# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts
-# to their (included header) dependencies and fail to build outside absl
 ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({
-    "//absl:windows": ABSL_MSVC_TEST_FLAGS,
-    "//absl:llvm_compiler": ABSL_LLVM_TEST_FLAGS,
+    "//absl:msvc_compiler": ABSL_MSVC_TEST_FLAGS,
+    "//absl:clang-cl_compiler": ABSL_CLANG_CL_TEST_FLAGS,
+    "//absl:clang_compiler": ABSL_LLVM_TEST_FLAGS,
     "//conditions:default": ABSL_GCC_TEST_FLAGS,
 })
 
 ABSL_DEFAULT_LINKOPTS = select({
-    "//absl:windows": ABSL_MSVC_LINKOPTS,
+    "//absl:msvc_compiler": ABSL_MSVC_LINKOPTS,
     "//conditions:default": [],
 })
 
diff --git a/grpc/third_party/abseil-cpp/absl/copts/copts.py b/grpc/third_party/abseil-cpp/absl/copts/copts.py
index a3437c1..cf52981 100644
--- a/grpc/third_party/abseil-cpp/absl/copts/copts.py
+++ b/grpc/third_party/abseil-cpp/absl/copts/copts.py
@@ -16,77 +16,6 @@
     "/W3",
 ]
 
-LLVM_BIG_WARNING_FLAGS = [
-    "-Wall",
-    "-Wextra",
-    "-Weverything",
-]
-
-# Docs on single flags is preceded by a comment.
-# Docs on groups of flags is preceded by ###.
-LLVM_DISABLE_WARNINGS_FLAGS = [
-    # Abseil does not support C++98
-    "-Wno-c++98-compat-pedantic",
-    # Turns off all implicit conversion warnings. Most are re-enabled below.
-    "-Wno-conversion",
-    "-Wno-covered-switch-default",
-    "-Wno-deprecated",
-    "-Wno-disabled-macro-expansion",
-    "-Wno-double-promotion",
-    ###
-    # Turned off as they include valid C++ code.
-    "-Wno-comma",
-    "-Wno-extra-semi",
-    "-Wno-extra-semi-stmt",
-    "-Wno-packed",
-    "-Wno-padded",
-    ###
-    # Google style does not use unsigned integers, though STL containers
-    # have unsigned types.
-    "-Wno-sign-compare",
-    ###
-    "-Wno-float-conversion",
-    "-Wno-float-equal",
-    "-Wno-format-nonliteral",
-    # Too aggressive: warns on Clang extensions enclosed in Clang-only
-    # compilation paths.
-    "-Wno-gcc-compat",
-    ###
-    # Some internal globals are necessary. Don't do this at home.
-    "-Wno-global-constructors",
-    "-Wno-exit-time-destructors",
-    ###
-    "-Wno-non-modular-include-in-module",
-    "-Wno-old-style-cast",
-    # Warns on preferred usage of non-POD types such as string_view
-    "-Wno-range-loop-analysis",
-    "-Wno-reserved-id-macro",
-    "-Wno-shorten-64-to-32",
-    "-Wno-switch-enum",
-    "-Wno-thread-safety-negative",
-    "-Wno-unknown-warning-option",
-    "-Wno-unreachable-code",
-    # Causes warnings on include guards
-    "-Wno-unused-macros",
-    "-Wno-weak-vtables",
-    # Causes warnings on usage of types/compare.h comparison operators.
-    "-Wno-zero-as-null-pointer-constant",
-    ###
-    # Implicit conversion warnings turned off by -Wno-conversion
-    # which are re-enabled below.
-    "-Wbitfield-enum-conversion",
-    "-Wbool-conversion",
-    "-Wconstant-conversion",
-    "-Wenum-conversion",
-    "-Wint-conversion",
-    "-Wliteral-conversion",
-    "-Wnon-literal-null-conversion",
-    "-Wnull-conversion",
-    "-Wobjc-literal-conversion",
-    "-Wno-sign-conversion",
-    "-Wstring-conversion",
-]
-
 LLVM_TEST_DISABLE_WARNINGS_FLAGS = [
     "-Wno-c99-extensions",
     "-Wno-deprecated-declarations",
@@ -125,6 +54,7 @@
         "-Wextra",
         "-Wcast-qual",
         "-Wconversion-null",
+        "-Wformat-security",
         "-Wmissing-declarations",
         "-Woverlength-strings",
         "-Wpointer-arith",
@@ -134,13 +64,6 @@
         "-Wvarargs",
         "-Wvla",  # variable-length array
         "-Wwrite-strings",
-        # gcc-4.x has spurious missing field initializer warnings.
-        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
-        # Remove when gcc-4.x is no longer supported.
-        "-Wno-missing-field-initializers",
-        # Google style does not use unsigned integers, though STL containers
-        # have unsigned types.
-        "-Wno-sign-compare",
         # Don't define min and max macros (Build on Windows using gcc)
         "-DNOMINMAX",
     ],
@@ -153,15 +76,48 @@
         "-Wno-unused-parameter",
         "-Wno-unused-private-field",
     ],
-    "ABSL_LLVM_FLAGS":
-        LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS + [
-            # Don't define min and max macros (Build on Windows using clang)
-            "-DNOMINMAX",
-        ],
+    "ABSL_LLVM_FLAGS": [
+        "-Wall",
+        "-Wextra",
+        "-Wcast-qual",
+        "-Wconversion",
+        "-Wfloat-overflow-conversion",
+        "-Wfloat-zero-conversion",
+        "-Wfor-loop-analysis",
+        "-Wformat-security",
+        "-Wgnu-redeclared-enum",
+        "-Winfinite-recursion",
+        "-Wliteral-conversion",
+        "-Wmissing-declarations",
+        "-Woverlength-strings",
+        "-Wpointer-arith",
+        "-Wself-assign",
+        "-Wshadow",
+        "-Wstring-conversion",
+        "-Wtautological-overlap-compare",
+        "-Wundef",
+        "-Wuninitialized",
+        "-Wunreachable-code",
+        "-Wunused-comparison",
+        "-Wunused-local-typedefs",
+        "-Wunused-result",
+        "-Wvla",
+        "-Wwrite-strings",
+        # Warnings that are enabled by group warning flags like -Wall that we
+        # explicitly disable.
+        "-Wno-float-conversion",
+        "-Wno-implicit-float-conversion",
+        "-Wno-implicit-int-float-conversion",
+        "-Wno-implicit-int-conversion",
+        "-Wno-shorten-64-to-32",
+        "-Wno-sign-conversion",
+        # Don't define min and max macros (Build on Windows using clang)
+        "-DNOMINMAX",
+    ],
     "ABSL_LLVM_TEST_FLAGS":
         LLVM_TEST_DISABLE_WARNINGS_FLAGS,
     "ABSL_CLANG_CL_FLAGS":
-        (MSVC_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES),
+        (MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES),
     "ABSL_CLANG_CL_TEST_FLAGS":
         LLVM_TEST_DISABLE_WARNINGS_FLAGS,
     "ABSL_MSVC_FLAGS":
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/debugging/BUILD.bazel
index 86faac9..5385bcb 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/debugging/BUILD.bazel
@@ -66,7 +66,8 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS + select({
-        "//absl:windows": ["-DEFAULTLIB:dbghelp.lib"],
+        "//absl:msvc_compiler": ["-DEFAULTLIB:dbghelp.lib"],
+        "//absl:clang-cl_compiler": ["-DEFAULTLIB:dbghelp.lib"],
         "//conditions:default": [],
     }),
     deps = [
@@ -86,11 +87,13 @@
     name = "symbolize_test",
     srcs = ["symbolize_test.cc"],
     copts = ABSL_TEST_COPTS + select({
-        "//absl:windows": ["/Z7"],
+        "//absl:msvc_compiler": ["/Z7"],
+        "//absl:clang-cl_compiler": ["/Z7"],
         "//conditions:default": [],
     }),
     linkopts = ABSL_DEFAULT_LINKOPTS + select({
-        "//absl:windows": ["/DEBUG"],
+        "//absl:msvc_compiler": ["/DEBUG"],
+        "//absl:clang-cl_compiler": ["/DEBUG"],
         "//conditions:default": [],
     }),
     deps = [
@@ -148,7 +151,8 @@
     srcs = ["failure_signal_handler_test.cc"],
     copts = ABSL_TEST_COPTS,
     linkopts = select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
         "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
@@ -239,7 +243,7 @@
 # These targets exists for use in tests only, explicitly configuring the
 # LEAK_SANITIZER macro. It must be linked with -fsanitize=leak for lsan.
 ABSL_LSAN_LINKOPTS = select({
-    "//absl:llvm_compiler": ["-fsanitize=leak"],
+    "//absl:clang_compiler": ["-fsanitize=leak"],
     "//conditions:default": [],
 })
 
@@ -249,13 +253,14 @@
     srcs = ["leak_check.cc"],
     hdrs = ["leak_check.h"],
     copts = select({
-        "//absl:llvm_compiler": ["-DLEAK_SANITIZER"],
+        "//absl:clang_compiler": ["-DLEAK_SANITIZER"],
         "//conditions:default": [],
     }),
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = ["//visibility:private"],
     deps = [
         "//absl/base:config",
+        "//absl/base:core_headers",
     ],
 )
 
@@ -269,6 +274,7 @@
     visibility = ["//visibility:private"],
     deps = [
         "//absl/base:config",
+        "//absl/base:core_headers",
     ],
 )
 
@@ -276,7 +282,7 @@
     name = "leak_check_test",
     srcs = ["leak_check_test.cc"],
     copts = select({
-        "//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
+        "//absl:clang_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
         "//conditions:default": [],
     }),
     linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc b/grpc/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
index 5d13bdb..a9ed6ef 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
@@ -21,6 +21,7 @@
 #ifdef _WIN32
 #include <windows.h>
 #else
+#include <sched.h>
 #include <unistd.h>
 #endif
 
@@ -219,17 +220,24 @@
   absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data));
 }
 
-static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) {
-  char buf[64];
+static void WriteSignalMessage(int signo, int cpu,
+                               void (*writerfn)(const char*)) {
+  char buf[96];
+  char on_cpu[32] = {0};
+  if (cpu != -1) {
+    snprintf(on_cpu, sizeof(on_cpu), " on cpu %d", cpu);
+  }
   const char* const signal_string =
       debugging_internal::FailureSignalToString(signo);
   if (signal_string != nullptr && signal_string[0] != '\0') {
-    snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n",
+    snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n",
              signal_string,
-             static_cast<long>(time(nullptr)));  // NOLINT(runtime/int)
+             static_cast<long>(time(nullptr)),   // NOLINT(runtime/int)
+             on_cpu);
   } else {
-    snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n",
-             signo, static_cast<long>(time(nullptr)));  // NOLINT(runtime/int)
+    snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n",
+             signo, static_cast<long>(time(nullptr)),  // NOLINT(runtime/int)
+             on_cpu);
   }
   writerfn(buf);
 }
@@ -269,10 +277,10 @@
 // Called by AbslFailureSignalHandler() to write the failure info. It is
 // called once with writerfn set to WriteToStderr() and then possibly
 // with writerfn set to the user provided function.
-static void WriteFailureInfo(int signo, void* ucontext,
+static void WriteFailureInfo(int signo, void* ucontext, int cpu,
                              void (*writerfn)(const char*)) {
   WriterFnStruct writerfn_struct{writerfn};
-  WriteSignalMessage(signo, writerfn);
+  WriteSignalMessage(signo, cpu, writerfn);
   WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper,
                   &writerfn_struct);
 }
@@ -334,6 +342,14 @@
     }
   }
 
+  // Increase the chance that the CPU we report was the same CPU on which the
+  // signal was received by doing this as early as possible, i.e. after
+  // verifying that this is not a recursive signal handler invocation.
+  int my_cpu = -1;
+#ifdef ABSL_HAVE_SCHED_GETCPU
+  my_cpu = sched_getcpu();
+#endif
+
 #ifdef ABSL_HAVE_ALARM
   // Set an alarm to abort the program in case this code hangs or deadlocks.
   if (fsh_options.alarm_on_failure_secs > 0) {
@@ -344,12 +360,12 @@
 #endif
 
   // First write to stderr.
-  WriteFailureInfo(signo, ucontext, WriteToStderr);
+  WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr);
 
   // Riskier code (because it is less likely to be async-signal-safe)
   // goes after this point.
   if (fsh_options.writerfn != nullptr) {
-    WriteFailureInfo(signo, ucontext, fsh_options.writerfn);
+    WriteFailureInfo(signo, ucontext, my_cpu, fsh_options.writerfn);
   }
 
   if (fsh_options.call_previous_handler) {
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc b/grpc/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc
index d8283b2..6a62428 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc
@@ -122,6 +122,12 @@
           "*** ", absl::debugging_internal::FailureSignalToString(signo),
           " received at ")));
 
+  // On platforms where it is possible to get the current CPU, the
+  // CPU number is also logged. Check that it is present in output.
+#if defined(__linux__)
+  EXPECT_THAT(error_line, testing::HasSubstr(" on cpu "));
+#endif
+
   if (absl::debugging_internal::StackTraceWorksForTest()) {
     std::getline(error_output, error_line);
     EXPECT_THAT(error_line, StartsWith("PC: "));
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/internal/demangle.cc b/grpc/third_party/abseil-cpp/absl/debugging/internal/demangle.cc
index 46cdb67..5cd5632 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/internal/demangle.cc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/internal/demangle.cc
@@ -386,24 +386,28 @@
 // by GCC 4.5.x and later versions (and our locally-modified version of GCC
 // 4.4.x) to indicate functions which have been cloned during optimization.
 // We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix.
+// Additionally, '_' is allowed along with the alphanumeric sequence.
 static bool IsFunctionCloneSuffix(const char *str) {
   size_t i = 0;
   while (str[i] != '\0') {
-    // Consume a single .<alpha>+.<digit>+ sequence.
-    if (str[i] != '.' || !IsAlpha(str[i + 1])) {
+    bool parsed = false;
+    // Consume a single [.<alpha> | _]*[.<digit>]* sequence.
+    if (str[i] == '.' && (IsAlpha(str[i + 1]) || str[i + 1] == '_')) {
+      parsed = true;
+      i += 2;
+      while (IsAlpha(str[i]) || str[i] == '_') {
+        ++i;
+      }
+    }
+    if (str[i] == '.' && IsDigit(str[i + 1])) {
+      parsed = true;
+      i += 2;
+      while (IsDigit(str[i])) {
+        ++i;
+      }
+    }
+    if (!parsed)
       return false;
-    }
-    i += 2;
-    while (IsAlpha(str[i])) {
-      ++i;
-    }
-    if (str[i] != '.' || !IsDigit(str[i + 1])) {
-      return false;
-    }
-    i += 2;
-    while (IsDigit(str[i])) {
-      ++i;
-    }
   }
   return true;  // Consumed everything in "str".
 }
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc b/grpc/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc
index 0bed735..6b14290 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc
@@ -70,12 +70,34 @@
   EXPECT_STREQ("Foo()", tmp);
   EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp)));
   EXPECT_STREQ("Foo()", tmp);
-  // Invalid (truncated), should not demangle.
-  EXPECT_FALSE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp)));
+  // Demangle suffixes produced by -funique-internal-linkage-names.
+  EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345.isra.2.constprop.18", tmp,
+                       sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // Suffixes without the number should also demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // Suffixes with just the number should also demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.123", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // (.clone. followed by non-number), should also demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // (.clone. followed by multiple numbers), should also demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.clone.123.456", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // (a long valid suffix), should demangle.
+  EXPECT_TRUE(Demangle("_ZL3Foov.part.9.165493.constprop.775.31805", tmp,
+                       sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // Invalid (. without anything else), should not demangle.
+  EXPECT_FALSE(Demangle("_ZL3Foov.", tmp, sizeof(tmp)));
+  // Invalid (. with mix of alpha and digits), should not demangle.
+  EXPECT_FALSE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp)));
   // Invalid (.clone. not followed by number), should not demangle.
   EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp)));
-  // Invalid (.clone. followed by non-number), should not demangle.
-  EXPECT_FALSE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp)));
   // Invalid (.constprop. not followed by number), should not demangle.
   EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp)));
 }
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc b/grpc/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc
index 6e5ff1f..589a3ef 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc
@@ -46,26 +46,42 @@
     ucontext_t* context = reinterpret_cast<ucontext_t*>(vuc);
 #if defined(__aarch64__)
     return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__alpha__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_pc);
 #elif defined(__arm__)
     return reinterpret_cast<void*>(context->uc_mcontext.arm_pc);
+#elif defined(__hppa__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_iaoq[0]);
 #elif defined(__i386__)
     if (14 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
       return reinterpret_cast<void*>(context->uc_mcontext.gregs[14]);
+#elif defined(__ia64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_ip);
+#elif defined(__m68k__)
+    return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
 #elif defined(__mips__)
     return reinterpret_cast<void*>(context->uc_mcontext.pc);
 #elif defined(__powerpc64__)
     return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]);
 #elif defined(__powerpc__)
-    return reinterpret_cast<void*>(context->uc_mcontext.regs->nip);
+    return reinterpret_cast<void*>(context->uc_mcontext.uc_regs->gregs[32]);
 #elif defined(__riscv)
     return reinterpret_cast<void*>(context->uc_mcontext.__gregs[REG_PC]);
 #elif defined(__s390__) && !defined(__s390x__)
     return reinterpret_cast<void*>(context->uc_mcontext.psw.addr & 0x7fffffff);
 #elif defined(__s390__) && defined(__s390x__)
     return reinterpret_cast<void*>(context->uc_mcontext.psw.addr);
+#elif defined(__sh__)
+    return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__sparc__) && !defined(__arch64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.gregs[19]);
+#elif defined(__sparc__) && defined(__arch64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.mc_gregs[19]);
 #elif defined(__x86_64__)
     if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
       return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
+#elif defined(__e2k__)
+    return reinterpret_cast<void*>(context->uc_mcontext.cr0_hi);
 #else
 #error "Undefined Architecture."
 #endif
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc b/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc
index 14a76f1..f4859d7 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -37,8 +37,11 @@
   absl::debugging_internal::VDSOSupport vdso;
   if (vdso.IsPresent()) {
     absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
-    if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC,
-                           &symbol_info) ||
+    auto lookup = [&](int type) {
+      return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", type,
+                               &symbol_info);
+    };
+    if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) ||
         symbol_info.address == nullptr) {
       // Unexpected: VDSO is present, yet the expected symbol is missing
       // or null.
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h b/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h
index 90af852..cca410d 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h
+++ b/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h
@@ -21,6 +21,8 @@
 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
 #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
 
+#include "absl/base/config.h"
+
 #if defined(ABSL_STACKTRACE_INL_HEADER)
 #error ABSL_STACKTRACE_INL_HEADER cannot be directly set
 
@@ -29,19 +31,8 @@
     "absl/debugging/internal/stacktrace_win32-inl.inc"
 
 #elif defined(__APPLE__)
+#ifdef ABSL_HAVE_THREAD_LOCAL
 // Thread local support required for UnwindImpl.
-// Notes:
-// * Xcode's clang did not support `thread_local` until version 8, and
-//   even then not for all iOS < 9.0.
-// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
-//   targeting iOS 9.x.
-// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
-//   making __has_feature unreliable there.
-//
-// Otherwise, `__has_feature` is only supported by Clang so it has be inside
-// `defined(__APPLE__)` check.
-#if __has_feature(cxx_thread_local) && \
-    !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
 #define ABSL_STACKTRACE_INL_HEADER \
   "absl/debugging/internal/stacktrace_generic-inl.inc"
 #endif
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc b/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc
index 2e7c2f4..cf8c051 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -131,7 +131,12 @@
       const ucontext_t* signal_context =
           reinterpret_cast<const ucontext_t*>(uc);
       void **const sp_before_signal =
-          reinterpret_cast<void**>(signal_context->uc_mcontext.gp_regs[PT_R1]);
+#if defined(__PPC64__)
+          reinterpret_cast<void **>(signal_context->uc_mcontext.gp_regs[PT_R1]);
+#else
+          reinterpret_cast<void **>(
+              signal_context->uc_mcontext.uc_regs->gregs[PT_R1]);
+#endif
       // Check that alleged sp before signal is nonnull and is reasonably
       // aligned.
       if (sp_before_signal != nullptr &&
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/internal/symbolize.h b/grpc/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
index b3729af..4f26130 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
+++ b/grpc/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
@@ -118,16 +118,14 @@
 //   filename != nullptr
 //
 // Returns true if the file was successfully registered.
-bool RegisterFileMappingHint(
-    const void* start, const void* end, uint64_t offset, const char* filename);
+bool RegisterFileMappingHint(const void* start, const void* end,
+                             uint64_t offset, const char* filename);
 
 // Looks up the file mapping registered by RegisterFileMappingHint for an
 // address range. If there is one, the file name is stored in *filename and
 // *start and *end are modified to reflect the registered mapping. Returns
 // whether any hint was found.
-bool GetFileMappingHint(const void** start,
-                        const void** end,
-                        uint64_t    *  offset,
+bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset,
                         const char** filename);
 
 }  // namespace debugging_internal
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/leak_check.cc b/grpc/third_party/abseil-cpp/absl/debugging/leak_check.cc
index ff90495..764ca0a 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/leak_check.cc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/leak_check.cc
@@ -16,6 +16,7 @@
 // When lsan is not linked in, these functions are not available,
 // therefore Abseil code which depends on these functions is conditioned on the
 // definition of LEAK_SANITIZER.
+#include "absl/base/attributes.h"
 #include "absl/debugging/leak_check.h"
 
 #ifndef LEAK_SANITIZER
@@ -23,6 +24,7 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 bool HaveLeakSanitizer() { return false; }
+bool LeakCheckerIsActive() { return false; }
 void DoIgnoreLeak(const void*) { }
 void RegisterLivePointers(const void*, size_t) { }
 void UnRegisterLivePointers(const void*, size_t) { }
@@ -35,9 +37,23 @@
 
 #include <sanitizer/lsan_interface.h>
 
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+extern "C" ABSL_ATTRIBUTE_WEAK int __lsan_is_turned_off();
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 bool HaveLeakSanitizer() { return true; }
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+bool LeakCheckerIsActive() {
+  return !(&__lsan_is_turned_off && __lsan_is_turned_off());
+}
+#else
+bool LeakCheckerIsActive() { return true; }
+#endif
+
+bool FindAndReportLeaks() { return __lsan_do_recoverable_leak_check(); }
 void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); }
 void RegisterLivePointers(const void* ptr, size_t size) {
   __lsan_register_root_region(ptr, size);
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/leak_check.h b/grpc/third_party/abseil-cpp/absl/debugging/leak_check.h
index 7a5a22d..5fc2b05 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/leak_check.h
+++ b/grpc/third_party/abseil-cpp/absl/debugging/leak_check.h
@@ -43,6 +43,12 @@
 // currently built into this target.
 bool HaveLeakSanitizer();
 
+// LeakCheckerIsActive()
+//
+// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is
+// currently built into this target and is turned on.
+bool LeakCheckerIsActive();
+
 // DoIgnoreLeak()
 //
 // Implements `IgnoreLeak()` below. This function should usually
@@ -62,7 +68,8 @@
 //
 // If the passed `ptr` does not point to an actively allocated object at the
 // time `IgnoreLeak()` is called, the call is a no-op; if it is actively
-// allocated, the object must not get deallocated later.
+// allocated, leak sanitizer will assume this object is referenced even if
+// there is no actual reference in user memory.
 //
 template <typename T>
 T* IgnoreLeak(T* ptr) {
@@ -70,6 +77,19 @@
   return ptr;
 }
 
+// FindAndReportLeaks()
+//
+// If any leaks are detected, prints a leak report and returns true.  This
+// function may be called repeatedly, and does not affect end-of-process leak
+// checking.
+//
+// Example:
+// if (FindAndReportLeaks()) {
+//   ... diagnostic already printed. Exit with failure code.
+//   exit(1)
+// }
+bool FindAndReportLeaks();
+
 // LeakCheckDisabler
 //
 // This helper class indicates that any heap allocations done in the code block
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/leak_check_test.cc b/grpc/third_party/abseil-cpp/absl/debugging/leak_check_test.cc
index b5cc487..9fcfc8e 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/leak_check_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/leak_check_test.cc
@@ -23,8 +23,10 @@
 TEST(LeakCheckTest, DetectLeakSanitizer) {
 #ifdef ABSL_EXPECT_LEAK_SANITIZER
   EXPECT_TRUE(absl::HaveLeakSanitizer());
+  EXPECT_TRUE(absl::LeakCheckerIsActive());
 #else
   EXPECT_FALSE(absl::HaveLeakSanitizer());
+  EXPECT_FALSE(absl::LeakCheckerIsActive());
 #endif
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc b/grpc/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc
index cdadd40..443ce9e 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc
@@ -77,8 +77,8 @@
 
   char tmp_buf[1024];
   if (debugging_internal::Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) {
-    int len = strlen(tmp_buf);
-    if (len + 1 <= out_size) {  // +1 for '\0'
+    size_t len = strlen(tmp_buf);
+    if (len + 1 <= static_cast<size_t>(out_size)) {  // +1 for '\0'
       assert(len < sizeof(tmp_buf));
       memmove(out, tmp_buf, len + 1);
     }
diff --git a/grpc/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc b/grpc/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc
index 7c36fd1..f4d5727 100644
--- a/grpc/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc
+++ b/grpc/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc
@@ -1281,7 +1281,7 @@
     const int phnum = obj->elf_header.e_phnum;
     const int phentsize = obj->elf_header.e_phentsize;
     size_t phoff = obj->elf_header.e_phoff;
-    int num_executable_load_segments = 0;
+    size_t num_executable_load_segments = 0;
     for (int j = 0; j < phnum; j++) {
       ElfW(Phdr) phdr;
       if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) {
@@ -1342,7 +1342,7 @@
         // Note: some binaries have multiple "rx" LOAD segments. We must
         // find the right one.
         ElfW(Phdr) *phdr = nullptr;
-        for (int j = 0; j < obj->phdr.size(); j++) {
+        for (size_t j = 0; j < obj->phdr.size(); j++) {
           ElfW(Phdr) &p = obj->phdr[j];
           if (p.p_type != PT_LOAD) {
             // We only expect PT_LOADs. This must be PT_NULL that we didn't
diff --git a/grpc/third_party/abseil-cpp/absl/flags/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/flags/BUILD.bazel
index 62fb9a8..147249e 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/flags/BUILD.bazel
@@ -114,7 +114,6 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    visibility = ["//visibility:private"],
     deps = [
         "//absl/base:config",
         "//absl/base:fast_type_id",
@@ -192,6 +191,7 @@
     ],
     hdrs = [
         "internal/flag.h",
+        "internal/sequence_lock.h",
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -377,11 +377,17 @@
         "flag_benchmark.cc",
     ],
     copts = ABSL_TEST_COPTS,
+    linkopts = select({
+        "//conditions:default": [],
+    }) + ABSL_DEFAULT_LINKOPTS,
     tags = ["benchmark"],
     visibility = ["//visibility:private"],
     deps = [
+        "flag_benchmark.lds",
         ":flag",
         ":marshalling",
+        ":parse",
+        ":reflection",
         "//absl/strings",
         "//absl/time",
         "//absl/types:optional",
@@ -415,6 +421,7 @@
         ":flag",
         ":parse",
         ":reflection",
+        ":usage_internal",
         "//absl/base:raw_logging_internal",
         "//absl/base:scoped_set_env",
         "//absl/strings",
@@ -473,6 +480,25 @@
 )
 
 cc_test(
+    name = "sequence_lock_test",
+    size = "small",
+    timeout = "moderate",
+    srcs = [
+        "internal/sequence_lock_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    shard_count = 31,
+    deps = [
+        ":flag_internal",
+        "//absl/base",
+        "//absl/container:fixed_array",
+        "//absl/time",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "usage_config_test",
     size = "small",
     srcs = [
diff --git a/grpc/third_party/abseil-cpp/absl/flags/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/flags/CMakeLists.txt
index 8855191..caac69c 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/flags/CMakeLists.txt
@@ -176,6 +176,7 @@
     "internal/flag.cc"
   HDRS
     "internal/flag.h"
+    "internal/sequence_lock.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   LINKOPTS
@@ -366,6 +367,7 @@
     absl::flags
     absl::flags_parse
     absl::flags_reflection
+    absl::flags_usage_internal
     absl::raw_logging_internal
     absl::scoped_set_env
     absl::span
@@ -417,6 +419,20 @@
 
 absl_cc_test(
   NAME
+    flags_sequence_lock_test
+  SRCS
+    "internal/sequence_lock_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::base
+    absl::flags_internal
+    absl::time
+    gmock_main
+)
+
+absl_cc_test(
+  NAME
     flags_usage_config_test
   SRCS
     "usage_config_test.cc"
diff --git a/grpc/third_party/abseil-cpp/absl/flags/config.h b/grpc/third_party/abseil-cpp/absl/flags/config.h
index 813a925..5ab1f31 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/config.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/config.h
@@ -45,17 +45,6 @@
 #define ABSL_FLAGS_STRIP_HELP ABSL_FLAGS_STRIP_NAMES
 #endif
 
-// ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD macro is used for using atomics with
-// double words, e.g. absl::Duration.
-// For reasons in bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878, modern
-// versions of GCC do not support cmpxchg16b instruction in standard atomics.
-#ifdef ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD
-#error "ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD should not be defined."
-#elif defined(__clang__) && defined(__x86_64__) && \
-    defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)
-#define ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD 1
-#endif
-
 // ABSL_FLAGS_INTERNAL_HAS_RTTI macro is used for selecting if we can use RTTI
 // for flag type identification.
 #ifdef ABSL_FLAGS_INTERNAL_HAS_RTTI
diff --git a/grpc/third_party/abseil-cpp/absl/flags/flag.h b/grpc/third_party/abseil-cpp/absl/flags/flag.h
index a9cb2b7..f09580b 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/flag.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/flag.h
@@ -301,13 +301,15 @@
 #if ABSL_FLAGS_STRIP_NAMES
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
 #define ABSL_FLAG_IMPL_FILENAME() ""
-#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
-  absl::flags_internal::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(flag))
+#define ABSL_FLAG_IMPL_REGISTRAR(T, flag)                                      \
+  absl::flags_internal::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
+                                                nullptr)
 #else
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
 #define ABSL_FLAG_IMPL_FILENAME() __FILE__
-#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
-  absl::flags_internal::FlagRegistrar<T, true>(ABSL_FLAG_IMPL_FLAG_PTR(flag))
+#define ABSL_FLAG_IMPL_REGISTRAR(T, flag)                                     \
+  absl::flags_internal::FlagRegistrar<T, true>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
+                                               __FILE__)
 #endif
 
 // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP
diff --git a/grpc/third_party/abseil-cpp/absl/flags/flag_benchmark.cc b/grpc/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
index 7b52c9b..57584f8 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
@@ -20,6 +20,8 @@
 
 #include "absl/flags/flag.h"
 #include "absl/flags/marshalling.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/reflection.h"
 #include "absl/strings/string_view.h"
 #include "absl/time/time.h"
 #include "absl/types/optional.h"
@@ -101,7 +103,33 @@
 
 #define FLAG_DEF(T) ABSL_FLAG(T, T##_flag, {}, "");
 
+#if defined(__clang__) && defined(__linux__)
+// Force the flags used for benchmarks into a separate ELF section.
+// This ensures that, even when other parts of the code might change size,
+// the layout of the flags across cachelines is kept constant. This makes
+// benchmark results more reproducible across unrelated code changes.
+#pragma clang section data = ".benchmark_flags"
+#endif
 BENCHMARKED_TYPES(FLAG_DEF)
+#if defined(__clang__) && defined(__linux__)
+#pragma clang section data = ""
+#endif
+// Register thousands of flags to bloat up the size of the registry.
+// This mimics real life production binaries.
+#define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, "");
+#define DEFINE_FLAG_1(name) DEFINE_FLAG_0(name##0) DEFINE_FLAG_0(name##1)
+#define DEFINE_FLAG_2(name) DEFINE_FLAG_1(name##0) DEFINE_FLAG_1(name##1)
+#define DEFINE_FLAG_3(name) DEFINE_FLAG_2(name##0) DEFINE_FLAG_2(name##1)
+#define DEFINE_FLAG_4(name) DEFINE_FLAG_3(name##0) DEFINE_FLAG_3(name##1)
+#define DEFINE_FLAG_5(name) DEFINE_FLAG_4(name##0) DEFINE_FLAG_4(name##1)
+#define DEFINE_FLAG_6(name) DEFINE_FLAG_5(name##0) DEFINE_FLAG_5(name##1)
+#define DEFINE_FLAG_7(name) DEFINE_FLAG_6(name##0) DEFINE_FLAG_6(name##1)
+#define DEFINE_FLAG_8(name) DEFINE_FLAG_7(name##0) DEFINE_FLAG_7(name##1)
+#define DEFINE_FLAG_9(name) DEFINE_FLAG_8(name##0) DEFINE_FLAG_8(name##1)
+#define DEFINE_FLAG_10(name) DEFINE_FLAG_9(name##0) DEFINE_FLAG_9(name##1)
+#define DEFINE_FLAG_11(name) DEFINE_FLAG_10(name##0) DEFINE_FLAG_10(name##1)
+#define DEFINE_FLAG_12(name) DEFINE_FLAG_11(name##0) DEFINE_FLAG_11(name##1)
+DEFINE_FLAG_12(bloat_flag_);
 
 namespace {
 
@@ -111,10 +139,24 @@
       benchmark::DoNotOptimize(absl::GetFlag(FLAGS_##T##_flag)); \
     }                                                            \
   }                                                              \
-  BENCHMARK(BM_GetFlag_##T);
+  BENCHMARK(BM_GetFlag_##T)->ThreadRange(1, 16);
 
 BENCHMARKED_TYPES(BM_GetFlag)
 
+void BM_ThreadedFindCommandLineFlag(benchmark::State& state) {
+  char dummy[] = "dummy";
+  char* argv[] = {dummy};
+  // We need to ensure that flags have been parsed. That is where the registry
+  // is finalized.
+  absl::ParseCommandLine(1, argv);
+
+  for (auto s : state) {
+    benchmark::DoNotOptimize(
+        absl::FindCommandLineFlag("bloat_flag_010101010101"));
+  }
+}
+BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16);
+
 }  // namespace
 
 #define InvokeGetFlag(T)                                               \
diff --git a/grpc/third_party/abseil-cpp/absl/flags/flag_benchmark.lds b/grpc/third_party/abseil-cpp/absl/flags/flag_benchmark.lds
new file mode 100644
index 0000000..af115df
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/flags/flag_benchmark.lds
@@ -0,0 +1,13 @@
+/* This linker script forces the flags used by flags_benchmark
+ * into a separate page-aligned section. This isn't necessary for
+ * correctness but ensures that the benchmark results are more
+ * reproducible across unrelated code changes.
+ */
+SECTIONS {
+  .benchmark_flags : {
+    . = ALIGN(0x1000);
+    * (.benchmark_flags);
+  }
+}
+
+INSERT AFTER .data
diff --git a/grpc/third_party/abseil-cpp/absl/flags/flag_test.cc b/grpc/third_party/abseil-cpp/absl/flags/flag_test.cc
index 654c812..6912b54 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/flag_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/flag_test.cc
@@ -18,6 +18,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <atomic>
 #include <cmath>
 #include <new>
 #include <string>
@@ -26,6 +27,7 @@
 
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
+#include "absl/base/macros.h"
 #include "absl/flags/config.h"
 #include "absl/flags/declare.h"
 #include "absl/flags/internal/flag.h"
@@ -108,16 +110,16 @@
   EXPECT_EQ(flags::StorageKind<int64_t>(),
             flags::FlagValueStorageKind::kOneWordAtomic);
 
-#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)
   EXPECT_EQ(flags::StorageKind<S1>(),
-            flags::FlagValueStorageKind::kTwoWordsAtomic);
+            flags::FlagValueStorageKind::kSequenceLocked);
   EXPECT_EQ(flags::StorageKind<S2>(),
-            flags::FlagValueStorageKind::kTwoWordsAtomic);
-#else
-  EXPECT_EQ(flags::StorageKind<S1>(),
-            flags::FlagValueStorageKind::kAlignedBuffer);
-  EXPECT_EQ(flags::StorageKind<S2>(),
-            flags::FlagValueStorageKind::kAlignedBuffer);
+            flags::FlagValueStorageKind::kSequenceLocked);
+// Make sure absl::Duration uses the sequence-locked code path. MSVC 2015
+// doesn't consider absl::Duration to be trivially-copyable so we just
+// restrict this to clang as it seems to be a well-behaved compiler.
+#ifdef __clang__
+  EXPECT_EQ(flags::StorageKind<absl::Duration>(),
+            flags::FlagValueStorageKind::kSequenceLocked);
 #endif
 
   EXPECT_EQ(flags::StorageKind<std::string>(),
@@ -175,7 +177,7 @@
   EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help");
   EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file");
 
-  flags::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(f2))
+  flags::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(f2), nullptr)
       .OnUpdate(TestCallback);
 
   EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2");
@@ -583,6 +585,43 @@
 
 // --------------------------------------------------------------------
 
+TEST_F(FlagTest, ConcurrentSetAndGet) {
+  static constexpr int kNumThreads = 8;
+  // Two arbitrary durations. One thread will concurrently flip the flag
+  // between these two values, while the other threads read it and verify
+  // that no other value is seen.
+  static const absl::Duration kValidDurations[] = {
+      absl::Seconds(int64_t{0x6cebf47a9b68c802}) + absl::Nanoseconds(229702057),
+      absl::Seconds(int64_t{0x23fec0307e4e9d3}) + absl::Nanoseconds(44555374)};
+  absl::SetFlag(&FLAGS_test_flag_12, kValidDurations[0]);
+
+  std::atomic<bool> stop{false};
+  std::vector<std::thread> threads;
+  auto* handle = absl::FindCommandLineFlag("test_flag_12");
+  for (int i = 0; i < kNumThreads; i++) {
+    threads.emplace_back([&]() {
+      while (!stop.load(std::memory_order_relaxed)) {
+        // Try loading the flag both directly and via a reflection
+        // handle.
+        absl::Duration v = absl::GetFlag(FLAGS_test_flag_12);
+        EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]);
+        v = *handle->TryGet<absl::Duration>();
+        EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]);
+      }
+    });
+  }
+  absl::Time end_time = absl::Now() + absl::Seconds(1);
+  int i = 0;
+  while (absl::Now() < end_time) {
+    absl::SetFlag(&FLAGS_test_flag_12,
+                  kValidDurations[i++ % ABSL_ARRAYSIZE(kValidDurations)]);
+  }
+  stop.store(true, std::memory_order_relaxed);
+  for (auto& t : threads) t.join();
+}
+
+// --------------------------------------------------------------------
+
 int GetDflt1() { return 1; }
 
 }  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h b/grpc/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h
index cb46fe2..ebfe81b 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h
@@ -24,7 +24,7 @@
 namespace flags_internal {
 
 // An alias for flag fast type id. This value identifies the flag value type
-// simialarly to typeid(T), without relying on RTTI being available. In most
+// similarly to typeid(T), without relying on RTTI being available. In most
 // cases this id is enough to uniquely identify the flag's value type. In a few
 // cases we'll have to resort to using actual RTTI implementation if it is
 // available.
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/flag.cc b/grpc/third_party/abseil-cpp/absl/flags/internal/flag.cc
index 1502e7f..f83c1fe 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/internal/flag.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/flag.cc
@@ -96,7 +96,8 @@
         counter_(counter) {}
 
   ~FlagState() override {
-    if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer)
+    if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer &&
+        flag_impl_.ValueStorageKind() != FlagValueStorageKind::kSequenceLocked)
       return;
     flags_internal::Delete(flag_impl_.op_, value_.heap_allocated);
   }
@@ -118,11 +119,9 @@
   union SavedValue {
     explicit SavedValue(void* v) : heap_allocated(v) {}
     explicit SavedValue(int64_t v) : one_word(v) {}
-    explicit SavedValue(flags_internal::AlignedTwoWords v) : two_words(v) {}
 
     void* heap_allocated;
     int64_t one_word;
-    flags_internal::AlignedTwoWords two_words;
   } value_;
   bool modified_;
   bool on_command_line_;
@@ -164,17 +163,15 @@
                            std::memory_order_release);
       break;
     }
-    case FlagValueStorageKind::kTwoWordsAtomic: {
+    case FlagValueStorageKind::kSequenceLocked: {
       // For this storage kind the default_value_ always points to gen_func
       // during initialization.
       assert(def_kind == FlagDefaultKind::kGenFunc);
-      alignas(AlignedTwoWords) std::array<char, sizeof(AlignedTwoWords)> buf{};
-      (*default_value_.gen_func)(buf.data());
-      auto atomic_value = absl::bit_cast<AlignedTwoWords>(buf);
-      TwoWordsValue().store(atomic_value, std::memory_order_release);
+      (*default_value_.gen_func)(AtomicBufferValue());
       break;
     }
   }
+  seq_lock_.MarkInitialized();
 }
 
 absl::Mutex* FlagImpl::DataGuard() const {
@@ -231,23 +228,21 @@
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kAlignedBuffer:
       Copy(op_, src, AlignedBufferValue());
+      seq_lock_.IncrementModificationCount();
       break;
     case FlagValueStorageKind::kOneWordAtomic: {
       int64_t one_word_val = 0;
       std::memcpy(&one_word_val, src, Sizeof(op_));
       OneWordValue().store(one_word_val, std::memory_order_release);
+      seq_lock_.IncrementModificationCount();
       break;
     }
-    case FlagValueStorageKind::kTwoWordsAtomic: {
-      AlignedTwoWords two_words_val{0, 0};
-      std::memcpy(&two_words_val, src, Sizeof(op_));
-      TwoWordsValue().store(two_words_val, std::memory_order_release);
+    case FlagValueStorageKind::kSequenceLocked: {
+      seq_lock_.Write(AtomicBufferValue(), src, Sizeof(op_));
       break;
     }
   }
-
   modified_ = true;
-  ++counter_;
   InvokeCallback();
 }
 
@@ -266,6 +261,10 @@
   return flags_internal::FastTypeId(op_);
 }
 
+int64_t FlagImpl::ModificationCount() const {
+  return seq_lock_.ModificationCount();
+}
+
 bool FlagImpl::IsSpecifiedOnCommandLine() const {
   absl::MutexLock l(DataGuard());
   return on_command_line_;
@@ -291,11 +290,11 @@
               OneWordValue().load(std::memory_order_acquire));
       return flags_internal::Unparse(op_, one_word_val.data());
     }
-    case FlagValueStorageKind::kTwoWordsAtomic: {
-      const auto two_words_val =
-          absl::bit_cast<std::array<char, sizeof(AlignedTwoWords)>>(
-              TwoWordsValue().load(std::memory_order_acquire));
-      return flags_internal::Unparse(op_, two_words_val.data());
+    case FlagValueStorageKind::kSequenceLocked: {
+      std::unique_ptr<void, DynValueDeleter> cloned(flags_internal::Alloc(op_),
+                                                    DynValueDeleter{op_});
+      ReadSequenceLockedData(cloned.get());
+      return flags_internal::Unparse(op_, cloned.get());
     }
   }
 
@@ -345,17 +344,22 @@
     case FlagValueStorageKind::kAlignedBuffer: {
       return absl::make_unique<FlagState>(
           *this, flags_internal::Clone(op_, AlignedBufferValue()), modified,
-          on_command_line, counter_);
+          on_command_line, ModificationCount());
     }
     case FlagValueStorageKind::kOneWordAtomic: {
       return absl::make_unique<FlagState>(
           *this, OneWordValue().load(std::memory_order_acquire), modified,
-          on_command_line, counter_);
+          on_command_line, ModificationCount());
     }
-    case FlagValueStorageKind::kTwoWordsAtomic: {
-      return absl::make_unique<FlagState>(
-          *this, TwoWordsValue().load(std::memory_order_acquire), modified,
-          on_command_line, counter_);
+    case FlagValueStorageKind::kSequenceLocked: {
+      void* cloned = flags_internal::Alloc(op_);
+      // Read is guaranteed to be successful because we hold the lock.
+      bool success =
+          seq_lock_.TryRead(cloned, AtomicBufferValue(), Sizeof(op_));
+      assert(success);
+      static_cast<void>(success);
+      return absl::make_unique<FlagState>(*this, cloned, modified,
+                                          on_command_line, ModificationCount());
     }
   }
   return nullptr;
@@ -363,21 +367,18 @@
 
 bool FlagImpl::RestoreState(const FlagState& flag_state) {
   absl::MutexLock l(DataGuard());
-
-  if (flag_state.counter_ == counter_) {
+  if (flag_state.counter_ == ModificationCount()) {
     return false;
   }
 
   switch (ValueStorageKind()) {
     case FlagValueStorageKind::kAlignedBuffer:
+    case FlagValueStorageKind::kSequenceLocked:
       StoreValue(flag_state.value_.heap_allocated);
       break;
     case FlagValueStorageKind::kOneWordAtomic:
       StoreValue(&flag_state.value_.one_word);
       break;
-    case FlagValueStorageKind::kTwoWordsAtomic:
-      StoreValue(&flag_state.value_.two_words);
-      break;
   }
 
   modified_ = flag_state.modified_;
@@ -400,16 +401,16 @@
   return OffsetValue<void>();
 }
 
+std::atomic<uint64_t>* FlagImpl::AtomicBufferValue() const {
+  assert(ValueStorageKind() == FlagValueStorageKind::kSequenceLocked);
+  return OffsetValue<std::atomic<uint64_t>>();
+}
+
 std::atomic<int64_t>& FlagImpl::OneWordValue() const {
   assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic);
   return OffsetValue<FlagOneWordValue>()->value;
 }
 
-std::atomic<AlignedTwoWords>& FlagImpl::TwoWordsValue() const {
-  assert(ValueStorageKind() == FlagValueStorageKind::kTwoWordsAtomic);
-  return OffsetValue<FlagTwoWordsValue>()->value;
-}
-
 // Attempts to parse supplied `value` string using parsing routine in the `flag`
 // argument. If parsing successful, this function replaces the dst with newly
 // parsed value. In case if any error is encountered in either step, the error
@@ -443,15 +444,27 @@
       std::memcpy(dst, &one_word_val, Sizeof(op_));
       break;
     }
-    case FlagValueStorageKind::kTwoWordsAtomic: {
-      const AlignedTwoWords two_words_val =
-          TwoWordsValue().load(std::memory_order_acquire);
-      std::memcpy(dst, &two_words_val, Sizeof(op_));
+    case FlagValueStorageKind::kSequenceLocked: {
+      ReadSequenceLockedData(dst);
       break;
     }
   }
 }
 
+void FlagImpl::ReadSequenceLockedData(void* dst) const {
+  int size = Sizeof(op_);
+  // Attempt to read using the sequence lock.
+  if (ABSL_PREDICT_TRUE(seq_lock_.TryRead(dst, AtomicBufferValue(), size))) {
+    return;
+  }
+  // We failed due to contention. Acquire the lock to prevent contention
+  // and try again.
+  absl::ReaderMutexLock l(DataGuard());
+  bool success = seq_lock_.TryRead(dst, AtomicBufferValue(), size);
+  assert(success);
+  static_cast<void>(success);
+}
+
 void FlagImpl::Write(const void* src) {
   absl::MutexLock l(DataGuard());
 
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/flag.h b/grpc/third_party/abseil-cpp/absl/flags/internal/flag.h
index 370d8a0..e6bade0 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/internal/flag.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/flag.h
@@ -36,6 +36,7 @@
 #include "absl/flags/config.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
+#include "absl/flags/internal/sequence_lock.h"
 #include "absl/flags/marshalling.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/string_view.h"
@@ -308,59 +309,23 @@
     bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&
               (sizeof(T) <= 8)>;
 
-#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)
-// Clang does not always produce cmpxchg16b instruction when alignment of a 16
-// bytes type is not 16.
-struct alignas(16) AlignedTwoWords {
-  int64_t first;
-  int64_t second;
-
-  bool IsInitialized() const {
-    return first != flags_internal::UninitializedFlagValue();
-  }
-};
-
-template <typename T>
-using FlagUseTwoWordsStorage = std::integral_constant<
+template <class T>
+using FlagShouldUseSequenceLock = std::integral_constant<
     bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&
-              (sizeof(T) > 8) && (sizeof(T) <= 16)>;
-#else
-// This is actually unused and only here to avoid ifdefs in other palces.
-struct AlignedTwoWords {
-  constexpr AlignedTwoWords() noexcept : dummy() {}
-  constexpr AlignedTwoWords(int64_t, int64_t) noexcept : dummy() {}
-  char dummy;
-
-  bool IsInitialized() const {
-    std::abort();
-    return true;
-  }
-};
-
-// This trait should be type dependent, otherwise SFINAE below will fail
-template <typename T>
-using FlagUseTwoWordsStorage =
-    std::integral_constant<bool, sizeof(T) != sizeof(T)>;
-#endif
-
-template <typename T>
-using FlagUseBufferStorage =
-    std::integral_constant<bool, !FlagUseOneWordStorage<T>::value &&
-                                     !FlagUseTwoWordsStorage<T>::value>;
+              (sizeof(T) > 8)>;
 
 enum class FlagValueStorageKind : uint8_t {
   kAlignedBuffer = 0,
   kOneWordAtomic = 1,
-  kTwoWordsAtomic = 2
+  kSequenceLocked = 2,
 };
 
 template <typename T>
 static constexpr FlagValueStorageKind StorageKind() {
-  return FlagUseBufferStorage<T>::value
-             ? FlagValueStorageKind::kAlignedBuffer
-             : FlagUseOneWordStorage<T>::value
-                   ? FlagValueStorageKind::kOneWordAtomic
-                   : FlagValueStorageKind::kTwoWordsAtomic;
+  return FlagUseOneWordStorage<T>::value ? FlagValueStorageKind::kOneWordAtomic
+         : FlagShouldUseSequenceLock<T>::value
+             ? FlagValueStorageKind::kSequenceLocked
+             : FlagValueStorageKind::kAlignedBuffer;
 }
 
 struct FlagOneWordValue {
@@ -369,27 +334,20 @@
   std::atomic<int64_t> value;
 };
 
-struct FlagTwoWordsValue {
-  constexpr FlagTwoWordsValue()
-      : value(AlignedTwoWords{UninitializedFlagValue(), 0}) {}
-
-  std::atomic<AlignedTwoWords> value;
-};
-
 template <typename T,
           FlagValueStorageKind Kind = flags_internal::StorageKind<T>()>
 struct FlagValue;
 
 template <typename T>
 struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> {
-  bool Get(T&) const { return false; }
+  bool Get(const SequenceLock&, T&) const { return false; }
 
   alignas(T) char value[sizeof(T)];
 };
 
 template <typename T>
 struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue {
-  bool Get(T& dst) const {
+  bool Get(const SequenceLock&, T& dst) const {
     int64_t one_word_val = value.load(std::memory_order_acquire);
     if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) {
       return false;
@@ -400,15 +358,16 @@
 };
 
 template <typename T>
-struct FlagValue<T, FlagValueStorageKind::kTwoWordsAtomic> : FlagTwoWordsValue {
-  bool Get(T& dst) const {
-    AlignedTwoWords two_words_val = value.load(std::memory_order_acquire);
-    if (ABSL_PREDICT_FALSE(!two_words_val.IsInitialized())) {
-      return false;
-    }
-    std::memcpy(&dst, static_cast<const void*>(&two_words_val), sizeof(T));
-    return true;
+struct FlagValue<T, FlagValueStorageKind::kSequenceLocked> {
+  bool Get(const SequenceLock& lock, T& dst) const {
+    return lock.TryRead(&dst, value_words, sizeof(T));
   }
+
+  static constexpr int kNumWords =
+      flags_internal::AlignUp(sizeof(T), sizeof(uint64_t)) / sizeof(uint64_t);
+
+  alignas(T) alignas(
+      std::atomic<uint64_t>) std::atomic<uint64_t> value_words[kNumWords];
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -451,7 +410,6 @@
         def_kind_(static_cast<uint8_t>(default_arg.kind)),
         modified_(false),
         on_command_line_(false),
-        counter_(0),
         callback_(nullptr),
         default_value_(default_arg.source),
         data_guard_{} {}
@@ -498,15 +456,17 @@
   // flag.cc, we can define it in that file as well.
   template <typename StorageT>
   StorageT* OffsetValue() const;
-  // This is an accessor for a value stored in an aligned buffer storage.
+  // This is an accessor for a value stored in an aligned buffer storage
+  // used for non-trivially-copyable data types.
   // Returns a mutable pointer to the start of a buffer.
   void* AlignedBufferValue() const;
+
+  // The same as above, but used for sequencelock-protected storage.
+  std::atomic<uint64_t>* AtomicBufferValue() const;
+
   // This is an accessor for a value stored as one word atomic. Returns a
   // mutable reference to an atomic value.
   std::atomic<int64_t>& OneWordValue() const;
-  // This is an accessor for a value stored as two words atomic. Returns a
-  // mutable reference to an atomic value.
-  std::atomic<AlignedTwoWords>& TwoWordsValue() const;
 
   // Attempts to parse supplied `value` string. If parsing is successful,
   // returns new value. Otherwise returns nullptr.
@@ -516,6 +476,12 @@
   // Stores the flag value based on the pointer to the source.
   void StoreValue(const void* src) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
 
+  // Copy the flag data, protected by `seq_lock_` into `dst`.
+  //
+  // REQUIRES: ValueStorageKind() == kSequenceLocked.
+  void ReadSequenceLockedData(void* dst) const
+      ABSL_LOCKS_EXCLUDED(*DataGuard());
+
   FlagHelpKind HelpSourceKind() const {
     return static_cast<FlagHelpKind>(help_source_kind_);
   }
@@ -541,6 +507,8 @@
   void CheckDefaultValueParsingRoundtrip() const override
       ABSL_LOCKS_EXCLUDED(*DataGuard());
 
+  int64_t ModificationCount() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+
   // Interfaces to save and restore flags to/from persistent state.
   // Returns current flag state or nullptr if flag does not support
   // saving and restoring a state.
@@ -587,8 +555,9 @@
   // Unique tag for absl::call_once call to initialize this flag.
   absl::once_flag init_control_;
 
-  // Mutation counter
-  int64_t counter_ ABSL_GUARDED_BY(*DataGuard());
+  // Sequence lock / mutation counter.
+  flags_internal::SequenceLock seq_lock_;
+
   // Optional flag's callback and absl::Mutex to guard the invocations.
   FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard());
   // Either a pointer to the function generating the default value based on the
@@ -649,7 +618,9 @@
     impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
 #endif
 
-    if (!value_.Get(u.value)) impl_.Read(&u.value);
+    if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) {
+      impl_.Read(&u.value);
+    }
     return std::move(u.value);
   }
   void Set(const T& v) {
@@ -750,8 +721,9 @@
 template <typename T, bool do_register>
 class FlagRegistrar {
  public:
-  explicit FlagRegistrar(Flag<T>& flag) : flag_(flag) {
-    if (do_register) flags_internal::RegisterCommandLineFlag(flag_.impl_);
+  explicit FlagRegistrar(Flag<T>& flag, const char* filename) : flag_(flag) {
+    if (do_register)
+      flags_internal::RegisterCommandLineFlag(flag_.impl_, filename);
   }
 
   FlagRegistrar OnUpdate(FlagCallbackFunc cb) && {
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/registry.h b/grpc/third_party/abseil-cpp/absl/flags/internal/registry.h
index 1df2db7..4b68c85 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/internal/registry.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/registry.h
@@ -30,16 +30,15 @@
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 
-// Executes specified visitor for each non-retired flag in the registry.
-// Requires the caller hold the registry lock.
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor);
 // Executes specified visitor for each non-retired flag in the registry. While
 // callback are executed, the registry is locked and can't be changed.
 void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
 
 //-----------------------------------------------------------------------------
 
-bool RegisterCommandLineFlag(CommandLineFlag&);
+bool RegisterCommandLineFlag(CommandLineFlag&, const char* filename);
+
+void FinalizeRegistry();
 
 //-----------------------------------------------------------------------------
 // Retired registrations:
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/sequence_lock.h b/grpc/third_party/abseil-cpp/absl/flags/internal/sequence_lock.h
new file mode 100644
index 0000000..807b2a7
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/sequence_lock.h
@@ -0,0 +1,187 @@
+//
+// Copyright 2020 The Abseil 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
+//
+//      https://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 ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
+#define ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <atomic>
+#include <cassert>
+#include <cstring>
+
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+// Align 'x' up to the nearest 'align' bytes.
+inline constexpr size_t AlignUp(size_t x, size_t align) {
+  return align * ((x + align - 1) / align);
+}
+
+// A SequenceLock implements lock-free reads. A sequence counter is incremented
+// before and after each write, and readers access the counter before and after
+// accessing the protected data. If the counter is verified to not change during
+// the access, and the sequence counter value was even, then the reader knows
+// that the read was race-free and valid. Otherwise, the reader must fall back
+// to a Mutex-based code path.
+//
+// This particular SequenceLock starts in an "uninitialized" state in which
+// TryRead() returns false. It must be enabled by calling MarkInitialized().
+// This serves as a marker that the associated flag value has not yet been
+// initialized and a slow path needs to be taken.
+//
+// The memory reads and writes protected by this lock must use the provided
+// `TryRead()` and `Write()` functions. These functions behave similarly to
+// `memcpy()`, with one oddity: the protected data must be an array of
+// `std::atomic<int64>`. This is to comply with the C++ standard, which
+// considers data races on non-atomic objects to be undefined behavior. See "Can
+// Seqlocks Get Along With Programming Language Memory Models?"[1] by Hans J.
+// Boehm for more details.
+//
+// [1] https://www.hpl.hp.com/techreports/2012/HPL-2012-68.pdf
+class SequenceLock {
+ public:
+  constexpr SequenceLock() : lock_(kUninitialized) {}
+
+  // Mark that this lock is ready for use.
+  void MarkInitialized() {
+    assert(lock_.load(std::memory_order_relaxed) == kUninitialized);
+    lock_.store(0, std::memory_order_release);
+  }
+
+  // Copy "size" bytes of data from "src" to "dst", protected as a read-side
+  // critical section of the sequence lock.
+  //
+  // Unlike traditional sequence lock implementations which loop until getting a
+  // clean read, this implementation returns false in the case of concurrent
+  // calls to `Write`. In such a case, the caller should fall back to a
+  // locking-based slow path.
+  //
+  // Returns false if the sequence lock was not yet marked as initialized.
+  //
+  // NOTE: If this returns false, "dst" may be overwritten with undefined
+  // (potentially uninitialized) data.
+  bool TryRead(void* dst, const std::atomic<uint64_t>* src, size_t size) const {
+    // Acquire barrier ensures that no loads done by f() are reordered
+    // above the first load of the sequence counter.
+    int64_t seq_before = lock_.load(std::memory_order_acquire);
+    if (ABSL_PREDICT_FALSE(seq_before & 1) == 1) return false;
+    RelaxedCopyFromAtomic(dst, src, size);
+    // Another acquire fence ensures that the load of 'lock_' below is
+    // strictly ordered after the RelaxedCopyToAtomic call above.
+    std::atomic_thread_fence(std::memory_order_acquire);
+    int64_t seq_after = lock_.load(std::memory_order_relaxed);
+    return ABSL_PREDICT_TRUE(seq_before == seq_after);
+  }
+
+  // Copy "size" bytes from "src" to "dst" as a write-side critical section
+  // of the sequence lock. Any concurrent readers will be forced to retry
+  // until they get a read that does not conflict with this write.
+  //
+  // This call must be externally synchronized against other calls to Write,
+  // but may proceed concurrently with reads.
+  void Write(std::atomic<uint64_t>* dst, const void* src, size_t size) {
+    // We can use relaxed instructions to increment the counter since we
+    // are extenally synchronized. The std::atomic_thread_fence below
+    // ensures that the counter updates don't get interleaved with the
+    // copy to the data.
+    int64_t orig_seq = lock_.load(std::memory_order_relaxed);
+    assert((orig_seq & 1) == 0);  // Must be initially unlocked.
+    lock_.store(orig_seq + 1, std::memory_order_relaxed);
+
+    // We put a release fence between update to lock_ and writes to shared data.
+    // Thus all stores to shared data are effectively release operations and
+    // update to lock_ above cannot be re-ordered past any of them. Note that
+    // this barrier is not for the fetch_add above.  A release barrier for the
+    // fetch_add would be before it, not after.
+    std::atomic_thread_fence(std::memory_order_release);
+    RelaxedCopyToAtomic(dst, src, size);
+    // "Release" semantics ensure that none of the writes done by
+    // RelaxedCopyToAtomic() can be reordered after the following modification.
+    lock_.store(orig_seq + 2, std::memory_order_release);
+  }
+
+  // Return the number of times that Write() has been called.
+  //
+  // REQUIRES: This must be externally synchronized against concurrent calls to
+  // `Write()` or `IncrementModificationCount()`.
+  // REQUIRES: `MarkInitialized()` must have been previously called.
+  int64_t ModificationCount() const {
+    int64_t val = lock_.load(std::memory_order_relaxed);
+    assert(val != kUninitialized && (val & 1) == 0);
+    return val / 2;
+  }
+
+  // REQUIRES: This must be externally synchronized against concurrent calls to
+  // `Write()` or `ModificationCount()`.
+  // REQUIRES: `MarkInitialized()` must have been previously called.
+  void IncrementModificationCount() {
+    int64_t val = lock_.load(std::memory_order_relaxed);
+    assert(val != kUninitialized);
+    lock_.store(val + 2, std::memory_order_relaxed);
+  }
+
+ private:
+  // Perform the equivalent of "memcpy(dst, src, size)", but using relaxed
+  // atomics.
+  static void RelaxedCopyFromAtomic(void* dst, const std::atomic<uint64_t>* src,
+                                    size_t size) {
+    char* dst_byte = static_cast<char*>(dst);
+    while (size >= sizeof(uint64_t)) {
+      uint64_t word = src->load(std::memory_order_relaxed);
+      std::memcpy(dst_byte, &word, sizeof(word));
+      dst_byte += sizeof(word);
+      src++;
+      size -= sizeof(word);
+    }
+    if (size > 0) {
+      uint64_t word = src->load(std::memory_order_relaxed);
+      std::memcpy(dst_byte, &word, size);
+    }
+  }
+
+  // Perform the equivalent of "memcpy(dst, src, size)", but using relaxed
+  // atomics.
+  static void RelaxedCopyToAtomic(std::atomic<uint64_t>* dst, const void* src,
+                                  size_t size) {
+    const char* src_byte = static_cast<const char*>(src);
+    while (size >= sizeof(uint64_t)) {
+      uint64_t word;
+      std::memcpy(&word, src_byte, sizeof(word));
+      dst->store(word, std::memory_order_relaxed);
+      src_byte += sizeof(word);
+      dst++;
+      size -= sizeof(word);
+    }
+    if (size > 0) {
+      uint64_t word = 0;
+      std::memcpy(&word, src_byte, size);
+      dst->store(word, std::memory_order_relaxed);
+    }
+  }
+
+  static constexpr int64_t kUninitialized = -1;
+  std::atomic<int64_t> lock_;
+};
+
+}  // namespace flags_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/sequence_lock_test.cc b/grpc/third_party/abseil-cpp/absl/flags/internal/sequence_lock_test.cc
new file mode 100644
index 0000000..c3ec372
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/sequence_lock_test.cc
@@ -0,0 +1,169 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/flags/internal/sequence_lock.h"
+
+#include <algorithm>
+#include <atomic>
+#include <thread>  // NOLINT(build/c++11)
+#include <tuple>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/container/fixed_array.h"
+#include "absl/time/clock.h"
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class ConcurrentSequenceLockTest
+    : public testing::TestWithParam<std::tuple<int, int>> {
+ public:
+  ConcurrentSequenceLockTest()
+      : buf_bytes_(std::get<0>(GetParam())),
+        num_threads_(std::get<1>(GetParam())) {}
+
+ protected:
+  const int buf_bytes_;
+  const int num_threads_;
+};
+
+TEST_P(ConcurrentSequenceLockTest, ReadAndWrite) {
+  const int buf_words =
+      flags::AlignUp(buf_bytes_, sizeof(uint64_t)) / sizeof(uint64_t);
+
+  // The buffer that will be protected by the SequenceLock.
+  absl::FixedArray<std::atomic<uint64_t>> protected_buf(buf_words);
+  for (auto& v : protected_buf) v = -1;
+
+  flags::SequenceLock seq_lock;
+  std::atomic<bool> stop{false};
+  std::atomic<int64_t> bad_reads{0};
+  std::atomic<int64_t> good_reads{0};
+  std::atomic<int64_t> unsuccessful_reads{0};
+
+  // Start a bunch of threads which read 'protected_buf' under the sequence
+  // lock. The main thread will concurrently update 'protected_buf'. The updates
+  // always consist of an array of identical integers. The reader ensures that
+  // any data it reads matches that pattern (i.e. the reads are not "torn").
+  std::vector<std::thread> threads;
+  for (int i = 0; i < num_threads_; i++) {
+    threads.emplace_back([&]() {
+      absl::FixedArray<char> local_buf(buf_bytes_);
+      while (!stop.load(std::memory_order_relaxed)) {
+        if (seq_lock.TryRead(local_buf.data(), protected_buf.data(),
+                             buf_bytes_)) {
+          bool good = true;
+          for (const auto& v : local_buf) {
+            if (v != local_buf[0]) good = false;
+          }
+          if (good) {
+            good_reads.fetch_add(1, std::memory_order_relaxed);
+          } else {
+            bad_reads.fetch_add(1, std::memory_order_relaxed);
+          }
+        } else {
+          unsuccessful_reads.fetch_add(1, std::memory_order_relaxed);
+        }
+      }
+    });
+  }
+  while (unsuccessful_reads.load(std::memory_order_relaxed) < num_threads_) {
+    absl::SleepFor(absl::Milliseconds(1));
+  }
+  seq_lock.MarkInitialized();
+
+  // Run a maximum of 5 seconds. On Windows, the scheduler behavior seems
+  // somewhat unfair and without an explicit timeout for this loop, the tests
+  // can run a long time.
+  absl::Time deadline = absl::Now() + absl::Seconds(5);
+  for (int i = 0; i < 100 && absl::Now() < deadline; i++) {
+    absl::FixedArray<char> writer_buf(buf_bytes_);
+    for (auto& v : writer_buf) v = i;
+    seq_lock.Write(protected_buf.data(), writer_buf.data(), buf_bytes_);
+    absl::SleepFor(absl::Microseconds(10));
+  }
+  stop.store(true, std::memory_order_relaxed);
+  for (auto& t : threads) t.join();
+  ASSERT_GE(good_reads, 0);
+  ASSERT_EQ(bad_reads, 0);
+}
+
+// Simple helper for generating a range of thread counts.
+// Generates [low, low*scale, low*scale^2, ...high)
+// (even if high is between low*scale^k and low*scale^(k+1)).
+std::vector<int> MultiplicativeRange(int low, int high, int scale) {
+  std::vector<int> result;
+  for (int current = low; current < high; current *= scale) {
+    result.push_back(current);
+  }
+  result.push_back(high);
+  return result;
+}
+
+#ifndef ABSL_HAVE_THREAD_SANITIZER
+const int kMaxThreads = absl::base_internal::NumCPUs();
+#else
+// With TSAN, a lot of threads contending for atomic access on the sequence
+// lock make this test run too slowly.
+const int kMaxThreads = std::min(absl::base_internal::NumCPUs(), 4);
+#endif
+
+// Return all of the interesting buffer sizes worth testing:
+// powers of two and adjacent values.
+std::vector<int> InterestingBufferSizes() {
+  std::vector<int> ret;
+  for (int v : MultiplicativeRange(1, 128, 2)) {
+    ret.push_back(v);
+    if (v > 1) {
+      ret.push_back(v - 1);
+    }
+    ret.push_back(v + 1);
+  }
+  return ret;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    TestManyByteSizes, ConcurrentSequenceLockTest,
+    testing::Combine(
+        // Buffer size (bytes).
+        testing::ValuesIn(InterestingBufferSizes()),
+        // Number of reader threads.
+        testing::ValuesIn(MultiplicativeRange(1, kMaxThreads, 2))));
+
+// Simple single-threaded test, parameterized by the size of the buffer to be
+// protected.
+class SequenceLockTest : public testing::TestWithParam<int> {};
+
+TEST_P(SequenceLockTest, SingleThreaded) {
+  const int size = GetParam();
+  absl::FixedArray<std::atomic<uint64_t>> protected_buf(
+      flags::AlignUp(size, sizeof(uint64_t)) / sizeof(uint64_t));
+
+  flags::SequenceLock seq_lock;
+  seq_lock.MarkInitialized();
+
+  std::vector<char> src_buf(size, 'x');
+  seq_lock.Write(protected_buf.data(), src_buf.data(), size);
+
+  std::vector<char> dst_buf(size, '0');
+  ASSERT_TRUE(seq_lock.TryRead(dst_buf.data(), protected_buf.data(), size));
+  ASSERT_EQ(src_buf, dst_buf);
+}
+INSTANTIATE_TEST_SUITE_P(TestManyByteSizes, SequenceLockTest,
+                         // Buffer size (bytes).
+                         testing::Range(1, 128));
+
+}  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/usage.cc b/grpc/third_party/abseil-cpp/absl/flags/internal/usage.cc
index 0805df3..a588c7f 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/internal/usage.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/usage.cc
@@ -37,26 +37,26 @@
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
 
-ABSL_FLAG(bool, help, false,
-          "show help on important flags for this binary [tip: all flags can "
-          "have two dashes]");
-ABSL_FLAG(bool, helpfull, false, "show help on all flags");
-ABSL_FLAG(bool, helpshort, false,
-          "show help on only the main module for this program");
-ABSL_FLAG(bool, helppackage, false,
-          "show help on all modules in the main package");
-ABSL_FLAG(bool, version, false, "show version and build info and exit");
-ABSL_FLAG(bool, only_check_args, false, "exit after checking all flags");
-ABSL_FLAG(std::string, helpon, "",
-          "show help on the modules named by this flag value");
-ABSL_FLAG(std::string, helpmatch, "",
-          "show help on modules whose name contains the specified substr");
+// Dummy global variables to prevent anyone else defining these.
+bool FLAGS_help = false;
+bool FLAGS_helpfull = false;
+bool FLAGS_helpshort = false;
+bool FLAGS_helppackage = false;
+bool FLAGS_version = false;
+bool FLAGS_only_check_args = false;
+bool FLAGS_helpon = false;
+bool FLAGS_helpmatch = false;
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 namespace {
 
+using PerFlagFilter = std::function<bool(const absl::CommandLineFlag&)>;
+
+// Maximum length size in a human readable format.
+constexpr size_t kHrfMaxLineLength = 80;
+
 // This class is used to emit an XML element with `tag` and `text`.
 // It adds opening and closing tags and escapes special characters in the text.
 // For example:
@@ -109,9 +109,12 @@
  public:
   // Pretty printer holds on to the std::ostream& reference to direct an output
   // to that stream.
-  FlagHelpPrettyPrinter(int max_line_len, std::ostream& out)
+  FlagHelpPrettyPrinter(size_t max_line_len, size_t min_line_len,
+                        size_t wrapped_line_indent, std::ostream& out)
       : out_(out),
         max_line_len_(max_line_len),
+        min_line_len_(min_line_len),
+        wrapped_line_indent_(wrapped_line_indent),
         line_len_(0),
         first_line_(true) {}
 
@@ -145,7 +148,8 @@
       }
 
       // Write the token, ending the string first if necessary/possible.
-      if (!new_line && (line_len_ + token.size() >= max_line_len_)) {
+      if (!new_line &&
+          (line_len_ + static_cast<int>(token.size()) >= max_line_len_)) {
         EndLine();
         new_line = true;
       }
@@ -164,13 +168,12 @@
 
   void StartLine() {
     if (first_line_) {
-      out_ << "    ";
-      line_len_ = 4;
+      line_len_ = min_line_len_;
       first_line_ = false;
     } else {
-      out_ << "      ";
-      line_len_ = 6;
+      line_len_ = min_line_len_ + wrapped_line_indent_;
     }
+    out_ << std::string(line_len_, ' ');
   }
   void EndLine() {
     out_ << '\n';
@@ -179,13 +182,15 @@
 
  private:
   std::ostream& out_;
-  const int max_line_len_;
-  int line_len_;
+  const size_t max_line_len_;
+  const size_t min_line_len_;
+  const size_t wrapped_line_indent_;
+  size_t line_len_;
   bool first_line_;
 };
 
 void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) {
-  FlagHelpPrettyPrinter printer(80, out);  // Max line length is 80.
+  FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 4, 2, out);
 
   // Flag name.
   printer.Write(absl::StrCat("--", flag.Name()));
@@ -221,7 +226,7 @@
 // If a flag's help message has been stripped (e.g. by adding '#define
 // STRIP_FLAG_HELP 1' then this flag will not be displayed by '--help'
 // and its variants.
-void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
+void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb,
                    HelpFormat format, absl::string_view program_usage_message) {
   if (format == HelpFormat::kHumanReadable) {
     out << flags_internal::ShortProgramInvocationName() << ": "
@@ -256,10 +261,10 @@
     // If the flag has been stripped, pretend that it doesn't exist.
     if (flag.Help() == flags_internal::kStrippedFlagHelp) return;
 
-    std::string flag_filename = flag.Filename();
-
     // Make sure flag satisfies the filter
-    if (!filter_cb || !filter_cb(flag_filename)) return;
+    if (!filter_cb(flag)) return;
+
+    std::string flag_filename = flag.Filename();
 
     matching_flags[std::string(flags_internal::Package(flag_filename))]
                   [flag_filename]
@@ -289,15 +294,34 @@
   }
 
   if (format == HelpFormat::kHumanReadable) {
+    FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 0, 0, out);
+
     if (filter_cb && matching_flags.empty()) {
-      out << "  No modules matched: use -helpfull\n";
+      printer.Write("No flags matched.\n", true);
     }
+    printer.EndLine();
+    printer.Write(
+        "Try --helpfull to get a list of all flags or --help=substring "
+        "shows help for flags which include specified substring in either "
+        "in the name, or description or path.\n",
+        true);
   } else {
     // The end of the document.
     out << "</AllFlags>\n";
   }
 }
 
+void FlagsHelpImpl(std::ostream& out,
+                   flags_internal::FlagKindFilter filename_filter_cb,
+                   HelpFormat format, absl::string_view program_usage_message) {
+  FlagsHelpImpl(
+      out,
+      [&](const absl::CommandLineFlag& flag) {
+        return filename_filter_cb && filename_filter_cb(flag.Filename());
+      },
+      format, program_usage_message);
+}
+
 }  // namespace
 
 // --------------------------------------------------------------------
@@ -309,7 +333,7 @@
 }
 
 // --------------------------------------------------------------------
-// Produces the help messages for all flags matching the filter.
+// Produces the help messages for all flags matching the filename filter.
 // If filter is empty produces help messages for all flags.
 void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
                absl::string_view program_usage_message) {
@@ -324,68 +348,171 @@
 // If so, handles them appropriately.
 int HandleUsageFlags(std::ostream& out,
                      absl::string_view program_usage_message) {
-  if (absl::GetFlag(FLAGS_helpshort)) {
-    flags_internal::FlagsHelpImpl(
-        out, flags_internal::GetUsageConfig().contains_helpshort_flags,
-        HelpFormat::kHumanReadable, program_usage_message);
-    return 1;
-  }
+  switch (GetFlagsHelpMode()) {
+    case HelpMode::kNone:
+      break;
+    case HelpMode::kImportant:
+      flags_internal::FlagsHelpImpl(
+          out, flags_internal::GetUsageConfig().contains_help_flags,
+          GetFlagsHelpFormat(), program_usage_message);
+      return 1;
 
-  if (absl::GetFlag(FLAGS_helpfull)) {
-    // show all options
-    flags_internal::FlagsHelp(out, "", HelpFormat::kHumanReadable,
-                              program_usage_message);
-    return 1;
-  }
+    case HelpMode::kShort:
+      flags_internal::FlagsHelpImpl(
+          out, flags_internal::GetUsageConfig().contains_helpshort_flags,
+          GetFlagsHelpFormat(), program_usage_message);
+      return 1;
 
-  if (!absl::GetFlag(FLAGS_helpon).empty()) {
-    flags_internal::FlagsHelp(
-        out, absl::StrCat("/", absl::GetFlag(FLAGS_helpon), "."),
-        HelpFormat::kHumanReadable, program_usage_message);
-    return 1;
-  }
+    case HelpMode::kFull:
+      flags_internal::FlagsHelp(out, "", GetFlagsHelpFormat(),
+                                program_usage_message);
+      return 1;
 
-  if (!absl::GetFlag(FLAGS_helpmatch).empty()) {
-    flags_internal::FlagsHelp(out, absl::GetFlag(FLAGS_helpmatch),
-                              HelpFormat::kHumanReadable,
-                              program_usage_message);
-    return 1;
-  }
+    case HelpMode::kPackage:
+      flags_internal::FlagsHelpImpl(
+          out, flags_internal::GetUsageConfig().contains_helppackage_flags,
+          GetFlagsHelpFormat(), program_usage_message);
 
-  if (absl::GetFlag(FLAGS_help)) {
-    flags_internal::FlagsHelpImpl(
-        out, flags_internal::GetUsageConfig().contains_help_flags,
-        HelpFormat::kHumanReadable, program_usage_message);
+      return 1;
 
-    out << "\nTry --helpfull to get a list of all flags.\n";
+    case HelpMode::kMatch: {
+      std::string substr = GetFlagsHelpMatchSubstr();
+      if (substr.empty()) {
+        // show all options
+        flags_internal::FlagsHelp(out, substr, GetFlagsHelpFormat(),
+                                  program_usage_message);
+      } else {
+        auto filter_cb = [&substr](const absl::CommandLineFlag& flag) {
+          if (absl::StrContains(flag.Name(), substr)) return true;
+          if (absl::StrContains(flag.Filename(), substr)) return true;
+          if (absl::StrContains(flag.Help(), substr)) return true;
 
-    return 1;
-  }
+          return false;
+        };
+        flags_internal::FlagsHelpImpl(
+            out, filter_cb, HelpFormat::kHumanReadable, program_usage_message);
+      }
 
-  if (absl::GetFlag(FLAGS_helppackage)) {
-    flags_internal::FlagsHelpImpl(
-        out, flags_internal::GetUsageConfig().contains_helppackage_flags,
-        HelpFormat::kHumanReadable, program_usage_message);
+      return 1;
+    }
+    case HelpMode::kVersion:
+      if (flags_internal::GetUsageConfig().version_string)
+        out << flags_internal::GetUsageConfig().version_string();
+      // Unlike help, we may be asking for version in a script, so return 0
+      return 0;
 
-    out << "\nTry --helpfull to get a list of all flags.\n";
-
-    return 1;
-  }
-
-  if (absl::GetFlag(FLAGS_version)) {
-    if (flags_internal::GetUsageConfig().version_string)
-      out << flags_internal::GetUsageConfig().version_string();
-    // Unlike help, we may be asking for version in a script, so return 0
-    return 0;
-  }
-
-  if (absl::GetFlag(FLAGS_only_check_args)) {
-    return 0;
+    case HelpMode::kOnlyCheckArgs:
+      return 0;
   }
 
   return -1;
 }
 
+// --------------------------------------------------------------------
+// Globals representing usage reporting flags
+
+namespace {
+
+ABSL_CONST_INIT absl::Mutex help_attributes_guard(absl::kConstInit);
+ABSL_CONST_INIT std::string* match_substr
+    ABSL_GUARDED_BY(help_attributes_guard) = nullptr;
+ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(help_attributes_guard) =
+    HelpMode::kNone;
+ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(help_attributes_guard) =
+    HelpFormat::kHumanReadable;
+
+}  // namespace
+
+std::string GetFlagsHelpMatchSubstr() {
+  absl::MutexLock l(&help_attributes_guard);
+  if (match_substr == nullptr) return "";
+  return *match_substr;
+}
+
+void SetFlagsHelpMatchSubstr(absl::string_view substr) {
+  absl::MutexLock l(&help_attributes_guard);
+  if (match_substr == nullptr) match_substr = new std::string;
+  match_substr->assign(substr.data(), substr.size());
+}
+
+HelpMode GetFlagsHelpMode() {
+  absl::MutexLock l(&help_attributes_guard);
+  return help_mode;
+}
+
+void SetFlagsHelpMode(HelpMode mode) {
+  absl::MutexLock l(&help_attributes_guard);
+  help_mode = mode;
+}
+
+HelpFormat GetFlagsHelpFormat() {
+  absl::MutexLock l(&help_attributes_guard);
+  return help_format;
+}
+
+void SetFlagsHelpFormat(HelpFormat format) {
+  absl::MutexLock l(&help_attributes_guard);
+  help_format = format;
+}
+
+// Deduces usage flags from the input argument in a form --name=value or
+// --name. argument is already split into name and value before we call this
+// function.
+bool DeduceUsageFlags(absl::string_view name, absl::string_view value) {
+  if (absl::ConsumePrefix(&name, "help")) {
+    if (name == "") {
+      if (value.empty()) {
+        SetFlagsHelpMode(HelpMode::kImportant);
+      } else {
+        SetFlagsHelpMode(HelpMode::kMatch);
+        SetFlagsHelpMatchSubstr(value);
+      }
+      return true;
+    }
+
+    if (name == "match") {
+      SetFlagsHelpMode(HelpMode::kMatch);
+      SetFlagsHelpMatchSubstr(value);
+      return true;
+    }
+
+    if (name == "on") {
+      SetFlagsHelpMode(HelpMode::kMatch);
+      SetFlagsHelpMatchSubstr(absl::StrCat("/", value, "."));
+      return true;
+    }
+
+    if (name == "full") {
+      SetFlagsHelpMode(HelpMode::kFull);
+      return true;
+    }
+
+    if (name == "short") {
+      SetFlagsHelpMode(HelpMode::kShort);
+      return true;
+    }
+
+    if (name == "package") {
+      SetFlagsHelpMode(HelpMode::kPackage);
+      return true;
+    }
+
+    return false;
+  }
+
+  if (name == "version") {
+    SetFlagsHelpMode(HelpMode::kVersion);
+    return true;
+  }
+
+  if (name == "only_check_args") {
+    SetFlagsHelpMode(HelpMode::kOnlyCheckArgs);
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/usage.h b/grpc/third_party/abseil-cpp/absl/flags/internal/usage.h
index 0c62dc4..c0bcac5 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/internal/usage.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/usage.h
@@ -36,7 +36,8 @@
   kHumanReadable,
 };
 
-// Outputs the help message describing specific flag.
+// Streams the help message describing `flag` to `out`.
+// The default value for `flag` is included in the output.
 void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
               HelpFormat format = HelpFormat::kHumanReadable);
 
@@ -65,17 +66,39 @@
 int HandleUsageFlags(std::ostream& out,
                      absl::string_view program_usage_message);
 
+// --------------------------------------------------------------------
+// Globals representing usage reporting flags
+
+enum class HelpMode {
+  kNone,
+  kImportant,
+  kShort,
+  kFull,
+  kPackage,
+  kMatch,
+  kVersion,
+  kOnlyCheckArgs
+};
+
+// Returns substring to filter help output (--help=substr argument)
+std::string GetFlagsHelpMatchSubstr();
+// Returns the requested help mode.
+HelpMode GetFlagsHelpMode();
+// Returns the requested help format.
+HelpFormat GetFlagsHelpFormat();
+
+// These are corresponding setters to the attributes above.
+void SetFlagsHelpMatchSubstr(absl::string_view);
+void SetFlagsHelpMode(HelpMode);
+void SetFlagsHelpFormat(HelpFormat);
+
+// Deduces usage flags from the input argument in a form --name=value or
+// --name. argument is already split into name and value before we call this
+// function.
+bool DeduceUsageFlags(absl::string_view name, absl::string_view value);
+
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
 
-ABSL_DECLARE_FLAG(bool, help);
-ABSL_DECLARE_FLAG(bool, helpfull);
-ABSL_DECLARE_FLAG(bool, helpshort);
-ABSL_DECLARE_FLAG(bool, helppackage);
-ABSL_DECLARE_FLAG(bool, version);
-ABSL_DECLARE_FLAG(bool, only_check_args);
-ABSL_DECLARE_FLAG(std::string, helpon);
-ABSL_DECLARE_FLAG(std::string, helpmatch);
-
 #endif  // ABSL_FLAGS_INTERNAL_USAGE_H_
diff --git a/grpc/third_party/abseil-cpp/absl/flags/internal/usage_test.cc b/grpc/third_party/abseil-cpp/absl/flags/internal/usage_test.cc
index 6e583fb..b5c2487 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/internal/usage_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/internal/usage_test.cc
@@ -87,6 +87,11 @@
     default_config.normalize_filename = &NormalizeFileName;
     absl::SetFlagsUsageConfig(default_config);
   }
+  ~UsageReportingTest() override {
+    flags::SetFlagsHelpMode(flags::HelpMode::kNone);
+    flags::SetFlagsHelpMatchSubstr("");
+    flags::SetFlagsHelpFormat(flags::HelpFormat::kHumanReadable);
+  }
 
  private:
   absl::FlagSaver flag_saver_;
@@ -191,6 +196,10 @@
       Some more help.
       Even more long long long long long long long long long long long long help
       message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )";
 
   std::stringstream test_buf_01;
@@ -214,7 +223,11 @@
   EXPECT_EQ(test_buf_04.str(),
             R"(usage_test: Custom usage message
 
-  No modules matched: use -helpfull
+No flags matched.
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 
   std::stringstream test_buf_05;
@@ -226,12 +239,8 @@
       absl::StartsWith(test_out_str, "usage_test: Custom usage message"));
   EXPECT_TRUE(absl::StrContains(
       test_out_str, "Flags from absl/flags/internal/usage_test.cc:"));
-  EXPECT_TRUE(absl::StrContains(test_out_str,
-                                "Flags from absl/flags/internal/usage.cc:"));
   EXPECT_TRUE(
       absl::StrContains(test_out_str, "-usage_reporting_test_flag_01 "));
-  EXPECT_TRUE(absl::StrContains(test_out_str, "-help (show help"))
-      << test_out_str;
 }
 
 // --------------------------------------------------------------------
@@ -244,7 +253,7 @@
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
-  absl::SetFlag(&FLAGS_helpshort, true);
+  flags::SetFlagsHelpMode(flags::HelpMode::kShort);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -267,13 +276,17 @@
       Some more help.
       Even more long long long long long long long long long long long long help
       message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 }
 
 // --------------------------------------------------------------------
 
-TEST_F(UsageReportingTest, TestUsageFlag_help) {
-  absl::SetFlag(&FLAGS_help, true);
+TEST_F(UsageReportingTest, TestUsageFlag_help_simple) {
+  flags::SetFlagsHelpMode(flags::HelpMode::kImportant);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -297,14 +310,74 @@
       Even more long long long long long long long long long long long long help
       message.); default: "";
 
-Try --helpfull to get a list of all flags.
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_help_one_flag) {
+  flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+  flags::SetFlagsHelpMatchSubstr("usage_reporting_test_flag_06");
+
+  std::stringstream test_buf;
+  EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+  EXPECT_EQ(test_buf.str(),
+            R"(usage_test: Custom usage message
+
+  Flags from absl/flags/internal/usage_test.cc:
+    --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+      Some more help.
+      Even more long long long long long long long long long long long long help
+      message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) {
+  flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+  flags::SetFlagsHelpMatchSubstr("test_flag");
+
+  std::stringstream test_buf;
+  EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+  EXPECT_EQ(test_buf.str(),
+            R"(usage_test: Custom usage message
+
+  Flags from absl/flags/internal/usage_test.cc:
+    --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+      default: 101;
+    --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+      default: false;
+    --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+      default: 1.03;
+    --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+      default: 1000000000000004;
+    --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+      default: UDT{};
+    --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+      Some more help.
+      Even more long long long long long long long long long long long long help
+      message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
-  absl::SetFlag(&FLAGS_helppackage, true);
+  flags::SetFlagsHelpMode(flags::HelpMode::kPackage);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -328,14 +401,16 @@
       Even more long long long long long long long long long long long long help
       message.); default: "";
 
-Try --helpfull to get a list of all flags.
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_version) {
-  absl::SetFlag(&FLAGS_version, true);
+  flags::SetFlagsHelpMode(flags::HelpMode::kVersion);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
@@ -349,7 +424,7 @@
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) {
-  absl::SetFlag(&FLAGS_only_check_args, true);
+  flags::SetFlagsHelpMode(flags::HelpMode::kOnlyCheckArgs);
 
   std::stringstream test_buf;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
@@ -359,17 +434,22 @@
 // --------------------------------------------------------------------
 
 TEST_F(UsageReportingTest, TestUsageFlag_helpon) {
-  absl::SetFlag(&FLAGS_helpon, "bla-bla");
+  flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+  flags::SetFlagsHelpMatchSubstr("/bla-bla.");
 
   std::stringstream test_buf_01;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf_01, kTestUsageMessage), 1);
   EXPECT_EQ(test_buf_01.str(),
             R"(usage_test: Custom usage message
 
-  No modules matched: use -helpfull
+No flags matched.
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 
-  absl::SetFlag(&FLAGS_helpon, "usage_test");
+  flags::SetFlagsHelpMatchSubstr("/usage_test.");
 
   std::stringstream test_buf_02;
   EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), 1);
@@ -392,6 +472,10 @@
       Some more help.
       Even more long long long long long long long long long long long long help
       message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
 )");
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/flags/marshalling.h b/grpc/third_party/abseil-cpp/absl/flags/marshalling.h
index 0b50335..7cbc136 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/marshalling.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/marshalling.h
@@ -83,7 +83,7 @@
 //   // AbslParseFlag converts from a string to OutputMode.
 //   // Must be in same namespace as OutputMode.
 //
-//   // Parses an OutputMode from the command line flag value `text. Returns
+//   // Parses an OutputMode from the command line flag value `text`. Returns
 //   // `true` and sets `*mode` on success; returns `false` and sets `*error`
 //   // on failure.
 //   bool AbslParseFlag(absl::string_view text,
@@ -139,7 +139,7 @@
 //
 //   // Within the implementation, `AbslParseFlag()` will, in turn invoke
 //   // `absl::ParseFlag()` on its constituent `int` and `std::string` types
-//   // (which have built-in Abseil flag support.
+//   // (which have built-in Abseil flag support).
 //
 //   bool AbslParseFlag(absl::string_view text, MyFlagType* flag,
 //                      std::string* err) {
diff --git a/grpc/third_party/abseil-cpp/absl/flags/parse.cc b/grpc/third_party/abseil-cpp/absl/flags/parse.cc
index 4f4bb3d..dd1a679 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/parse.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/parse.cc
@@ -611,6 +611,11 @@
                                         OnUndefinedFlag on_undef_flag) {
   ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
 
+  // Once parsing has started we will not have more flag registrations.
+  // If we did, they would be missing during parsing, which is a problem on
+  // itself.
+  flags_internal::FinalizeRegistry();
+
   // This routine does not return anything since we abort on failure.
   CheckDefaultValuesParsingRoundtrip();
 
@@ -708,6 +713,11 @@
     std::tie(flag, is_negative) = LocateFlag(flag_name);
 
     if (flag == nullptr) {
+      // Usage flags are not modeled as Abseil flags. Locate them separately.
+      if (flags_internal::DeduceUsageFlags(flag_name, value)) {
+        continue;
+      }
+
       if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
         undefined_flag_names.emplace_back(arg_from_argv,
                                           std::string(flag_name));
diff --git a/grpc/third_party/abseil-cpp/absl/flags/parse_test.cc b/grpc/third_party/abseil-cpp/absl/flags/parse_test.cc
index d35a6e4..41bc0bc 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/parse_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/parse_test.cc
@@ -28,6 +28,7 @@
 #include "absl/flags/declare.h"
 #include "absl/flags/flag.h"
 #include "absl/flags/internal/parse.h"
+#include "absl/flags/internal/usage.h"
 #include "absl/flags/reflection.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
@@ -207,6 +208,9 @@
 using testing::ElementsAreArray;
 
 class ParseTest : public testing::Test {
+ public:
+  ~ParseTest() override { flags::SetFlagsHelpMode(flags::HelpMode::kNone); }
+
  private:
   absl::FlagSaver flag_saver_;
 };
@@ -851,7 +855,7 @@
 
 // --------------------------------------------------------------------
 
-TEST_F(ParseDeathTest, TestHelpFlagHandling) {
+TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) {
   const char* in_args1[] = {
       "testbin",
       "--help",
@@ -870,11 +874,38 @@
       flags::UsageFlagsAction::kIgnoreUsage,
       flags::OnUndefinedFlag::kAbortIfUndefined);
 
+  EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
 }
 
 // --------------------------------------------------------------------
 
+TEST_F(ParseDeathTest, TestSubstringHelpFlagHandling) {
+  const char* in_args1[] = {
+      "testbin",
+      "--help=abcd",
+  };
+
+  auto out_args1 = flags::ParseCommandLineImpl(
+      2, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs,
+      flags::UsageFlagsAction::kIgnoreUsage,
+      flags::OnUndefinedFlag::kAbortIfUndefined);
+
+  EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kMatch);
+  EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd");
+
+  const char* in_args2[] = {"testbin", "--help", "some_positional_arg"};
+
+  auto out_args2 = flags::ParseCommandLineImpl(
+      3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs,
+      flags::UsageFlagsAction::kIgnoreUsage,
+      flags::OnUndefinedFlag::kAbortIfUndefined);
+
+  EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
+}
+
+// --------------------------------------------------------------------
+
 TEST_F(ParseTest, WasPresentOnCommandLine) {
   const char* in_args1[] = {
       "testbin",        "arg1", "--bool_flag",
diff --git a/grpc/third_party/abseil-cpp/absl/flags/reflection.cc b/grpc/third_party/abseil-cpp/absl/flags/reflection.cc
index d706022..0c76110 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/reflection.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/reflection.cc
@@ -17,6 +17,7 @@
 
 #include <assert.h>
 
+#include <atomic>
 #include <map>
 #include <string>
 
@@ -49,28 +50,30 @@
   ~FlagRegistry() = default;
 
   // Store a flag in this registry. Takes ownership of *flag.
-  void RegisterFlag(CommandLineFlag& flag);
+  void RegisterFlag(CommandLineFlag& flag, const char* filename);
 
   void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); }
   void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.Unlock(); }
 
   // Returns the flag object for the specified name, or nullptr if not found.
   // Will emit a warning if a 'retired' flag is specified.
-  CommandLineFlag* FindFlagLocked(absl::string_view name);
+  CommandLineFlag* FindFlag(absl::string_view name);
 
   static FlagRegistry& GlobalRegistry();  // returns a singleton registry
 
  private:
   friend class flags_internal::FlagSaverImpl;  // reads all the flags in order
                                                // to copy them
-  friend void ForEachFlagUnlocked(
-      std::function<void(CommandLineFlag&)> visitor);
+  friend void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
+  friend void FinalizeRegistry();
 
-  // The map from name to flag, for FindFlagLocked().
+  // The map from name to flag, for FindFlag().
   using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
   using FlagIterator = FlagMap::iterator;
   using FlagConstIterator = FlagMap::const_iterator;
   FlagMap flags_;
+  std::vector<CommandLineFlag*> flat_flags_;
+  std::atomic<bool> finalized_flags_{false};
 
   absl::Mutex lock_;
 
@@ -79,15 +82,6 @@
   FlagRegistry& operator=(const FlagRegistry&);
 };
 
-CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
-  FlagConstIterator i = flags_.find(name);
-  if (i == flags_.end()) {
-    return nullptr;
-  }
-
-  return i->second;
-}
-
 namespace {
 
 class FlagRegistryLock {
@@ -101,8 +95,37 @@
 
 }  // namespace
 
-void FlagRegistry::RegisterFlag(CommandLineFlag& flag) {
+CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) {
+  if (finalized_flags_.load(std::memory_order_acquire)) {
+    // We could save some gcus here if we make `Name()` be non-virtual.
+    // We could move the `const char*` name to the base class.
+    auto it = std::partition_point(
+        flat_flags_.begin(), flat_flags_.end(),
+        [=](CommandLineFlag* f) { return f->Name() < name; });
+    if (it != flat_flags_.end() && (*it)->Name() == name) return *it;
+  }
+
+  FlagRegistryLock frl(*this);
+  auto it = flags_.find(name);
+  return it != flags_.end() ? it->second : nullptr;
+}
+
+void FlagRegistry::RegisterFlag(CommandLineFlag& flag, const char* filename) {
+  if (filename != nullptr &&
+      flag.Filename() != GetUsageConfig().normalize_filename(filename)) {
+    flags_internal::ReportUsageError(
+        absl::StrCat(
+            "Inconsistency between flag object and registration for flag '",
+            flag.Name(),
+            "', likely due to duplicate flags or an ODR violation. Relevant "
+            "files: ",
+            flag.Filename(), " and ", filename),
+        true);
+    std::exit(1);
+  }
+
   FlagRegistryLock registry_lock(*this);
+
   std::pair<FlagIterator, bool> ins =
       flags_.insert(FlagMap::value_type(flag.Name(), &flag));
   if (ins.second == false) {  // means the name was already in the map
@@ -152,27 +175,39 @@
 
 // --------------------------------------------------------------------
 
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor) {
-  FlagRegistry& registry = FlagRegistry::GlobalRegistry();
-  for (FlagRegistry::FlagConstIterator i = registry.flags_.begin();
-       i != registry.flags_.end(); ++i) {
-    visitor(*i->second);
-  }
-}
-
 void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
   FlagRegistry& registry = FlagRegistry::GlobalRegistry();
+
+  if (registry.finalized_flags_.load(std::memory_order_acquire)) {
+    for (const auto& i : registry.flat_flags_) visitor(*i);
+  }
+
   FlagRegistryLock frl(registry);
-  ForEachFlagUnlocked(visitor);
+  for (const auto& i : registry.flags_) visitor(*i.second);
 }
 
 // --------------------------------------------------------------------
 
-bool RegisterCommandLineFlag(CommandLineFlag& flag) {
-  FlagRegistry::GlobalRegistry().RegisterFlag(flag);
+bool RegisterCommandLineFlag(CommandLineFlag& flag, const char* filename) {
+  FlagRegistry::GlobalRegistry().RegisterFlag(flag, filename);
   return true;
 }
 
+void FinalizeRegistry() {
+  auto& registry = FlagRegistry::GlobalRegistry();
+  FlagRegistryLock frl(registry);
+  if (registry.finalized_flags_.load(std::memory_order_relaxed)) {
+    // Was already finalized. Ignore the second time.
+    return;
+  }
+  registry.flat_flags_.reserve(registry.flags_.size());
+  for (const auto& f : registry.flags_) {
+    registry.flat_flags_.push_back(f.second);
+  }
+  registry.flags_.clear();
+  registry.finalized_flags_.store(true, std::memory_order_release);
+}
+
 // --------------------------------------------------------------------
 
 namespace {
@@ -244,7 +279,7 @@
   static_assert(alignof(RetiredFlagObj) == kRetiredFlagObjAlignment, "");
   auto* flag = ::new (static_cast<void*>(buf))
       flags_internal::RetiredFlagObj(name, type_id);
-  FlagRegistry::GlobalRegistry().RegisterFlag(*flag);
+  FlagRegistry::GlobalRegistry().RegisterFlag(*flag, nullptr);
 }
 
 // --------------------------------------------------------------------
@@ -298,9 +333,7 @@
   if (name.empty()) return nullptr;
   flags_internal::FlagRegistry& registry =
       flags_internal::FlagRegistry::GlobalRegistry();
-  flags_internal::FlagRegistryLock frl(registry);
-
-  return registry.FindFlagLocked(name);
+  return registry.FindFlag(name);
 }
 
 // --------------------------------------------------------------------
@@ -308,7 +341,7 @@
 absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags() {
   absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> res;
   flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
-    res.insert({flag.Name(), &flag});
+    if (!flag.IsRetired()) res.insert({flag.Name(), &flag});
   });
   return res;
 }
diff --git a/grpc/third_party/abseil-cpp/absl/flags/reflection.h b/grpc/third_party/abseil-cpp/absl/flags/reflection.h
index 4ce0ab6..e6baf5d 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/reflection.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/reflection.h
@@ -64,7 +64,7 @@
 //   void MyFunc() {
 //    absl::FlagSaver fs;
 //    ...
-//    absl::SetFlag(FLAGS_myFlag, otherValue);
+//    absl::SetFlag(&FLAGS_myFlag, otherValue);
 //    ...
 //  } // scope of FlagSaver left, flags return to previous state
 //
diff --git a/grpc/third_party/abseil-cpp/absl/flags/reflection_test.cc b/grpc/third_party/abseil-cpp/absl/flags/reflection_test.cc
index 1a1dcb4..79cfa90 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/reflection_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/reflection_test.cc
@@ -32,12 +32,8 @@
 ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
 ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
 
-ABSL_DECLARE_FLAG(bool, help);
-
 namespace {
 
-namespace flags = absl::flags_internal;
-
 class ReflectionTest : public testing::Test {
  protected:
   void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
@@ -66,12 +62,9 @@
 // --------------------------------------------------------------------
 
 TEST_F(ReflectionTest, TestGetAllFlags) {
-  (void)absl::GetFlag(FLAGS_help);  // Force linking of usage flags.
-
   auto all_flags = absl::GetAllFlags();
   EXPECT_NE(all_flags.find("int_flag"), all_flags.end());
-  EXPECT_NE(all_flags.find("bool_retired_flag"), all_flags.end());
-  EXPECT_NE(all_flags.find("help"), all_flags.end());
+  EXPECT_EQ(all_flags.find("bool_retired_flag"), all_flags.end());
   EXPECT_EQ(all_flags.find("some_undefined_flag"), all_flags.end());
 
   std::vector<absl::string_view> flag_names_first_attempt;
diff --git a/grpc/third_party/abseil-cpp/absl/flags/usage_config.cc b/grpc/third_party/abseil-cpp/absl/flags/usage_config.cc
index ae2f548..5d7426d 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/usage_config.cc
+++ b/grpc/third_party/abseil-cpp/absl/flags/usage_config.cc
@@ -34,7 +34,8 @@
 
 // Additional report of fatal usage error message before we std::exit. Error is
 // fatal if is_fatal argument to ReportUsageError is true.
-ABSL_ATTRIBUTE_WEAK void AbslInternalReportFatalUsageError(absl::string_view) {}
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(
+    AbslInternalReportFatalUsageError)(absl::string_view) {}
 
 }  // extern "C"
 
@@ -128,7 +129,7 @@
   std::cerr << "ERROR: " << msg << std::endl;
 
   if (is_fatal) {
-    AbslInternalReportFatalUsageError(msg);
+    ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)(msg);
   }
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/flags/usage_config.h b/grpc/third_party/abseil-cpp/absl/flags/usage_config.h
index 96eecea..ded7030 100644
--- a/grpc/third_party/abseil-cpp/absl/flags/usage_config.h
+++ b/grpc/third_party/abseil-cpp/absl/flags/usage_config.h
@@ -127,7 +127,8 @@
 
 // Additional report of fatal usage error message before we std::exit. Error is
 // fatal if is_fatal argument to ReportUsageError is true.
-void AbslInternalReportFatalUsageError(absl::string_view);
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)(
+    absl::string_view);
 
 }  // extern "C"
 
diff --git a/grpc/third_party/abseil-cpp/absl/hash/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/hash/BUILD.bazel
index 5b1e2d0..4b2c220 100644
--- a/grpc/third_party/abseil-cpp/absl/hash/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/hash/BUILD.bazel
@@ -37,6 +37,8 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":city",
+        ":wyhash",
+        "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
         "//absl/container:fixed_array",
@@ -81,6 +83,25 @@
     ],
 )
 
+cc_binary(
+    name = "hash_benchmark",
+    testonly = 1,
+    srcs = ["hash_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":hash",
+        "//absl/base:core_headers",
+        "//absl/random",
+        "//absl/strings",
+        "//absl/strings:cord",
+        "//absl/strings:cord_test_helpers",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
 cc_library(
     name = "spy_hash_state",
     testonly = 1,
@@ -120,3 +141,30 @@
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_library(
+    name = "wyhash",
+    srcs = ["internal/wyhash.cc"],
+    hdrs = ["internal/wyhash.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        "//absl/base:config",
+        "//absl/base:endian",
+        "//absl/numeric:int128",
+    ],
+)
+
+cc_test(
+    name = "wyhash_test",
+    srcs = ["internal/wyhash_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":wyhash",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/grpc/third_party/abseil-cpp/absl/hash/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/hash/CMakeLists.txt
index 61365e9..b43bfa5 100644
--- a/grpc/third_party/abseil-cpp/absl/hash/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/hash/CMakeLists.txt
@@ -24,7 +24,9 @@
     "internal/hash.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
-  DEPS
+    DEPS
+    absl::city
+    absl::config
     absl::core_headers
     absl::endian
     absl::fixed_array
@@ -34,7 +36,7 @@
     absl::optional
     absl::variant
     absl::utility
-    absl::city
+    absl::wyhash
   PUBLIC
 )
 
@@ -114,3 +116,30 @@
     gmock_main
 )
 
+absl_cc_library(
+  NAME
+    wyhash
+  HDRS
+    "internal/wyhash.h"
+  SRCS
+    "internal/wyhash.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::endian
+    absl::int128
+)
+
+absl_cc_test(
+  NAME
+    wyhash_test
+  SRCS
+    "internal/wyhash_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::wyhash
+    absl::strings
+    gmock_main
+)
diff --git a/grpc/third_party/abseil-cpp/absl/hash/hash_benchmark.cc b/grpc/third_party/abseil-cpp/absl/hash/hash_benchmark.cc
new file mode 100644
index 0000000..d498ac2
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/hash/hash_benchmark.cc
@@ -0,0 +1,254 @@
+// Copyright 2018 The Abseil 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
+//
+//      https://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 <string>
+#include <type_traits>
+#include <typeindex>
+#include <utility>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/hash/hash.h"
+#include "absl/random/random.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/cord_test_helpers.h"
+#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+using absl::Hash;
+
+template <template <typename> class H, typename T>
+void RunBenchmark(benchmark::State& state, T value) {
+  H<T> h;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(value);
+    benchmark::DoNotOptimize(h(value));
+  }
+}
+
+}  // namespace
+
+template <typename T>
+using AbslHash = absl::Hash<T>;
+
+class TypeErasedInterface {
+ public:
+  virtual ~TypeErasedInterface() = default;
+
+  template <typename H>
+  friend H AbslHashValue(H state, const TypeErasedInterface& wrapper) {
+    state = H::combine(std::move(state), std::type_index(typeid(wrapper)));
+    wrapper.HashValue(absl::HashState::Create(&state));
+    return state;
+  }
+
+ private:
+  virtual void HashValue(absl::HashState state) const = 0;
+};
+
+template <typename T>
+struct TypeErasedAbslHash {
+  class Wrapper : public TypeErasedInterface {
+   public:
+    explicit Wrapper(const T& value) : value_(value) {}
+
+   private:
+    void HashValue(absl::HashState state) const override {
+      absl::HashState::combine(std::move(state), value_);
+    }
+
+    const T& value_;
+  };
+
+  size_t operator()(const T& value) {
+    return absl::Hash<Wrapper>{}(Wrapper(value));
+  }
+};
+
+template <typename FuncType>
+inline FuncType* ODRUseFunction(FuncType* ptr) {
+  volatile FuncType* dummy = ptr;
+  return dummy;
+}
+
+absl::Cord FlatCord(size_t size) {
+  absl::Cord result(std::string(size, 'a'));
+  result.Flatten();
+  return result;
+}
+
+absl::Cord FragmentedCord(size_t size) {
+  const size_t orig_size = size;
+  std::vector<std::string> chunks;
+  size_t chunk_size = std::max<size_t>(1, size / 10);
+  while (size > chunk_size) {
+    chunks.push_back(std::string(chunk_size, 'a'));
+    size -= chunk_size;
+  }
+  if (size > 0) {
+    chunks.push_back(std::string(size, 'a'));
+  }
+  absl::Cord result = absl::MakeFragmentedCord(chunks);
+  (void) orig_size;
+  assert(result.size() == orig_size);
+  return result;
+}
+
+// Generates a benchmark and a codegen method for the provided types.  The
+// codegen method provides a well known entrypoint for dumping assembly.
+#define MAKE_BENCHMARK(hash, name, ...)                          \
+  namespace {                                                    \
+  void BM_##hash##_##name(benchmark::State& state) {             \
+    RunBenchmark<hash>(state, __VA_ARGS__);                      \
+  }                                                              \
+  BENCHMARK(BM_##hash##_##name);                                 \
+  }                                                              \
+  size_t Codegen##hash##name(const decltype(__VA_ARGS__)& arg);  \
+  size_t Codegen##hash##name(const decltype(__VA_ARGS__)& arg) { \
+    return hash<decltype(__VA_ARGS__)>{}(arg);                   \
+  }                                                              \
+  bool absl_hash_test_odr_use##hash##name =                      \
+      ODRUseFunction(&Codegen##hash##name);
+
+MAKE_BENCHMARK(AbslHash, Int32, int32_t{});
+MAKE_BENCHMARK(AbslHash, Int64, int64_t{});
+MAKE_BENCHMARK(AbslHash, Double, 1.2);
+MAKE_BENCHMARK(AbslHash, DoubleZero, 0.0);
+MAKE_BENCHMARK(AbslHash, PairInt32Int32, std::pair<int32_t, int32_t>{});
+MAKE_BENCHMARK(AbslHash, PairInt64Int64, std::pair<int64_t, int64_t>{});
+MAKE_BENCHMARK(AbslHash, TupleInt32BoolInt64,
+               std::tuple<int32_t, bool, int64_t>{});
+MAKE_BENCHMARK(AbslHash, String_0, std::string());
+MAKE_BENCHMARK(AbslHash, String_10, std::string(10, 'a'));
+MAKE_BENCHMARK(AbslHash, String_30, std::string(30, 'a'));
+MAKE_BENCHMARK(AbslHash, String_90, std::string(90, 'a'));
+MAKE_BENCHMARK(AbslHash, String_200, std::string(200, 'a'));
+MAKE_BENCHMARK(AbslHash, String_5000, std::string(5000, 'a'));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_0, absl::Cord());
+MAKE_BENCHMARK(AbslHash, Cord_Flat_10, FlatCord(10));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_30, FlatCord(30));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_90, FlatCord(90));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_200, FlatCord(200));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_5000, FlatCord(5000));
+MAKE_BENCHMARK(AbslHash, Cord_Fragmented_200, FragmentedCord(200));
+MAKE_BENCHMARK(AbslHash, Cord_Fragmented_5000, FragmentedCord(5000));
+MAKE_BENCHMARK(AbslHash, VectorInt64_10, std::vector<int64_t>(10));
+MAKE_BENCHMARK(AbslHash, VectorInt64_100, std::vector<int64_t>(100));
+MAKE_BENCHMARK(AbslHash, VectorDouble_10, std::vector<double>(10, 1.1));
+MAKE_BENCHMARK(AbslHash, VectorDouble_100, std::vector<double>(100, 1.1));
+MAKE_BENCHMARK(AbslHash, PairStringString_0,
+               std::make_pair(std::string(), std::string()));
+MAKE_BENCHMARK(AbslHash, PairStringString_10,
+               std::make_pair(std::string(10, 'a'), std::string(10, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_30,
+               std::make_pair(std::string(30, 'a'), std::string(30, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_90,
+               std::make_pair(std::string(90, 'a'), std::string(90, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_200,
+               std::make_pair(std::string(200, 'a'), std::string(200, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_5000,
+               std::make_pair(std::string(5000, 'a'), std::string(5000, 'b')));
+
+MAKE_BENCHMARK(TypeErasedAbslHash, Int32, int32_t{});
+MAKE_BENCHMARK(TypeErasedAbslHash, Int64, int64_t{});
+MAKE_BENCHMARK(TypeErasedAbslHash, PairInt32Int32,
+               std::pair<int32_t, int32_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, PairInt64Int64,
+               std::pair<int64_t, int64_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, TupleInt32BoolInt64,
+               std::tuple<int32_t, bool, int64_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, String_0, std::string());
+MAKE_BENCHMARK(TypeErasedAbslHash, String_10, std::string(10, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_30, std::string(30, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_90, std::string(90, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_200, std::string(200, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_5000, std::string(5000, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_10,
+               std::vector<double>(10, 1.1));
+MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_100,
+               std::vector<double>(100, 1.1));
+
+// The latency benchmark attempts to model the speed of the hash function in
+// production. When a hash function is used for hashtable lookups it is rarely
+// used to hash N items in a tight loop nor on constant sized strings. Instead,
+// after hashing there is a potential equality test plus a (usually) large
+// amount of user code. To simulate this effectively we introduce a data
+// dependency between elements we hash by using the hash of the Nth element as
+// the selector of the N+1th element to hash. This isolates the hash function
+// code much like in production. As a bonus we use the hash to generate strings
+// of size [1,N] (instead of fixed N) to disable perfect branch predictions in
+// hash function implementations.
+namespace {
+// 16kb fits in L1 cache of most CPUs we care about. Keeping memory latency low
+// will allow us to attribute most time to CPU which means more accurate
+// measurements.
+static constexpr size_t kEntropySize = 16 << 10;
+static char entropy[kEntropySize + 1024];
+ABSL_ATTRIBUTE_UNUSED static const bool kInitialized = [] {
+  absl::BitGen gen;
+  static_assert(sizeof(entropy) % sizeof(uint64_t) == 0, "");
+  for (int i = 0; i != sizeof(entropy); i += sizeof(uint64_t)) {
+    auto rand = absl::Uniform<uint64_t>(gen);
+    memcpy(&entropy[i], &rand, sizeof(uint64_t));
+  }
+  return true;
+}();
+}  // namespace
+
+template <class T>
+struct PodRand {
+  static_assert(std::is_pod<T>::value, "");
+  static_assert(kEntropySize + sizeof(T) < sizeof(entropy), "");
+
+  T Get(size_t i) const {
+    T v;
+    memcpy(&v, &entropy[i % kEntropySize], sizeof(T));
+    return v;
+  }
+};
+
+template <size_t N>
+struct StringRand {
+  static_assert(kEntropySize + N < sizeof(entropy), "");
+
+  absl::string_view Get(size_t i) const {
+    // This has a small bias towards small numbers. Because max N is ~200 this
+    // is very small and prefer to be very fast instead of absolutely accurate.
+    // Also we pass N = 2^K+1 so that mod reduces to a bitand.
+    size_t s = (i % (N - 1)) + 1;
+    return {&entropy[i % kEntropySize], s};
+  }
+};
+
+#define MAKE_LATENCY_BENCHMARK(hash, name, ...)              \
+  namespace {                                                \
+  void BM_latency_##hash##_##name(benchmark::State& state) { \
+    __VA_ARGS__ r;                                           \
+    hash<decltype(r.Get(0))> h;                              \
+    size_t i = 871401241;                                    \
+    for (auto _ : state) {                                   \
+      benchmark::DoNotOptimize(i = h(r.Get(i)));             \
+    }                                                        \
+  }                                                          \
+  BENCHMARK(BM_latency_##hash##_##name);                     \
+  }  // namespace
+
+MAKE_LATENCY_BENCHMARK(AbslHash, Int32, PodRand<int32_t>);
+MAKE_LATENCY_BENCHMARK(AbslHash, Int64, PodRand<int64_t>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String9, StringRand<9>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String33, StringRand<33>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String65, StringRand<65>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String257, StringRand<257>);
diff --git a/grpc/third_party/abseil-cpp/absl/hash/hash_test.cc b/grpc/third_party/abseil-cpp/absl/hash/hash_test.cc
index 39ba24a..1d2e6cf 100644
--- a/grpc/third_party/abseil-cpp/absl/hash/hash_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/hash/hash_test.cc
@@ -82,8 +82,8 @@
 }
 
 REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath);
-using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
-                                uint64_t, size_t>;
+using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
+                                uint32_t, uint64_t, size_t>;
 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
 
 enum LegacyEnum { kValue1, kValue2, kValue3 };
@@ -819,8 +819,8 @@
 }
 
 REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage);
-using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
-                                uint64_t, size_t>;
+using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
+                                uint32_t, uint64_t, size_t>;
 INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes);
 
 struct StructWithPadding {
diff --git a/grpc/third_party/abseil-cpp/absl/hash/internal/city.cc b/grpc/third_party/abseil-cpp/absl/hash/internal/city.cc
index e122c18..5460134 100644
--- a/grpc/third_party/abseil-cpp/absl/hash/internal/city.cc
+++ b/grpc/third_party/abseil-cpp/absl/hash/internal/city.cc
@@ -200,10 +200,6 @@
 
 static uint64_t ShiftMix(uint64_t val) { return val ^ (val >> 47); }
 
-static uint64_t HashLen16(uint64_t u, uint64_t v) {
-  return Hash128to64(uint128(u, v));
-}
-
 static uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) {
   // Murmur-inspired hashing.
   uint64_t a = (u ^ v) * mul;
@@ -214,6 +210,11 @@
   return b;
 }
 
+static uint64_t HashLen16(uint64_t u, uint64_t v) {
+  const uint64_t kMul = 0x9ddfea08eb382d69ULL;
+  return HashLen16(u, v, kMul);
+}
+
 static uint64_t HashLen0to16(const char *s, size_t len) {
   if (len >= 8) {
     uint64_t mul = k2 + len * 2;
@@ -253,9 +254,8 @@
 
 // Return a 16-byte hash for 48 bytes.  Quick and dirty.
 // Callers do best to use "random-looking" values for a and b.
-static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t x,
-                                                        uint64_t y, uint64_t z,
-                                                        uint64_t a, uint64_t b) {
+static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
+    uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) {
   a += w;
   b = Rotate(b + a + z, 21);
   uint64_t c = a;
@@ -266,8 +266,9 @@
 }
 
 // Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
-static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s, uint64_t a,
-                                                        uint64_t b) {
+static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s,
+                                                            uint64_t a,
+                                                            uint64_t b) {
   return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
                                 Fetch64(s + 24), a, b);
 }
@@ -310,8 +311,10 @@
   uint64_t x = Fetch64(s + len - 40);
   uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
   uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
-  std::pair<uint64_t, uint64_t> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
-  std::pair<uint64_t, uint64_t> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+  std::pair<uint64_t, uint64_t> v =
+      WeakHashLen32WithSeeds(s + len - 64, len, z);
+  std::pair<uint64_t, uint64_t> w =
+      WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
   x = x * k1 + Fetch64(s);
 
   // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
@@ -337,7 +340,7 @@
 }
 
 uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
-                           uint64_t seed1) {
+                             uint64_t seed1) {
   return HashLen16(CityHash64(s, len) - seed0, seed1);
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/hash/internal/city.h b/grpc/third_party/abseil-cpp/absl/hash/internal/city.h
index 161c774..393da0b 100644
--- a/grpc/third_party/abseil-cpp/absl/hash/internal/city.h
+++ b/grpc/third_party/abseil-cpp/absl/hash/internal/city.h
@@ -56,11 +56,6 @@
 ABSL_NAMESPACE_BEGIN
 namespace hash_internal {
 
-typedef std::pair<uint64_t, uint64_t> uint128;
-
-inline uint64_t Uint128Low64(const uint128 &x) { return x.first; }
-inline uint64_t Uint128High64(const uint128 &x) { return x.second; }
-
 // Hash function for a byte array.
 uint64_t CityHash64(const char *s, size_t len);
 
@@ -71,24 +66,11 @@
 // Hash function for a byte array.  For convenience, two seeds are also
 // hashed into the result.
 uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
-                           uint64_t seed1);
+                             uint64_t seed1);
 
 // Hash function for a byte array.  Most useful in 32-bit binaries.
 uint32_t CityHash32(const char *s, size_t len);
 
-// Hash 128 input bits down to 64 bits of output.
-// This is intended to be a reasonably good hash function.
-inline uint64_t Hash128to64(const uint128 &x) {
-  // Murmur-inspired hashing.
-  const uint64_t kMul = 0x9ddfea08eb382d69ULL;
-  uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
-  a ^= (a >> 47);
-  uint64_t b = (Uint128High64(x) ^ a) * kMul;
-  b ^= (b >> 47);
-  b *= kMul;
-  return b;
-}
-
 }  // namespace hash_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/hash/internal/hash.cc b/grpc/third_party/abseil-cpp/absl/hash/internal/hash.cc
index b44ecb3..1433eb9 100644
--- a/grpc/third_party/abseil-cpp/absl/hash/internal/hash.cc
+++ b/grpc/third_party/abseil-cpp/absl/hash/internal/hash.cc
@@ -18,9 +18,9 @@
 ABSL_NAMESPACE_BEGIN
 namespace hash_internal {
 
-uint64_t CityHashState::CombineLargeContiguousImpl32(uint64_t state,
-                                                     const unsigned char* first,
-                                                     size_t len) {
+uint64_t HashState::CombineLargeContiguousImpl32(uint64_t state,
+                                                 const unsigned char* first,
+                                                 size_t len) {
   while (len >= PiecewiseChunkSize()) {
     state =
         Mix(state, absl::hash_internal::CityHash32(reinterpret_cast<const char*>(first),
@@ -33,13 +33,11 @@
                                std::integral_constant<int, 4>{});
 }
 
-uint64_t CityHashState::CombineLargeContiguousImpl64(uint64_t state,
-                                                     const unsigned char* first,
-                                                     size_t len) {
+uint64_t HashState::CombineLargeContiguousImpl64(uint64_t state,
+                                                 const unsigned char* first,
+                                                 size_t len) {
   while (len >= PiecewiseChunkSize()) {
-    state =
-        Mix(state, absl::hash_internal::CityHash64(reinterpret_cast<const char*>(first),
-                                         PiecewiseChunkSize()));
+    state = Mix(state, Hash64(first, PiecewiseChunkSize()));
     len -= PiecewiseChunkSize();
     first += PiecewiseChunkSize();
   }
@@ -48,7 +46,24 @@
                                std::integral_constant<int, 8>{});
 }
 
-ABSL_CONST_INIT const void* const CityHashState::kSeed = &kSeed;
+ABSL_CONST_INIT const void* const HashState::kSeed = &kSeed;
+
+// The salt array used by Wyhash. This array is NOT the mechanism used to make
+// absl::Hash non-deterministic between program invocations.  See `Seed()` for
+// that mechanism.
+//
+// Any random values are fine. These values are just digits from the decimal
+// part of pi.
+// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
+constexpr uint64_t kWyhashSalt[5] = {
+    uint64_t{0x243F6A8885A308D3}, uint64_t{0x13198A2E03707344},
+    uint64_t{0xA4093822299F31D0}, uint64_t{0x082EFA98EC4E6C89},
+    uint64_t{0x452821E638D01377},
+};
+
+uint64_t HashState::WyhashImpl(const unsigned char* data, size_t len) {
+  return Wyhash(data, len, Seed(), kWyhashSalt);
+}
 
 }  // namespace hash_internal
 ABSL_NAMESPACE_END
diff --git a/grpc/third_party/abseil-cpp/absl/hash/internal/hash.h b/grpc/third_party/abseil-cpp/absl/hash/internal/hash.h
index 9e608f7..7fb0af0 100644
--- a/grpc/third_party/abseil-cpp/absl/hash/internal/hash.h
+++ b/grpc/third_party/abseil-cpp/absl/hash/internal/hash.h
@@ -38,9 +38,11 @@
 #include <utility>
 #include <vector>
 
-#include "absl/base/internal/endian.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/unaligned_access.h"
 #include "absl/base/port.h"
 #include "absl/container/fixed_array.h"
+#include "absl/hash/internal/wyhash.h"
 #include "absl/meta/type_traits.h"
 #include "absl/numeric/int128.h"
 #include "absl/strings/string_view.h"
@@ -712,9 +714,8 @@
 struct is_hashable
     : std::integral_constant<bool, HashSelect::template Apply<T>::value> {};
 
-// CityHashState
-class ABSL_DLL CityHashState
-    : public HashStateBase<CityHashState> {
+// HashState
+class ABSL_DLL HashState : public HashStateBase<HashState> {
   // absl::uint128 is not an alias or a thin wrapper around the intrinsic.
   // We use the intrinsic when available to improve performance.
 #ifdef ABSL_HAVE_INTRINSIC_INT128
@@ -733,23 +734,22 @@
 
  public:
   // Move only
-  CityHashState(CityHashState&&) = default;
-  CityHashState& operator=(CityHashState&&) = default;
+  HashState(HashState&&) = default;
+  HashState& operator=(HashState&&) = default;
 
-  // CityHashState::combine_contiguous()
+  // HashState::combine_contiguous()
   //
   // Fundamental base case for hash recursion: mixes the given range of bytes
   // into the hash state.
-  static CityHashState combine_contiguous(CityHashState hash_state,
-                                          const unsigned char* first,
-                                          size_t size) {
-    return CityHashState(
+  static HashState combine_contiguous(HashState hash_state,
+                                      const unsigned char* first, size_t size) {
+    return HashState(
         CombineContiguousImpl(hash_state.state_, first, size,
                               std::integral_constant<int, sizeof(size_t)>{}));
   }
-  using CityHashState::HashStateBase::combine_contiguous;
+  using HashState::HashStateBase::combine_contiguous;
 
-  // CityHashState::hash()
+  // HashState::hash()
   //
   // For performance reasons in non-opt mode, we specialize this for
   // integral types.
@@ -761,24 +761,24 @@
     return static_cast<size_t>(Mix(Seed(), static_cast<uint64_t>(value)));
   }
 
-  // Overload of CityHashState::hash()
+  // Overload of HashState::hash()
   template <typename T, absl::enable_if_t<!IntegralFastPath<T>::value, int> = 0>
   static size_t hash(const T& value) {
-    return static_cast<size_t>(combine(CityHashState{}, value).state_);
+    return static_cast<size_t>(combine(HashState{}, value).state_);
   }
 
  private:
   // Invoked only once for a given argument; that plus the fact that this is
   // move-only ensures that there is only one non-moved-from object.
-  CityHashState() : state_(Seed()) {}
+  HashState() : state_(Seed()) {}
 
   // Workaround for MSVC bug.
   // We make the type copyable to fix the calling convention, even though we
   // never actually copy it. Keep it private to not affect the public API of the
   // type.
-  CityHashState(const CityHashState&) = default;
+  HashState(const HashState&) = default;
 
-  explicit CityHashState(uint64_t state) : state_(state) {}
+  explicit HashState(uint64_t state) : state_(state) {}
 
   // Implementation of the base case for combine_contiguous where we actually
   // mix the bytes into the state.
@@ -791,7 +791,8 @@
   static uint64_t CombineContiguousImpl(uint64_t state,
                                         const unsigned char* first, size_t len,
                                         std::integral_constant<int, 8>
-                                        /* sizeof_size_t*/);
+                                        /* sizeof_size_t */);
+
 
   // Slow dispatch path for calls to CombineContiguousImpl with a size argument
   // larger than PiecewiseChunkSize().  Has the same effect as calling
@@ -804,26 +805,54 @@
                                                size_t len);
 
   // Reads 9 to 16 bytes from p.
-  // The first 8 bytes are in .first, the rest (zero padded) bytes are in
-  // .second.
+  // The least significant 8 bytes are in .first, the rest (zero padded) bytes
+  // are in .second.
   static std::pair<uint64_t, uint64_t> Read9To16(const unsigned char* p,
                                                  size_t len) {
-    uint64_t high = little_endian::Load64(p + len - 8);
-    return {little_endian::Load64(p), high >> (128 - len * 8)};
+    uint64_t low_mem = absl::base_internal::UnalignedLoad64(p);
+    uint64_t high_mem = absl::base_internal::UnalignedLoad64(p + len - 8);
+#ifdef ABSL_IS_LITTLE_ENDIAN
+    uint64_t most_significant = high_mem;
+    uint64_t least_significant = low_mem;
+#else
+    uint64_t most_significant = low_mem;
+    uint64_t least_significant = high_mem;
+#endif
+    return {least_significant, most_significant >> (128 - len * 8)};
   }
 
   // Reads 4 to 8 bytes from p. Zero pads to fill uint64_t.
   static uint64_t Read4To8(const unsigned char* p, size_t len) {
-    return (static_cast<uint64_t>(little_endian::Load32(p + len - 4))
-            << (len - 4) * 8) |
-           little_endian::Load32(p);
+    uint32_t low_mem = absl::base_internal::UnalignedLoad32(p);
+    uint32_t high_mem = absl::base_internal::UnalignedLoad32(p + len - 4);
+#ifdef ABSL_IS_LITTLE_ENDIAN
+    uint32_t most_significant = high_mem;
+    uint32_t least_significant = low_mem;
+#else
+    uint32_t most_significant = low_mem;
+    uint32_t least_significant = high_mem;
+#endif
+    return (static_cast<uint64_t>(most_significant) << (len - 4) * 8) |
+           least_significant;
   }
 
   // Reads 1 to 3 bytes from p. Zero pads to fill uint32_t.
   static uint32_t Read1To3(const unsigned char* p, size_t len) {
-    return static_cast<uint32_t>((p[0]) |                         //
-                                 (p[len / 2] << (len / 2 * 8)) |  //
-                                 (p[len - 1] << ((len - 1) * 8)));
+    unsigned char mem0 = p[0];
+    unsigned char mem1 = p[len / 2];
+    unsigned char mem2 = p[len - 1];
+#ifdef ABSL_IS_LITTLE_ENDIAN
+    unsigned char significant2 = mem2;
+    unsigned char significant1 = mem1;
+    unsigned char significant0 = mem0;
+#else
+    unsigned char significant2 = mem0;
+    unsigned char significant1 = mem1;
+    unsigned char significant0 = mem2;
+#endif
+    return static_cast<uint32_t>(significant0 |                     //
+                                 (significant1 << (len / 2 * 8)) |  //
+                                 (significant2 << ((len - 1) * 8)));
   }
 
   ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Mix(uint64_t state, uint64_t v) {
@@ -838,6 +867,19 @@
     return static_cast<uint64_t>(m ^ (m >> (sizeof(m) * 8 / 2)));
   }
 
+  // An extern to avoid bloat on a direct call to Wyhash() with fixed values for
+  // both the seed and salt parameters.
+  static uint64_t WyhashImpl(const unsigned char* data, size_t len);
+
+  ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Hash64(const unsigned char* data,
+                                                      size_t len) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+    return WyhashImpl(data, len);
+#else
+    return absl::hash_internal::CityHash64(reinterpret_cast<const char*>(data), len);
+#endif
+  }
+
   // Seed()
   //
   // A non-deterministic seed.
@@ -855,15 +897,22 @@
   // On other platforms this is still going to be non-deterministic but most
   // probably per-build and not per-process.
   ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Seed() {
+#if (!defined(__clang__) || __clang_major__ > 11) && \
+    !defined(__apple_build_version__)
+    return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&kSeed));
+#else
+    // Workaround the absence of
+    // https://github.com/llvm/llvm-project/commit/bc15bf66dcca76cc06fe71fca35b74dc4d521021.
     return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(kSeed));
+#endif
   }
   static const void* const kSeed;
 
   uint64_t state_;
 };
 
-// CityHashState::CombineContiguousImpl()
-inline uint64_t CityHashState::CombineContiguousImpl(
+// HashState::CombineContiguousImpl()
+inline uint64_t HashState::CombineContiguousImpl(
     uint64_t state, const unsigned char* first, size_t len,
     std::integral_constant<int, 4> /* sizeof_size_t */) {
   // For large values we use CityHash, for small ones we just use a
@@ -885,18 +934,18 @@
   return Mix(state, v);
 }
 
-// Overload of CityHashState::CombineContiguousImpl()
-inline uint64_t CityHashState::CombineContiguousImpl(
+// Overload of HashState::CombineContiguousImpl()
+inline uint64_t HashState::CombineContiguousImpl(
     uint64_t state, const unsigned char* first, size_t len,
     std::integral_constant<int, 8> /* sizeof_size_t */) {
-  // For large values we use CityHash, for small ones we just use a
-  // multiplicative hash.
+  // For large values we use Wyhash or CityHash depending on the platform, for
+  // small ones we just use a multiplicative hash.
   uint64_t v;
   if (len > 16) {
     if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) {
       return CombineLargeContiguousImpl64(state, first, len);
     }
-    v = absl::hash_internal::CityHash64(reinterpret_cast<const char*>(first), len);
+    v = Hash64(first, len);
   } else if (len > 8) {
     auto p = Read9To16(first, len);
     state = Mix(state, p.first);
@@ -927,7 +976,7 @@
 
 template <typename T>
 struct HashImpl {
-  size_t operator()(const T& value) const { return CityHashState::hash(value); }
+  size_t operator()(const T& value) const { return HashState::hash(value); }
 };
 
 template <typename T>
diff --git a/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash.cc b/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash.cc
new file mode 100644
index 0000000..642bde4
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash.cc
@@ -0,0 +1,111 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 "absl/hash/internal/wyhash.h"
+
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/numeric/int128.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace hash_internal {
+
+static uint64_t WyhashMix(uint64_t v0, uint64_t v1) {
+  absl::uint128 p = v0;
+  p *= v1;
+  return absl::Uint128Low64(p) ^ absl::Uint128High64(p);
+}
+
+uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
+                const uint64_t salt[]) {
+  const uint8_t* ptr = static_cast<const uint8_t*>(data);
+  uint64_t starting_length = static_cast<uint64_t>(len);
+  uint64_t current_state = seed ^ salt[0];
+
+  if (len > 64) {
+    // If we have more than 64 bytes, we're going to handle chunks of 64
+    // bytes at a time. We're going to build up two separate hash states
+    // which we will then hash together.
+    uint64_t duplicated_state = current_state;
+
+    do {
+      uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+      uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+      uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
+      uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
+      uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32);
+      uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40);
+      uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48);
+      uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56);
+
+      uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state);
+      uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state);
+      current_state = (cs0 ^ cs1);
+
+      uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state);
+      uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state);
+      duplicated_state = (ds0 ^ ds1);
+
+      ptr += 64;
+      len -= 64;
+    } while (len > 64);
+
+    current_state = current_state ^ duplicated_state;
+  }
+
+  // We now have a data `ptr` with at most 64 bytes and the current state
+  // of the hashing state machine stored in current_state.
+  while (len > 16) {
+    uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+    uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+
+    current_state = WyhashMix(a ^ salt[1], b ^ current_state);
+
+    ptr += 16;
+    len -= 16;
+  }
+
+  // We now have a data `ptr` with at most 16 bytes.
+  uint64_t a = 0;
+  uint64_t b = 0;
+  if (len > 8) {
+    // When we have at least 9 and at most 16 bytes, set A to the first 64
+    // bits of the input and B to the last 64 bits of the input. Yes, they will
+    // overlap in the middle if we are working with less than the full 16
+    // bytes.
+    a = absl::base_internal::UnalignedLoad64(ptr);
+    b = absl::base_internal::UnalignedLoad64(ptr + len - 8);
+  } else if (len > 3) {
+    // If we have at least 4 and at most 8 bytes, set A to the first 32
+    // bits and B to the last 32 bits.
+    a = absl::base_internal::UnalignedLoad32(ptr);
+    b = absl::base_internal::UnalignedLoad32(ptr + len - 4);
+  } else if (len > 0) {
+    // If we have at least 1 and at most 3 bytes, read all of the provided
+    // bits into A, with some adjustments.
+    a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]);
+    b = 0;
+  } else {
+    a = 0;
+    b = 0;
+  }
+
+  uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state);
+  uint64_t z = salt[1] ^ starting_length;
+  return WyhashMix(w, z);
+}
+
+}  // namespace hash_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash.h b/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash.h
new file mode 100644
index 0000000..4aff4e9
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash.h
@@ -0,0 +1,48 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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.
+//
+// This file provides the Google-internal implementation of the Wyhash
+// algorithm.
+//
+// Wyhash is a fast hash function for hash tables, the fastest we've currently
+// (late 2020) found that passes the SMHasher tests. The algorithm relies on
+// intrinsic 128-bit multiplication for speed. This is not meant to be secure -
+// just fast.
+
+#ifndef ABSL_HASH_INTERNAL_WYHASH_H_
+#define ABSL_HASH_INTERNAL_WYHASH_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace hash_internal {
+
+// Hash function for a byte array. A 64-bit seed and a set of five 64-bit
+// integers are hashed into the result.
+//
+// To allow all hashable types (including string_view and Span) to depend on
+// this algoritm, we keep the API low-level, with as few dependencies as
+// possible.
+uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
+                const uint64_t salt[5]);
+
+}  // namespace hash_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_HASH_INTERNAL_WYHASH_H_
diff --git a/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash_test.cc b/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash_test.cc
new file mode 100644
index 0000000..9fb06d2
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/hash/internal/wyhash_test.cc
@@ -0,0 +1,486 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 "absl/hash/internal/wyhash.h"
+
+#include "absl/strings/escaping.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+static const uint64_t kCurrentSeed = 0;
+static const uint64_t kSalt[5] = {0xa0761d6478bd642f, 0xe7037ed1a0b428dbl,
+                                  0x8ebc6af09c88c6e3, 0x589965cc75374cc3l,
+                                  0x1d8e4e27c47d124f};
+
+// Note: We don't account for endianness, so the values here are only correct if
+// you're also running on a little endian platform.
+
+TEST(WyhashTest, EmptyString) {
+  const std::string s = "";
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      4808886099364463827);
+}
+
+TEST(WyhashTest, Spaces) {
+  const std::string s = "   ";
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      1686201463024549249);
+}
+
+TEST(WyhashTest, RepeatingString) {
+  const std::string s = "aaaa";
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      6646112255271966632);
+}
+
+TEST(WyhashTest, HexString) {
+  const std::string small = "\x01\x02\x03";
+  const std::string med = "\x01\x02\x03\x04";
+
+  EXPECT_EQ(absl::hash_internal::Wyhash(small.c_str(), small.length(),
+                                        kCurrentSeed, kSalt),
+            11989428023081740911ULL);
+  EXPECT_EQ(absl::hash_internal::Wyhash(med.c_str(), med.length(), kCurrentSeed,
+                                        kSalt),
+            9765997711188871556ULL);
+}
+
+TEST(WyhashTest, Words) {
+  const std::string s = "third_party|wyhash|64";
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      3702018632387611330);
+}
+
+TEST(WyhashTest, LongString) {
+  const std::string s =
+      "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz"
+      "0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOp"
+      "QrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEf"
+      "GhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz012345"
+      "6789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789";
+
+  EXPECT_EQ(
+      absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+      9245411362605796064ULL);
+}
+
+TEST(WyhashTest, BigReference) {
+  struct ExpectedResult {
+    absl::string_view base64_data;
+    uint64_t seed;
+    uint64_t hash;
+  } expected_results[] = {
+      {"", uint64_t{0xec42b7ab404b8acb}, uint64_t{0xe5a40d39ab796423}},
+      {"Zw==", uint64_t{0xeeee074043a3ee0f}, uint64_t{0xa6564b468248c683}},
+      {"xmk=", uint64_t{0x857902089c393de}, uint64_t{0xef192f401b116e1c}},
+      {"c1H/", uint64_t{0x993df040024ca3af}, uint64_t{0xbe8dc0c54617639d}},
+      {"SuwpzQ==", uint64_t{0xc4e4c2acea740e96}, uint64_t{0x93d7f665b5521c8e}},
+      {"uqvy++M=", uint64_t{0x6a214b3db872d0cf}, uint64_t{0x646d70bb42445f28}},
+      {"RnzCVPgb", uint64_t{0x44343db6a89dba4d}, uint64_t{0x96a7b1e3cc9bd426}},
+      {"6OeNdlouYw==", uint64_t{0x77b5d6d1ae1dd483},
+       uint64_t{0x76020289ab0790c4}},
+      {"M5/JmmYyDbc=", uint64_t{0x89ab8ecb44d221f1},
+       uint64_t{0x39f842e4133b9b44}},
+      {"MVijWiVdBRdY", uint64_t{0x60244b17577ca81b},
+       uint64_t{0x2b8d7047be4bcaab}},
+      {"6V7Uq7LNxpu0VA==", uint64_t{0x59a08dcee0717067},
+       uint64_t{0x99628abef6716a97}},
+      {"EQ6CdEEhPdyHcOk=", uint64_t{0xf5f20db3ade57396},
+       uint64_t{0x4432e02ba42b2740}},
+      {"PqFB4fxnPgF+l+rc", uint64_t{0xbf8dee0751ad3efb},
+       uint64_t{0x74d810efcad7918a}},
+      {"a5aPOFwq7LA7+zKvPA==", uint64_t{0x6b7a06b268d63e30},
+       uint64_t{0x88c84e986002507f}},
+      {"VOwY21wCGv5D+/qqOvs=", uint64_t{0xb8c37f0ae0f54c82},
+       uint64_t{0x4f99acf193cf39b9}},
+      {"KdHmBTx8lHXYvmGJ+Vy7", uint64_t{0x9fcbed0c38e50eef},
+       uint64_t{0xd90e7a3655891e37}},
+      {"qJkPlbHr8bMF7/cA6aE65Q==", uint64_t{0x2af4bade1d8e3a1d},
+       uint64_t{0x3bb378b1d4df8fcf}},
+      {"ygvL0EhHZL0fIx6oHHtkxRQ=", uint64_t{0x714e3aa912da2f2c},
+       uint64_t{0xf78e94045c052d47}},
+      {"c1rFXkt5YztwZCQRngncqtSs", uint64_t{0xf5ee75e3cbb82c1c},
+       uint64_t{0x26da0b2130da6b40}},
+      {"8hsQrzszzeNQSEcVXLtvIhm6mw==", uint64_t{0x620e7007321b93b9},
+       uint64_t{0x30b4d426af8c6986}},
+      {"ffUL4RocfyP4KfikGxO1yk7omDI=", uint64_t{0xc08528cac2e551fc},
+       uint64_t{0x5413b4aaf3baaeae}},
+      {"OOB5TT00vF9Od/rLbAWshiErqhpV", uint64_t{0x6a1debf9cc3ad39},
+       uint64_t{0x756ab265370a1597}},
+      {"or5wtXM7BFzTNpSzr+Lw5J5PMhVJ/Q==", uint64_t{0x7e0a3c88111fc226},
+       uint64_t{0xdaf5f4b7d09814fb}},
+      {"gk6pCHDUsoopVEiaCrzVDhioRKxb844=", uint64_t{0x1301fef15df39edb},
+       uint64_t{0x8f874ae37742b75e}},
+      {"TNctmwlC5QbEM6/No4R/La3UdkfeMhzs", uint64_t{0x64e181f3d5817ab},
+       uint64_t{0x8fecd03956121ce8}},
+      {"SsQw9iAjhWz7sgcE9OwLuSC6hsM+BfHs2Q==", uint64_t{0xafafc44961078ecb},
+       uint64_t{0x229c292ea7a08285}},
+      {"ZzO3mVCj4xTT2TT3XqDyEKj2BZQBvrS8RHg=", uint64_t{0x4f7bb45549250094},
+       uint64_t{0xbb4bf0692d14bae}},
+      {"+klp5iPQGtppan5MflEls0iEUzqU+zGZkDJX", uint64_t{0xa30061abaa2818c},
+       uint64_t{0x207b24ca3bdac1db}},
+      {"RO6bvOnlJc8I9eniXlNgqtKy0IX6VNg16NRmgg==", uint64_t{0xd902ee3e44a5705f},
+       uint64_t{0x64f6cd6745d3825b}},
+      {"ZJjZqId1ZXBaij9igClE3nyliU5XWdNRrayGlYA=", uint64_t{0x316d36da516f583},
+       uint64_t{0xa2b2e1656b58df1e}},
+      {"7BfkhfGMDGbxfMB8uyL85GbaYQtjr2K8g7RpLzr/", uint64_t{0x402d83f9f834f616},
+       uint64_t{0xd01d30d9ee7a148}},
+      {"rycWk6wHH7htETQtje9PidS2YzXBx+Qkg2fY7ZYS7A==",
+       uint64_t{0x9c604164c016b72c}, uint64_t{0x1cb4cd00ab804e3b}},
+      {"RTkC2OUK+J13CdGllsH0H5WqgspsSa6QzRZouqx6pvI=",
+       uint64_t{0x3f4507e01f9e73ba}, uint64_t{0x4697f2637fd90999}},
+      {"tKjKmbLCNyrLCM9hycOAXm4DKNpM12oZ7dLTmUx5iwAi",
+       uint64_t{0xc3fe0d5be8d2c7c7}, uint64_t{0x8383a756b5688c07}},
+      {"VprUGNH+5NnNRaORxgH/ySrZFQFDL+4VAodhfBNinmn8cg==",
+       uint64_t{0x531858a40bfa7ea1}, uint64_t{0x695c29cb3696a975}},
+      {"gc1xZaY+q0nPcUvOOnWnT3bqfmT/geth/f7Dm2e/DemMfk4=",
+       uint64_t{0x86689478a7a7e8fa}, uint64_t{0xda2e5a5a5e971521}},
+      {"Mr35fIxqx1ukPAL0su1yFuzzAU3wABCLZ8+ZUFsXn47UmAph",
+       uint64_t{0x4ec948b8e7f27288}, uint64_t{0x7935d4befa056b2b}},
+      {"A9G8pw2+m7+rDtWYAdbl8tb2fT7FFo4hLi2vAsa5Y8mKH3CX3g==",
+       uint64_t{0xce46c7213c10032}, uint64_t{0x38dd541ca95420fe}},
+      {"DFaJGishGwEHDdj9ixbCoaTjz9KS0phLNWHVVdFsM93CvPft3hM=",
+       uint64_t{0xf63e96ee6f32a8b6}, uint64_t{0xcc06c7a4963f967f}},
+      {"7+Ugx+Kr3aRNgYgcUxru62YkTDt5Hqis+2po81hGBkcrJg4N0uuy",
+       uint64_t{0x1cfe85e65fc5225}, uint64_t{0xbf0f6f66e232fb20}},
+      {"H2w6O8BUKqu6Tvj2xxaecxEI2wRgIgqnTTG1WwOgDSINR13Nm4d4Vg==",
+       uint64_t{0x45c474f1cee1d2e8}, uint64_t{0xf7efb32d373fe71a}},
+      {"1XBMnIbqD5jy65xTDaf6WtiwtdtQwv1dCVoqpeKj+7cTR1SaMWMyI04=",
+       uint64_t{0x6e024e14015f329c}, uint64_t{0xe2e64634b1c12660}},
+      {"znZbdXG2TSFrKHEuJc83gPncYpzXGbAebUpP0XxzH0rpe8BaMQ17nDbt",
+       uint64_t{0x760c40502103ae1c}, uint64_t{0x285b8fd1638e306d}},
+      {"ylu8Atu13j1StlcC1MRMJJXIl7USgDDS22HgVv0WQ8hx/8pNtaiKB17hCQ==",
+       uint64_t{0x17fd05c3c560c320}, uint64_t{0x658e8a4e3b714d6c}},
+      {"M6ZVVzsd7vAvbiACSYHioH/440dp4xG2mLlBnxgiqEvI/aIEGpD0Sf4VS0g=",
+       uint64_t{0x8b34200a6f8e90d9}, uint64_t{0xf391fb968e0eb398}},
+      {"li3oFSXLXI+ubUVGJ4blP6mNinGKLHWkvGruun85AhVn6iuMtocbZPVhqxzn",
+       uint64_t{0x6be89e50818bdf69}, uint64_t{0x744a9ea0cc144bf2}},
+      {"kFuQHuUCqBF3Tc3hO4dgdIp223ShaCoog48d5Do5zMqUXOh5XpGK1t5XtxnfGA==",
+       uint64_t{0xfb389773315b47d8}, uint64_t{0x12636f2be11012f1}},
+      {"jWmOad0v0QhXVJd1OdGuBZtDYYS8wBVHlvOeTQx9ZZnm8wLEItPMeihj72E0nWY=",
+       uint64_t{0x4f2512a23f61efee}, uint64_t{0x29c57de825948f80}},
+      {"z+DHU52HaOQdW4JrZwDQAebEA6rm13Zg/9lPYA3txt3NjTBqFZlOMvTRnVzRbl23",
+       uint64_t{0x59ccd92fc16c6fda}, uint64_t{0x58c6f99ab0d1c021}},
+      {"MmBiGDfYeTayyJa/tVycg+rN7f9mPDFaDc+23j0TlW9094er0ADigsl4QX7V3gG/qw==",
+       uint64_t{0x25c5a7f5bd330919}, uint64_t{0x13e7b5a7b82fe3bb}},
+      {"774RK+9rOL4iFvs1q2qpo/JVc/I39buvNjqEFDtDvyoB0FXxPI2vXqOrk08VPfIHkmU=",
+       uint64_t{0x51df4174d34c97d7}, uint64_t{0x10fbc87901e02b63}},
+      {"+slatXiQ7/2lK0BkVUI1qzNxOOLP3I1iK6OfHaoxgqT63FpzbElwEXSwdsryq3UlHK0I",
+       uint64_t{0x80ce6d76f89cb57}, uint64_t{0xa24c9184901b748b}},
+      {"64mVTbQ47dHjHlOHGS/hjJwr/"
+       "K2frCNpn87exOqMzNUVYiPKmhCbfS7vBUce5tO6Ec9osQ==",
+       uint64_t{0x20961c911965f684}, uint64_t{0xcac4fd4c5080e581}},
+      {"fIsaG1r530SFrBqaDj1kqE0AJnvvK8MNEZbII2Yw1OK77v0V59xabIh0B5axaz/"
+       "+a2V5WpA=",
+       uint64_t{0x4e5b926ec83868e7}, uint64_t{0xc38bdb7483ba68e1}},
+      {"PGih0zDEOWCYGxuHGDFu9Ivbff/"
+       "iE7BNUq65tycTR2R76TerrXALRosnzaNYO5fjFhTi+CiS",
+       uint64_t{0x3927b30b922eecef}, uint64_t{0xdb2a8069b2ceaffa}},
+      {"RnpA/"
+       "zJnEnnLjmICORByRVb9bCOgxF44p3VMiW10G7PvW7IhwsWajlP9kIwNA9FjAD2GoQHk2Q="
+       "=",
+       uint64_t{0xbd0291284a49b61c}, uint64_t{0xdf9fe91d0d1c7887}},
+      {"qFklMceaTHqJpy2qavJE+EVBiNFOi6OxjOA3LeIcBop1K7w8xQi3TrDk+"
+       "BrWPRIbfprszSaPfrI=",
+       uint64_t{0x73a77c575bcc956}, uint64_t{0xe83f49e96e2e6a08}},
+      {"cLbfUtLl3EcQmITWoTskUR8da/VafRDYF/ylPYwk7/"
+       "zazk6ssyrzxMN3mmSyvrXR2yDGNZ3WDrTT",
+       uint64_t{0x766a0e2ade6d09a6}, uint64_t{0xc69e61b62ca2b62}},
+      {"s/"
+       "Jf1+"
+       "FbsbCpXWPTUSeWyMH6e4CvTFvPE5Fs6Z8hvFITGyr0dtukHzkI84oviVLxhM1xMxrMAy1db"
+       "w==",
+       uint64_t{0x2599f4f905115869}, uint64_t{0xb4a4f3f85f8298fe}},
+      {"FvyQ00+j7nmYZVQ8hI1Edxd0AWplhTfWuFGiu34AK5X8u2hLX1bE97sZM0CmeLe+"
+       "7LgoUT1fJ/axybE=",
+       uint64_t{0xd8256e5444d21e53}, uint64_t{0x167a1b39e1e95f41}},
+      {"L8ncxMaYLBH3g9buPu8hfpWZNlOF7nvWLNv9IozH07uQsIBWSKxoPy8+"
+       "LW4tTuzC6CIWbRGRRD1sQV/4",
+       uint64_t{0xf664a91333fb8dfd}, uint64_t{0xf8a2a5649855ee41}},
+      {"CDK0meI07yrgV2kQlZZ+"
+       "wuVqhc2NmzqeLH7bmcA6kchsRWFPeVF5Wqjjaj556ABeUoUr3yBmfU3kWOakkg==",
+       uint64_t{0x9625b859be372cd1}, uint64_t{0x27992565b595c498}},
+      {"d23/vc5ONh/"
+       "HkMiq+gYk4gaCNYyuFKwUkvn46t+dfVcKfBTYykr4kdvAPNXGYLjM4u1YkAEFpJP+"
+       "nX7eOvs=",
+       uint64_t{0x7b99940782e29898}, uint64_t{0x3e08cca5b71f9346}},
+      {"NUR3SRxBkxTSbtQORJpu/GdR6b/h6sSGfsMj/KFd99ahbh+9r7LSgSGmkGVB/"
+       "mGoT0pnMTQst7Lv2q6QN6Vm",
+       uint64_t{0x4fe12fa5383b51a8}, uint64_t{0xad406b10c770a6d2}},
+      {"2BOFlcI3Z0RYDtS9T9Ie9yJoXlOdigpPeeT+CRujb/"
+       "O39Ih5LPC9hP6RQk1kYESGyaLZZi3jtabHs7DiVx/VDg==",
+       uint64_t{0xe2ccb09ac0f5b4b6}, uint64_t{0xd1713ce6e552bcf2}},
+      {"FF2HQE1FxEvWBpg6Z9zAMH+Zlqx8S1JD/"
+       "wIlViL6ZDZY63alMDrxB0GJQahmAtjlm26RGLnjW7jmgQ4Ie3I+014=",
+       uint64_t{0x7d0a37adbd7b753b}, uint64_t{0x753b287194c73ad3}},
+      {"tHmO7mqVL/PX11nZrz50Hc+M17Poj5lpnqHkEN+4bpMx/"
+       "YGbkrGOaYjoQjgmt1X2QyypK7xClFrjeWrCMdlVYtbW",
+       uint64_t{0xd3ae96ef9f7185f2}, uint64_t{0x5ae41a95f600af1c}},
+      {"/WiHi9IQcxRImsudkA/KOTqGe8/"
+       "gXkhKIHkjddv5S9hi02M049dIK3EUyAEjkjpdGLUs+BN0QzPtZqjIYPOgwsYE9g==",
+       uint64_t{0x4fb88ea63f79a0d8}, uint64_t{0x4a61163b86a8bb4c}},
+      {"qds+1ExSnU11L4fTSDz/QE90g4Jh6ioqSh3KDOTOAo2pQGL1k/"
+       "9CCC7J23YF27dUTzrWsCQA2m4epXoCc3yPHb3xElA=",
+       uint64_t{0xed564e259bb5ebe9}, uint64_t{0x42eeaa79e760c7e4}},
+      {"8FVYHx40lSQPTHheh08Oq0/"
+       "pGm2OlG8BEf8ezvAxHuGGdgCkqpXIueJBF2mQJhTfDy5NncO8ntS7vaKs7sCNdDaNGOEi",
+       uint64_t{0x3e3256b60c428000}, uint64_t{0x698df622ef465b0a}},
+      {"4ZoEIrJtstiCkeew3oRzmyJHVt/pAs2pj0HgHFrBPztbQ10NsQ/"
+       "lM6DM439QVxpznnBSiHMgMQJhER+70l72LqFTO1JiIQ==",
+       uint64_t{0xfb05bad59ec8705}, uint64_t{0x157583111e1a6026}},
+      {"hQPtaYI+wJyxXgwD5n8jGIKFKaFA/"
+       "P83KqCKZfPthnjwdOFysqEOYwAaZuaaiv4cDyi9TyS8hk5cEbNP/jrI7q6pYGBLbsM=",
+       uint64_t{0xafdc251dbf97b5f8}, uint64_t{0xaa1388f078e793e0}},
+      {"S4gpMSKzMD7CWPsSfLeYyhSpfWOntyuVZdX1xSBjiGvsspwOZcxNKCRIOqAA0moUfOh3I5+"
+       "juQV4rsqYElMD/gWfDGpsWZKQ",
+       uint64_t{0x10ec9c92ddb5dcbc}, uint64_t{0xf10d68d0f3309360}},
+      {"oswxop+"
+       "bthuDLT4j0PcoSKby4LhF47ZKg8K17xxHf74UsGCzTBbOz0MM8hQEGlyqDT1iUiAYnaPaUp"
+       "L2mRK0rcIUYA4qLt5uOw==",
+       uint64_t{0x9a767d5822c7dac4}, uint64_t{0x2af056184457a3de}},
+      {"0II/"
+       "697p+"
+       "BtLSjxj5989OXI004TogEb94VUnDzOVSgMXie72cuYRvTFNIBgtXlKfkiUjeqVpd4a+"
+       "n5bxNOD1TGrjQtzKU5r7obo=",
+       uint64_t{0xee46254080d6e2db}, uint64_t{0x6d0058e1590b2489}},
+      {"E84YZW2qipAlMPmctrg7TKlwLZ68l4L+c0xRDUfyyFrA4MAti0q9sHq3TDFviH0Y+"
+       "Kq3tEE5srWFA8LM9oomtmvm5PYxoaarWPLc",
+       uint64_t{0xbbb669588d8bf398}, uint64_t{0x638f287f68817f12}},
+      {"x3pa4HIElyZG0Nj7Vdy9IdJIR4izLmypXw5PCmZB5y68QQ4uRaVVi3UthsoJROvbjDJkP2D"
+       "Q6L/eN8pFeLFzNPKBYzcmuMOb5Ull7w==",
+       uint64_t{0xdc2afaa529beef44}, uint64_t{0xc46b71fecefd5467}},
+      {"jVDKGYIuWOP/"
+       "QKLdd2wi8B2VJA8Wh0c8PwrXJVM8FOGM3voPDVPyDJOU6QsBDPseoR8uuKd19OZ/"
+       "zAvSCB+zlf6upAsBlheUKgCfKww=",
+       uint64_t{0xf1f67391d45013a8}, uint64_t{0x2c8e94679d964e0a}},
+      {"mkquunhmYe1aR2wmUz4vcvLEcKBoe6H+kjUok9VUn2+eTSkWs4oDDtJvNCWtY5efJwg/"
+       "j4PgjRYWtqnrCkhaqJaEvkkOwVfgMIwF3e+d",
+       uint64_t{0x16fce2b8c65a3429}, uint64_t{0x8612b797ce22503a}},
+      {"fRelvKYonTQ+s+rnnvQw+JzGfFoPixtna0vzcSjiDqX5s2Kg2//"
+       "UGrK+AVCyMUhO98WoB1DDbrsOYSw2QzrcPe0+3ck9sePvb+Q/IRaHbw==",
+       uint64_t{0xf4b096699f49fe67}, uint64_t{0x59f929babfba7170}},
+      {"DUwXFJzagljo44QeJ7/"
+       "6ZKw4QXV18lhkYT2jglMr8WB3CHUU4vdsytvw6AKv42ZcG6fRkZkq9fpnmXy6xG0aO3WPT1"
+       "eHuyFirAlkW+zKtwg=",
+       uint64_t{0xca584c4bc8198682}, uint64_t{0x9527556923fb49a0}},
+      {"cYmZCrOOBBongNTr7e4nYn52uQUy2mfe48s50JXx2AZ6cRAt/"
+       "xRHJ5QbEoEJOeOHsJyM4nbzwFm++SlT6gFZZHJpkXJ92JkR86uS/eV1hJUR",
+       uint64_t{0xed269fc3818b6aad}, uint64_t{0x1039ab644f5e150b}},
+      {"EXeHBDfhwzAKFhsMcH9+2RHwV+mJaN01+9oacF6vgm8mCXRd6jeN9U2oAb0of5c5cO4i+"
+       "Vb/LlHZSMI490SnHU0bejhSCC2gsC5d2K30ER3iNA==",
+       uint64_t{0x33f253cbb8fe66a8}, uint64_t{0x7816c83f3aa05e6d}},
+      {"FzkzRYoNjkxFhZDso94IHRZaJUP61nFYrh5MwDwv9FNoJ5jyNCY/"
+       "eazPZk+tbmzDyJIGw2h3GxaWZ9bSlsol/vK98SbkMKCQ/wbfrXRLcDzdd/8=",
+       uint64_t{0xd0b76b2c1523d99c}, uint64_t{0xf51d2f564518c619}},
+      {"Re4aXISCMlYY/XsX7zkIFR04ta03u4zkL9dVbLXMa/q6hlY/CImVIIYRN3VKP4pnd0AUr/"
+       "ugkyt36JcstAInb4h9rpAGQ7GMVOgBniiMBZ/MGU7H",
+       uint64_t{0xfd28f0811a2a237f}, uint64_t{0x67d494cff03ac004}},
+      {"ueLyMcqJXX+MhO4UApylCN9WlTQ+"
+       "ltJmItgG7vFUtqs2qNwBMjmAvr5u0sAKd8jpzV0dDPTwchbIeAW5zbtkA2NABJV6hFM48ib"
+       "4/J3A5mseA3cS8w==",
+       uint64_t{0x6261fb136482e84}, uint64_t{0x2802d636ced1cfbb}},
+      {"6Si7Yi11L+jZMkwaN+GUuzXMrlvEqviEkGOilNq0h8TdQyYKuFXzkYc/"
+       "q74gP3pVCyiwz9KpVGMM9vfnq36riMHRknkmhQutxLZs5fbmOgEO69HglCU=",
+       uint64_t{0x458efc750bca7c3a}, uint64_t{0xf64e20bad771cb12}},
+      {"Q6AbOofGuTJOegPh9Clm/"
+       "9crtUMQqylKrTc1fhfJo1tqvpXxhU4k08kntL1RG7woRnFrVh2UoMrL1kjin+s9CanT+"
+       "y4hHwLqRranl9FjvxfVKm3yvg68",
+       uint64_t{0xa7e69ff84e5e7c27}, uint64_t{0xb9a6cf84a83e15e}},
+      {"ieQEbIPvqY2YfIjHnqfJiO1/MIVRk0RoaG/WWi3kFrfIGiNLCczYoklgaecHMm/"
+       "1sZ96AjO+a5stQfZbJQwS7Sc1ODABEdJKcTsxeW2hbh9A6CFzpowP1A==",
+       uint64_t{0x3c59bfd0c29efe9e}, uint64_t{0x8da6630319609301}},
+      {"zQUv8hFB3zh2GGl3KTvCmnfzE+"
+       "SUgQPVaSVIELFX5H9cE3FuVFGmymkPQZJLAyzC90Cmi8GqYCvPqTuAAB//"
+       "XTJxy4bCcVArgZG9zJXpjowpNBfr3ngWrSE=",
+       uint64_t{0x10befacc6afd298d}, uint64_t{0x40946a86e2a996f3}},
+      {"US4hcC1+op5JKGC7eIs8CUgInjKWKlvKQkapulxW262E/"
+       "B2ye79QxOexf188u2mFwwe3WTISJHRZzS61IwljqAWAWoBAqkUnW8SHmIDwHUP31J0p5sGd"
+       "P47L",
+       uint64_t{0x41d5320b0a38efa7}, uint64_t{0xcab7f5997953fa76}},
+      {"9bHUWFna2LNaGF6fQLlkx1Hkt24nrkLE2CmFdWgTQV3FFbUe747SSqYw6ebpTa07MWSpWRP"
+       "sHesVo2B9tqHbe7eQmqYebPDFnNqrhSdZwFm9arLQVs+7a3Ic6A==",
+       uint64_t{0x58db1c7450fe17f3}, uint64_t{0x39129ca0e04fc465}},
+      {"Kb3DpHRUPhtyqgs3RuXjzA08jGb59hjKTOeFt1qhoINfYyfTt2buKhD6YVffRCPsgK9SeqZ"
+       "qRPJSyaqsa0ovyq1WnWW8jI/NhvAkZTVHUrX2pC+cD3OPYT05Dag=",
+       uint64_t{0x6098c055a335b7a6}, uint64_t{0x5238221fd685e1b8}},
+      {"gzxyMJIPlU+bJBwhFUCHSofZ/"
+       "319LxqMoqnt3+L6h2U2+ZXJCSsYpE80xmR0Ta77Jq54o92SMH87HV8dGOaCTuAYF+"
+       "lDL42SY1P316Cl0sZTS2ow3ZqwGbcPNs/1",
+       uint64_t{0x1bbacec67845a801}, uint64_t{0x175130c407dbcaab}},
+      {"uR7V0TW+FGVMpsifnaBAQ3IGlr1wx5sKd7TChuqRe6OvUXTlD4hKWy8S+"
+       "8yyOw8lQabism19vOQxfmocEOW/"
+       "vzY0pEa87qHrAZy4s9fH2Bltu8vaOIe+agYohhYORQ==",
+       uint64_t{0xc419cfc7442190}, uint64_t{0x2f20e7536c0b0df}},
+      {"1UR5eoo2aCwhacjZHaCh9bkOsITp6QunUxHQ2SfeHv0imHetzt/"
+       "Z70mhyWZBalv6eAx+YfWKCUib2SHDtz/"
+       "A2dc3hqUWX5VfAV7FQsghPUAtu6IiRatq4YSLpDvKZBQ=",
+       uint64_t{0xc95e510d94ba270c}, uint64_t{0x2742cb488a04ad56}},
+      {"opubR7H63BH7OtY+Avd7QyQ25UZ8kLBdFDsBTwZlY6gA/"
+       "u+x+"
+       "czC9AaZMgmQrUy15DH7YMGsvdXnviTtI4eVI4aF1H9Rl3NXMKZgwFOsdTfdcZeeHVRzBBKX"
+       "8jUfh1il",
+       uint64_t{0xff1ae05c98089c3f}, uint64_t{0xd6afb593879ff93b}},
+      {"DC0kXcSXtfQ9FbSRwirIn5tgPri0sbzHSa78aDZVDUKCMaBGyFU6BmrulywYX8yzvwprdLs"
+       "oOwTWN2wMjHlPDqrvVHNEjnmufRDblW+nSS+xtKNs3N5xsxXdv6JXDrAB/Q==",
+       uint64_t{0x90c02b8dceced493}, uint64_t{0xf50ad64caac0ca7f}},
+      {"BXRBk+3wEP3Lpm1y75wjoz+PgB0AMzLe8tQ1AYU2/"
+       "oqrQB2YMC6W+9QDbcOfkGbeH+b7IBkt/"
+       "gwCMw2HaQsRFEsurXtcQ3YwRuPz5XNaw5NAvrNa67Fm7eRzdE1+hWLKtA8=",
+       uint64_t{0x9f8a76697ab1aa36}, uint64_t{0x2ade95c4261364ae}},
+      {"RRBSvEGYnzR9E45Aps/+WSnpCo/X7gJLO4DRnUqFrJCV/kzWlusLE/"
+       "6ZU6RoUf2ROwcgEvUiXTGjLs7ts3t9SXnJHxC1KiOzxHdYLMhVvgNd3hVSAXODpKFSkVXND"
+       "55G2L1W",
+       uint64_t{0x6ba1bf3d811a531d}, uint64_t{0x5c4f3299faacd07a}},
+      {"jeh6Qazxmdi57pa9S3XSnnZFIRrnc6s8QLrah5OX3SB/V2ErSPoEAumavzQPkdKF1/"
+       "SfvmdL+qgF1C+Yawy562QaFqwVGq7+tW0yxP8FStb56ZRgNI4IOmI30s1Ei7iops9Uuw==",
+       uint64_t{0x6a418974109c67b4}, uint64_t{0xfffe3bff0ae5e9bc}},
+      {"6QO5nnDrY2/"
+       "wrUXpltlKy2dSBcmK15fOY092CR7KxAjNfaY+"
+       "aAmtWbbzQk3MjBg03x39afSUN1fkrWACdyQKRaGxgwq6MGNxI6W+8DLWJBHzIXrntrE/"
+       "ml6fnNXEpxplWJ1vEs4=",
+       uint64_t{0x8472f1c2b3d230a3}, uint64_t{0x1db785c0005166e4}},
+      {"0oPxeEHhqhcFuwonNfLd5jF3RNATGZS6NPoS0WklnzyokbTqcl4BeBkMn07+fDQv83j/"
+       "BpGUwcWO05f3+DYzocfnizpFjLJemFGsls3gxcBYxcbqWYev51tG3lN9EvRE+X9+Pwww",
+       uint64_t{0x5e06068f884e73a7}, uint64_t{0xea000d962ad18418}},
+      {"naSBSjtOKgAOg8XVbR5cHAW3Y+QL4Pb/JO9/"
+       "oy6L08wvVRZqo0BrssMwhzBP401Um7A4ppAupbQeJFdMrysY34AuSSNvtNUy5VxjNECwiNt"
+       "gwYHw7yakDUv8WvonctmnoSPKENegQg==",
+       uint64_t{0x55290b1a8f170f59}, uint64_t{0xe42aef38359362d9}},
+      {"vPyl8DxVeRe1OpilKb9KNwpGkQRtA94UpAHetNh+"
+       "95V7nIW38v7PpzhnTWIml5kw3So1Si0TXtIUPIbsu32BNhoH7QwFvLM+"
+       "JACgSpc5e3RjsL6Qwxxi11npwxRmRUqATDeMUfRAjxg=",
+       uint64_t{0x5501cfd83dfe706a}, uint64_t{0xc8e95657348a3891}},
+      {"QC9i2GjdTMuNC1xQJ74ngKfrlA4w3o58FhvNCltdIpuMhHP1YsDA78scQPLbZ3OCUgeQguY"
+       "f/vw6zAaVKSgwtaykqg5ka/4vhz4hYqWU5ficdXqClHl+zkWEY26slCNYOM5nnDlly8Cj",
+       uint64_t{0xe43ed13d13a66990}, uint64_t{0xc162eca864f238c6}},
+      {"7CNIgQhAHX27nxI0HeB5oUTnTdgKpRDYDKwRcXfSFGP1XeT9nQF6WKCMjL1tBV6x7KuJ91G"
+       "Zz11F4c+8s+MfqEAEpd4FHzamrMNjGcjCyrVtU6y+7HscMVzr7Q/"
+       "ODLcPEFztFnwjvCjmHw==",
+       uint64_t{0xdf43bc375cf5283f}, uint64_t{0xbe1fb373e20579ad}},
+      {"Qa/hC2RPXhANSospe+gUaPfjdK/yhQvfm4cCV6/pdvCYWPv8p1kMtKOX3h5/"
+       "8oZ31fsmx4Axphu5qXJokuhZKkBUJueuMpxRyXpwSWz2wELx5glxF7CM0Fn+"
+       "OevnkhUn5jsPlG2r5jYlVn8=",
+       uint64_t{0x8112b806d288d7b5}, uint64_t{0x628a1d4f40aa6ffd}},
+      {"kUw/0z4l3a89jTwN5jpG0SHY5km/"
+       "IVhTjgM5xCiPRLncg40aqWrJ5vcF891AOq5hEpSq0bUCJUMFXgct7kvnys905HjerV7Vs1G"
+       "y84tgVJ70/2+pAZTsB/PzNOE/G6sOj4+GbTzkQu819OLB",
+       uint64_t{0xd52a18abb001cb46}, uint64_t{0xa87bdb7456340f90}},
+      {"VDdfSDbO8Tdj3T5W0XM3EI7iHh5xpIutiM6dvcJ/fhe23V/srFEkDy5iZf/"
+       "VnA9kfi2C79ENnFnbOReeuZW1b3MUXB9lgC6U4pOTuC+"
+       "jHK3Qnpyiqzj7h3ISJSuo2pob7vY6VHZo6Fn7exEqHg==",
+       uint64_t{0xe12b76a2433a1236}, uint64_t{0x5960ef3ba982c801}},
+      {"Ldfvy3ORdquM/R2fIkhH/ONi69mcP1AEJ6n/"
+       "oropwecAsLJzQSgezSY8bEiEs0VnFTBBsW+RtZY6tDj03fnb3amNUOq1b7jbqyQkL9hpl+"
+       "2Z2J8IaVSeownWl+bQcsR5/xRktIMckC5AtF4YHfU=",
+       uint64_t{0x175bf7319cf1fa00}, uint64_t{0x5026586df9a431ec}},
+      {"BrbNpb42+"
+       "VzZAjJw6QLirXzhweCVRfwlczzZ0VX2xluskwBqyfnGovz5EuX79JJ31VNXa5hTkAyQat3l"
+       "YKRADTdAdwE5PqM1N7YaMqqsqoAAAeuYVXuk5eWCykYmClNdSspegwgCuT+403JigBzi",
+       uint64_t{0xd63d57b3f67525ae}, uint64_t{0xfe4b8a20fdf0840b}},
+      {"gB3NGHJJvVcuPyF0ZSvHwnWSIfmaI7La24VMPQVoIIWF7Z74NltPZZpx2f+cocESM+"
+       "ILzQW9p+BC8x5IWz7N4Str2WLGKMdgmaBfNkEhSHQDU0IJEOnpUt0HmjhFaBlx0/"
+       "LTmhua+rQ6Wup8ezLwfg==",
+       uint64_t{0x933faea858832b73}, uint64_t{0xdcb761867da7072f}},
+      {"hTKHlRxx6Pl4gjG+6ksvvj0CWFicUg3WrPdSJypDpq91LUWRni2KF6+"
+       "81ZoHBFhEBrCdogKqeK+hy9bLDnx7g6rAFUjtn1+cWzQ2YjiOpz4+"
+       "ROBB7lnwjyTGWzJD1rXtlso1g2qVH8XJVigC5M9AIxM=",
+       uint64_t{0x53d061e5f8e7c04f}, uint64_t{0xc10d4653667275b7}},
+      {"IWQBelSQnhrr0F3BhUpXUIDauhX6f95Qp+A0diFXiUK7irwPG1oqBiqHyK/SH/"
+       "9S+"
+       "rln9DlFROAmeFdH0OCJi2tFm4afxYzJTFR4HnR4cG4x12JqHaZLQx6iiu6CE3rtWBVz99oA"
+       "wCZUOEXIsLU24o2Y",
+       uint64_t{0xdb4124556dd515e0}, uint64_t{0x727720deec13110b}},
+      {"TKo+l+"
+       "1dOXdLvIrFqeLaHdm0HZnbcdEgOoLVcGRiCbAMR0j5pIFw8D36tefckAS1RCFOH5IgP8yiF"
+       "T0Gd0a2hI3+"
+       "fTKA7iK96NekxWeoeqzJyctc6QsoiyBlkZerRxs5RplrxoeNg29kKDTM0K94mnhD9g==",
+       uint64_t{0x4fb31a0dd681ee71}, uint64_t{0x710b009662858dc9}},
+      {"YU4e7G6EfQYvxCFoCrrT0EFgVLHFfOWRTJQJ5gxM3G2b+"
+       "1kJf9YPrpsxF6Xr6nYtS8reEEbDoZJYqnlk9lXSkVArm88Cqn6d25VCx3+"
+       "49MqC0trIlXtb7SXUUhwpJK16T0hJUfPH7s5cMZXc6YmmbFuBNPE=",
+       uint64_t{0x27cc72eefa138e4c}, uint64_t{0xfbf8f7a3ecac1eb7}},
+      {"/I/"
+       "eImMwPo1U6wekNFD1Jxjk9XQVi1D+"
+       "FPdqcHifYXQuP5aScNQfxMAmaPR2XhuOQhADV5tTVbBKwCDCX4E3jcDNHzCiPvViZF1W27t"
+       "xaf2BbFQdwKrNCmrtzcluBFYu0XZfc7RU1RmxK/RtnF1qHsq/O4pp",
+       uint64_t{0x44bc2dfba4bd3ced}, uint64_t{0xb6fc4fcd0722e3df}},
+      {"CJTT9WGcY2XykTdo8KodRIA29qsqY0iHzWZRjKHb9alwyJ7RZAE3V5Juv4MY3MeYEr1EPCC"
+       "MxO7yFXqT8XA8YTjaMp3bafRt17Pw8JC4iKJ1zN+WWKOESrj+"
+       "3aluGQqn8z1EzqY4PH7rLG575PYeWsP98BugdA==",
+       uint64_t{0x242da1e3a439bed8}, uint64_t{0x7cb86dcc55104aac}},
+      {"ZlhyQwLhXQyIUEnMH/"
+       "AEW27vh9xrbNKJxpWGtrEmKhd+nFqAfbeNBQjW0SfG1YI0xQkQMHXjuTt4P/"
+       "EpZRtA47ibZDVS8TtaxwyBjuIDwqcN09eCtpC+Ls+"
+       "vWDTLmBeDM3u4hmzz4DQAYsLiZYSJcldg9Q3wszw=",
+       uint64_t{0xdc559c746e35c139}, uint64_t{0x19e71e9b45c3a51e}},
+      {"v2KU8y0sCrBghmnm8lzGJlwo6D6ObccAxCf10heoDtYLosk4ztTpLlpSFEyu23MLA1tJkcg"
+       "Rko04h19QMG0mOw/"
+       "wc93EXAweriBqXfvdaP85sZABwiKO+6rtS9pacRVpYYhHJeVTQ5NzrvBvi1huxAr+"
+       "xswhVMfL",
+       uint64_t{0xd0b0350275b9989}, uint64_t{0x51de38573c2bea48}},
+      {"QhKlnIS6BuVCTQsnoE67E/"
+       "yrgogE8EwO7xLaEGei26m0gEU4OksefJgppDh3X0x0Cs78Dr9IHK5b977CmZlrTRmwhlP8p"
+       "M+UzXPNRNIZuN3ntOum/QhUWP8SGpirheXENWsXMQ/"
+       "nxtxakyEtrNkKk471Oov9juP8oQ==",
+       uint64_t{0xb04489e41d17730c}, uint64_t{0xa73ab6996d6df158}},
+      {"/ZRMgnoRt+Uo6fUPr9FqQvKX7syhgVqWu+"
+       "WUSsiQ68UlN0efSP6Eced5gJZL6tg9gcYJIkhjuQNITU0Q3TjVAnAcobgbJikCn6qZ6pRxK"
+       "BY4MTiAlfGD3T7R7hwJwx554MAy++Zb/YUFlnCaCJiwQMnowF7aQzwYFCo=",
+       uint64_t{0x2217285eb4572156}, uint64_t{0x55ef2b8c930817b2}},
+      {"NB7tU5fNE8nI+SXGfipc7sRkhnSkUF1krjeo6k+8FITaAtdyz+"
+       "o7mONgXmGLulBPH9bEwyYhKNVY0L+njNQrZ9YC2aXsFD3PdZsxAFaBT3VXEzh+"
+       "NGBTjDASNL3mXyS8Yv1iThGfHoY7T4aR0NYGJ+k+pR6f+KrPC96M",
+       uint64_t{0x12c2e8e68aede73b}, uint64_t{0xb2850bf5fae87157}},
+      {"8T6wrqCtEO6/rwxF6lvMeyuigVOLwPipX/FULvwyu+1wa5sQGav/"
+       "2FsLHUVn6cGSi0LlFwLewGHPFJDLR0u4t7ZUyM//"
+       "x6da0sWgOa5hzDqjsVGmjxEHXiaXKW3i4iSZNuxoNbMQkIbVML+"
+       "DkYu9ND0O2swg4itGeVSzXA==",
+       uint64_t{0x4d612125bdc4fd00}, uint64_t{0xecf3de1acd04651f}},
+      {"Ntf1bMRdondtMv1CYr3G80iDJ4WSAlKy5H34XdGruQiCrnRGDBa+"
+       "eUi7vKp4gp3BBcVGl8eYSasVQQjn7MLvb3BjtXx6c/"
+       "bCL7JtpzQKaDnPr9GWRxpBXVxKREgMM7d8lm35EODv0w+"
+       "hQLfVSh8OGs7fsBb68nNWPLeeSOo=",
+       uint64_t{0x81826b553954464e}, uint64_t{0xcc0a40552559ff32}},
+      {"VsSAw72Ro6xks02kaiLuiTEIWBC5bgqr4WDnmP8vglXzAhixk7td926rm9jNimL+"
+       "kroPSygZ9gl63aF5DCPOACXmsbmhDrAQuUzoh9ZKhWgElLQsrqo1KIjWoZT5b5QfVUXY9lS"
+       "IBg3U75SqORoTPq7HalxxoIT5diWOcJQi",
+       uint64_t{0xc2e5d345dc0ddd2d}, uint64_t{0xc385c374f20315b1}},
+      {"j+loZ+C87+"
+       "bJxNVebg94gU0mSLeDulcHs84tQT7BZM2rzDSLiCNxUedHr1ZWJ9ejTiBa0dqy2I2ABc++"
+       "xzOLcv+//YfibtjKtYggC6/3rv0XCc7xu6d/"
+       "O6xO+XOBhOWAQ+IHJVHf7wZnDxIXB8AUHsnjEISKj7823biqXjyP3g==",
+       uint64_t{0x3da6830a9e32631e}, uint64_t{0xb90208a4c7234183}},
+      {"f3LlpcPElMkspNtDq5xXyWU62erEaKn7RWKlo540gR6mZsNpK1czV/"
+       "sOmqaq8XAQLEn68LKj6/"
+       "cFkJukxRzCa4OF1a7cCAXYFp9+wZDu0bw4y63qbpjhdCl8GO6Z2lkcXy7KOzbPE01ukg7+"
+       "gN+7uKpoohgAhIwpAKQXmX5xtd0=",
+       uint64_t{0xc9ae5c8759b4877a}, uint64_t{0x58aa1ca7a4c075d9}},
+  };
+
+  for (const auto& expected_result : expected_results) {
+    std::string str;
+    ASSERT_TRUE(absl::Base64Unescape(expected_result.base64_data, &str));
+    EXPECT_EQ(absl::hash_internal::Wyhash(str.data(), str.size(),
+                                          expected_result.seed, kSalt),
+              expected_result.hash);
+  }
+}
+
+}  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/meta/type_traits.h b/grpc/third_party/abseil-cpp/absl/meta/type_traits.h
index 75689bb..d5cb5f3 100644
--- a/grpc/third_party/abseil-cpp/absl/meta/type_traits.h
+++ b/grpc/third_party/abseil-cpp/absl/meta/type_traits.h
@@ -610,8 +610,22 @@
 template <typename T>
 using underlying_type_t = typename std::underlying_type<T>::type;
 
-template <typename T>
-using result_of_t = typename std::result_of<T>::type;
+
+namespace type_traits_internal {
+
+#if __cplusplus >= 201703L
+// std::result_of is deprecated (C++17) or removed (C++20)
+template<typename> struct result_of;
+template<typename F, typename... Args>
+struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
+#else
+template<typename F> using result_of = std::result_of<F>;
+#endif
+
+}  // namespace type_traits_internal
+
+template<typename F>
+using result_of_t = typename type_traits_internal::result_of<F>::type;
 
 namespace type_traits_internal {
 // In MSVC we can't probe std::hash or stdext::hash because it triggers a
diff --git a/grpc/third_party/abseil-cpp/absl/numeric/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/numeric/BUILD.bazel
index f808f5d..ea587bf 100644
--- a/grpc/third_party/abseil-cpp/absl/numeric/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/numeric/BUILD.bazel
@@ -25,6 +25,35 @@
 licenses(["notice"])
 
 cc_library(
+    name = "bits",
+    hdrs = [
+        "bits.h",
+        "internal/bits.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:config",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "bits_test",
+    size = "small",
+    srcs = [
+        "bits_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":bits",
+        "//absl/random",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "int128",
     srcs = [
         "int128.cc",
@@ -35,7 +64,7 @@
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
-        "//absl/base:bits",
+        ":bits",
         "//absl/base:config",
         "//absl/base:core_headers",
     ],
@@ -72,3 +101,15 @@
         "@com_github_google_benchmark//:benchmark_main",
     ],
 )
+
+cc_library(
+    name = "representation",
+    hdrs = [
+        "internal/representation.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:config",
+    ],
+)
diff --git a/grpc/third_party/abseil-cpp/absl/numeric/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/numeric/CMakeLists.txt
index 1e12d80..781987d 100644
--- a/grpc/third_party/abseil-cpp/absl/numeric/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/numeric/CMakeLists.txt
@@ -16,6 +16,33 @@
 
 absl_cc_library(
   NAME
+    bits
+  HDRS
+    "bits.h"
+    "internal/bits.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::core_headers
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    bits_test
+  SRCS
+    "bits_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::bits
+    absl::core_headers
+    absl::random_random
+    gmock_main
+)
+
+absl_cc_library(
+  NAME
     int128
   HDRS
     "int128.h"
@@ -26,9 +53,9 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
-    absl::bits
     absl::config
     absl::core_headers
+    absl::bits
   PUBLIC
 )
 
@@ -59,3 +86,15 @@
     absl::int128
   PUBLIC
 )
+
+absl_cc_library(
+  NAME
+    numeric_representation
+  HDRS
+    "internal/representation.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+  PUBLIC
+)
diff --git a/grpc/third_party/abseil-cpp/absl/numeric/bits.h b/grpc/third_party/abseil-cpp/absl/numeric/bits.h
new file mode 100644
index 0000000..52013ad
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/numeric/bits.h
@@ -0,0 +1,177 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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.
+//
+// -----------------------------------------------------------------------------
+// File: bits.h
+// -----------------------------------------------------------------------------
+//
+// This file contains implementations of C++20's bitwise math functions, as
+// defined by:
+//
+// P0553R4:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html
+// P0556R3:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0556r3.html
+// P1355R2:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1355r2.html
+// P1956R1:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1956r1.pdf
+//
+// When using a standard library that implements these functions, we use the
+// standard library's implementation.
+
+#ifndef ABSL_NUMERIC_BITS_H_
+#define ABSL_NUMERIC_BITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#if (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) || \
+    (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+#include <bit>
+#endif
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/numeric/internal/bits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+#if !(defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+// rotating
+template <class T>
+ABSL_MUST_USE_RESULT constexpr
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    rotl(T x, int s) noexcept {
+  return numeric_internal::RotateLeft(x, s);
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT constexpr
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    rotr(T x, int s) noexcept {
+  return numeric_internal::RotateRight(x, s);
+}
+
+// Counting functions
+//
+// While these functions are typically constexpr, on some platforms, they may
+// not be marked as constexpr due to constraints of the compiler/available
+// intrinsics.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countl_zero(T x) noexcept {
+  return numeric_internal::CountLeadingZeroes(x);
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countl_one(T x) noexcept {
+  // Avoid integer promotion to a wider type
+  return countl_zero(static_cast<T>(~x));
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CTZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countr_zero(T x) noexcept {
+  return numeric_internal::CountTrailingZeroes(x);
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CTZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countr_one(T x) noexcept {
+  // Avoid integer promotion to a wider type
+  return countr_zero(static_cast<T>(~x));
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    popcount(T x) noexcept {
+  return numeric_internal::Popcount(x);
+}
+#else  // defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+
+using std::countl_one;
+using std::countl_zero;
+using std::countr_one;
+using std::countr_zero;
+using std::popcount;
+using std::rotl;
+using std::rotr;
+
+#endif
+
+#if !(defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L)
+// Returns: true if x is an integral power of two; false otherwise.
+template <class T>
+constexpr inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+has_single_bit(T x) noexcept {
+  return x != 0 && (x & (x - 1)) == 0;
+}
+
+// Returns: If x == 0, 0; otherwise one plus the base-2 logarithm of x, with any
+// fractional part discarded.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_width(T x) noexcept {
+  return std::numeric_limits<T>::digits - countl_zero(x);
+}
+
+// Returns: If x == 0, 0; otherwise the maximal value y such that
+// has_single_bit(y) is true and y <= x.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_floor(T x) noexcept {
+  return x == 0 ? 0 : T{1} << (bit_width(x) - 1);
+}
+
+// Returns: N, where N is the smallest power of 2 greater than or equal to x.
+//
+// Preconditions: N is representable as a value of type T.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_ceil(T x) {
+  // If T is narrower than unsigned, T{1} << bit_width will be promoted.  We
+  // want to force it to wraparound so that bit_ceil of an invalid value are not
+  // core constant expressions.
+  //
+  // BitCeilNonPowerOf2 triggers an overflow in constexpr contexts if we would
+  // undergo promotion to unsigned but not fit the result into T without
+  // truncation.
+  return has_single_bit(x) ? T{1} << (bit_width(x) - 1)
+                           : numeric_internal::BitCeilNonPowerOf2(x);
+}
+#else  // defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L
+
+using std::bit_ceil;
+using std::bit_floor;
+using std::bit_width;
+using std::has_single_bit;
+
+#endif
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_BITS_H_
diff --git a/grpc/third_party/abseil-cpp/absl/numeric/bits_test.cc b/grpc/third_party/abseil-cpp/absl/numeric/bits_test.cc
new file mode 100644
index 0000000..7c942aa
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/numeric/bits_test.cc
@@ -0,0 +1,573 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 "absl/numeric/bits.h"
+
+#include <limits>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/random/random.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+TEST(Rotate, Left) {
+  static_assert(rotl(uint8_t{0x12}, 0) == uint8_t{0x12}, "");
+  static_assert(rotl(uint16_t{0x1234}, 0) == uint16_t{0x1234}, "");
+  static_assert(rotl(uint32_t{0x12345678UL}, 0) == uint32_t{0x12345678UL}, "");
+  static_assert(rotl(uint64_t{0x12345678ABCDEF01ULL}, 0) ==
+                    uint64_t{0x12345678ABCDEF01ULL},
+                "");
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, 0), uint8_t{0x12});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, 0), uint16_t{0x1234});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 0), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 0),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, 8), uint8_t{0x12});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, 16), uint16_t{0x1234});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 32), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 64),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, -8), uint8_t{0x12});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, -16), uint16_t{0x1234});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, -32), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, -64),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, 4), uint8_t{0x21});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, 4), uint16_t{0x2341});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 4), uint32_t{0x23456781UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 4),
+            uint64_t{0x2345678ABCDEF011ULL});
+
+  EXPECT_EQ(rotl(uint8_t{0x12}, -4), uint8_t{0x21});
+  EXPECT_EQ(rotl(uint16_t{0x1234}, -4), uint16_t{0x4123});
+  EXPECT_EQ(rotl(uint32_t{0x12345678UL}, -4), uint32_t{0x81234567UL});
+  EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, -4),
+            uint64_t{0x112345678ABCDEF0ULL});
+}
+
+TEST(Rotate, Right) {
+  static_assert(rotr(uint8_t{0x12}, 0) == uint8_t{0x12}, "");
+  static_assert(rotr(uint16_t{0x1234}, 0) == uint16_t{0x1234}, "");
+  static_assert(rotr(uint32_t{0x12345678UL}, 0) == uint32_t{0x12345678UL}, "");
+  static_assert(rotr(uint64_t{0x12345678ABCDEF01ULL}, 0) ==
+                    uint64_t{0x12345678ABCDEF01ULL},
+                "");
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, 0), uint8_t{0x12});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, 0), uint16_t{0x1234});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 0), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 0),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, 8), uint8_t{0x12});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, 16), uint16_t{0x1234});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 32), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 64),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, -8), uint8_t{0x12});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, -16), uint16_t{0x1234});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, -32), uint32_t{0x12345678UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, -64),
+            uint64_t{0x12345678ABCDEF01ULL});
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, 4), uint8_t{0x21});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, 4), uint16_t{0x4123});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 4), uint32_t{0x81234567UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 4),
+            uint64_t{0x112345678ABCDEF0ULL});
+
+  EXPECT_EQ(rotr(uint8_t{0x12}, -4), uint8_t{0x21});
+  EXPECT_EQ(rotr(uint16_t{0x1234}, -4), uint16_t{0x2341});
+  EXPECT_EQ(rotr(uint32_t{0x12345678UL}, -4), uint32_t{0x23456781UL});
+  EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, -4),
+            uint64_t{0x2345678ABCDEF011ULL});
+}
+
+TEST(Rotate, Symmetry) {
+  // rotr(x, s) is equivalent to rotl(x, -s)
+  absl::BitGen rng;
+  constexpr int kTrials = 100;
+
+  for (int i = 0; i < kTrials; ++i) {
+    uint8_t value = absl::Uniform(rng, std::numeric_limits<uint8_t>::min(),
+                                  std::numeric_limits<uint8_t>::max());
+    int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint8_t>::digits,
+                              2 * std::numeric_limits<uint8_t>::digits);
+
+    EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    uint16_t value = absl::Uniform(rng, std::numeric_limits<uint16_t>::min(),
+                                   std::numeric_limits<uint16_t>::max());
+    int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint16_t>::digits,
+                              2 * std::numeric_limits<uint16_t>::digits);
+
+    EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    uint32_t value = absl::Uniform(rng, std::numeric_limits<uint32_t>::min(),
+                                   std::numeric_limits<uint32_t>::max());
+    int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint32_t>::digits,
+                              2 * std::numeric_limits<uint32_t>::digits);
+
+    EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    uint64_t value = absl::Uniform(rng, std::numeric_limits<uint64_t>::min(),
+                                   std::numeric_limits<uint64_t>::max());
+    int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint64_t>::digits,
+                              2 * std::numeric_limits<uint64_t>::digits);
+
+    EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+  }
+}
+
+TEST(Counting, LeadingZeroes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(countl_zero(uint8_t{}) == 8, "");
+  static_assert(countl_zero(static_cast<uint8_t>(-1)) == 0, "");
+  static_assert(countl_zero(uint16_t{}) == 16, "");
+  static_assert(countl_zero(static_cast<uint16_t>(-1)) == 0, "");
+  static_assert(countl_zero(uint32_t{}) == 32, "");
+  static_assert(countl_zero(~uint32_t{}) == 0, "");
+  static_assert(countl_zero(uint64_t{}) == 64, "");
+  static_assert(countl_zero(~uint64_t{}) == 0, "");
+#endif
+
+  EXPECT_EQ(countl_zero(uint8_t{}), 8);
+  EXPECT_EQ(countl_zero(static_cast<uint8_t>(-1)), 0);
+  EXPECT_EQ(countl_zero(uint16_t{}), 16);
+  EXPECT_EQ(countl_zero(static_cast<uint16_t>(-1)), 0);
+  EXPECT_EQ(countl_zero(uint32_t{}), 32);
+  EXPECT_EQ(countl_zero(~uint32_t{}), 0);
+  EXPECT_EQ(countl_zero(uint64_t{}), 64);
+  EXPECT_EQ(countl_zero(~uint64_t{}), 0);
+
+  for (int i = 0; i < 8; i++) {
+    EXPECT_EQ(countl_zero(static_cast<uint8_t>(1u << i)), 7 - i);
+  }
+
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(countl_zero(static_cast<uint16_t>(1u << i)), 15 - i);
+  }
+
+  for (int i = 0; i < 32; i++) {
+    EXPECT_EQ(countl_zero(uint32_t{1} << i), 31 - i);
+  }
+
+  for (int i = 0; i < 64; i++) {
+    EXPECT_EQ(countl_zero(uint64_t{1} << i), 63 - i);
+  }
+}
+
+TEST(Counting, LeadingOnes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(countl_one(uint8_t{}) == 0, "");
+  static_assert(countl_one(static_cast<uint8_t>(-1)) == 8, "");
+  static_assert(countl_one(uint16_t{}) == 0, "");
+  static_assert(countl_one(static_cast<uint16_t>(-1)) == 16, "");
+  static_assert(countl_one(uint32_t{}) == 0, "");
+  static_assert(countl_one(~uint32_t{}) == 32, "");
+  static_assert(countl_one(uint64_t{}) == 0, "");
+  static_assert(countl_one(~uint64_t{}) == 64, "");
+#endif
+
+  EXPECT_EQ(countl_one(uint8_t{}), 0);
+  EXPECT_EQ(countl_one(static_cast<uint8_t>(-1)), 8);
+  EXPECT_EQ(countl_one(uint16_t{}), 0);
+  EXPECT_EQ(countl_one(static_cast<uint16_t>(-1)), 16);
+  EXPECT_EQ(countl_one(uint32_t{}), 0);
+  EXPECT_EQ(countl_one(~uint32_t{}), 32);
+  EXPECT_EQ(countl_one(uint64_t{}), 0);
+  EXPECT_EQ(countl_one(~uint64_t{}), 64);
+}
+
+TEST(Counting, TrailingZeroes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CTZ
+  static_assert(countr_zero(uint8_t{}) == 8, "");
+  static_assert(countr_zero(static_cast<uint8_t>(-1)) == 0, "");
+  static_assert(countr_zero(uint16_t{}) == 16, "");
+  static_assert(countr_zero(static_cast<uint16_t>(-1)) == 0, "");
+  static_assert(countr_zero(uint32_t{}) == 32, "");
+  static_assert(countr_zero(~uint32_t{}) == 0, "");
+  static_assert(countr_zero(uint64_t{}) == 64, "");
+  static_assert(countr_zero(~uint64_t{}) == 0, "");
+#endif
+
+  EXPECT_EQ(countr_zero(uint8_t{}), 8);
+  EXPECT_EQ(countr_zero(static_cast<uint8_t>(-1)), 0);
+  EXPECT_EQ(countr_zero(uint16_t{}), 16);
+  EXPECT_EQ(countr_zero(static_cast<uint16_t>(-1)), 0);
+  EXPECT_EQ(countr_zero(uint32_t{}), 32);
+  EXPECT_EQ(countr_zero(~uint32_t{}), 0);
+  EXPECT_EQ(countr_zero(uint64_t{}), 64);
+  EXPECT_EQ(countr_zero(~uint64_t{}), 0);
+}
+
+TEST(Counting, TrailingOnes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CTZ
+  static_assert(countr_one(uint8_t{}) == 0, "");
+  static_assert(countr_one(static_cast<uint8_t>(-1)) == 8, "");
+  static_assert(countr_one(uint16_t{}) == 0, "");
+  static_assert(countr_one(static_cast<uint16_t>(-1)) == 16, "");
+  static_assert(countr_one(uint32_t{}) == 0, "");
+  static_assert(countr_one(~uint32_t{}) == 32, "");
+  static_assert(countr_one(uint64_t{}) == 0, "");
+  static_assert(countr_one(~uint64_t{}) == 64, "");
+#endif
+
+  EXPECT_EQ(countr_one(uint8_t{}), 0);
+  EXPECT_EQ(countr_one(static_cast<uint8_t>(-1)), 8);
+  EXPECT_EQ(countr_one(uint16_t{}), 0);
+  EXPECT_EQ(countr_one(static_cast<uint16_t>(-1)), 16);
+  EXPECT_EQ(countr_one(uint32_t{}), 0);
+  EXPECT_EQ(countr_one(~uint32_t{}), 32);
+  EXPECT_EQ(countr_one(uint64_t{}), 0);
+  EXPECT_EQ(countr_one(~uint64_t{}), 64);
+}
+
+TEST(Counting, Popcount) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT
+  static_assert(popcount(uint8_t{}) == 0, "");
+  static_assert(popcount(uint8_t{1}) == 1, "");
+  static_assert(popcount(static_cast<uint8_t>(-1)) == 8, "");
+  static_assert(popcount(uint16_t{}) == 0, "");
+  static_assert(popcount(uint16_t{1}) == 1, "");
+  static_assert(popcount(static_cast<uint16_t>(-1)) == 16, "");
+  static_assert(popcount(uint32_t{}) == 0, "");
+  static_assert(popcount(uint32_t{1}) == 1, "");
+  static_assert(popcount(~uint32_t{}) == 32, "");
+  static_assert(popcount(uint64_t{}) == 0, "");
+  static_assert(popcount(uint64_t{1}) == 1, "");
+  static_assert(popcount(~uint64_t{}) == 64, "");
+#endif  // ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT
+
+  EXPECT_EQ(popcount(uint8_t{}), 0);
+  EXPECT_EQ(popcount(uint8_t{1}), 1);
+  EXPECT_EQ(popcount(static_cast<uint8_t>(-1)), 8);
+  EXPECT_EQ(popcount(uint16_t{}), 0);
+  EXPECT_EQ(popcount(uint16_t{1}), 1);
+  EXPECT_EQ(popcount(static_cast<uint16_t>(-1)), 16);
+  EXPECT_EQ(popcount(uint32_t{}), 0);
+  EXPECT_EQ(popcount(uint32_t{1}), 1);
+  EXPECT_EQ(popcount(~uint32_t{}), 32);
+  EXPECT_EQ(popcount(uint64_t{}), 0);
+  EXPECT_EQ(popcount(uint64_t{1}), 1);
+  EXPECT_EQ(popcount(~uint64_t{}), 64);
+
+  for (int i = 0; i < 8; i++) {
+    EXPECT_EQ(popcount(static_cast<uint8_t>(uint8_t{1} << i)), 1);
+    EXPECT_EQ(popcount(static_cast<uint8_t>(static_cast<uint8_t>(-1) ^
+                                            (uint8_t{1} << i))),
+              7);
+  }
+
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(popcount(static_cast<uint16_t>(uint16_t{1} << i)), 1);
+    EXPECT_EQ(popcount(static_cast<uint16_t>(static_cast<uint16_t>(-1) ^
+                                             (uint16_t{1} << i))),
+              15);
+  }
+
+  for (int i = 0; i < 32; i++) {
+    EXPECT_EQ(popcount(uint32_t{1} << i), 1);
+    EXPECT_EQ(popcount(static_cast<uint32_t>(-1) ^ (uint32_t{1} << i)), 31);
+  }
+
+  for (int i = 0; i < 64; i++) {
+    EXPECT_EQ(popcount(uint64_t{1} << i), 1);
+    EXPECT_EQ(popcount(static_cast<uint64_t>(-1) ^ (uint64_t{1} << i)), 63);
+  }
+}
+
+template <typename T>
+struct PopcountInput {
+  T value = 0;
+  int expected = 0;
+};
+
+template <typename T>
+PopcountInput<T> GeneratePopcountInput(absl::BitGen& gen) {
+  PopcountInput<T> ret;
+  for (int i = 0; i < std::numeric_limits<T>::digits; i++) {
+    bool coin = absl::Bernoulli(gen, 0.2);
+    if (coin) {
+      ret.value |= T{1} << i;
+      ret.expected++;
+    }
+  }
+  return ret;
+}
+
+TEST(Counting, PopcountFuzz) {
+  absl::BitGen rng;
+  constexpr int kTrials = 100;
+
+  for (int i = 0; i < kTrials; ++i) {
+    auto input = GeneratePopcountInput<uint8_t>(rng);
+    EXPECT_EQ(popcount(input.value), input.expected);
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    auto input = GeneratePopcountInput<uint16_t>(rng);
+    EXPECT_EQ(popcount(input.value), input.expected);
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    auto input = GeneratePopcountInput<uint32_t>(rng);
+    EXPECT_EQ(popcount(input.value), input.expected);
+  }
+
+  for (int i = 0; i < kTrials; ++i) {
+    auto input = GeneratePopcountInput<uint64_t>(rng);
+    EXPECT_EQ(popcount(input.value), input.expected);
+  }
+}
+
+TEST(IntegralPowersOfTwo, SingleBit) {
+  EXPECT_FALSE(has_single_bit(uint8_t{}));
+  EXPECT_FALSE(has_single_bit(static_cast<uint8_t>(-1)));
+  EXPECT_FALSE(has_single_bit(uint16_t{}));
+  EXPECT_FALSE(has_single_bit(static_cast<uint16_t>(-1)));
+  EXPECT_FALSE(has_single_bit(uint32_t{}));
+  EXPECT_FALSE(has_single_bit(~uint32_t{}));
+  EXPECT_FALSE(has_single_bit(uint64_t{}));
+  EXPECT_FALSE(has_single_bit(~uint64_t{}));
+
+  static_assert(!has_single_bit(0u), "");
+  static_assert(has_single_bit(1u), "");
+  static_assert(has_single_bit(2u), "");
+  static_assert(!has_single_bit(3u), "");
+  static_assert(has_single_bit(4u), "");
+  static_assert(!has_single_bit(1337u), "");
+  static_assert(has_single_bit(65536u), "");
+  static_assert(has_single_bit(uint32_t{1} << 30), "");
+  static_assert(has_single_bit(uint64_t{1} << 42), "");
+
+  EXPECT_FALSE(has_single_bit(0u));
+  EXPECT_TRUE(has_single_bit(1u));
+  EXPECT_TRUE(has_single_bit(2u));
+  EXPECT_FALSE(has_single_bit(3u));
+  EXPECT_TRUE(has_single_bit(4u));
+  EXPECT_FALSE(has_single_bit(1337u));
+  EXPECT_TRUE(has_single_bit(65536u));
+  EXPECT_TRUE(has_single_bit(uint32_t{1} << 30));
+  EXPECT_TRUE(has_single_bit(uint64_t{1} << 42));
+
+  EXPECT_TRUE(has_single_bit(
+      static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() / 2 + 1)));
+  EXPECT_TRUE(has_single_bit(
+      static_cast<uint16_t>(std::numeric_limits<uint16_t>::max() / 2 + 1)));
+  EXPECT_TRUE(has_single_bit(
+      static_cast<uint32_t>(std::numeric_limits<uint32_t>::max() / 2 + 1)));
+  EXPECT_TRUE(has_single_bit(
+      static_cast<uint64_t>(std::numeric_limits<uint64_t>::max() / 2 + 1)));
+}
+
+template <typename T, T arg, T = bit_ceil(arg)>
+bool IsBitCeilConstantExpression(int) {
+  return true;
+}
+template <typename T, T arg>
+bool IsBitCeilConstantExpression(char) {
+  return false;
+}
+
+TEST(IntegralPowersOfTwo, Ceiling) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(bit_ceil(0u) == 1, "");
+  static_assert(bit_ceil(1u) == 1, "");
+  static_assert(bit_ceil(2u) == 2, "");
+  static_assert(bit_ceil(3u) == 4, "");
+  static_assert(bit_ceil(4u) == 4, "");
+  static_assert(bit_ceil(1337u) == 2048, "");
+  static_assert(bit_ceil(65536u) == 65536, "");
+  static_assert(bit_ceil(65536u - 1337u) == 65536, "");
+  static_assert(bit_ceil(uint32_t{0x80000000}) == uint32_t{0x80000000}, "");
+  static_assert(bit_ceil(uint64_t{0x40000000000}) == uint64_t{0x40000000000},
+                "");
+  static_assert(
+      bit_ceil(uint64_t{0x8000000000000000}) == uint64_t{0x8000000000000000},
+      "");
+
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x0}>(0)));
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x80}>(0)));
+  EXPECT_FALSE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x81}>(0)));
+  EXPECT_FALSE((IsBitCeilConstantExpression<uint8_t, uint8_t{0xff}>(0)));
+
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x0}>(0)));
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x8000}>(0)));
+  EXPECT_FALSE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x8001}>(0)));
+  EXPECT_FALSE((IsBitCeilConstantExpression<uint16_t, uint16_t{0xffff}>(0)));
+
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint32_t, uint32_t{0x0}>(0)));
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint32_t, uint32_t{0x80000000}>(0)));
+  EXPECT_FALSE(
+      (IsBitCeilConstantExpression<uint32_t, uint32_t{0x80000001}>(0)));
+  EXPECT_FALSE(
+      (IsBitCeilConstantExpression<uint32_t, uint32_t{0xffffffff}>(0)));
+
+  EXPECT_TRUE((IsBitCeilConstantExpression<uint64_t, uint64_t{0x0}>(0)));
+  EXPECT_TRUE(
+      (IsBitCeilConstantExpression<uint64_t, uint64_t{0x8000000000000000}>(0)));
+  EXPECT_FALSE(
+      (IsBitCeilConstantExpression<uint64_t, uint64_t{0x8000000000000001}>(0)));
+  EXPECT_FALSE(
+      (IsBitCeilConstantExpression<uint64_t, uint64_t{0xffffffffffffffff}>(0)));
+#endif
+
+  EXPECT_EQ(bit_ceil(0u), 1);
+  EXPECT_EQ(bit_ceil(1u), 1);
+  EXPECT_EQ(bit_ceil(2u), 2);
+  EXPECT_EQ(bit_ceil(3u), 4);
+  EXPECT_EQ(bit_ceil(4u), 4);
+  EXPECT_EQ(bit_ceil(1337u), 2048);
+  EXPECT_EQ(bit_ceil(65536u), 65536);
+  EXPECT_EQ(bit_ceil(65536u - 1337u), 65536);
+  EXPECT_EQ(bit_ceil(uint64_t{0x40000000000}), uint64_t{0x40000000000});
+}
+
+TEST(IntegralPowersOfTwo, Floor) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(bit_floor(0u) == 0, "");
+  static_assert(bit_floor(1u) == 1, "");
+  static_assert(bit_floor(2u) == 2, "");
+  static_assert(bit_floor(3u) == 2, "");
+  static_assert(bit_floor(4u) == 4, "");
+  static_assert(bit_floor(1337u) == 1024, "");
+  static_assert(bit_floor(65536u) == 65536, "");
+  static_assert(bit_floor(65536u - 1337u) == 32768, "");
+  static_assert(bit_floor(uint64_t{0x40000000000}) == uint64_t{0x40000000000},
+                "");
+#endif
+
+  EXPECT_EQ(bit_floor(0u), 0);
+  EXPECT_EQ(bit_floor(1u), 1);
+  EXPECT_EQ(bit_floor(2u), 2);
+  EXPECT_EQ(bit_floor(3u), 2);
+  EXPECT_EQ(bit_floor(4u), 4);
+  EXPECT_EQ(bit_floor(1337u), 1024);
+  EXPECT_EQ(bit_floor(65536u), 65536);
+  EXPECT_EQ(bit_floor(65536u - 1337u), 32768);
+  EXPECT_EQ(bit_floor(uint64_t{0x40000000000}), uint64_t{0x40000000000});
+
+  for (int i = 0; i < 8; i++) {
+    uint8_t input = uint8_t{1} << i;
+    EXPECT_EQ(bit_floor(input), input);
+    if (i > 0) {
+      EXPECT_EQ(bit_floor(static_cast<uint8_t>(input + 1)), input);
+    }
+  }
+
+  for (int i = 0; i < 16; i++) {
+    uint16_t input = uint16_t{1} << i;
+    EXPECT_EQ(bit_floor(input), input);
+    if (i > 0) {
+      EXPECT_EQ(bit_floor(static_cast<uint16_t>(input + 1)), input);
+    }
+  }
+
+  for (int i = 0; i < 32; i++) {
+    uint32_t input = uint32_t{1} << i;
+    EXPECT_EQ(bit_floor(input), input);
+    if (i > 0) {
+      EXPECT_EQ(bit_floor(input + 1), input);
+    }
+  }
+
+  for (int i = 0; i < 64; i++) {
+    uint64_t input = uint64_t{1} << i;
+    EXPECT_EQ(bit_floor(input), input);
+    if (i > 0) {
+      EXPECT_EQ(bit_floor(input + 1), input);
+    }
+  }
+}
+
+TEST(IntegralPowersOfTwo, Width) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+  static_assert(bit_width(uint8_t{}) == 0, "");
+  static_assert(bit_width(uint8_t{1}) == 1, "");
+  static_assert(bit_width(uint8_t{3}) == 2, "");
+  static_assert(bit_width(static_cast<uint8_t>(-1)) == 8, "");
+  static_assert(bit_width(uint16_t{}) == 0, "");
+  static_assert(bit_width(uint16_t{1}) == 1, "");
+  static_assert(bit_width(uint16_t{3}) == 2, "");
+  static_assert(bit_width(static_cast<uint16_t>(-1)) == 16, "");
+  static_assert(bit_width(uint32_t{}) == 0, "");
+  static_assert(bit_width(uint32_t{1}) == 1, "");
+  static_assert(bit_width(uint32_t{3}) == 2, "");
+  static_assert(bit_width(~uint32_t{}) == 32, "");
+  static_assert(bit_width(uint64_t{}) == 0, "");
+  static_assert(bit_width(uint64_t{1}) == 1, "");
+  static_assert(bit_width(uint64_t{3}) == 2, "");
+  static_assert(bit_width(~uint64_t{}) == 64, "");
+#endif
+
+  EXPECT_EQ(bit_width(uint8_t{}), 0);
+  EXPECT_EQ(bit_width(uint8_t{1}), 1);
+  EXPECT_EQ(bit_width(uint8_t{3}), 2);
+  EXPECT_EQ(bit_width(static_cast<uint8_t>(-1)), 8);
+  EXPECT_EQ(bit_width(uint16_t{}), 0);
+  EXPECT_EQ(bit_width(uint16_t{1}), 1);
+  EXPECT_EQ(bit_width(uint16_t{3}), 2);
+  EXPECT_EQ(bit_width(static_cast<uint16_t>(-1)), 16);
+  EXPECT_EQ(bit_width(uint32_t{}), 0);
+  EXPECT_EQ(bit_width(uint32_t{1}), 1);
+  EXPECT_EQ(bit_width(uint32_t{3}), 2);
+  EXPECT_EQ(bit_width(~uint32_t{}), 32);
+  EXPECT_EQ(bit_width(uint64_t{}), 0);
+  EXPECT_EQ(bit_width(uint64_t{1}), 1);
+  EXPECT_EQ(bit_width(uint64_t{3}), 2);
+  EXPECT_EQ(bit_width(~uint64_t{}), 64);
+
+  for (int i = 0; i < 8; i++) {
+    EXPECT_EQ(bit_width(static_cast<uint8_t>(uint8_t{1} << i)), i + 1);
+  }
+
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(bit_width(static_cast<uint16_t>(uint16_t{1} << i)), i + 1);
+  }
+
+  for (int i = 0; i < 32; i++) {
+    EXPECT_EQ(bit_width(uint32_t{1} << i), i + 1);
+  }
+
+  for (int i = 0; i < 64; i++) {
+    EXPECT_EQ(bit_width(uint64_t{1} << i), i + 1);
+  }
+}
+
+// On GCC and Clang, anticiapte that implementations will be constexpr
+#if defined(__GNUC__)
+static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT,
+              "popcount should be constexpr");
+static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_CLZ, "clz should be constexpr");
+static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_CTZ, "ctz should be constexpr");
+#endif
+
+}  // namespace
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/numeric/int128.cc b/grpc/third_party/abseil-cpp/absl/numeric/int128.cc
index e21e5e9..5160df7 100644
--- a/grpc/third_party/abseil-cpp/absl/numeric/int128.cc
+++ b/grpc/third_party/abseil-cpp/absl/numeric/int128.cc
@@ -23,8 +23,8 @@
 #include <string>
 #include <type_traits>
 
-#include "absl/base/internal/bits.h"
 #include "absl/base/optimization.h"
+#include "absl/numeric/bits.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -43,11 +43,11 @@
 inline ABSL_ATTRIBUTE_ALWAYS_INLINE int Fls128(uint128 n) {
   if (uint64_t hi = Uint128High64(n)) {
     ABSL_INTERNAL_ASSUME(hi != 0);
-    return 127 - base_internal::CountLeadingZeros64(hi);
+    return 127 - countl_zero(hi);
   }
   const uint64_t low = Uint128Low64(n);
   ABSL_INTERNAL_ASSUME(low != 0);
-  return 63 - base_internal::CountLeadingZeros64(low);
+  return 63 - countl_zero(low);
 }
 
 // Long division/modulo for uint128 implemented using the shift-subtract
diff --git a/grpc/third_party/abseil-cpp/absl/numeric/internal/bits.h b/grpc/third_party/abseil-cpp/absl/numeric/internal/bits.h
new file mode 100644
index 0000000..bfef06b
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/numeric/internal/bits.h
@@ -0,0 +1,358 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 ABSL_NUMERIC_INTERNAL_BITS_H_
+#define ABSL_NUMERIC_INTERNAL_BITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+// Clang on Windows has __builtin_clzll; otherwise we need to use the
+// windows intrinsic functions.
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <intrin.h>
+#endif
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+// GCC
+#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) 1
+#else
+#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) ABSL_HAVE_BUILTIN(x)
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountl) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll)
+#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT
+#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 0
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll)
+#define ABSL_INTERNAL_CONSTEXPR_CLZ constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_CLZ
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 0
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll)
+#define ABSL_INTERNAL_CONSTEXPR_CTZ constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_CTZ
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 0
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace numeric_internal {
+
+constexpr bool IsPowerOf2(unsigned int x) noexcept {
+  return x != 0 && (x & (x - 1)) == 0;
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateRight(
+    T x, int s) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+
+  return static_cast<T>(x >> (s & (std::numeric_limits<T>::digits - 1))) |
+         static_cast<T>(x << ((-s) & (std::numeric_limits<T>::digits - 1)));
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft(
+    T x, int s) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+
+  return static_cast<T>(x << (s & (std::numeric_limits<T>::digits - 1))) |
+         static_cast<T>(x >> ((-s) & (std::numeric_limits<T>::digits - 1)));
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount32(uint32_t x) noexcept {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcount)
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_popcount does not take 32-bit arg");
+  return __builtin_popcount(x);
+#else
+  x -= ((x >> 1) & 0x55555555);
+  x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+  return static_cast<int>((((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24);
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount64(uint64_t x) noexcept {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll)
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_popcount does not take 64-bit arg");
+  return __builtin_popcountll(x);
+#else
+  x -= (x >> 1) & 0x5555555555555555ULL;
+  x = ((x >> 2) & 0x3333333333333333ULL) + (x & 0x3333333333333333ULL);
+  return static_cast<int>(
+      (((x + (x >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
+#endif
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount(T x) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(x) <= sizeof(uint64_t), "T is too large");
+  return sizeof(x) <= sizeof(uint32_t) ? Popcount32(x) : Popcount64(x);
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes32(uint32_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz)
+  // Use __builtin_clz, which uses the following instructions:
+  //  x86: bsr, lzcnt
+  //  ARM64: clz
+  //  PPC: cntlzd
+
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_clz does not take 32-bit arg");
+  // Handle 0 as a special case because __builtin_clz(0) is undefined.
+  return x == 0 ? 32 : __builtin_clz(x);
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (_BitScanReverse(&result, x)) {
+    return 31 - result;
+  }
+  return 32;
+#else
+  int zeroes = 28;
+  if (x >> 16) {
+    zeroes -= 16;
+    x >>= 16;
+  }
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes16(uint16_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_clzs)
+  static_assert(sizeof(unsigned short) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_clzs does not take 16-bit arg");
+  return x == 0 ? 16 : __builtin_clzs(x);
+#else
+  return CountLeadingZeroes32(x) - 16;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes64(uint64_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll)
+  // Use __builtin_clzll, which uses the following instructions:
+  //  x86: bsr, lzcnt
+  //  ARM64: clz
+  //  PPC: cntlzd
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_clzll does not take 64-bit arg");
+
+  // Handle 0 as a special case because __builtin_clzll(0) is undefined.
+  return x == 0 ? 64 : __builtin_clzll(x);
+#elif defined(_MSC_VER) && !defined(__clang__) && \
+    (defined(_M_X64) || defined(_M_ARM64))
+  // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (_BitScanReverse64(&result, x)) {
+    return 63 - result;
+  }
+  return 64;
+#elif defined(_MSC_VER) && !defined(__clang__)
+  // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if ((x >> 32) &&
+      _BitScanReverse(&result, static_cast<unsigned long>(x >> 32))) {
+    return 31 - result;
+  }
+  if (_BitScanReverse(&result, static_cast<unsigned long>(x))) {
+    return 63 - result;
+  }
+  return 64;
+#else
+  int zeroes = 60;
+  if (x >> 32) {
+    zeroes -= 32;
+    x >>= 32;
+  }
+  if (x >> 16) {
+    zeroes -= 16;
+    x >>= 16;
+  }
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+#endif
+}
+
+template <typename T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes(T x) {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(T) <= sizeof(uint64_t), "T too large");
+  return sizeof(T) <= sizeof(uint16_t)
+             ? CountLeadingZeroes16(static_cast<uint16_t>(x)) -
+                   (std::numeric_limits<uint16_t>::digits -
+                    std::numeric_limits<T>::digits)
+             : (sizeof(T) <= sizeof(uint32_t)
+                    ? CountLeadingZeroes32(static_cast<uint32_t>(x)) -
+                          (std::numeric_limits<uint32_t>::digits -
+                           std::numeric_limits<T>::digits)
+                    : CountLeadingZeroes64(x));
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero32(uint32_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz)
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_ctz does not take 32-bit arg");
+  return __builtin_ctz(x);
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  _BitScanForward(&result, x);
+  return result;
+#else
+  int c = 31;
+  x &= ~x + 1;
+  if (x & 0x0000FFFF) c -= 16;
+  if (x & 0x00FF00FF) c -= 8;
+  if (x & 0x0F0F0F0F) c -= 4;
+  if (x & 0x33333333) c -= 2;
+  if (x & 0x55555555) c -= 1;
+  return c;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero64(uint64_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll)
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_ctzll does not take 64-bit arg");
+  return __builtin_ctzll(x);
+#elif defined(_MSC_VER) && !defined(__clang__) && \
+    (defined(_M_X64) || defined(_M_ARM64))
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  _BitScanForward64(&result, x);
+  return result;
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (static_cast<uint32_t>(x) == 0) {
+    _BitScanForward(&result, static_cast<unsigned long>(x >> 32));
+    return result + 32;
+  }
+  _BitScanForward(&result, static_cast<unsigned long>(x));
+  return result;
+#else
+  int c = 63;
+  x &= ~x + 1;
+  if (x & 0x00000000FFFFFFFF) c -= 32;
+  if (x & 0x0000FFFF0000FFFF) c -= 16;
+  if (x & 0x00FF00FF00FF00FF) c -= 8;
+  if (x & 0x0F0F0F0F0F0F0F0F) c -= 4;
+  if (x & 0x3333333333333333) c -= 2;
+  if (x & 0x5555555555555555) c -= 1;
+  return c;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero16(uint16_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_ctzs)
+  static_assert(sizeof(unsigned short) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_ctzs does not take 16-bit arg");
+  return __builtin_ctzs(x);
+#else
+  return CountTrailingZeroesNonzero32(x);
+#endif
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroes(T x) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(T) <= sizeof(uint64_t), "T too large");
+  return x == 0 ? std::numeric_limits<T>::digits
+                : (sizeof(T) <= sizeof(uint16_t)
+                       ? CountTrailingZeroesNonzero16(static_cast<uint16_t>(x))
+                       : (sizeof(T) <= sizeof(uint32_t)
+                              ? CountTrailingZeroesNonzero32(
+                                    static_cast<uint32_t>(x))
+                              : CountTrailingZeroesNonzero64(x)));
+}
+
+// If T is narrower than unsigned, T{1} << bit_width will be promoted.  We
+// want to force it to wraparound so that bit_ceil of an invalid value are not
+// core constant expressions.
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    BitCeilPromotionHelper(T x, T promotion) {
+  return (T{1} << (x + promotion)) >> promotion;
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    BitCeilNonPowerOf2(T x) {
+  // If T is narrower than unsigned, it undergoes promotion to unsigned when we
+  // shift.  We calculate the number of bits added by the wider type.
+  return BitCeilPromotionHelper(
+      static_cast<T>(std::numeric_limits<T>::digits - CountLeadingZeroes(x)),
+      T{sizeof(T) >= sizeof(unsigned) ? 0
+                                      : std::numeric_limits<unsigned>::digits -
+                                            std::numeric_limits<T>::digits});
+}
+
+}  // namespace numeric_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_INTERNAL_BITS_H_
diff --git a/grpc/third_party/abseil-cpp/absl/numeric/internal/representation.h b/grpc/third_party/abseil-cpp/absl/numeric/internal/representation.h
new file mode 100644
index 0000000..82d332f
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/numeric/internal/representation.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Abseil 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
+//
+//     https://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 ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_
+#define ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_
+
+#include <limits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace numeric_internal {
+
+// Returns true iff long double is represented as a pair of doubles added
+// together.
+inline constexpr bool IsDoubleDouble() {
+  // A double-double value always has exactly twice the precision of a double
+  // value--one double carries the high digits and one double carries the low
+  // digits. This property is not shared with any other common floating-point
+  // representation, so this test won't trigger false positives. For reference,
+  // this table gives the number of bits of precision of each common
+  // floating-point representation:
+  //
+  //                type     precision
+  //         IEEE single          24 b
+  //         IEEE double          53
+  //     x86 long double          64
+  //       double-double         106
+  //      IEEE quadruple         113
+  //
+  // Note in particular that a quadruple-precision float has greater precision
+  // than a double-double float despite taking up the same amount of memory; the
+  // quad has more of its bits allocated to the mantissa than the double-double
+  // has.
+  return std::numeric_limits<long double>::digits ==
+         2 * std::numeric_limits<double>::digits;
+}
+
+}  // namespace numeric_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_
diff --git a/grpc/third_party/abseil-cpp/absl/random/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/random/BUILD.bazel
index 81e150e..66ffcbc 100644
--- a/grpc/third_party/abseil-cpp/absl/random/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/random/BUILD.bazel
@@ -69,6 +69,7 @@
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/random/internal:distribution_caller",
         "//absl/random/internal:fast_uniform_bits",
         "//absl/random/internal:fastmath",
@@ -187,6 +188,7 @@
         ":distributions",
         ":random",
         "//absl/base:raw_logging_internal",
+        "//absl/numeric:representation",
         "//absl/random/internal:distribution_test_util",
         "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
@@ -307,6 +309,7 @@
         ":random",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
+        "//absl/numeric:representation",
         "//absl/random/internal:distribution_test_util",
         "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
@@ -330,6 +333,7 @@
         ":random",
         "//absl/base:core_headers",
         "//absl/base:raw_logging_internal",
+        "//absl/numeric:representation",
         "//absl/random/internal:distribution_test_util",
         "//absl/random/internal:sequence_urbg",
         "//absl/strings",
@@ -376,6 +380,7 @@
         ":distributions",
         ":random",
         "//absl/base:raw_logging_internal",
+        "//absl/numeric:representation",
         "//absl/random/internal:distribution_test_util",
         "//absl/random/internal:pcg_engine",
         "//absl/random/internal:sequence_urbg",
diff --git a/grpc/third_party/abseil-cpp/absl/random/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/random/CMakeLists.txt
index 7d7bec8..3009a03 100644
--- a/grpc/third_party/abseil-cpp/absl/random/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/random/CMakeLists.txt
@@ -259,6 +259,7 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::numeric_representation
     absl::random_distributions
     absl::random_random
     absl::random_internal_distribution_test_util
@@ -381,6 +382,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::core_headers
+    absl::numeric_representation
     absl::random_distributions
     absl::random_internal_distribution_test_util
     absl::random_internal_pcg_engine
@@ -404,6 +406,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::core_headers
+    absl::numeric_representation
     absl::random_distributions
     absl::random_internal_distribution_test_util
     absl::random_internal_sequence_urbg
@@ -446,6 +449,7 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::numeric_representation
     absl::random_distributions
     absl::random_internal_distribution_test_util
     absl::random_internal_pcg_engine
@@ -611,6 +615,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::config
+    absl::endian
   TESTONLY
 )
 
@@ -758,6 +763,7 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::endian
     absl::random_internal_iostream_state_saver
     absl::random_internal_randen
     absl::raw_logging_internal
@@ -1119,6 +1125,7 @@
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::endian
     absl::random_internal_randen_slow
     gtest_main
 )
diff --git a/grpc/third_party/abseil-cpp/absl/random/beta_distribution_test.cc b/grpc/third_party/abseil-cpp/absl/random/beta_distribution_test.cc
index 277e4dc..44cdfdd 100644
--- a/grpc/third_party/abseil-cpp/absl/random/beta_distribution_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/beta_distribution_test.cc
@@ -21,12 +21,14 @@
 #include <random>
 #include <sstream>
 #include <string>
+#include <type_traits>
 #include <unordered_map>
 #include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
 #include "absl/random/internal/pcg_engine.h"
@@ -42,7 +44,15 @@
 template <typename IntType>
 class BetaDistributionInterfaceTest : public ::testing::Test {};
 
-using RealTypes = ::testing::Types<float, double, long double>;
+// double-double arithmetic is not supported well by either GCC or Clang; see
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
+// https://bugs.llvm.org/show_bug.cgi?id=49131, and
+// https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
+// with double doubles until compiler support is better.
+using RealTypes =
+    std::conditional<absl::numeric_internal::IsDoubleDouble(),
+                     ::testing::Types<float, double>,
+                     ::testing::Types<float, double, long double>>::type;
 TYPED_TEST_CASE(BetaDistributionInterfaceTest, RealTypes);
 
 TYPED_TEST(BetaDistributionInterfaceTest, SerializeTest) {
@@ -53,9 +63,6 @@
   const TypeParam kLargeA =
       std::exp(std::log((std::numeric_limits<TypeParam>::max)()) -
                std::log(std::log((std::numeric_limits<TypeParam>::max)())));
-  const TypeParam kLargeAPPC = std::exp(
-      std::log((std::numeric_limits<TypeParam>::max)()) -
-      std::log(std::log((std::numeric_limits<TypeParam>::max)())) - 10.0f);
   using param_type = typename absl::beta_distribution<TypeParam>::param_type;
 
   constexpr int kCount = 1000;
@@ -76,9 +83,6 @@
       kLargeA,                                //
       std::nextafter(kLargeA, TypeParam(0)),  //
       std::nextafter(kLargeA, std::numeric_limits<TypeParam>::max()),
-      kLargeAPPC,  //
-      std::nextafter(kLargeAPPC, TypeParam(0)),
-      std::nextafter(kLargeAPPC, std::numeric_limits<TypeParam>::max()),
       // Boundary cases.
       std::numeric_limits<TypeParam>::max(),
       std::numeric_limits<TypeParam>::epsilon(),
@@ -125,28 +129,6 @@
 
       ss >> after;
 
-#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
-    defined(__ppc__) || defined(__PPC__)
-      if (std::is_same<TypeParam, long double>::value) {
-        // Roundtripping floating point values requires sufficient precision
-        // to reconstruct the exact value. It turns out that long double
-        // has some errors doing this on ppc.
-        if (alpha <= std::numeric_limits<double>::max() &&
-            alpha >= std::numeric_limits<double>::lowest()) {
-          EXPECT_EQ(static_cast<double>(before.alpha()),
-                    static_cast<double>(after.alpha()))
-              << ss.str();
-        }
-        if (beta <= std::numeric_limits<double>::max() &&
-            beta >= std::numeric_limits<double>::lowest()) {
-          EXPECT_EQ(static_cast<double>(before.beta()),
-                    static_cast<double>(after.beta()))
-              << ss.str();
-        }
-        continue;
-      }
-#endif
-
       EXPECT_EQ(before.alpha(), after.alpha());
       EXPECT_EQ(before.beta(), after.beta());
       EXPECT_EQ(before, after)           //
diff --git a/grpc/third_party/abseil-cpp/absl/random/exponential_distribution_test.cc b/grpc/third_party/abseil-cpp/absl/random/exponential_distribution_test.cc
index 8e9e69b..af11d61 100644
--- a/grpc/third_party/abseil-cpp/absl/random/exponential_distribution_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/exponential_distribution_test.cc
@@ -30,6 +30,7 @@
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/macros.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
 #include "absl/random/internal/pcg_engine.h"
@@ -47,11 +48,15 @@
 template <typename RealType>
 class ExponentialDistributionTypedTest : public ::testing::Test {};
 
-#if defined(__EMSCRIPTEN__)
-using RealTypes = ::testing::Types<float, double>;
-#else
-using RealTypes = ::testing::Types<float, double, long double>;
-#endif  // defined(__EMSCRIPTEN__)
+// double-double arithmetic is not supported well by either GCC or Clang; see
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
+// https://bugs.llvm.org/show_bug.cgi?id=49131, and
+// https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
+// with double doubles until compiler support is better.
+using RealTypes =
+    std::conditional<absl::numeric_internal::IsDoubleDouble(),
+                     ::testing::Types<float, double>,
+                     ::testing::Types<float, double, long double>>::type;
 TYPED_TEST_CASE(ExponentialDistributionTypedTest, RealTypes);
 
 TYPED_TEST(ExponentialDistributionTypedTest, SerializeTest) {
@@ -130,23 +135,6 @@
 
     ss >> after;
 
-#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
-    defined(__ppc__) || defined(__PPC__)
-    if (std::is_same<TypeParam, long double>::value) {
-      // Roundtripping floating point values requires sufficient precision to
-      // reconstruct the exact value. It turns out that long double has some
-      // errors doing this on ppc, particularly for values
-      // near {1.0 +/- epsilon}.
-      if (lambda <= std::numeric_limits<double>::max() &&
-          lambda >= std::numeric_limits<double>::lowest()) {
-        EXPECT_EQ(static_cast<double>(before.lambda()),
-                  static_cast<double>(after.lambda()))
-            << ss.str();
-      }
-      continue;
-    }
-#endif
-
     EXPECT_EQ(before.lambda(), after.lambda())  //
         << ss.str() << " "                      //
         << (ss.good() ? "good " : "")           //
diff --git a/grpc/third_party/abseil-cpp/absl/random/gaussian_distribution_test.cc b/grpc/third_party/abseil-cpp/absl/random/gaussian_distribution_test.cc
index 02ac578..c0bac2b 100644
--- a/grpc/third_party/abseil-cpp/absl/random/gaussian_distribution_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/gaussian_distribution_test.cc
@@ -21,12 +21,14 @@
 #include <iterator>
 #include <random>
 #include <string>
+#include <type_traits>
 #include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/macros.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
 #include "absl/random/internal/sequence_urbg.h"
@@ -43,7 +45,15 @@
 template <typename RealType>
 class GaussianDistributionInterfaceTest : public ::testing::Test {};
 
-using RealTypes = ::testing::Types<float, double, long double>;
+// double-double arithmetic is not supported well by either GCC or Clang; see
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
+// https://bugs.llvm.org/show_bug.cgi?id=49131, and
+// https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
+// with double doubles until compiler support is better.
+using RealTypes =
+    std::conditional<absl::numeric_internal::IsDoubleDouble(),
+                     ::testing::Types<float, double>,
+                     ::testing::Types<float, double, long double>>::type;
 TYPED_TEST_CASE(GaussianDistributionInterfaceTest, RealTypes);
 
 TYPED_TEST(GaussianDistributionInterfaceTest, SerializeTest) {
@@ -129,32 +139,6 @@
 
         ss >> after;
 
-#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
-    defined(__ppc__) || defined(__PPC__) || defined(__EMSCRIPTEN__)
-        if (std::is_same<TypeParam, long double>::value) {
-          // Roundtripping floating point values requires sufficient precision
-          // to reconstruct the exact value.  It turns out that long double
-          // has some errors doing this on ppc, particularly for values
-          // near {1.0 +/- epsilon}.
-          //
-          // Emscripten is even worse, implementing long double as a 128-bit
-          // type, but shipping with a strtold() that doesn't support that.
-          if (mean <= std::numeric_limits<double>::max() &&
-              mean >= std::numeric_limits<double>::lowest()) {
-            EXPECT_EQ(static_cast<double>(before.mean()),
-                      static_cast<double>(after.mean()))
-                << ss.str();
-          }
-          if (stddev <= std::numeric_limits<double>::max() &&
-              stddev >= std::numeric_limits<double>::lowest()) {
-            EXPECT_EQ(static_cast<double>(before.stddev()),
-                      static_cast<double>(after.stddev()))
-                << ss.str();
-          }
-          continue;
-        }
-#endif
-
         EXPECT_EQ(before.mean(), after.mean());
         EXPECT_EQ(before.stddev(), after.stddev())  //
             << ss.str() << " "                      //
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/random/internal/BUILD.bazel
index 8485e28..612b150 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/BUILD.bazel
@@ -75,7 +75,8 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS + select({
-        "//absl:windows": ["-DEFAULTLIB:bcrypt.lib"],
+        "//absl:msvc_compiler": ["-DEFAULTLIB:bcrypt.lib"],
+        "//absl:clang-cl_compiler": ["-DEFAULTLIB:bcrypt.lib"],
         "//conditions:default": [],
     }),
     deps = [
@@ -98,7 +99,8 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
         "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
@@ -124,7 +126,10 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = ["//absl/base:config"],
+    deps = [
+        "//absl/base:config",
+        "//absl/base:endian",
+    ],
 )
 
 cc_library(
@@ -175,8 +180,8 @@
     deps = [
         ":fastmath",
         ":traits",
-        "//absl/base:bits",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
     ],
 )
 
@@ -187,7 +192,7 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = ["//absl/base:bits"],
+    deps = ["//absl/numeric:bits"],
 )
 
 cc_library(
@@ -197,8 +202,8 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":traits",
-        "//absl/base:bits",
         "//absl/base:config",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
     ],
 )
@@ -229,6 +234,7 @@
         ":iostream_state_saver",
         "//absl/base:config",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
     ],
 )
@@ -241,6 +247,7 @@
     deps = [
         ":iostream_state_saver",
         ":randen",
+        "//absl/base:endian",
         "//absl/meta:type_traits",
     ],
 )
@@ -320,7 +327,8 @@
         "randen_hwaes.h",
     ],
     copts = ABSL_DEFAULT_COPTS + ABSL_RANDOM_RANDEN_COPTS + select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
         "//conditions:default": ["-Wno-pass-failed"],
     }),
     linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -400,8 +408,8 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":generate_real",
-        "//absl/base:bits",
         "//absl/flags:flag",
+        "//absl/numeric:bits",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -605,6 +613,7 @@
     deps = [
         ":platform",
         ":randen_slow",
+        "//absl/base:endian",
         "@com_google_googletest//:gtest_main",
     ],
 )
@@ -634,7 +643,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":wide_multiply",
-        "//absl/base:bits",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/explicit_seed_seq.h b/grpc/third_party/abseil-cpp/absl/random/internal/explicit_seed_seq.h
index 6a743ea..e3aa31a 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/explicit_seed_seq.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/explicit_seed_seq.h
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include "absl/base/config.h"
+#include "absl/base/internal/endian.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -73,7 +74,7 @@
   template <typename OutIterator>
   void generate(OutIterator begin, OutIterator end) {
     for (size_t index = 0; begin != end; begin++) {
-      *begin = state_.empty() ? 0 : state_[index++];
+      *begin = state_.empty() ? 0 : little_endian::FromHost32(state_[index++]);
       if (index >= state_.size()) {
         index = 0;
       }
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/fastmath.h b/grpc/third_party/abseil-cpp/absl/random/internal/fastmath.h
index 6baeb5a..963b769 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/fastmath.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/fastmath.h
@@ -22,27 +22,22 @@
 #include <cmath>
 #include <cstdint>
 
-#include "absl/base/internal/bits.h"
+#include "absl/numeric/bits.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// Returns the position of the first bit set.
-inline int LeadingSetBit(uint64_t n) {
-  return 64 - base_internal::CountLeadingZeros64(n);
-}
-
 // Compute log2(n) using integer operations.
 // While std::log2 is more accurate than std::log(n) / std::log(2), for
 // very large numbers--those close to std::numeric_limits<uint64_t>::max() - 2,
 // for instance--std::log2 rounds up rather than down, which introduces
 // definite skew in the results.
 inline int IntLog2Floor(uint64_t n) {
-  return (n <= 1) ? 0 : (63 - base_internal::CountLeadingZeros64(n));
+  return (n <= 1) ? 0 : (63 - countl_zero(n));
 }
 inline int IntLog2Ceil(uint64_t n) {
-  return (n <= 1) ? 0 : (64 - base_internal::CountLeadingZeros64(n - 1));
+  return (n <= 1) ? 0 : (64 - countl_zero(n - 1));
 }
 
 inline double StirlingLogFactorial(double n) {
@@ -55,18 +50,6 @@
          (1.0 / 360.0) * ninv * ninv * ninv;
 }
 
-// Rotate value right.
-//
-// We only implement the uint32_t / uint64_t versions because
-// 1) those are the only ones we use, and
-// 2) those are the only ones where clang detects the rotate idiom correctly.
-inline constexpr uint32_t rotr(uint32_t value, uint8_t bits) {
-  return (value >> (bits & 31)) | (value << ((-bits) & 31));
-}
-inline constexpr uint64_t rotr(uint64_t value, uint8_t bits) {
-  return (value >> (bits & 63)) | (value << ((-bits) & 63));
-}
-
 }  // namespace random_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/fastmath_test.cc b/grpc/third_party/abseil-cpp/absl/random/internal/fastmath_test.cc
index 65859c2..0d6f9dc 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/fastmath_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/fastmath_test.cc
@@ -27,19 +27,6 @@
 
 namespace {
 
-TEST(DistributionImplTest, LeadingSetBit) {
-  using absl::random_internal::LeadingSetBit;
-  constexpr uint64_t kZero = 0;
-  EXPECT_EQ(0, LeadingSetBit(kZero));
-  EXPECT_EQ(64, LeadingSetBit(~kZero));
-
-  for (int index = 0; index < 64; index++) {
-    uint64_t x = static_cast<uint64_t>(1) << index;
-    EXPECT_EQ(index + 1, LeadingSetBit(x)) << index;
-    EXPECT_EQ(index + 1, LeadingSetBit(x + x - 1)) << index;
-  }
-}
-
 TEST(FastMathTest, IntLog2FloorTest) {
   using absl::random_internal::IntLog2Floor;
   constexpr uint64_t kZero = 0;
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/generate_real.h b/grpc/third_party/abseil-cpp/absl/random/internal/generate_real.h
index 20f6d20..4f62873 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/generate_real.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/generate_real.h
@@ -23,8 +23,8 @@
 #include <limits>
 #include <type_traits>
 
-#include "absl/base/internal/bits.h"
 #include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
 #include "absl/random/internal/fastmath.h"
 #include "absl/random/internal/traits.h"
 
@@ -120,7 +120,7 @@
 
   // Number of leading zeros is mapped to the exponent: 2^-clz
   // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0
-  int clz = base_internal::CountLeadingZeros64(bits);
+  int clz = countl_zero(bits);
   bits <<= (IncludeZero ? clz : (clz & 63));  // remove 0-bits.
   exp -= clz;                                 // set the exponent.
   bits >>= (63 - kExp);
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/generate_real_test.cc b/grpc/third_party/abseil-cpp/absl/random/internal/generate_real_test.cc
index aa02f0c..b099dbf 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/generate_real_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/generate_real_test.cc
@@ -20,8 +20,8 @@
 #include <string>
 
 #include "gtest/gtest.h"
-#include "absl/base/internal/bits.h"
 #include "absl/flags/flag.h"
+#include "absl/numeric/bits.h"
 
 ABSL_FLAG(int64_t, absl_random_test_trials, 50000,
           "Number of trials for the probability tests.");
@@ -413,14 +413,13 @@
 }
 
 TEST(GenerateRealTest, ExhaustiveFloat) {
-  using absl::base_internal::CountLeadingZeros64;
   auto ToFloat = [](uint64_t a) {
     return GenerateRealFromBits<float, GeneratePositiveTag, true>(a);
   };
 
   // Rely on RandU64ToFloat generating values from greatest to least when
-  // supplied with uint64_t values from greatest (0xfff...) to least (0x0).  Thus,
-  // this algorithm stores the previous value, and if the new value is at
+  // supplied with uint64_t values from greatest (0xfff...) to least (0x0).
+  // Thus, this algorithm stores the previous value, and if the new value is at
   // greater than or equal to the previous value, then there is a collision in
   // the generation algorithm.
   //
@@ -464,7 +463,7 @@
 
     // Adjust decrement and check value based on how many leading 0
     // bits are set in the current value.
-    const int clz = CountLeadingZeros64(x);
+    const int clz = absl::countl_zero(x);
     if (clz < kDig) {
       dec <<= (kDig - clz);
       chk = (~uint64_t(0)) >> (clz + 1);
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/iostream_state_saver_test.cc b/grpc/third_party/abseil-cpp/absl/random/internal/iostream_state_saver_test.cc
index 7bb8ad9..6e66266 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/iostream_state_saver_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/iostream_state_saver_test.cc
@@ -14,6 +14,9 @@
 
 #include "absl/random/internal/iostream_state_saver.h"
 
+#include <errno.h>
+#include <stdio.h>
+
 #include <sstream>
 #include <string>
 
@@ -272,7 +275,6 @@
   }
 }
 
-#if !defined(__EMSCRIPTEN__)
 TEST(IOStreamStateSaver, RoundTripLongDoubles) {
   // Technically, C++ only guarantees that long double is at least as large as a
   // double.  Practically it varies from 64-bits to 128-bits.
@@ -350,7 +352,6 @@
     }
   }
 }
-#endif  // !defined(__EMSCRIPTEN__)
 
 TEST(StrToDTest, DoubleMin) {
   const char kV[] = "2.22507385850720138e-308";
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/mock_helpers.h b/grpc/third_party/abseil-cpp/absl/random/internal/mock_helpers.h
index 9af27ab..9d6ab21 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/mock_helpers.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/mock_helpers.h
@@ -80,6 +80,13 @@
   }
 
  public:
+  // InvokeMock is private; this provides access for some specialized use cases.
+  template <typename URBG>
+  static inline bool PrivateInvokeMock(URBG* urbg, IdType type,
+                                       void* args_tuple, void* result) {
+    return urbg->InvokeMock(type, args_tuple, result);
+  }
+
   // Invoke a mock for the KeyT (may or may not be a signature).
   //
   // KeyT is used to generate a typeid-based lookup key for the mock.
@@ -109,14 +116,14 @@
   // The mocked function signature will be composed from KeyT as:
   //   result_type(args...)
   template <typename KeyT, typename MockURBG>
-  static auto MockFor(MockURBG& m) -> decltype(
-      std::declval<MockURBG>()
-          .template RegisterMock<typename KeySignature<KeyT>::result_type,
-                                 typename KeySignature<KeyT>::arg_tuple_type>(
-              std::declval<IdType>())) {
+  static auto MockFor(MockURBG& m)
+      -> decltype(m.template RegisterMock<
+                  typename KeySignature<KeyT>::result_type,
+                  typename KeySignature<KeyT>::arg_tuple_type>(
+          m, std::declval<IdType>())) {
     return m.template RegisterMock<typename KeySignature<KeyT>::result_type,
                                    typename KeySignature<KeyT>::arg_tuple_type>(
-        ::absl::base_internal::FastTypeId<KeyT>());
+        m, ::absl::base_internal::FastTypeId<KeyT>());
   }
 };
 
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/mock_overload_set.h b/grpc/third_party/abseil-cpp/absl/random/internal/mock_overload_set.h
index dccc6ce..0d9c6c1 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/mock_overload_set.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/mock_overload_set.h
@@ -19,7 +19,6 @@
 #include <type_traits>
 
 #include "gmock/gmock.h"
-#include "gtest/gtest.h"
 #include "absl/random/internal/mock_helpers.h"
 #include "absl/random/mocking_bit_gen.h"
 
@@ -45,10 +44,12 @@
                 "Overload signature must have return type matching the "
                 "distribution result_type.");
   using KeyT = Ret(DistrT, std::tuple<Args...>);
-  auto gmock_Call(
-      absl::MockingBitGen& gen,  // NOLINT(google-runtime-references)
-      const ::testing::Matcher<Args>&... matchers)
+
+  template <typename MockURBG>
+  auto gmock_Call(MockURBG& gen, const ::testing::Matcher<Args>&... matchers)
       -> decltype(MockHelpers::MockFor<KeyT>(gen).gmock_Call(matchers...)) {
+    static_assert(std::is_base_of<MockingBitGen, MockURBG>::value,
+                  "Mocking requires an absl::MockingBitGen");
     return MockHelpers::MockFor<KeyT>(gen).gmock_Call(matchers...);
   }
 };
@@ -59,12 +60,14 @@
                 "Overload signature must have return type matching the "
                 "distribution result_type.");
   using KeyT = Ret(DistrT, std::tuple<Arg, Args...>);
-  auto gmock_Call(
-      const ::testing::Matcher<Arg>& matcher,
-      absl::MockingBitGen& gen,  // NOLINT(google-runtime-references)
-      const ::testing::Matcher<Args>&... matchers)
+
+  template <typename MockURBG>
+  auto gmock_Call(const ::testing::Matcher<Arg>& matcher, MockURBG& gen,
+                  const ::testing::Matcher<Args>&... matchers)
       -> decltype(MockHelpers::MockFor<KeyT>(gen).gmock_Call(matcher,
                                                              matchers...)) {
+    static_assert(std::is_base_of<MockingBitGen, MockURBG>::value,
+                  "Mocking requires an absl::MockingBitGen");
     return MockHelpers::MockFor<KeyT>(gen).gmock_Call(matcher, matchers...);
   }
 };
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/pcg_engine.h b/grpc/third_party/abseil-cpp/absl/random/internal/pcg_engine.h
index 53c23fe..8efaf2e 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/pcg_engine.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/pcg_engine.h
@@ -19,6 +19,7 @@
 
 #include "absl/base/config.h"
 #include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/random/internal/fastmath.h"
 #include "absl/random/internal/iostream_state_saver.h"
@@ -261,7 +262,7 @@
     uint64_t rotate = h >> 58u;
     uint64_t s = Uint128Low64(state) ^ h;
 #endif
-    return random_internal::rotr(s, rotate);
+    return rotr(s, rotate);
   }
 };
 
@@ -281,8 +282,8 @@
   using state_type = uint64_t;
   using result_type = uint32_t;
   inline uint32_t operator()(uint64_t state) {
-    return random_internal::rotr(
-        static_cast<uint32_t>(((state >> 18) ^ state) >> 27), state >> 59);
+    return rotr(static_cast<uint32_t>(((state >> 18) ^ state) >> 27),
+                state >> 59);
   }
 };
 
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/randen.cc b/grpc/third_party/abseil-cpp/absl/random/internal/randen.cc
index 78a1e00..c1bc044 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/randen.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/randen.cc
@@ -17,7 +17,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/random/internal/randen_detect.h"
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
 //
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/randen.h b/grpc/third_party/abseil-cpp/absl/random/internal/randen.h
index c2834aa..9a3840b 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/randen.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/randen.h
@@ -26,7 +26,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
 //
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/randen_detect.cc b/grpc/third_party/abseil-cpp/absl/random/internal/randen_detect.cc
index d63230c..bbe7b96 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/randen_detect.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/randen_detect.cc
@@ -1,13 +1,13 @@
 // Copyright 2017 The Abseil Authors.
 //
-// Licensed under the Apache License, Version 2.0 (the"License");
+// 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
 //
 //      https://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,
+// 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.
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/randen_engine.h b/grpc/third_party/abseil-cpp/absl/random/internal/randen_engine.h
index 6b33731..92bb890 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/randen_engine.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/randen_engine.h
@@ -23,6 +23,7 @@
 #include <limits>
 #include <type_traits>
 
+#include "absl/base/internal/endian.h"
 #include "absl/meta/type_traits.h"
 #include "absl/random/internal/iostream_state_saver.h"
 #include "absl/random/internal/randen.h"
@@ -76,7 +77,7 @@
       impl_.Generate(state_);
     }
 
-    return state_[next_++];
+    return little_endian::ToHost(state_[next_++]);
   }
 
   template <class SeedSequence>
@@ -181,7 +182,8 @@
       // In the case that `elem` is `uint8_t`, it must be cast to something
       // larger so that it prints as an integer rather than a character. For
       // simplicity, apply the cast all circumstances.
-      os << static_cast<numeric_type>(elem) << os.fill();
+      os << static_cast<numeric_type>(little_endian::FromHost(elem))
+         << os.fill();
     }
     os << engine.next_;
     return os;
@@ -200,7 +202,7 @@
       // necessary to read a wider type and then cast it to uint8_t.
       numeric_type value;
       is >> value;
-      elem = static_cast<result_type>(value);
+      elem = little_endian::ToHost(static_cast<result_type>(value));
     }
     is >> next;
     if (is.fail()) {
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/randen_hwaes.h b/grpc/third_party/abseil-cpp/absl/random/internal/randen_hwaes.h
index bce36b5..71a7f69 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/randen_hwaes.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/randen_hwaes.h
@@ -26,7 +26,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
 //
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/randen_slow.h b/grpc/third_party/abseil-cpp/absl/random/internal/randen_slow.h
index b6f137e..532c3a8 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/randen_slow.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/randen_slow.h
@@ -23,7 +23,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // RandenSlow implements the basic state manipulation methods for
 // architectures lacking AES hardware acceleration intrinsics.
 class RandenSlow {
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/randen_slow_test.cc b/grpc/third_party/abseil-cpp/absl/random/internal/randen_slow_test.cc
index 4a53583..4861ffa 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/randen_slow_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/randen_slow_test.cc
@@ -17,6 +17,7 @@
 #include <cstring>
 
 #include "gtest/gtest.h"
+#include "absl/base/internal/endian.h"
 #include "absl/random/internal/randen_traits.h"
 
 namespace {
@@ -56,7 +57,7 @@
 
   uint64_t* id = d.state;
   for (const auto& elem : kGolden) {
-    EXPECT_EQ(elem, *id++);
+    EXPECT_EQ(absl::little_endian::FromHost64(elem), *id++);
   }
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/randen_traits.h b/grpc/third_party/abseil-cpp/absl/random/internal/randen_traits.h
index 53caa93..120022c 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/randen_traits.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/randen_traits.h
@@ -28,7 +28,7 @@
 ABSL_NAMESPACE_BEGIN
 namespace random_internal {
 
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
 // 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
 // generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
 //
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/wide_multiply.h b/grpc/third_party/abseil-cpp/absl/random/internal/wide_multiply.h
index 0afcbe0..b6e6c4b 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/wide_multiply.h
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/wide_multiply.h
@@ -26,7 +26,7 @@
 #endif
 
 #include "absl/base/config.h"
-#include "absl/base/internal/bits.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/random/internal/traits.h"
 
diff --git a/grpc/third_party/abseil-cpp/absl/random/internal/wide_multiply_test.cc b/grpc/third_party/abseil-cpp/absl/random/internal/wide_multiply_test.cc
index ca8ce92..e276cb5 100644
--- a/grpc/third_party/abseil-cpp/absl/random/internal/wide_multiply_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/internal/wide_multiply_test.cc
@@ -15,7 +15,6 @@
 #include "absl/random/internal/wide_multiply.h"
 
 #include "gtest/gtest.h"
-#include "absl/base/internal/bits.h"
 #include "absl/numeric/int128.h"
 
 using absl::random_internal::MultiplyU64ToU128;
diff --git a/grpc/third_party/abseil-cpp/absl/random/log_uniform_int_distribution.h b/grpc/third_party/abseil-cpp/absl/random/log_uniform_int_distribution.h
index 960816e..43e1011 100644
--- a/grpc/third_party/abseil-cpp/absl/random/log_uniform_int_distribution.h
+++ b/grpc/third_party/abseil-cpp/absl/random/log_uniform_int_distribution.h
@@ -23,6 +23,7 @@
 #include <ostream>
 #include <type_traits>
 
+#include "absl/numeric/bits.h"
 #include "absl/random/internal/fastmath.h"
 #include "absl/random/internal/generate_real.h"
 #include "absl/random/internal/iostream_state_saver.h"
@@ -68,8 +69,10 @@
       if (base_ == 2) {
         // Determine where the first set bit is on range(), giving a log2(range)
         // value which can be used to construct bounds.
-        log_range_ = (std::min)(random_internal::LeadingSetBit(range()),
-                                std::numeric_limits<unsigned_type>::digits);
+        log_range_ =
+            (std::min)(bit_width(range()),
+                       static_cast<unsigned_type>(
+                           std::numeric_limits<unsigned_type>::digits));
       } else {
         // NOTE: Computing the logN(x) introduces error from 2 sources:
         // 1. Conversion of int to double loses precision for values >=
diff --git a/grpc/third_party/abseil-cpp/absl/random/mocking_bit_gen.h b/grpc/third_party/abseil-cpp/absl/random/mocking_bit_gen.h
index 6d2f2c8..7b2b80e 100644
--- a/grpc/third_party/abseil-cpp/absl/random/mocking_bit_gen.h
+++ b/grpc/third_party/abseil-cpp/absl/random/mocking_bit_gen.h
@@ -104,10 +104,7 @@
 class MockingBitGen {
  public:
   MockingBitGen() = default;
-
-  ~MockingBitGen() {
-    for (const auto& del : deleters_) del();
-  }
+  ~MockingBitGen() = default;
 
   // URBG interface
   using result_type = absl::BitGen::result_type;
@@ -117,14 +114,6 @@
   result_type operator()() { return gen_(); }
 
  private:
-  using match_impl_fn = void (*)(void* mock_fn, void* t_erased_arg_tuple,
-                                 void* t_erased_result);
-
-  struct MockData {
-    void* mock_fn = nullptr;
-    match_impl_fn match_impl = nullptr;
-  };
-
   // GetMockFnType returns the testing::MockFunction for a result and tuple.
   // This method only exists for type deduction and is otherwise unimplemented.
   template <typename ResultT, typename... Args>
@@ -136,17 +125,46 @@
   // NOTE: MockFnCaller is essentially equivalent to the lambda:
   // [fn](auto... args) { return fn->Call(std::move(args)...)}
   // however that fails to build on some supported platforms.
-  template <typename ResultT, typename MockFnType, typename Tuple>
+  template <typename MockFnType, typename ResultT, typename Tuple>
   struct MockFnCaller;
+
   // specialization for std::tuple.
-  template <typename ResultT, typename MockFnType, typename... Args>
-  struct MockFnCaller<ResultT, MockFnType, std::tuple<Args...>> {
+  template <typename MockFnType, typename ResultT, typename... Args>
+  struct MockFnCaller<MockFnType, ResultT, std::tuple<Args...>> {
     MockFnType* fn;
     inline ResultT operator()(Args... args) {
       return fn->Call(std::move(args)...);
     }
   };
 
+  // FunctionHolder owns a particular ::testing::MockFunction associated with
+  // a mocked type signature, and implement the type-erased Apply call, which
+  // applies type-erased arguments to the mock.
+  class FunctionHolder {
+   public:
+    virtual ~FunctionHolder() = default;
+
+    // Call is a dispatch function which converts the
+    // generic type-erased parameters into a specific mock invocation call.
+    virtual void Apply(/*ArgTupleT*/ void* args_tuple,
+                       /*ResultT*/ void* result) = 0;
+  };
+
+  template <typename MockFnType, typename ResultT, typename ArgTupleT>
+  class FunctionHolderImpl final : public FunctionHolder {
+   public:
+    void Apply(void* args_tuple, void* result) override {
+      // Requires tuple_args to point to a ArgTupleT, which is a
+      // std::tuple<Args...> used to invoke the mock function. Requires result
+      // to point to a ResultT, which is the result of the call.
+      *static_cast<ResultT*>(result) =
+          absl::apply(MockFnCaller<MockFnType, ResultT, ArgTupleT>{&mock_fn_},
+                      *static_cast<ArgTupleT*>(args_tuple));
+    }
+
+    MockFnType mock_fn_;
+  };
+
   // MockingBitGen::RegisterMock
   //
   // RegisterMock<ResultT, ArgTupleT>(FastTypeIdType) is the main extension
@@ -157,37 +175,31 @@
   //
   // The returned MockFunction<...> type can be used to setup additional
   // distribution parameters of the expectation.
-  template <typename ResultT, typename ArgTupleT>
-  auto RegisterMock(base_internal::FastTypeIdType type)
+  template <typename ResultT, typename ArgTupleT, typename SelfT>
+  auto RegisterMock(SelfT&, base_internal::FastTypeIdType type)
       -> decltype(GetMockFnType(std::declval<ResultT>(),
                                 std::declval<ArgTupleT>()))& {
-    using MockFnType = decltype(
-        GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
-    auto& mock = mocks_[type];
-    if (!mock.mock_fn) {
-      auto* mock_fn = new MockFnType;
-      mock.mock_fn = mock_fn;
-      mock.match_impl = &MatchImpl<ResultT, ArgTupleT>;
-      deleters_.emplace_back([mock_fn] { delete mock_fn; });
-    }
-    return *static_cast<MockFnType*>(mock.mock_fn);
-  }
+    using MockFnType = decltype(GetMockFnType(std::declval<ResultT>(),
+                                              std::declval<ArgTupleT>()));
 
-  // MockingBitGen::MatchImpl<> is a dispatch function which converts the
-  // generic type-erased parameters into a specific mock invocation call.
-  // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
-  // used to invoke the mock function.
-  // Requires result to point to a ResultT, which is the result of the call.
-  template <typename ResultT, typename ArgTupleT>
-  static void MatchImpl(/*MockFnType<ResultT, Args...>*/ void* mock_fn,
-                        /*ArgTupleT*/ void* args_tuple,
-                        /*ResultT*/ void* result) {
-    using MockFnType = decltype(
-        GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
-    *static_cast<ResultT*>(result) = absl::apply(
-        MockFnCaller<ResultT, MockFnType, ArgTupleT>{
-            static_cast<MockFnType*>(mock_fn)},
-        *static_cast<ArgTupleT*>(args_tuple));
+    using WrappedFnType = absl::conditional_t<
+        std::is_same<SelfT, ::testing::NiceMock<absl::MockingBitGen>>::value,
+        ::testing::NiceMock<MockFnType>,
+        absl::conditional_t<
+            std::is_same<SelfT,
+                         ::testing::NaggyMock<absl::MockingBitGen>>::value,
+            ::testing::NaggyMock<MockFnType>,
+            absl::conditional_t<
+                std::is_same<SelfT,
+                             ::testing::StrictMock<absl::MockingBitGen>>::value,
+                ::testing::StrictMock<MockFnType>, MockFnType>>>;
+
+    using ImplT = FunctionHolderImpl<WrappedFnType, ResultT, ArgTupleT>;
+    auto& mock = mocks_[type];
+    if (!mock) {
+      mock = absl::make_unique<ImplT>();
+    }
+    return static_cast<ImplT*>(mock.get())->mock_fn_;
   }
 
   // MockingBitGen::InvokeMock
@@ -206,13 +218,13 @@
     // Trigger a mock, if there exists one that matches `param`.
     auto it = mocks_.find(type);
     if (it == mocks_.end()) return false;
-    auto* mock_data = static_cast<MockData*>(&it->second);
-    mock_data->match_impl(mock_data->mock_fn, args_tuple, result);
+    it->second->Apply(args_tuple, result);
     return true;
   }
 
-  absl::flat_hash_map<base_internal::FastTypeIdType, MockData> mocks_;
-  std::vector<std::function<void()>> deleters_;
+  absl::flat_hash_map<base_internal::FastTypeIdType,
+                      std::unique_ptr<FunctionHolder>>
+      mocks_;
   absl::BitGen gen_;
 
   template <typename>
diff --git a/grpc/third_party/abseil-cpp/absl/random/mocking_bit_gen_test.cc b/grpc/third_party/abseil-cpp/absl/random/mocking_bit_gen_test.cc
index f0ffc9a..f63b6e4 100644
--- a/grpc/third_party/abseil-cpp/absl/random/mocking_bit_gen_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/mocking_bit_gen_test.cc
@@ -26,6 +26,8 @@
 #include "absl/random/random.h"
 
 namespace {
+
+using ::testing::_;
 using ::testing::Ne;
 using ::testing::Return;
 
@@ -344,4 +346,47 @@
   EXPECT_EQ(absl::Poisson<int>(gen, 2.0), 4);
 }
 
+TEST(MockingBitGen, NiceMock) {
+  ::testing::NiceMock<absl::MockingBitGen> gen;
+  ON_CALL(absl::MockUniform<int>(), Call(gen, _, _)).WillByDefault(Return(145));
+
+  ON_CALL(absl::MockPoisson<int>(), Call(gen, _)).WillByDefault(Return(3));
+
+  EXPECT_EQ(absl::Uniform(gen, 1, 1000), 145);
+  EXPECT_EQ(absl::Uniform(gen, 10, 1000), 145);
+  EXPECT_EQ(absl::Uniform(gen, 100, 1000), 145);
+}
+
+TEST(MockingBitGen, NaggyMock) {
+  // This is difficult to test, as only the output matters, so just verify
+  // that ON_CALL can be installed. Anything else requires log inspection.
+  ::testing::NaggyMock<absl::MockingBitGen> gen;
+
+  ON_CALL(absl::MockUniform<int>(), Call(gen, _, _)).WillByDefault(Return(145));
+  ON_CALL(absl::MockPoisson<int>(), Call(gen, _)).WillByDefault(Return(3));
+
+  EXPECT_EQ(absl::Uniform(gen, 1, 1000), 145);
+}
+
+TEST(MockingBitGen, StrictMock_NotEnough) {
+  EXPECT_NONFATAL_FAILURE(
+      []() {
+        ::testing::StrictMock<absl::MockingBitGen> gen;
+        EXPECT_CALL(absl::MockUniform<int>(), Call(gen, _, _))
+            .WillOnce(Return(145));
+      }(),
+      "unsatisfied and active");
+}
+
+TEST(MockingBitGen, StrictMock_TooMany) {
+  ::testing::StrictMock<absl::MockingBitGen> gen;
+
+  EXPECT_CALL(absl::MockUniform<int>(), Call(gen, _, _)).WillOnce(Return(145));
+  EXPECT_EQ(absl::Uniform(gen, 1, 1000), 145);
+
+  EXPECT_NONFATAL_FAILURE(
+      [&]() { EXPECT_EQ(absl::Uniform(gen, 10, 1000), 0); }(),
+      "over-saturated and active");
+}
+
 }  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/random/uniform_int_distribution.h b/grpc/third_party/abseil-cpp/absl/random/uniform_int_distribution.h
index da66564..c1f54cc 100644
--- a/grpc/third_party/abseil-cpp/absl/random/uniform_int_distribution.h
+++ b/grpc/third_party/abseil-cpp/absl/random/uniform_int_distribution.h
@@ -196,7 +196,7 @@
 uniform_int_distribution<IntType>::Generate(
     URBG& g,  // NOLINT(runtime/references)
     typename random_internal::make_unsigned_bits<IntType>::type R) {
-    random_internal::FastUniformBits<unsigned_type> fast_bits;
+  random_internal::FastUniformBits<unsigned_type> fast_bits;
   unsigned_type bits = fast_bits(g);
   const unsigned_type Lim = R + 1;
   if ((R & Lim) == 0) {
diff --git a/grpc/third_party/abseil-cpp/absl/random/uniform_real_distribution_test.cc b/grpc/third_party/abseil-cpp/absl/random/uniform_real_distribution_test.cc
index be107cd..18bcd3b 100644
--- a/grpc/third_party/abseil-cpp/absl/random/uniform_real_distribution_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/random/uniform_real_distribution_test.cc
@@ -20,11 +20,13 @@
 #include <random>
 #include <sstream>
 #include <string>
+#include <type_traits>
 #include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/random/internal/chi_square.h"
 #include "absl/random/internal/distribution_test_util.h"
 #include "absl/random/internal/pcg_engine.h"
@@ -55,11 +57,15 @@
 template <typename RealType>
 class UniformRealDistributionTest : public ::testing::Test {};
 
-#if defined(__EMSCRIPTEN__)
-using RealTypes = ::testing::Types<float, double>;
-#else
-using RealTypes = ::testing::Types<float, double, long double>;
-#endif  // defined(__EMSCRIPTEN__)
+// double-double arithmetic is not supported well by either GCC or Clang; see
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
+// https://bugs.llvm.org/show_bug.cgi?id=49131, and
+// https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
+// with double doubles until compiler support is better.
+using RealTypes =
+    std::conditional<absl::numeric_internal::IsDoubleDouble(),
+                     ::testing::Types<float, double>,
+                     ::testing::Types<float, double, long double>>::type;
 
 TYPED_TEST_SUITE(UniformRealDistributionTest, RealTypes);
 
diff --git a/grpc/third_party/abseil-cpp/absl/status/internal/status_internal.h b/grpc/third_party/abseil-cpp/absl/status/internal/status_internal.h
index 1f82b8e..99a2d96 100644
--- a/grpc/third_party/abseil-cpp/absl/status/internal/status_internal.h
+++ b/grpc/third_party/abseil-cpp/absl/status/internal/status_internal.h
@@ -19,6 +19,17 @@
 #include "absl/container/inlined_vector.h"
 #include "absl/strings/cord.h"
 
+#ifndef SWIG
+// Disabled for SWIG as it doesn't parse attributes correctly.
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+// Returned Status objects may not be ignored. Codesearch doesn't handle ifdefs
+// as part of a class definitions (b/6995610), so we use a forward declaration.
+class ABSL_MUST_USE_RESULT Status;
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // !SWIG
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
@@ -36,6 +47,13 @@
 
 // Reference-counted representation of Status data.
 struct StatusRep {
+  StatusRep(absl::StatusCode code, std::string message,
+            std::unique_ptr<status_internal::Payloads> payloads)
+      : ref(int32_t{1}),
+        code(code),
+        message(std::move(message)),
+        payloads(std::move(payloads)) {}
+
   std::atomic<int32_t> ref;
   absl::StatusCode code;
   std::string message;
diff --git a/grpc/third_party/abseil-cpp/absl/status/internal/statusor_internal.h b/grpc/third_party/abseil-cpp/absl/status/internal/statusor_internal.h
index 96e41da..eaac2c0 100644
--- a/grpc/third_party/abseil-cpp/absl/status/internal/statusor_internal.h
+++ b/grpc/third_party/abseil-cpp/absl/status/internal/statusor_internal.h
@@ -17,6 +17,7 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/base/attributes.h"
 #include "absl/meta/type_traits.h"
 #include "absl/status/status.h"
 #include "absl/utility/utility.h"
@@ -135,18 +136,14 @@
  public:
   // Move type-agnostic error handling to the .cc.
   static void HandleInvalidStatusCtorArg(Status*);
-  static void Crash(const absl::Status& status);
+  ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status);
 };
 
 // Construct an instance of T in `p` through placement new, passing Args... to
 // the constructor.
 // This abstraction is here mostly for the gcc performance fix.
 template <typename T, typename... Args>
-void PlacementNew(void* p, Args&&... args) {
-#if defined(__GNUC__) && !defined(__clang__)
-  // Teach gcc that 'p' cannot be null, fixing code size issues.
-  if (p == nullptr) __builtin_unreachable();
-#endif
+ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(void* p, Args&&... args) {
   new (p) T(std::forward<Args>(args)...);
 }
 
@@ -215,7 +212,7 @@
   template <typename U,
             absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value,
                               int> = 0>
-  explicit StatusOrData(U&& v) : status_(v) {
+  explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
     EnsureNotOk();
   }
 
diff --git a/grpc/third_party/abseil-cpp/absl/status/status.cc b/grpc/third_party/abseil-cpp/absl/status/status.cc
index a27fd8b..51a0d26 100644
--- a/grpc/third_party/abseil-cpp/absl/status/status.cc
+++ b/grpc/third_party/abseil-cpp/absl/status/status.cc
@@ -207,13 +207,12 @@
   }
 }
 
-uintptr_t Status::NewRep(absl::StatusCode code, absl::string_view msg,
-                         std::unique_ptr<status_internal::Payloads> payloads) {
-  status_internal::StatusRep* rep = new status_internal::StatusRep;
-  rep->ref.store(1, std::memory_order_relaxed);
-  rep->code = code;
-  rep->message.assign(msg.data(), msg.size());
-  rep->payloads = std::move(payloads);
+uintptr_t Status::NewRep(
+    absl::StatusCode code, absl::string_view msg,
+    std::unique_ptr<status_internal::Payloads> payloads) {
+  status_internal::StatusRep* rep = new status_internal::StatusRep(
+      code, std::string(msg.data(), msg.size()),
+      std::move(payloads));
   return PointerToRep(rep);
 }
 
@@ -239,8 +238,9 @@
 void Status::PrepareToModify() {
   ABSL_RAW_CHECK(!ok(), "PrepareToModify shouldn't be called on OK status.");
   if (IsInlined(rep_)) {
-    rep_ = NewRep(static_cast<absl::StatusCode>(raw_code()),
-                  absl::string_view(), nullptr);
+    rep_ =
+        NewRep(static_cast<absl::StatusCode>(raw_code()), absl::string_view(),
+               nullptr);
     return;
   }
 
@@ -251,7 +251,8 @@
     if (rep->payloads) {
       payloads = absl::make_unique<status_internal::Payloads>(*rep->payloads);
     }
-    rep_ = NewRep(rep->code, message(), std::move(payloads));
+    rep_ = NewRep(rep->code, message(),
+                  std::move(payloads));
     UnrefNonInlined(rep_i);
   }
 }
@@ -290,20 +291,26 @@
   return true;
 }
 
-std::string Status::ToStringSlow() const {
+std::string Status::ToStringSlow(StatusToStringMode mode) const {
   std::string text;
   absl::StrAppend(&text, absl::StatusCodeToString(code()), ": ", message());
-  status_internal::StatusPayloadPrinter printer =
-      status_internal::GetStatusPayloadPrinter();
-  this->ForEachPayload([&](absl::string_view type_url,
-                           const absl::Cord& payload) {
-    absl::optional<std::string> result;
-    if (printer) result = printer(type_url, payload);
-    absl::StrAppend(
-        &text, " [", type_url, "='",
-        result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
-        "']");
-  });
+
+  const bool with_payload = (mode & StatusToStringMode::kWithPayload) ==
+                      StatusToStringMode::kWithPayload;
+
+  if (with_payload) {
+    status_internal::StatusPayloadPrinter printer =
+        status_internal::GetStatusPayloadPrinter();
+    this->ForEachPayload([&](absl::string_view type_url,
+                             const absl::Cord& payload) {
+      absl::optional<std::string> result;
+      if (printer) result = printer(type_url, payload);
+      absl::StrAppend(
+          &text, " [", type_url, "='",
+          result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
+          "']");
+    });
+  }
 
   return text;
 }
diff --git a/grpc/third_party/abseil-cpp/absl/status/status.h b/grpc/third_party/abseil-cpp/absl/status/status.h
index 42f634e..61486fe 100644
--- a/grpc/third_party/abseil-cpp/absl/status/status.h
+++ b/grpc/third_party/abseil-cpp/absl/status/status.h
@@ -57,6 +57,7 @@
 #include "absl/container/inlined_vector.h"
 #include "absl/status/internal/status_internal.h"
 #include "absl/strings/cord.h"
+#include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 
 namespace absl {
@@ -98,7 +99,7 @@
 
   // StatusCode::kCancelled
   //
-  // kCanelled (gRPC code "CANCELLED") indicates the operation was cancelled,
+  // kCancelled (gRPC code "CANCELLED") indicates the operation was cancelled,
   // typically by the caller.
   kCancelled = 1,
 
@@ -198,9 +199,9 @@
   // `kAborted`, and `kUnavailable`.
   kAborted = 10,
 
-  // StatusCode::kOutofRange
+  // StatusCode::kOutOfRange
   //
-  // kOutofRange (gRPC code "OUT_OF_RANGE") indicates the operation was
+  // kOutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was
   // attempted past the valid range, such as seeking or reading past an
   // end-of-file.
   //
@@ -279,6 +280,57 @@
 // Streams StatusCodeToString(code) to `os`.
 std::ostream& operator<<(std::ostream& os, StatusCode code);
 
+// absl::StatusToStringMode
+//
+// An `absl::StatusToStringMode` is an enumerated type indicating how
+// `absl::Status::ToString()` should construct the output string for an non-ok
+// status.
+enum class StatusToStringMode : int {
+  // ToString will not contain any extra data (such as payloads). It will only
+  // contain the error code and message, if any.
+  kWithNoExtraData = 0,
+  // ToString will contain the payloads.
+  kWithPayload = 1 << 0,
+  // ToString will include all the extra data this Status has.
+  kWithEverything = ~kWithNoExtraData,
+};
+
+// absl::StatusToStringMode is specified as a bitmask type, which means the
+// following operations must be provided:
+inline constexpr StatusToStringMode operator&(StatusToStringMode lhs,
+                                              StatusToStringMode rhs) {
+  return static_cast<StatusToStringMode>(static_cast<int>(lhs) &
+                                         static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator|(StatusToStringMode lhs,
+                                              StatusToStringMode rhs) {
+  return static_cast<StatusToStringMode>(static_cast<int>(lhs) |
+                                         static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator^(StatusToStringMode lhs,
+                                              StatusToStringMode rhs) {
+  return static_cast<StatusToStringMode>(static_cast<int>(lhs) ^
+                                         static_cast<int>(rhs));
+}
+inline constexpr StatusToStringMode operator~(StatusToStringMode arg) {
+  return static_cast<StatusToStringMode>(~static_cast<int>(arg));
+}
+inline StatusToStringMode& operator&=(StatusToStringMode& lhs,
+                                      StatusToStringMode rhs) {
+  lhs = lhs & rhs;
+  return lhs;
+}
+inline StatusToStringMode& operator|=(StatusToStringMode& lhs,
+                                      StatusToStringMode rhs) {
+  lhs = lhs | rhs;
+  return lhs;
+}
+inline StatusToStringMode& operator^=(StatusToStringMode& lhs,
+                                      StatusToStringMode rhs) {
+  lhs = lhs ^ rhs;
+  return lhs;
+}
+
 // absl::Status
 //
 // The `absl::Status` class is generally used to gracefully handle errors
@@ -360,7 +412,12 @@
 //     return result;
 //   }
 //
-class ABSL_MUST_USE_RESULT Status final {
+// For documentation see https://abseil.io/docs/cpp/guides/status.
+//
+// Returned Status objects may not be ignored. status_internal.h has a forward
+// declaration of the form
+// class ABSL_MUST_USE_RESULT Status;
+class Status final {
  public:
   // Constructors
 
@@ -370,10 +427,10 @@
   Status();
 
   // Creates a status in the canonical error space with the specified
-  // `absl::StatusCode` and error message.  If `code == absl::StatusCode::kOk`,
+  // `absl::StatusCode` and error message.  If `code == absl::StatusCode::kOk`,  // NOLINT
   // `msg` is ignored and an object identical to an OK status is constructed.
   //
-  // The `msg` string must be in UTF-8. The implementation may complain (e.g.,
+  // The `msg` string must be in UTF-8. The implementation may complain (e.g.,  // NOLINT
   // by printing a warning) if it is not.
   Status(absl::StatusCode code, absl::string_view msg);
 
@@ -442,15 +499,17 @@
 
   // Status::ToString()
   //
-  // Returns a combination of the error code name, the message and any
-  // associated payload messages. This string is designed simply to be human
-  // readable and its exact format should not be load bearing. Do not depend on
-  // the exact format of the result of `ToString()` which is subject to change.
+  // Returns a string based on the `mode`. By default, it returns combination of
+  // the error code name, the message and any associated payload messages. This
+  // string is designed simply to be human readable and its exact format should
+  // not be load bearing. Do not depend on the exact format of the result of
+  // `ToString()` which is subject to change.
   //
   // The printed code name and the message are generally substrings of the
   // result, and the payloads to be printed use the status payload printer
   // mechanism (which is internal).
-  std::string ToString() const;
+  std::string ToString(
+      StatusToStringMode mode = StatusToStringMode::kWithPayload) const;
 
   // Status::IgnoreError()
   //
@@ -550,8 +609,9 @@
   status_internal::Payloads* GetPayloads();
 
   // Takes ownership of payload.
-  static uintptr_t NewRep(absl::StatusCode code, absl::string_view msg,
-                          std::unique_ptr<status_internal::Payloads> payload);
+  static uintptr_t NewRep(
+      absl::StatusCode code, absl::string_view msg,
+      std::unique_ptr<status_internal::Payloads> payload);
   static bool EqualsSlow(const absl::Status& a, const absl::Status& b);
 
   // MSVC 14.0 limitation requires the const.
@@ -580,8 +640,7 @@
   static uintptr_t PointerToRep(status_internal::StatusRep* r);
   static status_internal::StatusRep* RepToPointer(uintptr_t r);
 
-  // Returns string for non-ok Status.
-  std::string ToStringSlow() const;
+  std::string ToStringSlow(StatusToStringMode mode) const;
 
   // Status supports two different representations.
   //  - When the low bit is off it is an inlined representation.
@@ -704,9 +763,11 @@
 
 inline Status& Status::operator=(Status&& x) {
   uintptr_t old_rep = rep_;
-  rep_ = x.rep_;
-  x.rep_ = MovedFromRep();
-  Unref(old_rep);
+  if (x.rep_ != old_rep) {
+    rep_ = x.rep_;
+    x.rep_ = MovedFromRep();
+    Unref(old_rep);
+  }
   return *this;
 }
 
@@ -743,8 +804,8 @@
   return !(lhs == rhs);
 }
 
-inline std::string Status::ToString() const {
-  return ok() ? "OK" : ToStringSlow();
+inline std::string Status::ToString(StatusToStringMode mode) const {
+  return ok() ? "OK" : ToStringSlow(mode);
 }
 
 inline void Status::IgnoreError() const {
diff --git a/grpc/third_party/abseil-cpp/absl/status/status_test.cc b/grpc/third_party/abseil-cpp/absl/status/status_test.cc
index ca9488a..0e1a43c 100644
--- a/grpc/third_party/abseil-cpp/absl/status/status_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/status/status_test.cc
@@ -280,6 +280,27 @@
                     HasSubstr("[bar='\\xff']")));
 }
 
+TEST(Status, ToStringMode) {
+  absl::Status s(absl::StatusCode::kInternal, "fail");
+  s.SetPayload("foo", absl::Cord("bar"));
+  s.SetPayload("bar", absl::Cord("\377"));
+
+  EXPECT_EQ("INTERNAL: fail",
+            s.ToString(absl::StatusToStringMode::kWithNoExtraData));
+
+  EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithPayload),
+              AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
+                    HasSubstr("[bar='\\xff']")));
+
+  EXPECT_THAT(s.ToString(absl::StatusToStringMode::kWithEverything),
+              AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
+                    HasSubstr("[bar='\\xff']")));
+
+  EXPECT_THAT(s.ToString(~absl::StatusToStringMode::kWithPayload),
+              AllOf(HasSubstr("INTERNAL: fail"), Not(HasSubstr("[foo='bar']")),
+                    Not(HasSubstr("[bar='\\xff']"))));
+}
+
 absl::Status EraseAndReturn(const absl::Status& base) {
   absl::Status copy = base;
   EXPECT_TRUE(copy.ErasePayload(kUrl1));
@@ -397,6 +418,12 @@
     assignee = std::move(status);
     EXPECT_EQ(assignee, copy);
   }
+  {
+    absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+    absl::Status copy(status);
+    status = static_cast<absl::Status&&>(status);
+    EXPECT_EQ(status, copy);
+  }
 }
 
 TEST(Status, Update) {
@@ -454,5 +481,4 @@
   test_swap(no_payload, with_payload);
   test_swap(with_payload, no_payload);
 }
-
 }  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/status/statusor.h b/grpc/third_party/abseil-cpp/absl/status/statusor.h
index bdf6039..b7c55cc 100644
--- a/grpc/third_party/abseil-cpp/absl/status/statusor.h
+++ b/grpc/third_party/abseil-cpp/absl/status/statusor.h
@@ -129,13 +129,13 @@
 // Example:
 //
 //   absl::StatusOr<int> i = GetCount();
-//   if (foo.ok()) {
+//   if (i.ok()) {
 //     updated_total += *i
 //   }
 //
 // NOTE: using `absl::StatusOr<T>::value()` when no valid value is present will
 // throw an exception if exceptions are enabled or terminate the process when
-// execeptions are not enabled.
+// exceptions are not enabled.
 //
 // Example:
 //
@@ -542,7 +542,7 @@
 
   // StatusOr<T>::value_or()
   //
-  // Returns the current value of `this->ok() == true`. Otherwise constructs a
+  // Returns the current value if `this->ok() == true`. Otherwise constructs a
   // value using the provided `default_value`.
   //
   // Unlike `value`, this function returns by value, copying the current value
diff --git a/grpc/third_party/abseil-cpp/absl/status/statusor_test.cc b/grpc/third_party/abseil-cpp/absl/status/statusor_test.cc
index 5e4b268..c2e8fb7 100644
--- a/grpc/third_party/abseil-cpp/absl/status/statusor_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/status/statusor_test.cc
@@ -292,6 +292,17 @@
   EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown);
 }
 
+TEST(StatusOr, StatusCtorForwards) {
+  absl::Status status(absl::StatusCode::kInternal, "Some error");
+
+  EXPECT_EQ(absl::StatusOr<int>(status).status().message(), "Some error");
+  EXPECT_EQ(status.message(), "Some error");
+
+  EXPECT_EQ(absl::StatusOr<int>(std::move(status)).status().message(),
+            "Some error");
+  EXPECT_NE(status.message(), "Some error");
+}
+
 // Define `EXPECT_DEATH_OR_THROW` to test the behavior of `StatusOr::value`,
 // which either throws `BadStatusOrAccess` or `LOG(FATAL)` based on whether
 // exceptions are enabled.
diff --git a/grpc/third_party/abseil-cpp/absl/strings/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/strings/BUILD.bazel
index 64a13ce..123b5ef 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/strings/BUILD.bazel
@@ -54,6 +54,7 @@
         "ascii.h",
         "charconv.h",
         "escaping.h",
+        "internal/string_constant.h",
         "match.h",
         "numbers.h",
         "str_cat.h",
@@ -68,7 +69,6 @@
     deps = [
         ":internal",
         "//absl/base",
-        "//absl/base:bits",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
@@ -76,6 +76,7 @@
         "//absl/base:throw_delegate",
         "//absl/memory",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
     ],
 )
@@ -223,6 +224,19 @@
 )
 
 cc_test(
+    name = "string_constant_test",
+    size = "small",
+    srcs = ["internal/string_constant_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/meta:type_traits",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "string_view_benchmark",
     srcs = ["string_view_benchmark.cc"],
     copts = ABSL_TEST_COPTS,
@@ -253,13 +267,31 @@
 
 cc_library(
     name = "cord_internal",
-    hdrs = ["internal/cord_internal.h"],
+    srcs = [
+        "internal/cord_internal.cc",
+        "internal/cord_rep_ring.cc",
+    ],
+    hdrs = [
+        "internal/cord_internal.h",
+        "internal/cord_rep_flat.h",
+        "internal/cord_rep_ring.h",
+        "internal/cord_rep_ring_reader.h",
+    ],
     copts = ABSL_DEFAULT_COPTS,
-    visibility = ["//visibility:private"],
+    visibility = [
+        "//visibility:private",
+    ],
     deps = [
         ":strings",
         "//absl/base:base_internal",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:endian",
+        "//absl/base:raw_logging_internal",
+        "//absl/base:throw_delegate",
         "//absl/container:compressed_tuple",
+        "//absl/container:inlined_vector",
+        "//absl/container:layout",
         "//absl/meta:type_traits",
     ],
 )
@@ -324,6 +356,38 @@
 )
 
 cc_test(
+    name = "cord_ring_test",
+    size = "medium",
+    srcs = ["cord_ring_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":cord_internal",
+        ":strings",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:raw_logging_internal",
+        "//absl/debugging:leak_check",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "cord_ring_reader_test",
+    size = "medium",
+    srcs = ["cord_ring_reader_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":cord_internal",
+        ":strings",
+        "//absl/base:core_headers",
+        "//absl/debugging:leak_check",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "substitute_test",
     size = "small",
     srcs = ["substitute_test.cc"],
@@ -639,12 +703,13 @@
     visibility = ["//visibility:private"],
     deps = [
         ":strings",
-        "//absl/base:bits",
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/functional:function_ref",
         "//absl/meta:type_traits",
+        "//absl/numeric:bits",
         "//absl/numeric:int128",
+        "//absl/numeric:representation",
         "//absl/types:optional",
         "//absl/types:span",
     ],
diff --git a/grpc/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/strings/CMakeLists.txt
index d6c2126..3b7ae63 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/strings/CMakeLists.txt
@@ -21,6 +21,7 @@
     "ascii.h"
     "charconv.h"
     "escaping.h"
+    "internal/string_constant.h"
     "match.h"
     "numbers.h"
     "str_cat.h"
@@ -160,6 +161,19 @@
 
 absl_cc_test(
   NAME
+    string_constant_test
+  SRCS
+    "internal/string_constant_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::strings
+    absl::type_traits
+    gmock_main
+)
+
+absl_cc_test(
+  NAME
     string_view_test
   SRCS
     "string_view_test.cc"
@@ -396,6 +410,7 @@
     absl::strings
     absl::config
     absl::core_headers
+    absl::numeric_representation
     absl::type_traits
     absl::int128
     absl::span
@@ -542,13 +557,19 @@
     "cord.h"
   SRCS
     "cord.cc"
+    "internal/cord_internal.cc"
     "internal/cord_internal.h"
+    "internal/cord_rep_ring.h"
+    "internal/cord_rep_ring.cc"
+    "internal/cord_rep_ring_reader.h"
+    "internal/cord_rep_flat.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::base
     absl::base_internal
     absl::compressed_tuple
+    absl::config
     absl::core_headers
     absl::endian
     absl::fixed_array
@@ -558,6 +579,7 @@
     absl::raw_logging_internal
     absl::strings
     absl::strings_internal
+    absl::throw_delegate
     absl::type_traits
   PUBLIC
 )
@@ -593,3 +615,35 @@
     absl::fixed_array
     gmock_main
 )
+
+absl_cc_test(
+  NAME
+    cord_ring_test
+  SRCS
+    "cord_ring_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::config
+    absl::cord
+    absl::strings
+    absl::base
+    absl::core_headers
+    absl::raw_logging_internal
+    gmock_main
+)
+
+absl_cc_test(
+  NAME
+    cord_ring_reader_test
+  SRCS
+    "cord_ring_reader_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::cord
+    absl::strings
+    absl::base
+    absl::core_headers
+    gmock_main
+)
diff --git a/grpc/third_party/abseil-cpp/absl/strings/ascii_test.cc b/grpc/third_party/abseil-cpp/absl/strings/ascii_test.cc
index 5ecd23f..83af782 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/ascii_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/ascii_test.cc
@@ -197,11 +197,15 @@
   const std::string str("GHIJKL");
   const std::string str2("MNOPQR");
   const absl::string_view sp(str2);
+  std::string mutable_str("STUVWX");
 
   EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf));
   EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str));
   EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp));
 
+  absl::AsciiStrToLower(&mutable_str);
+  EXPECT_EQ("stuvwx", mutable_str);
+
   char mutable_buf[] = "Mutable";
   std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
                  mutable_buf, absl::ascii_tolower);
diff --git a/grpc/third_party/abseil-cpp/absl/strings/charconv.cc b/grpc/third_party/abseil-cpp/absl/strings/charconv.cc
index 3613a65..b8674c2 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/charconv.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/charconv.cc
@@ -20,7 +20,7 @@
 #include <cstring>
 
 #include "absl/base/casts.h"
-#include "absl/base/internal/bits.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/strings/internal/charconv_bigint.h"
 #include "absl/strings/internal/charconv_parse.h"
@@ -242,11 +242,11 @@
 
 // Returns the bit width of the given uint128.  (Equivalently, returns 128
 // minus the number of leading zero bits.)
-int BitWidth(uint128 value) {
+unsigned BitWidth(uint128 value) {
   if (Uint128High64(value) == 0) {
-    return 64 - base_internal::CountLeadingZeros64(Uint128Low64(value));
+    return static_cast<unsigned>(bit_width(Uint128Low64(value)));
   }
-  return 128 - base_internal::CountLeadingZeros64(Uint128High64(value));
+  return 128 - countl_zero(Uint128High64(value));
 }
 
 // Calculates how far to the right a mantissa needs to be shifted to create a
@@ -519,7 +519,7 @@
     const strings_internal::ParsedFloat& parsed_hex) {
   uint64_t mantissa = parsed_hex.mantissa;
   int exponent = parsed_hex.exponent;
-  int mantissa_width = 64 - base_internal::CountLeadingZeros64(mantissa);
+  auto mantissa_width = static_cast<unsigned>(bit_width(mantissa));
   const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent);
   bool result_exact;
   exponent += shift;
diff --git a/grpc/third_party/abseil-cpp/absl/strings/charconv_test.cc b/grpc/third_party/abseil-cpp/absl/strings/charconv_test.cc
index 9090e9c..b83de5a 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/charconv_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/charconv_test.cc
@@ -653,7 +653,9 @@
                      negative_from_chars_float);
     EXPECT_TRUE(std::signbit(negative_from_chars_float));
     EXPECT_FALSE(Identical(negative_from_chars_float, from_chars_float));
-    from_chars_float = std::copysign(from_chars_float, -1.0);
+    // Use the (float, float) overload of std::copysign to prevent narrowing;
+    // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98251.
+    from_chars_float = std::copysign(from_chars_float, -1.0f);
     EXPECT_TRUE(Identical(negative_from_chars_float, from_chars_float));
   }
 }
diff --git a/grpc/third_party/abseil-cpp/absl/strings/cord.cc b/grpc/third_party/abseil-cpp/absl/strings/cord.cc
index 763dcc4..9353375 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/cord.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/cord.cc
@@ -36,6 +36,8 @@
 #include "absl/container/inlined_vector.h"
 #include "absl/strings/escaping.h"
 #include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+#include "absl/strings/internal/cord_rep_ring.h"
 #include "absl/strings/internal/resize_uninitialized.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
@@ -48,98 +50,20 @@
 using ::absl::cord_internal::CordRep;
 using ::absl::cord_internal::CordRepConcat;
 using ::absl::cord_internal::CordRepExternal;
+using ::absl::cord_internal::CordRepFlat;
+using ::absl::cord_internal::CordRepRing;
 using ::absl::cord_internal::CordRepSubstring;
+using ::absl::cord_internal::kMinFlatLength;
+using ::absl::cord_internal::kMaxFlatLength;
 
-// Various representations that we allow
-enum CordRepKind {
-  CONCAT        = 0,
-  EXTERNAL      = 1,
-  SUBSTRING     = 2,
+using ::absl::cord_internal::CONCAT;
+using ::absl::cord_internal::EXTERNAL;
+using ::absl::cord_internal::FLAT;
+using ::absl::cord_internal::RING;
+using ::absl::cord_internal::SUBSTRING;
 
-  // We have different tags for different sized flat arrays,
-  // starting with FLAT
-  FLAT          = 3,
-};
-
-namespace cord_internal {
-
-inline CordRepConcat* CordRep::concat() {
-  assert(tag == CONCAT);
-  return static_cast<CordRepConcat*>(this);
-}
-
-inline const CordRepConcat* CordRep::concat() const {
-  assert(tag == CONCAT);
-  return static_cast<const CordRepConcat*>(this);
-}
-
-inline CordRepSubstring* CordRep::substring() {
-  assert(tag == SUBSTRING);
-  return static_cast<CordRepSubstring*>(this);
-}
-
-inline const CordRepSubstring* CordRep::substring() const {
-  assert(tag == SUBSTRING);
-  return static_cast<const CordRepSubstring*>(this);
-}
-
-inline CordRepExternal* CordRep::external() {
-  assert(tag == EXTERNAL);
-  return static_cast<CordRepExternal*>(this);
-}
-
-inline const CordRepExternal* CordRep::external() const {
-  assert(tag == EXTERNAL);
-  return static_cast<const CordRepExternal*>(this);
-}
-
-}  // namespace cord_internal
-
-static const size_t kFlatOverhead = offsetof(CordRep, data);
-
-// Largest and smallest flat node lengths we are willing to allocate
-// Flat allocation size is stored in tag, which currently can encode sizes up
-// to 4K, encoded as multiple of either 8 or 32 bytes.
-// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc.
-static constexpr size_t kMaxFlatSize = 4096;
-static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
-static constexpr size_t kMinFlatLength = 32 - kFlatOverhead;
-
-// Prefer copying blocks of at most this size, otherwise reference count.
-static const size_t kMaxBytesToCopy = 511;
-
-// Helper functions for rounded div, and rounding to exact sizes.
-static size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
-static size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
-
-// Returns the size to the nearest equal or larger value that can be
-// expressed exactly as a tag value.
-static size_t RoundUpForTag(size_t size) {
-  return RoundUp(size, (size <= 1024) ? 8 : 32);
-}
-
-// Converts the allocated size to a tag, rounding down if the size
-// does not exactly match a 'tag expressible' size value. The result is
-// undefined if the size exceeds the maximum size that can be encoded in
-// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
-static uint8_t AllocatedSizeToTag(size_t size) {
-  const size_t tag = (size <= 1024) ? size / 8 : 128 + size / 32 - 1024 / 32;
-  assert(tag <= std::numeric_limits<uint8_t>::max());
-  return tag;
-}
-
-// Converts the provided tag to the corresponding allocated size
-static constexpr size_t TagToAllocatedSize(uint8_t tag) {
-  return (tag <= 128) ? (tag * 8) : (1024 + (tag - 128) * 32);
-}
-
-// Converts the provided tag to the corresponding available data length
-static constexpr size_t TagToLength(uint8_t tag) {
-  return TagToAllocatedSize(tag) - kFlatOverhead;
-}
-
-// Enforce that kMaxFlatSize maps to a well-known exact tag value.
-static_assert(TagToAllocatedSize(224) == kMaxFlatSize, "Bad tag logic");
+using ::absl::cord_internal::kInlinedVectorSize;
+using ::absl::cord_internal::kMaxBytesToCopy;
 
 constexpr uint64_t Fibonacci(unsigned char n, uint64_t a = 0, uint64_t b = 1) {
   return n == 0 ? a : Fibonacci(n - 1, b, a + b);
@@ -171,16 +95,10 @@
 
 static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length);
 
-// The inlined size to use with absl::InlinedVector.
-//
-// Note: The InlinedVectors in this file (and in cord.h) do not need to use
-// the same value for their inlined size. The fact that they do is historical.
-// It may be desirable for each to use a different inlined size optimized for
-// that InlinedVector's usage.
-//
-// TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
-// the inlined vector size (47 exists for backward compatibility).
-static const int kInlinedVectorSize = 47;
+static inline bool cord_ring_enabled() {
+  return cord_internal::cord_ring_buffer_enabled.load(
+      std::memory_order_relaxed);
+}
 
 static inline bool IsRootBalanced(CordRep* node) {
   if (node->tag != CONCAT) {
@@ -197,7 +115,8 @@
 }
 
 static CordRep* Rebalance(CordRep* node);
-static void DumpNode(CordRep* rep, bool include_data, std::ostream* os);
+static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
+                     int indent = 0);
 static bool VerifyNode(CordRep* root, CordRep* start_node,
                        bool full_validation);
 
@@ -217,96 +136,6 @@
   return node;
 }
 
-// --------------------------------------------------------------------
-// Memory management
-
-inline CordRep* Ref(CordRep* rep) {
-  if (rep != nullptr) {
-    rep->refcount.Increment();
-  }
-  return rep;
-}
-
-// This internal routine is called from the cold path of Unref below. Keeping it
-// in a separate routine allows good inlining of Unref into many profitable call
-// sites. However, the call to this function can be highly disruptive to the
-// register pressure in those callers. To minimize the cost to callers, we use
-// a special LLVM calling convention that preserves most registers. This allows
-// the call to this routine in cold paths to not disrupt the caller's register
-// pressure. This calling convention is not available on all platforms; we
-// intentionally allow LLVM to ignore the attribute rather than attempting to
-// hardcode the list of supported platforms.
-#if defined(__clang__) && !defined(__i386__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wattributes"
-__attribute__((preserve_most))
-#pragma clang diagnostic pop
-#endif
-static void UnrefInternal(CordRep* rep) {
-  assert(rep != nullptr);
-
-  absl::InlinedVector<CordRep*, kInlinedVectorSize> pending;
-  while (true) {
-    if (rep->tag == CONCAT) {
-      CordRepConcat* rep_concat = rep->concat();
-      CordRep* right = rep_concat->right;
-      if (!right->refcount.Decrement()) {
-        pending.push_back(right);
-      }
-      CordRep* left = rep_concat->left;
-      delete rep_concat;
-      rep = nullptr;
-      if (!left->refcount.Decrement()) {
-        rep = left;
-        continue;
-      }
-    } else if (rep->tag == EXTERNAL) {
-      CordRepExternal* rep_external = rep->external();
-      rep_external->releaser_invoker(rep_external);
-      rep = nullptr;
-    } else if (rep->tag == SUBSTRING) {
-      CordRepSubstring* rep_substring = rep->substring();
-      CordRep* child = rep_substring->child;
-      delete rep_substring;
-      rep = nullptr;
-      if (!child->refcount.Decrement()) {
-        rep = child;
-        continue;
-      }
-    } else {
-      // Flat CordReps are allocated and constructed with raw ::operator new
-      // and placement new, and must be destructed and deallocated
-      // accordingly.
-#if defined(__cpp_sized_deallocation)
-      size_t size = TagToAllocatedSize(rep->tag);
-      rep->~CordRep();
-      ::operator delete(rep, size);
-#else
-      rep->~CordRep();
-      ::operator delete(rep);
-#endif
-      rep = nullptr;
-    }
-
-    if (!pending.empty()) {
-      rep = pending.back();
-      pending.pop_back();
-    } else {
-      break;
-    }
-  }
-}
-
-inline void Unref(CordRep* rep) {
-  // Fast-path for two common, hot cases: a null rep and a shared root.
-  if (ABSL_PREDICT_TRUE(rep == nullptr ||
-                        rep->refcount.DecrementExpectHighRefcount())) {
-    return;
-  }
-
-  UnrefInternal(rep);
-}
-
 // Return the depth of a node
 static int Depth(const CordRep* rep) {
   if (rep->tag == CONCAT) {
@@ -330,12 +159,14 @@
 // The returned node has a refcount of 1.
 static CordRep* RawConcat(CordRep* left, CordRep* right) {
   // Avoid making degenerate concat nodes (one child is empty)
-  if (left == nullptr || left->length == 0) {
-    Unref(left);
+  if (left == nullptr) return right;
+  if (right == nullptr) return left;
+  if (left->length == 0) {
+    CordRep::Unref(left);
     return right;
   }
-  if (right == nullptr || right->length == 0) {
-    Unref(right);
+  if (right->length == 0) {
+    CordRep::Unref(right);
     return left;
   }
 
@@ -374,20 +205,27 @@
   return reps[0];
 }
 
-// Create a new flat node.
-static CordRep* NewFlat(size_t length_hint) {
-  if (length_hint <= kMinFlatLength) {
-    length_hint = kMinFlatLength;
-  } else if (length_hint > kMaxFlatLength) {
-    length_hint = kMaxFlatLength;
-  }
+static CordRepFlat* CreateFlat(const char* data, size_t length,
+                            size_t alloc_hint) {
+  CordRepFlat* flat = CordRepFlat::New(length + alloc_hint);
+  flat->length = length;
+  memcpy(flat->Data(), data, length);
+  return flat;
+}
 
-  // Round size up so it matches a size we can exactly express in a tag.
-  const size_t size = RoundUpForTag(length_hint + kFlatOverhead);
-  void* const raw_rep = ::operator new(size);
-  CordRep* rep = new (raw_rep) CordRep();
-  rep->tag = AllocatedSizeToTag(size);
-  return VerifyTree(rep);
+// Creates a new flat or ringbuffer out of the specified array.
+// The returned node has a refcount of 1.
+static CordRep* RingNewTree(const char* data, size_t length,
+                            size_t alloc_hint) {
+  if (length <= kMaxFlatLength) {
+    return CreateFlat(data, length, alloc_hint);
+  }
+  CordRepFlat* flat = CreateFlat(data, kMaxFlatLength, 0);
+  data += kMaxFlatLength;
+  length -= kMaxFlatLength;
+  size_t extra = (length - 1) / kMaxFlatLength + 1;
+  auto* root = CordRepRing::Create(flat, extra);
+  return CordRepRing::Append(root, {data, length}, alloc_hint);
 }
 
 // Create a new tree out of the specified array.
@@ -396,13 +234,16 @@
                         size_t length,
                         size_t alloc_hint) {
   if (length == 0) return nullptr;
+  if (cord_ring_enabled()) {
+    return RingNewTree(data, length, alloc_hint);
+  }
   absl::FixedArray<CordRep*> reps((length - 1) / kMaxFlatLength + 1);
   size_t n = 0;
   do {
     const size_t len = std::min(length, kMaxFlatLength);
-    CordRep* rep = NewFlat(len + alloc_hint);
+    CordRepFlat* rep = CordRepFlat::New(len + alloc_hint);
     rep->length = len;
-    memcpy(rep->data, data, len);
+    memcpy(rep->Data(), data, len);
     reps[n++] = VerifyTree(rep);
     data += len;
     length -= len;
@@ -425,7 +266,7 @@
 static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) {
   // Never create empty substring nodes
   if (length == 0) {
-    Unref(child);
+    CordRep::Unref(child);
     return nullptr;
   } else {
     CordRepSubstring* rep = new CordRepSubstring();
@@ -447,50 +288,58 @@
                                       bool nullify_tail) {
   static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15");
 
-  cord_internal::SmallMemmove(data_, data, n, nullify_tail);
-  data_[kMaxInline] = static_cast<char>(n);
+  cord_internal::SmallMemmove(data_.as_chars(), data, n, nullify_tail);
+  set_inline_size(n);
 }
 
 inline char* Cord::InlineRep::set_data(size_t n) {
   assert(n <= kMaxInline);
-  memset(data_, 0, sizeof(data_));
-  data_[kMaxInline] = static_cast<char>(n);
-  return data_;
+  ResetToEmpty();
+  set_inline_size(n);
+  return data_.as_chars();
 }
 
 inline CordRep* Cord::InlineRep::force_tree(size_t extra_hint) {
-  size_t len = data_[kMaxInline];
-  CordRep* result;
-  if (len > kMaxInline) {
-    memcpy(&result, data_, sizeof(result));
-  } else {
-    result = NewFlat(len + extra_hint);
-    result->length = len;
-    memcpy(result->data, data_, len);
-    set_tree(result);
+  if (data_.is_tree()) {
+    return data_.as_tree();
   }
+
+  size_t len = inline_size();
+  CordRepFlat* result = CordRepFlat::New(len + extra_hint);
+  result->length = len;
+  static_assert(kMinFlatLength >= sizeof(data_), "");
+  memcpy(result->Data(), data_.as_chars(), sizeof(data_));
+  set_tree(result);
   return result;
 }
 
 inline void Cord::InlineRep::reduce_size(size_t n) {
-  size_t tag = data_[kMaxInline];
+  size_t tag = inline_size();
   assert(tag <= kMaxInline);
   assert(tag >= n);
   tag -= n;
-  memset(data_ + tag, 0, n);
-  data_[kMaxInline] = static_cast<char>(tag);
+  memset(data_.as_chars() + tag, 0, n);
+  set_inline_size(static_cast<char>(tag));
 }
 
 inline void Cord::InlineRep::remove_prefix(size_t n) {
-  cord_internal::SmallMemmove(data_, data_ + n, data_[kMaxInline] - n);
+  cord_internal::SmallMemmove(data_.as_chars(), data_.as_chars() + n,
+                              inline_size() - n);
   reduce_size(n);
 }
 
+// Returns `rep` converted into a CordRepRing.
+// Directly returns `rep` if `rep` is already a CordRepRing.
+static CordRepRing* ForceRing(CordRep* rep, size_t extra) {
+  return (rep->tag == RING) ? rep->ring() : CordRepRing::Create(rep, extra);
+}
+
 void Cord::InlineRep::AppendTree(CordRep* tree) {
   if (tree == nullptr) return;
-  size_t len = data_[kMaxInline];
-  if (len == 0) {
+  if (data_.is_empty()) {
     set_tree(tree);
+  } else if (cord_ring_enabled()) {
+    set_tree(CordRepRing::Append(ForceRing(force_tree(0), 1), tree));
   } else {
     set_tree(Concat(force_tree(0), tree));
   }
@@ -498,9 +347,10 @@
 
 void Cord::InlineRep::PrependTree(CordRep* tree) {
   assert(tree != nullptr);
-  size_t len = data_[kMaxInline];
-  if (len == 0) {
+  if (data_.is_empty()) {
     set_tree(tree);
+  } else if (cord_ring_enabled()) {
+    set_tree(CordRepRing::Prepend(ForceRing(force_tree(0), 1), tree));
   } else {
     set_tree(Concat(tree, force_tree(0)));
   }
@@ -512,6 +362,15 @@
 // written to region and the actual size increase will be written to size.
 static inline bool PrepareAppendRegion(CordRep* root, char** region,
                                        size_t* size, size_t max_length) {
+  if (root->tag == RING && root->refcount.IsOne()) {
+    Span<char> span = root->ring()->GetAppendBuffer(max_length);
+    if (!span.empty()) {
+      *region = span.data();
+      *size = span.size();
+      return true;
+    }
+  }
+
   // Search down the right-hand path for a non-full FLAT node.
   CordRep* dst = root;
   while (dst->tag == CONCAT && dst->refcount.IsOne()) {
@@ -525,7 +384,7 @@
   }
 
   const size_t in_use = dst->length;
-  const size_t capacity = TagToLength(dst->tag);
+  const size_t capacity = dst->flat()->Capacity();
   if (in_use == capacity) {
     *region = nullptr;
     *size = 0;
@@ -540,7 +399,7 @@
   }
   dst->length += size_increase;
 
-  *region = dst->data + in_use;
+  *region = dst->flat()->Data() + in_use;
   *size = size_increase;
   return true;
 }
@@ -554,12 +413,14 @@
   }
 
   // Try to fit in the inline buffer if possible.
-  size_t inline_length = data_[kMaxInline];
-  if (inline_length < kMaxInline && max_length <= kMaxInline - inline_length) {
-    *region = data_ + inline_length;
-    *size = max_length;
-    data_[kMaxInline] = static_cast<char>(inline_length + max_length);
-    return;
+  if (!is_tree()) {
+    size_t inline_length = inline_size();
+    if (max_length <= kMaxInline - inline_length) {
+      *region = data_.as_chars() + inline_length;
+      *size = max_length;
+      set_inline_size(inline_length + max_length);
+      return;
+    }
   }
 
   CordRep* root = force_tree(max_length);
@@ -569,12 +430,16 @@
   }
 
   // Allocate new node.
-  CordRep* new_node =
-      NewFlat(std::max(static_cast<size_t>(root->length), max_length));
-  new_node->length =
-      std::min(static_cast<size_t>(TagToLength(new_node->tag)), max_length);
-  *region = new_node->data;
+  CordRepFlat* new_node =
+      CordRepFlat::New(std::max(static_cast<size_t>(root->length), max_length));
+  new_node->length = std::min(new_node->Capacity(), max_length);
+  *region = new_node->Data();
   *size = new_node->length;
+
+  if (cord_ring_enabled()) {
+    replace_tree(CordRepRing::Append(ForceRing(root, 1), new_node));
+    return;
+  }
   replace_tree(Concat(root, new_node));
 }
 
@@ -582,12 +447,14 @@
   const size_t max_length = std::numeric_limits<size_t>::max();
 
   // Try to fit in the inline buffer if possible.
-  size_t inline_length = data_[kMaxInline];
-  if (inline_length < kMaxInline) {
-    *region = data_ + inline_length;
-    *size = kMaxInline - inline_length;
-    data_[kMaxInline] = kMaxInline;
-    return;
+  if (!data_.is_tree()) {
+    size_t inline_length = inline_size();
+    if (inline_length < kMaxInline) {
+      *region = data_.as_chars() + inline_length;
+      *size = kMaxInline - inline_length;
+      set_inline_size(kMaxInline);
+      return;
+    }
   }
 
   CordRep* root = force_tree(max_length);
@@ -597,10 +464,15 @@
   }
 
   // Allocate new node.
-  CordRep* new_node = NewFlat(root->length);
-  new_node->length = TagToLength(new_node->tag);
-  *region = new_node->data;
+  CordRepFlat* new_node = CordRepFlat::New(root->length);
+  new_node->length = new_node->Capacity();
+  *region = new_node->Data();
   *size = new_node->length;
+
+  if (cord_ring_enabled()) {
+    replace_tree(CordRepRing::Append(ForceRing(root, 1), new_node));
+    return;
+  }
   replace_tree(Concat(root, new_node));
 }
 
@@ -608,7 +480,7 @@
 // will return true.
 static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) {
   if (rep->tag >= FLAT) {
-    *total_mem_usage += TagToAllocatedSize(rep->tag);
+    *total_mem_usage += rep->flat()->AllocatedSize();
     return true;
   }
   if (rep->tag == EXTERNAL) {
@@ -621,26 +493,24 @@
 void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) {
   ClearSlow();
 
-  memcpy(data_, src.data_, sizeof(data_));
+  data_ = src.data_;
   if (is_tree()) {
-    Ref(tree());
+    data_.set_profiled(false);
+    CordRep::Ref(tree());
+    clear_cordz_info();
   }
 }
 
 void Cord::InlineRep::ClearSlow() {
   if (is_tree()) {
-    Unref(tree());
+    CordRep::Unref(tree());
   }
-  memset(data_, 0, sizeof(data_));
+  ResetToEmpty();
 }
 
 // --------------------------------------------------------------------
 // Constructors and destructors
 
-Cord::Cord(const Cord& src) : contents_(src.contents_) {
-  Ref(contents_.tree());  // Does nothing if contents_ has embedded data
-}
-
 Cord::Cord(absl::string_view src) {
   const size_t n = src.size();
   if (n <= InlineRep::kMaxInline) {
@@ -684,14 +554,18 @@
 // The destruction code is separate so that the compiler can determine
 // that it does not need to call the destructor on a moved-from Cord.
 void Cord::DestroyCordSlow() {
-  Unref(VerifyTree(contents_.tree()));
+  if (CordRep* tree = contents_.tree()) {
+    CordRep::Unref(VerifyTree(tree));
+  }
 }
 
 // --------------------------------------------------------------------
 // Mutators
 
 void Cord::Clear() {
-  Unref(contents_.clear());
+  if (CordRep* tree = contents_.clear()) {
+    CordRep::Unref(tree);
+  }
 }
 
 Cord& Cord::operator=(absl::string_view src) {
@@ -702,19 +576,20 @@
   if (length <= InlineRep::kMaxInline) {
     // Embed into this->contents_
     contents_.set_data(data, length, true);
-    Unref(tree);
+    if (tree) CordRep::Unref(tree);
     return *this;
   }
   if (tree != nullptr && tree->tag >= FLAT &&
-      TagToLength(tree->tag) >= length && tree->refcount.IsOne()) {
+      tree->flat()->Capacity() >= length &&
+      tree->refcount.IsOne()) {
     // Copy in place if the existing FLAT node is reusable.
-    memmove(tree->data, data, length);
+    memmove(tree->flat()->Data(), data, length);
     tree->length = length;
     VerifyTree(tree);
     return *this;
   }
   contents_.set_tree(NewTree(data, length, 0));
-  Unref(tree);
+  if (tree) CordRep::Unref(tree);
   return *this;
 }
 
@@ -734,24 +609,25 @@
 // we keep it here to make diffs easier.
 void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) {
   if (src_size == 0) return;  // memcpy(_, nullptr, 0) is undefined.
-  // Try to fit in the inline buffer if possible.
-  size_t inline_length = data_[kMaxInline];
-  if (inline_length < kMaxInline && src_size <= kMaxInline - inline_length) {
-    // Append new data to embedded array
-    data_[kMaxInline] = static_cast<char>(inline_length + src_size);
-    memcpy(data_ + inline_length, src_data, src_size);
-    return;
-  }
-
-  CordRep* root = tree();
 
   size_t appended = 0;
-  if (root) {
+  CordRep* root = nullptr;
+  if (is_tree()) {
+    root = data_.as_tree();
     char* region;
     if (PrepareAppendRegion(root, &region, &appended, src_size)) {
       memcpy(region, src_data, appended);
     }
   } else {
+    // Try to fit in the inline buffer if possible.
+    size_t inline_length = inline_size();
+    if (src_size <= kMaxInline - inline_length) {
+      // Append new data to embedded array
+      memcpy(data_.as_chars() + inline_length, src_data, src_size);
+      set_inline_size(inline_length + src_size);
+      return;
+    }
+
     // It is possible that src_data == data_, but when we transition from an
     // InlineRep to a tree we need to assign data_ = root via set_tree. To
     // avoid corrupting the source data before we copy it, delay calling
@@ -760,10 +636,11 @@
     // either double the inlined size, or the added size + 10%.
     const size_t size1 = inline_length * 2 + src_size;
     const size_t size2 = inline_length + src_size / 10;
-    root = NewFlat(std::max<size_t>(size1, size2));
-    appended = std::min(src_size, TagToLength(root->tag) - inline_length);
-    memcpy(root->data, data_, inline_length);
-    memcpy(root->data + inline_length, src_data, appended);
+    root = CordRepFlat::New(std::max<size_t>(size1, size2));
+    appended = std::min(
+        src_size, root->flat()->Capacity() - inline_length);
+    memcpy(root->flat()->Data(), data_.as_chars(), inline_length);
+    memcpy(root->flat()->Data() + inline_length, src_data, appended);
     root->length = inline_length + appended;
     set_tree(root);
   }
@@ -774,6 +651,13 @@
     return;
   }
 
+  if (cord_ring_enabled()) {
+    absl::string_view data(src_data, src_size);
+    root = ForceRing(root, (data.size() - 1) / kMaxFlatLength + 1);
+    replace_tree(CordRepRing::Append(root->ring(), data));
+    return;
+  }
+
   // Use new block(s) for any remaining bytes that were not handled above.
   // Alloc extra memory only if the right child of the root of the new tree is
   // going to be a FLAT node, which will permit further inplace appends.
@@ -790,7 +674,7 @@
 }
 
 inline CordRep* Cord::TakeRep() const& {
-  return Ref(contents_.tree());
+  return CordRep::Ref(contents_.tree());
 }
 
 inline CordRep* Cord::TakeRep() && {
@@ -819,7 +703,7 @@
     }
     if (src_tree->tag >= FLAT) {
       // src tree just has one flat node.
-      contents_.AppendArray(src_tree->data, src_size);
+      contents_.AppendArray(src_tree->flat()->Data(), src_size);
       return;
     }
     if (&src == this) {
@@ -834,6 +718,7 @@
     return;
   }
 
+  // Guaranteed to be a tree (kMaxBytesToCopy > kInlinedSize)
   contents_.AppendTree(std::forward<C>(src).TakeRep());
 }
 
@@ -855,7 +740,7 @@
 void Cord::Prepend(const Cord& src) {
   CordRep* src_tree = src.contents_.tree();
   if (src_tree != nullptr) {
-    Ref(src_tree);
+    CordRep::Ref(src_tree);
     contents_.PrependTree(src_tree);
     return;
   }
@@ -867,18 +752,19 @@
 
 void Cord::Prepend(absl::string_view src) {
   if (src.empty()) return;  // memcpy(_, nullptr, 0) is undefined.
-  size_t cur_size = contents_.size();
-  if (!contents_.is_tree() && cur_size + src.size() <= InlineRep::kMaxInline) {
-    // Use embedded storage.
-    char data[InlineRep::kMaxInline + 1] = {0};
-    data[InlineRep::kMaxInline] = cur_size + src.size();  // set size
-    memcpy(data, src.data(), src.size());
-    memcpy(data + src.size(), contents_.data(), cur_size);
-    memcpy(reinterpret_cast<void*>(&contents_), data,
-           InlineRep::kMaxInline + 1);
-  } else {
-    contents_.PrependTree(NewTree(src.data(), src.size(), 0));
+  if (!contents_.is_tree()) {
+    size_t cur_size = contents_.inline_size();
+    if (cur_size + src.size() <= InlineRep::kMaxInline) {
+      // Use embedded storage.
+      char data[InlineRep::kMaxInline + 1] = {0};
+      memcpy(data, src.data(), src.size());
+      memcpy(data + src.size(), contents_.data(), cur_size);
+      memcpy(contents_.data_.as_chars(), data, InlineRep::kMaxInline + 1);
+      contents_.set_inline_size(cur_size + src.size());
+      return;
+    }
   }
+  contents_.PrependTree(NewTree(src.data(), src.size(), 0));
 }
 
 template <typename T, Cord::EnableIfString<T>>
@@ -894,7 +780,7 @@
 
 static CordRep* RemovePrefixFrom(CordRep* node, size_t n) {
   if (n >= node->length) return nullptr;
-  if (n == 0) return Ref(node);
+  if (n == 0) return CordRep::Ref(node);
   absl::InlinedVector<CordRep*, kInlinedVectorSize> rhs_stack;
 
   while (node->tag == CONCAT) {
@@ -912,7 +798,7 @@
   assert(n <= node->length);
 
   if (n == 0) {
-    Ref(node);
+    CordRep::Ref(node);
   } else {
     size_t start = n;
     size_t len = node->length - n;
@@ -921,10 +807,10 @@
       start += node->substring()->start;
       node = node->substring()->child;
     }
-    node = NewSubstring(Ref(node), start, len);
+    node = NewSubstring(CordRep::Ref(node), start, len);
   }
   while (!rhs_stack.empty()) {
-    node = Concat(node, Ref(rhs_stack.back()));
+    node = Concat(node, CordRep::Ref(rhs_stack.back()));
     rhs_stack.pop_back();
   }
   return node;
@@ -935,7 +821,7 @@
 // edited in place iff that node and all its ancestors have a refcount of 1.
 static CordRep* RemoveSuffixFrom(CordRep* node, size_t n) {
   if (n >= node->length) return nullptr;
-  if (n == 0) return Ref(node);
+  if (n == 0) return CordRep::Ref(node);
   absl::InlinedVector<CordRep*, kInlinedVectorSize> lhs_stack;
   bool inplace_ok = node->refcount.IsOne();
 
@@ -955,11 +841,11 @@
   assert(n <= node->length);
 
   if (n == 0) {
-    Ref(node);
+    CordRep::Ref(node);
   } else if (inplace_ok && node->tag != EXTERNAL) {
     // Consider making a new buffer if the current node capacity is much
     // larger than the new length.
-    Ref(node);
+    CordRep::Ref(node);
     node->length -= n;
   } else {
     size_t start = 0;
@@ -968,10 +854,10 @@
       start = node->substring()->start;
       node = node->substring()->child;
     }
-    node = NewSubstring(Ref(node), start, len);
+    node = NewSubstring(CordRep::Ref(node), start, len);
   }
   while (!lhs_stack.empty()) {
-    node = Concat(Ref(lhs_stack.back()), node);
+    node = Concat(CordRep::Ref(lhs_stack.back()), node);
     lhs_stack.pop_back();
   }
   return node;
@@ -984,9 +870,11 @@
   CordRep* tree = contents_.tree();
   if (tree == nullptr) {
     contents_.remove_prefix(n);
+  } else if (tree->tag == RING) {
+    contents_.replace_tree(CordRepRing::RemovePrefix(tree->ring(), n));
   } else {
     CordRep* newrep = RemovePrefixFrom(tree, n);
-    Unref(tree);
+    CordRep::Unref(tree);
     contents_.replace_tree(VerifyTree(newrep));
   }
 }
@@ -998,9 +886,11 @@
   CordRep* tree = contents_.tree();
   if (tree == nullptr) {
     contents_.reduce_size(n);
+  } else if (tree->tag == RING) {
+    contents_.replace_tree(CordRepRing::RemoveSuffix(tree->ring(), n));
   } else {
     CordRep* newrep = RemoveSuffixFrom(tree, n);
-    Unref(tree);
+    CordRep::Unref(tree);
     contents_.replace_tree(VerifyTree(newrep));
   }
 }
@@ -1033,13 +923,13 @@
       results.pop_back();
       results.push_back(Concat(left, right));
     } else if (pos == 0 && n == node->length) {
-      results.push_back(Ref(node));
+      results.push_back(CordRep::Ref(node));
     } else if (node->tag != CONCAT) {
       if (node->tag == SUBSTRING) {
         pos += node->substring()->start;
         node = node->substring()->child;
       }
-      results.push_back(NewSubstring(Ref(node), pos, n));
+      results.push_back(NewSubstring(CordRep::Ref(node), pos, n));
     } else if (pos + n <= node->concat()->left->length) {
       todo.push_back(SubRange(node->concat()->left, pos, n));
     } else if (pos >= node->concat()->left->length) {
@@ -1071,7 +961,7 @@
   } else if (new_size <= InlineRep::kMaxInline) {
     Cord::ChunkIterator it = chunk_begin();
     it.AdvanceBytes(pos);
-    char* dest = sub_cord.contents_.data_;
+    char* dest = sub_cord.contents_.data_.as_chars();
     size_t remaining_size = new_size;
     while (remaining_size > it->size()) {
       cord_internal::SmallMemmove(dest, it->data(), it->size());
@@ -1080,7 +970,10 @@
       ++it;
     }
     cord_internal::SmallMemmove(dest, it->data(), remaining_size);
-    sub_cord.contents_.data_[InlineRep::kMaxInline] = new_size;
+    sub_cord.contents_.set_inline_size(new_size);
+  } else if (tree->tag == RING) {
+    tree = CordRepRing::SubRing(CordRep::Ref(tree)->ring(), pos, new_size);
+    sub_cord.contents_.set_tree(tree);
   } else {
     sub_cord.contents_.set_tree(NewSubRange(tree, pos, new_size));
   }
@@ -1117,9 +1010,9 @@
           concat_node->left = concat_freelist_;
           concat_freelist_ = concat_node;
         } else {
-          Ref(concat_node->right);
-          Ref(concat_node->left);
-          Unref(concat_node);
+          CordRep::Ref(concat_node->right);
+          CordRep::Ref(concat_node->left);
+          CordRep::Unref(concat_node);
         }
       } else {
         AddNode(node);
@@ -1269,20 +1162,23 @@
 // Helper routine. Locates the first flat chunk of the Cord without
 // initializing the iterator.
 inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const {
-  size_t n = data_[kMaxInline];
-  if (n <= kMaxInline) {
-    return absl::string_view(data_, n);
+  if (!is_tree()) {
+    return absl::string_view(data_.as_chars(), data_.inline_size());
   }
 
   CordRep* node = tree();
   if (node->tag >= FLAT) {
-    return absl::string_view(node->data, node->length);
+    return absl::string_view(node->flat()->Data(), node->length);
   }
 
   if (node->tag == EXTERNAL) {
     return absl::string_view(node->external()->base, node->length);
   }
 
+  if (node->tag == RING) {
+    return node->ring()->entry_data(node->ring()->head());
+  }
+
   // Walk down the left branches until we hit a non-CONCAT node.
   while (node->tag == CONCAT) {
     node = node->concat()->left;
@@ -1299,7 +1195,7 @@
   }
 
   if (node->tag >= FLAT) {
-    return absl::string_view(node->data + offset, length);
+    return absl::string_view(node->flat()->Data() + offset, length);
   }
 
   assert((node->tag == EXTERNAL) && "Expect FLAT or EXTERNAL node here");
@@ -1482,26 +1378,22 @@
   }
 }
 
-Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
-  ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 &&
-                        "Attempted to iterate past `end()`");
-  assert(bytes_remaining_ >= current_chunk_.size());
-  bytes_remaining_ -= current_chunk_.size();
-
-  if (stack_of_right_children_.empty()) {
+Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() {
+  auto& stack_of_right_children = stack_of_right_children_;
+  if (stack_of_right_children.empty()) {
     assert(!current_chunk_.empty());  // Called on invalid iterator.
     // We have reached the end of the Cord.
     return *this;
   }
 
   // Process the next node on the stack.
-  CordRep* node = stack_of_right_children_.back();
-  stack_of_right_children_.pop_back();
+  CordRep* node = stack_of_right_children.back();
+  stack_of_right_children.pop_back();
 
   // Walk down the left branches until we hit a non-CONCAT node. Save the
   // right children to the stack for subsequent traversal.
   while (node->tag == CONCAT) {
-    stack_of_right_children_.push_back(node->concat()->right);
+    stack_of_right_children.push_back(node->concat()->right);
     node = node->concat()->left;
   }
 
@@ -1516,7 +1408,7 @@
   assert(node->tag == EXTERNAL || node->tag >= FLAT);
   assert(length != 0);
   const char* data =
-      node->tag == EXTERNAL ? node->external()->base : node->data;
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
   current_chunk_ = absl::string_view(data + offset, length);
   current_leaf_ = node;
   return *this;
@@ -1544,12 +1436,32 @@
     }
     return subcord;
   }
+
+  if (ring_reader_) {
+    size_t chunk_size = current_chunk_.size();
+    if (n <= chunk_size && n <= kMaxBytesToCopy) {
+      subcord = Cord(current_chunk_.substr(0, n));
+    } else {
+      auto* ring = CordRep::Ref(ring_reader_.ring())->ring();
+      size_t offset = ring_reader_.length() - bytes_remaining_;
+      subcord.contents_.set_tree(CordRepRing::SubRing(ring, offset, n));
+    }
+    if (n < chunk_size) {
+      bytes_remaining_ -= n;
+      current_chunk_.remove_prefix(n);
+    } else {
+      AdvanceBytesRing(n);
+    }
+    return subcord;
+  }
+
+  auto& stack_of_right_children = stack_of_right_children_;
   if (n < current_chunk_.size()) {
     // Range to read is a proper subrange of the current chunk.
     assert(current_leaf_ != nullptr);
-    CordRep* subnode = Ref(current_leaf_);
-    const char* data =
-        subnode->tag == EXTERNAL ? subnode->external()->base : subnode->data;
+    CordRep* subnode = CordRep::Ref(current_leaf_);
+    const char* data = subnode->tag == EXTERNAL ? subnode->external()->base
+                                                : subnode->flat()->Data();
     subnode = NewSubstring(subnode, current_chunk_.data() - data, n);
     subcord.contents_.set_tree(VerifyTree(subnode));
     RemoveChunkPrefix(n);
@@ -1559,10 +1471,10 @@
   // Range to read begins with a proper subrange of the current chunk.
   assert(!current_chunk_.empty());
   assert(current_leaf_ != nullptr);
-  CordRep* subnode = Ref(current_leaf_);
+  CordRep* subnode = CordRep::Ref(current_leaf_);
   if (current_chunk_.size() < subnode->length) {
-    const char* data =
-        subnode->tag == EXTERNAL ? subnode->external()->base : subnode->data;
+    const char* data = subnode->tag == EXTERNAL ? subnode->external()->base
+                                                : subnode->flat()->Data();
     subnode = NewSubstring(subnode, current_chunk_.data() - data,
                            current_chunk_.size());
   }
@@ -1572,20 +1484,20 @@
   // Process the next node(s) on the stack, reading whole subtrees depending on
   // their length and how many bytes we are advancing.
   CordRep* node = nullptr;
-  while (!stack_of_right_children_.empty()) {
-    node = stack_of_right_children_.back();
-    stack_of_right_children_.pop_back();
+  while (!stack_of_right_children.empty()) {
+    node = stack_of_right_children.back();
+    stack_of_right_children.pop_back();
     if (node->length > n) break;
     // TODO(qrczak): This might unnecessarily recreate existing concat nodes.
     // Avoiding that would need pretty complicated logic (instead of
-    // current_leaf_, keep current_subtree_ which points to the highest node
+    // current_leaf, keep current_subtree_ which points to the highest node
     // such that the current leaf can be found on the path of left children
     // starting from current_subtree_; delay creating subnode while node is
     // below current_subtree_; find the proper node along the path of left
     // children starting from current_subtree_ if this loop exits while staying
     // below current_subtree_; etc.; alternatively, push parents instead of
     // right children on the stack).
-    subnode = Concat(subnode, Ref(node));
+    subnode = Concat(subnode, CordRep::Ref(node));
     n -= node->length;
     bytes_remaining_ -= node->length;
     node = nullptr;
@@ -1603,11 +1515,11 @@
   while (node->tag == CONCAT) {
     if (node->concat()->left->length > n) {
       // Push right, descend left.
-      stack_of_right_children_.push_back(node->concat()->right);
+      stack_of_right_children.push_back(node->concat()->right);
       node = node->concat()->left;
     } else {
       // Read left, descend right.
-      subnode = Concat(subnode, Ref(node->concat()->left));
+      subnode = Concat(subnode, CordRep::Ref(node->concat()->left));
       n -= node->concat()->left->length;
       bytes_remaining_ -= node->concat()->left->length;
       node = node->concat()->right;
@@ -1626,9 +1538,11 @@
   // chunk.
   assert(node->tag == EXTERNAL || node->tag >= FLAT);
   assert(length > n);
-  if (n > 0) subnode = Concat(subnode, NewSubstring(Ref(node), offset, n));
+  if (n > 0) {
+    subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n));
+  }
   const char* data =
-      node->tag == EXTERNAL ? node->external()->base : node->data;
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
   current_chunk_ = absl::string_view(data + offset + n, length - n);
   current_leaf_ = node;
   bytes_remaining_ -= n;
@@ -1644,12 +1558,19 @@
   n -= current_chunk_.size();
   bytes_remaining_ -= current_chunk_.size();
 
+  if (stack_of_right_children_.empty()) {
+    // We have reached the end of the Cord.
+    assert(bytes_remaining_ == 0);
+    return;
+  }
+
   // Process the next node(s) on the stack, skipping whole subtrees depending on
   // their length and how many bytes we are advancing.
   CordRep* node = nullptr;
-  while (!stack_of_right_children_.empty()) {
-    node = stack_of_right_children_.back();
-    stack_of_right_children_.pop_back();
+  auto& stack_of_right_children = stack_of_right_children_;
+  while (!stack_of_right_children.empty()) {
+    node = stack_of_right_children.back();
+    stack_of_right_children.pop_back();
     if (node->length > n) break;
     n -= node->length;
     bytes_remaining_ -= node->length;
@@ -1667,7 +1588,7 @@
   while (node->tag == CONCAT) {
     if (node->concat()->left->length > n) {
       // Push right, descend left.
-      stack_of_right_children_.push_back(node->concat()->right);
+      stack_of_right_children.push_back(node->concat()->right);
       node = node->concat()->left;
     } else {
       // Skip left, descend right.
@@ -1688,7 +1609,7 @@
   assert(node->tag == EXTERNAL || node->tag >= FLAT);
   assert(length > n);
   const char* data =
-      node->tag == EXTERNAL ? node->external()->base : node->data;
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
   current_chunk_ = absl::string_view(data + offset + n, length - n);
   current_leaf_ = node;
   bytes_remaining_ -= n;
@@ -1706,7 +1627,9 @@
     assert(offset < rep->length);
     if (rep->tag >= FLAT) {
       // Get the "i"th character directly from the flat array.
-      return rep->data[offset];
+      return rep->flat()->Data()[offset];
+    } else if (rep->tag == RING) {
+      return rep->ring()->GetCharacter(offset);
     } else if (rep->tag == EXTERNAL) {
       // Get the "i"th character from the external array.
       return rep->external()->base[offset];
@@ -1737,9 +1660,9 @@
   // Try to put the contents into a new flat rep. If they won't fit in the
   // biggest possible flat node, use an external rep instead.
   if (total_size <= kMaxFlatLength) {
-    new_rep = NewFlat(total_size);
+    new_rep = CordRepFlat::New(total_size);
     new_rep->length = total_size;
-    new_buffer = new_rep->data;
+    new_buffer = new_rep->flat()->Data();
     CopyToArraySlowPath(new_buffer);
   } else {
     new_buffer = std::allocator<char>().allocate(total_size);
@@ -1750,7 +1673,9 @@
                                             s.size());
         });
   }
-  Unref(contents_.tree());
+  if (CordRep* tree = contents_.tree()) {
+    CordRep::Unref(tree);
+  }
   contents_.set_tree(new_rep);
   return absl::string_view(new_buffer, total_size);
 }
@@ -1758,7 +1683,7 @@
 /* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) {
   assert(rep != nullptr);
   if (rep->tag >= FLAT) {
-    *fragment = absl::string_view(rep->data, rep->length);
+    *fragment = absl::string_view(rep->flat()->Data(), rep->length);
     return true;
   } else if (rep->tag == EXTERNAL) {
     *fragment = absl::string_view(rep->external()->base, rep->length);
@@ -1766,8 +1691,8 @@
   } else if (rep->tag == SUBSTRING) {
     CordRep* child = rep->substring()->child;
     if (child->tag >= FLAT) {
-      *fragment =
-          absl::string_view(child->data + rep->substring()->start, rep->length);
+      *fragment = absl::string_view(
+          child->flat()->Data() + rep->substring()->start, rep->length);
       return true;
     } else if (child->tag == EXTERNAL) {
       *fragment = absl::string_view(
@@ -1781,6 +1706,15 @@
 /* static */ void Cord::ForEachChunkAux(
     absl::cord_internal::CordRep* rep,
     absl::FunctionRef<void(absl::string_view)> callback) {
+  if (rep->tag == RING) {
+    ChunkIterator it(rep), end;
+    while (it != end) {
+      callback(*it);
+      ++it;
+    }
+    return;
+  }
+
   assert(rep != nullptr);
   int stack_pos = 0;
   constexpr int stack_max = 128;
@@ -1822,9 +1756,9 @@
   }
 }
 
-static void DumpNode(CordRep* rep, bool include_data, std::ostream* os) {
+static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
+                     int indent) {
   const int kIndentStep = 1;
-  int indent = 0;
   absl::InlinedVector<CordRep*, kInlinedVectorSize> stack;
   absl::InlinedVector<int, kInlinedVectorSize> indents;
   for (;;) {
@@ -1845,17 +1779,28 @@
       *os << "SUBSTRING @ " << rep->substring()->start << "\n";
       indent += kIndentStep;
       rep = rep->substring()->child;
-    } else {  // Leaf
+    } else {  // Leaf or ring
       if (rep->tag == EXTERNAL) {
         *os << "EXTERNAL [";
         if (include_data)
           *os << absl::CEscape(std::string(rep->external()->base, rep->length));
         *os << "]\n";
-      } else {
-        *os << "FLAT cap=" << TagToLength(rep->tag) << " [";
+      } else if (rep->tag >= FLAT) {
+        *os << "FLAT cap=" << rep->flat()->Capacity()
+            << " [";
         if (include_data)
-          *os << absl::CEscape(std::string(rep->data, rep->length));
+          *os << absl::CEscape(std::string(rep->flat()->Data(), rep->length));
         *os << "]\n";
+      } else {
+        assert(rep->tag == RING);
+        auto* ring = rep->ring();
+        *os << "RING, entries = " << ring->entries() << "\n";
+        CordRepRing::index_type head = ring->head();
+        do {
+          DumpNode(ring->entry_child(head), include_data, os,
+                   indent + kIndentStep);
+          head = ring->advance(head);;
+        } while (head != ring->tail());
       }
       if (stack.empty()) break;
       rep = stack.back();
@@ -1900,8 +1845,9 @@
         worklist.push_back(node->concat()->left);
       }
     } else if (node->tag >= FLAT) {
-      ABSL_INTERNAL_CHECK(node->length <= TagToLength(node->tag),
-                          ReportError(root, node));
+      ABSL_INTERNAL_CHECK(
+          node->length <= node->flat()->Capacity(),
+          ReportError(root, node));
     } else if (node->tag == EXTERNAL) {
       ABSL_INTERNAL_CHECK(node->external()->base != nullptr,
                           ReportError(root, node));
@@ -1948,6 +1894,15 @@
         }
         next_node = right;
       }
+    } else if (cur_node->tag == RING) {
+      total_mem_usage += CordRepRing::AllocSize(cur_node->ring()->capacity());
+      const CordRepRing* ring = cur_node->ring();
+      CordRepRing::index_type pos = ring->head(), tail = ring->tail();
+      do {
+        CordRep* node = ring->entry_child(pos);
+        assert(node->tag >= FLAT || node->tag == EXTERNAL);
+        RepMemoryUsageLeaf(node, &total_mem_usage);
+      } while ((pos = ring->advance(pos)) != tail);
     } else {
       // Since cur_node is not a leaf or a concat node it must be a substring.
       assert(cur_node->tag == SUBSTRING);
@@ -1977,14 +1932,14 @@
 }
 
 namespace strings_internal {
-size_t CordTestAccess::FlatOverhead() { return kFlatOverhead; }
-size_t CordTestAccess::MaxFlatLength() { return kMaxFlatLength; }
+size_t CordTestAccess::FlatOverhead() { return cord_internal::kFlatOverhead; }
+size_t CordTestAccess::MaxFlatLength() { return cord_internal::kMaxFlatLength; }
 size_t CordTestAccess::FlatTagToLength(uint8_t tag) {
-  return TagToLength(tag);
+  return cord_internal::TagToLength(tag);
 }
 uint8_t CordTestAccess::LengthToTag(size_t s) {
   ABSL_INTERNAL_CHECK(s <= kMaxFlatLength, absl::StrCat("Invalid length ", s));
-  return AllocatedSizeToTag(s + kFlatOverhead);
+  return cord_internal::AllocatedSizeToTag(s + cord_internal::kFlatOverhead);
 }
 size_t CordTestAccess::SizeofCordRepConcat() { return sizeof(CordRepConcat); }
 size_t CordTestAccess::SizeofCordRepExternal() {
diff --git a/grpc/third_party/abseil-cpp/absl/strings/cord.h b/grpc/third_party/abseil-cpp/absl/strings/cord.h
index b8b251b..fa9cb91 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/cord.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/cord.h
@@ -25,7 +25,7 @@
 //
 // Because a Cord consists of these chunks, data can be added to or removed from
 // a Cord during its lifetime. Chunks may also be shared between Cords. Unlike a
-// `std::string`, a Cord can therefore accomodate data that changes over its
+// `std::string`, a Cord can therefore accommodate data that changes over its
 // lifetime, though it's not quite "mutable"; it can change only in the
 // attachment, detachment, or rearrangement of chunks of its constituent data.
 //
@@ -78,7 +78,10 @@
 #include "absl/functional/function_ref.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/internal/cord_rep_ring_reader.h"
 #include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/string_constant.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 
@@ -286,7 +289,7 @@
   bool StartsWith(const Cord& rhs) const;
   bool StartsWith(absl::string_view rhs) const;
 
-  // Cord::EndsWidth()
+  // Cord::EndsWith()
   //
   // Determines whether the Cord ends with the passed string data `rhs`.
   bool EndsWith(absl::string_view rhs) const;
@@ -360,14 +363,38 @@
     friend class CharIterator;
 
    private:
+    using CordRep = absl::cord_internal::CordRep;
+    using CordRepRing = absl::cord_internal::CordRepRing;
+    using CordRepRingReader = absl::cord_internal::CordRepRingReader;
+
+    // Stack of right children of concat nodes that we have to visit.
+    // Keep this at the end of the structure to avoid cache-thrashing.
+    // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+    // the inlined vector size (47 exists for backward compatibility).
+    using Stack = absl::InlinedVector<absl::cord_internal::CordRep*, 47>;
+
+    // Constructs a `begin()` iterator from `tree`. `tree` must not be null.
+    explicit ChunkIterator(cord_internal::CordRep* tree);
+
     // Constructs a `begin()` iterator from `cord`.
     explicit ChunkIterator(const Cord* cord);
 
+    // Initializes this instance from a tree. Invoked by constructors.
+    void InitTree(cord_internal::CordRep* tree);
+
     // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than
     // `current_chunk_.size()`.
     void RemoveChunkPrefix(size_t n);
     Cord AdvanceAndReadBytes(size_t n);
     void AdvanceBytes(size_t n);
+
+    // Stack specific operator++
+    ChunkIterator& AdvanceStack();
+
+    // Ring buffer specific operator++
+    ChunkIterator& AdvanceRing();
+    void AdvanceBytesRing(size_t n);
+
     // Iterates `n` bytes, where `n` is expected to be greater than or equal to
     // `current_chunk_.size()`.
     void AdvanceBytesSlowPath(size_t n);
@@ -381,8 +408,12 @@
     absl::cord_internal::CordRep* current_leaf_ = nullptr;
     // The number of bytes left in the `Cord` over which we are iterating.
     size_t bytes_remaining_ = 0;
-    absl::InlinedVector<absl::cord_internal::CordRep*, 4>
-        stack_of_right_children_;
+
+    // Cord reader for ring buffers. Empty if not traversing a ring buffer.
+    CordRepRingReader ring_reader_;
+
+    // See 'Stack' alias definition.
+    Stack stack_of_right_children_;
   };
 
   // Cord::ChunkIterator::chunk_begin()
@@ -624,6 +655,14 @@
     return c.HashFragmented(std::move(hash_state));
   }
 
+  // Create a Cord with the contents of StringConstant<T>::value.
+  // No allocations will be done and no data will be copied.
+  // This is an INTERNAL API and subject to change or removal. This API can only
+  // be used by spelling absl::strings_internal::MakeStringConstant, which is
+  // also an internal API.
+  template <typename T>
+  explicit constexpr Cord(strings_internal::StringConstant<T>);
+
  private:
   friend class CordTestPeer;
   friend bool operator==(const Cord& lhs, const Cord& rhs);
@@ -644,19 +683,17 @@
   // InlineRep holds either a tree pointer, or an array of kMaxInline bytes.
   class InlineRep {
    public:
-    static constexpr unsigned char kMaxInline = 15;
+    static constexpr unsigned char kMaxInline = cord_internal::kMaxInline;
     static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), "");
-    // Tag byte & kMaxInline means we are storing a pointer.
-    static constexpr unsigned char kTreeFlag = 1 << 4;
-    // Tag byte & kProfiledFlag means we are profiling the Cord.
-    static constexpr unsigned char kProfiledFlag = 1 << 5;
 
-    constexpr InlineRep() : data_{} {}
+    constexpr InlineRep() : data_() {}
     InlineRep(const InlineRep& src);
     InlineRep(InlineRep&& src);
     InlineRep& operator=(const InlineRep& src);
     InlineRep& operator=(InlineRep&& src) noexcept;
 
+    explicit constexpr InlineRep(cord_internal::InlineData data);
+
     void Swap(InlineRep* rhs);
     bool empty() const;
     size_t size() const;
@@ -666,6 +703,7 @@
     char* set_data(size_t n);  // Write data to the result
     // Returns nullptr if holding bytes
     absl::cord_internal::CordRep* tree() const;
+    absl::cord_internal::CordRep* as_tree() const;
     // Discards old pointer, if any
     void set_tree(absl::cord_internal::CordRep* rep);
     // Replaces a tree with a new root. This is faster than set_tree, but it
@@ -684,16 +722,16 @@
     void GetAppendRegion(char** region, size_t* size, size_t max_length);
     void GetAppendRegion(char** region, size_t* size);
     bool IsSame(const InlineRep& other) const {
-      return memcmp(data_, other.data_, sizeof(data_)) == 0;
+      return memcmp(&data_, &other.data_, sizeof(data_)) == 0;
     }
     int BitwiseCompare(const InlineRep& other) const {
       uint64_t x, y;
-      // Use memcpy to avoid anti-aliasing issues.
-      memcpy(&x, data_, sizeof(x));
-      memcpy(&y, other.data_, sizeof(y));
+      // Use memcpy to avoid aliasing issues.
+      memcpy(&x, &data_, sizeof(x));
+      memcpy(&y, &other.data_, sizeof(y));
       if (x == y) {
-        memcpy(&x, data_ + 8, sizeof(x));
-        memcpy(&y, other.data_ + 8, sizeof(y));
+        memcpy(&x, reinterpret_cast<const char*>(&data_) + 8, sizeof(x));
+        memcpy(&y, reinterpret_cast<const char*>(&other.data_) + 8, sizeof(y));
         if (x == y) return 0;
       }
       return absl::big_endian::FromHost64(x) < absl::big_endian::FromHost64(y)
@@ -706,16 +744,33 @@
       // to 15 bytes does not cause a memory allocation.
       absl::strings_internal::STLStringResizeUninitialized(dst,
                                                            sizeof(data_) - 1);
-      memcpy(&(*dst)[0], data_, sizeof(data_) - 1);
+      memcpy(&(*dst)[0], &data_, sizeof(data_) - 1);
       // erase is faster than resize because the logic for memory allocation is
       // not needed.
-      dst->erase(data_[kMaxInline]);
+      dst->erase(inline_size());
     }
 
     // Copies the inline contents into `dst`. Assumes the cord is not empty.
     void CopyToArray(char* dst) const;
 
-    bool is_tree() const { return data_[kMaxInline] > kMaxInline; }
+    bool is_tree() const { return data_.is_tree(); }
+
+    // Returns true if the Cord is being profiled by cordz.
+    bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); }
+
+    // Returns the profiled CordzInfo, or nullptr if not sampled.
+    absl::cord_internal::CordzInfo* cordz_info() const {
+      return data_.cordz_info();
+    }
+
+    // Sets the profiled CordzInfo. `cordz_info` must not be null.
+    void set_cordz_info(cord_internal::CordzInfo* cordz_info) {
+      assert(cordz_info != nullptr);
+      data_.set_cordz_info(cordz_info);
+    }
+
+    // Resets the current cordz_info to null / empty.
+    void clear_cordz_info() { data_.clear_cordz_info(); }
 
    private:
     friend class Cord;
@@ -724,10 +779,12 @@
     // Unrefs the tree, stops profiling, and zeroes the contents
     void ClearSlow();
 
-    // If the data has length <= kMaxInline, we store it in data_[0..len-1],
-    // and store the length in data_[kMaxInline].  Else we store it in a tree
-    // and store a pointer to that tree in data_[0..sizeof(CordRep*)-1].
-    alignas(absl::cord_internal::CordRep*) char data_[kMaxInline + 1];
+    void ResetToEmpty() { data_ = {}; }
+
+    void set_inline_size(size_t size) { data_.set_inline_size(size); }
+    size_t inline_size() const { return data_.inline_size(); }
+
+    cord_internal::InlineData data_;
   };
   InlineRep contents_;
 
@@ -878,13 +935,20 @@
   return cord;
 }
 
-inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) {
-  cord_internal::SmallMemmove(data_, src.data_, sizeof(data_));
+constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data)
+    : data_(data) {}
+
+inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src)
+    : data_(src.data_) {
+  if (is_tree()) {
+    data_.clear_cordz_info();
+    absl::cord_internal::CordRep::Ref(as_tree());
+  }
 }
 
 inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) {
-  memcpy(data_, src.data_, sizeof(data_));
-  memset(src.data_, 0, sizeof(data_));
+  data_ = src.data_;
+  src.ResetToEmpty();
 }
 
 inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) {
@@ -892,7 +956,7 @@
     return *this;
   }
   if (!is_tree() && !src.is_tree()) {
-    cord_internal::SmallMemmove(data_, src.data_, sizeof(data_));
+    data_ = src.data_;
     return *this;
   }
   AssignSlow(src);
@@ -904,8 +968,8 @@
   if (is_tree()) {
     ClearSlow();
   }
-  memcpy(data_, src.data_, sizeof(data_));
-  memset(src.data_, 0, sizeof(data_));
+  data_ = src.data_;
+  src.ResetToEmpty();
   return *this;
 }
 
@@ -913,44 +977,43 @@
   if (rhs == this) {
     return;
   }
-
-  Cord::InlineRep tmp;
-  cord_internal::SmallMemmove(tmp.data_, data_, sizeof(data_));
-  cord_internal::SmallMemmove(data_, rhs->data_, sizeof(data_));
-  cord_internal::SmallMemmove(rhs->data_, tmp.data_, sizeof(data_));
+  std::swap(data_, rhs->data_);
 }
 
 inline const char* Cord::InlineRep::data() const {
-  return is_tree() ? nullptr : data_;
+  return is_tree() ? nullptr : data_.as_chars();
+}
+
+inline absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const {
+  assert(data_.is_tree());
+  return data_.as_tree();
 }
 
 inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const {
   if (is_tree()) {
-    absl::cord_internal::CordRep* rep;
-    memcpy(&rep, data_, sizeof(rep));
-    return rep;
+    return as_tree();
   } else {
     return nullptr;
   }
 }
 
-inline bool Cord::InlineRep::empty() const { return data_[kMaxInline] == 0; }
+inline bool Cord::InlineRep::empty() const { return data_.is_empty(); }
 
 inline size_t Cord::InlineRep::size() const {
-  const char tag = data_[kMaxInline];
-  if (tag <= kMaxInline) return tag;
-  return static_cast<size_t>(tree()->length);
+  return is_tree() ? as_tree()->length : inline_size();
 }
 
 inline void Cord::InlineRep::set_tree(absl::cord_internal::CordRep* rep) {
   if (rep == nullptr) {
-    memset(data_, 0, sizeof(data_));
+    ResetToEmpty();
   } else {
-    bool was_tree = is_tree();
-    memcpy(data_, &rep, sizeof(rep));
-    memset(data_ + sizeof(rep), 0, sizeof(data_) - sizeof(rep) - 1);
-    if (!was_tree) {
-      data_[kMaxInline] = kTreeFlag;
+    if (data_.is_tree()) {
+      // `data_` already holds a 'tree' value and an optional cordz_info value.
+      // Replace the tree value only, leaving the cordz_info value unchanged.
+      data_.set_tree(rep);
+    } else {
+      // `data_` contains inlined data: initialize data_ to tree value `rep`.
+      data_.make_tree(rep);
     }
   }
 }
@@ -961,34 +1024,41 @@
     set_tree(rep);
     return;
   }
-  memcpy(data_, &rep, sizeof(rep));
-  memset(data_ + sizeof(rep), 0, sizeof(data_) - sizeof(rep) - 1);
+  data_.set_tree(rep);
 }
 
 inline absl::cord_internal::CordRep* Cord::InlineRep::clear() {
-  const char tag = data_[kMaxInline];
-  absl::cord_internal::CordRep* result = nullptr;
-  if (tag > kMaxInline) {
-    memcpy(&result, data_, sizeof(result));
-  }
-  memset(data_, 0, sizeof(data_));  // Clear the cord
+  absl::cord_internal::CordRep* result = tree();
+  ResetToEmpty();
   return result;
 }
 
 inline void Cord::InlineRep::CopyToArray(char* dst) const {
   assert(!is_tree());
-  size_t n = data_[kMaxInline];
+  size_t n = inline_size();
   assert(n != 0);
-  cord_internal::SmallMemmove(dst, data_, n);
+  cord_internal::SmallMemmove(dst, data_.as_chars(), n);
 }
 
 constexpr inline Cord::Cord() noexcept {}
 
+template <typename T>
+constexpr Cord::Cord(strings_internal::StringConstant<T>)
+    : contents_(strings_internal::StringConstant<T>::value.size() <=
+                        cord_internal::kMaxInline
+                    ? cord_internal::InlineData(
+                          strings_internal::StringConstant<T>::value)
+                    : cord_internal::InlineData(
+                          &cord_internal::ConstInitExternalStorage<
+                              strings_internal::StringConstant<T>>::value)) {}
+
 inline Cord& Cord::operator=(const Cord& x) {
   contents_ = x.contents_;
   return *this;
 }
 
+inline Cord::Cord(const Cord& src) : contents_(src.contents_) {}
+
 inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {}
 
 inline void Cord::swap(Cord& other) noexcept {
@@ -1072,17 +1142,64 @@
   return EqualsImpl(rhs, rhs_size);
 }
 
+inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) {
+  if (tree->tag == cord_internal::RING) {
+    current_chunk_ = ring_reader_.Reset(tree->ring());
+    return;
+  }
+
+  stack_of_right_children_.push_back(tree);
+  operator++();
+}
+
+inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree)
+    : bytes_remaining_(tree->length) {
+  InitTree(tree);
+}
+
 inline Cord::ChunkIterator::ChunkIterator(const Cord* cord)
     : bytes_remaining_(cord->size()) {
-  if (cord->empty()) return;
   if (cord->contents_.is_tree()) {
-    stack_of_right_children_.push_back(cord->contents_.tree());
-    operator++();
+    InitTree(cord->contents_.as_tree());
   } else {
-    current_chunk_ = absl::string_view(cord->contents_.data(), cord->size());
+    current_chunk_ =
+        absl::string_view(cord->contents_.data(), bytes_remaining_);
   }
 }
 
+inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceRing() {
+  current_chunk_ = ring_reader_.Next();
+  return *this;
+}
+
+inline void Cord::ChunkIterator::AdvanceBytesRing(size_t n) {
+  assert(n >= current_chunk_.size());
+  bytes_remaining_ -= n;
+  if (bytes_remaining_) {
+    if (n == current_chunk_.size()) {
+      current_chunk_ = ring_reader_.Next();
+    } else {
+      size_t offset = ring_reader_.length() - bytes_remaining_;
+      current_chunk_ = ring_reader_.Seek(offset);
+    }
+  } else {
+    current_chunk_ = {};
+  }
+}
+
+inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 &&
+                        "Attempted to iterate past `end()`");
+  assert(bytes_remaining_ >= current_chunk_.size());
+  bytes_remaining_ -= current_chunk_.size();
+  if (bytes_remaining_ > 0) {
+    return ring_reader_ ? AdvanceRing() : AdvanceStack();
+  } else {
+    current_chunk_ = {};
+  }
+  return *this;
+}
+
 inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) {
   ChunkIterator tmp(*this);
   operator++();
@@ -1114,10 +1231,11 @@
 }
 
 inline void Cord::ChunkIterator::AdvanceBytes(size_t n) {
+  assert(bytes_remaining_ >= n);
   if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) {
     RemoveChunkPrefix(n);
   } else if (n != 0) {
-    AdvanceBytesSlowPath(n);
+    ring_reader_ ? AdvanceBytesRing(n) : AdvanceBytesSlowPath(n);
   }
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/cord_ring_reader_test.cc b/grpc/third_party/abseil-cpp/absl/strings/cord_ring_reader_test.cc
new file mode 100644
index 0000000..585616f
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/cord_ring_reader_test.cc
@@ -0,0 +1,173 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 <cstdlib>
+#include <ctime>
+#include <memory>
+#include <random>
+#include <sstream>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/debugging/leak_check.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/internal/cord_rep_ring_reader.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+namespace {
+
+using testing::Eq;
+
+// Creates a flat for testing
+CordRep* MakeFlat(absl::string_view s) {
+  CordRepFlat* flat = CordRepFlat::New(s.length());
+  memcpy(flat->Data(), s.data(), s.length());
+  flat->length = s.length();
+  return flat;
+}
+
+CordRepRing* FromFlats(Span<absl::string_view const> flats) {
+  CordRepRing* ring = CordRepRing::Create(MakeFlat(flats[0]), flats.size() - 1);
+  for (int i = 1; i < flats.size(); ++i) {
+    ring = CordRepRing::Append(ring, MakeFlat(flats[i]));
+  }
+  return ring;
+}
+
+std::array<absl::string_view, 12> TestFlats() {
+  return {"abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+          "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+          "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+}
+
+TEST(CordRingReaderTest, DefaultInstance) {
+  CordRepRingReader reader;
+  EXPECT_FALSE(static_cast<bool>(reader));
+  EXPECT_THAT(reader.ring(), Eq(nullptr));
+#ifndef NDEBUG
+  EXPECT_DEATH_IF_SUPPORTED(reader.length(), ".*");
+  EXPECT_DEATH_IF_SUPPORTED(reader.consumed(), ".*");
+  EXPECT_DEATH_IF_SUPPORTED(reader.remaining(), ".*");
+  EXPECT_DEATH_IF_SUPPORTED(reader.Next(), ".*");
+  EXPECT_DEATH_IF_SUPPORTED(reader.Seek(0), ".*");
+#endif
+}
+
+TEST(CordRingReaderTest, Reset) {
+  CordRepRingReader reader;
+  auto flats = TestFlats();
+  CordRepRing* ring = FromFlats(flats);
+
+  absl::string_view first = reader.Reset(ring);
+  EXPECT_THAT(first, Eq(flats[0]));
+  EXPECT_TRUE(static_cast<bool>(reader));
+  EXPECT_THAT(reader.ring(), Eq(ring));
+  EXPECT_THAT(reader.index(), Eq(ring->head()));
+  EXPECT_THAT(reader.length(), Eq(ring->length));
+  EXPECT_THAT(reader.consumed(), Eq(flats[0].length()));
+  EXPECT_THAT(reader.remaining(), Eq(ring->length - reader.consumed()));
+
+  reader.Reset();
+  EXPECT_FALSE(static_cast<bool>(reader));
+  EXPECT_THAT(reader.ring(), Eq(nullptr));
+
+  CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, Next) {
+  CordRepRingReader reader;
+  auto flats = TestFlats();
+  CordRepRing* ring = FromFlats(flats);
+  CordRepRing::index_type head = ring->head();
+
+  reader.Reset(ring);
+  size_t consumed = reader.consumed();
+  size_t remaining = reader.remaining();
+  for (int i = 1; i < flats.size(); ++i) {
+    consumed += flats[i].length();
+    remaining -= flats[i].length();
+    absl::string_view next = reader.Next();
+    ASSERT_THAT(next, Eq(flats[i]));
+    ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+    ASSERT_THAT(reader.consumed(), Eq(consumed));
+    ASSERT_THAT(reader.remaining(), Eq(remaining));
+  }
+
+#ifndef NDEBUG
+  EXPECT_DEATH_IF_SUPPORTED(reader.Next(), ".*");
+#endif
+
+  CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, SeekForward) {
+  CordRepRingReader reader;
+  auto flats = TestFlats();
+  CordRepRing* ring = FromFlats(flats);
+  CordRepRing::index_type head = ring->head();
+
+  reader.Reset(ring);
+  size_t consumed = 0;
+  size_t remaining = ring->length;;
+  for (int i = 0; i < flats.size(); ++i) {
+    size_t offset = consumed;
+    consumed += flats[i].length();
+    remaining -= flats[i].length();
+    for (int off = 0; off < flats[i].length(); ++off) {
+      absl::string_view chunk = reader.Seek(offset + off);
+      ASSERT_THAT(chunk, Eq(flats[i].substr(off)));
+      ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+      ASSERT_THAT(reader.consumed(), Eq(consumed));
+      ASSERT_THAT(reader.remaining(), Eq(remaining));
+    }
+  }
+
+  CordRep::Unref(ring);
+}
+
+TEST(CordRingReaderTest, SeekBackward) {
+  CordRepRingReader reader;
+  auto flats = TestFlats();
+  CordRepRing* ring = FromFlats(flats);
+  CordRepRing::index_type head = ring->head();
+
+  reader.Reset(ring);
+  size_t consumed = ring->length;
+  size_t remaining = 0;
+  for (int i = flats.size() - 1; i >= 0; --i) {
+    size_t offset = consumed - flats[i].length();
+    for (int off = 0; off < flats[i].length(); ++off) {
+      absl::string_view chunk = reader.Seek(offset + off);
+      ASSERT_THAT(chunk, Eq(flats[i].substr(off)));
+      ASSERT_THAT(reader.index(), Eq(ring->advance(head, i)));
+      ASSERT_THAT(reader.consumed(), Eq(consumed));
+      ASSERT_THAT(reader.remaining(), Eq(remaining));
+    }
+    consumed -= flats[i].length();
+    remaining += flats[i].length();
+  }
+#ifndef NDEBUG
+  EXPECT_DEATH_IF_SUPPORTED(reader.Seek(ring->length), ".*");
+#endif
+  CordRep::Unref(ring);
+}
+
+}  // namespace
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/strings/cord_ring_test.cc b/grpc/third_party/abseil-cpp/absl/strings/cord_ring_test.cc
new file mode 100644
index 0000000..7d75e10
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/cord_ring_test.cc
@@ -0,0 +1,1572 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 <cstdlib>
+#include <ctime>
+#include <memory>
+#include <random>
+#include <sstream>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/debugging/leak_check.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+extern thread_local bool cord_ring;
+
+// TOOD(b/177688959): weird things happened with the original test
+#define ASAN_BUG_177688959_FIXED false
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+using RandomEngine = std::mt19937_64;
+
+using ::absl::cord_internal::CordRep;
+using ::absl::cord_internal::CordRepConcat;
+using ::absl::cord_internal::CordRepExternal;
+using ::absl::cord_internal::CordRepFlat;
+using ::absl::cord_internal::CordRepRing;
+using ::absl::cord_internal::CordRepSubstring;
+
+using ::absl::cord_internal::CONCAT;
+using ::absl::cord_internal::EXTERNAL;
+using ::absl::cord_internal::SUBSTRING;
+
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+using testing::Eq;
+using testing::Ge;
+using testing::Le;
+using testing::Lt;
+using testing::Ne;
+using testing::SizeIs;
+
+using index_type = CordRepRing::index_type;
+
+enum InputShareMode { kPrivate, kShared, kSharedIndirect };
+
+// TestParam class used by all test fixtures.
+// Not all fixtures use all possible input combinations
+struct TestParam {
+  TestParam() = default;
+  explicit TestParam(InputShareMode input_share_mode)
+      : input_share_mode(input_share_mode) {}
+
+  // Run the test with the 'rep under test' to be privately owned.
+  // Otherwise, the rep has a shared ref count of 2 or higher.
+  bool refcount_is_one = true;
+
+  // Run the test with the 'rep under test' being allocated with enough capacity
+  // to accommodate any modifications made to it. Otherwise, the rep has zero
+  // extra (reserve) capacity.
+  bool with_capacity = true;
+
+  // For test providing possibly shared input such as Append(.., CordpRep*),
+  // this field defines if that input is adopted with a refcount of one
+  // (privately owned / donated), or shared. For composite inputs such as
+  // 'substring of flat', we also have the 'shared indirect' value which means
+  // the top level node is not shared, but the contained child node is shared.
+  InputShareMode input_share_mode = kPrivate;
+
+  std::string ToString() const {
+    return absl::StrCat(refcount_is_one ? "Private" : "Shared",
+                        with_capacity ? "" : "_NoCapacity",
+                        (input_share_mode == kPrivate) ? ""
+                        : (input_share_mode == kShared)
+                            ? "_SharedInput"
+                            : "_IndirectSharedInput");
+  }
+};
+using TestParams = std::vector<TestParam>;
+
+// Matcher validating when mutable copies are required / performed.
+MATCHER_P2(EqIfPrivate, param, rep,
+           absl::StrCat("Equal 0x", absl::Hex(rep), " if private")) {
+  return param.refcount_is_one ? arg == rep : arg != rep;
+}
+
+// Matcher validating when mutable copies are required / performed.
+MATCHER_P2(EqIfPrivateAndCapacity, param, rep,
+           absl::StrCat("Equal 0x", absl::Hex(rep),
+                        " if private and capacity")) {
+  return (param.refcount_is_one && param.with_capacity) ? arg == rep
+                                                        : arg != rep;
+}
+
+MATCHER_P2(EqIfInputPrivate, param, rep, "Equal if input is private") {
+  return param.input_share_mode == kPrivate ? arg == rep : arg != rep;
+}
+
+// Matcher validating the core in-variants of the CordRepRing instance.
+MATCHER(IsValidRingBuffer, "RingBuffer is valid") {
+  std::stringstream ss;
+  if (!arg->IsValid(ss)) {
+    *result_listener << "\nERROR: " << ss.str() << "\nRING = " << *arg;
+    return false;
+  }
+  return true;
+}
+
+// Returns the flats contained in the provided CordRepRing
+std::vector<string_view> ToFlats(const CordRepRing* r) {
+  std::vector<string_view> flats;
+  flats.reserve(r->entries());
+  index_type pos = r->head();
+  do {
+    flats.push_back(r->entry_data(pos));
+  } while ((pos = r->advance(pos)) != r->tail());
+  return flats;
+}
+
+class not_a_string_view {
+ public:
+  explicit not_a_string_view(absl::string_view s)
+      : data_(s.data()), size_(s.size()) {}
+  explicit not_a_string_view(const void* data, size_t size)
+      : data_(data), size_(size) {}
+
+  not_a_string_view remove_prefix(size_t n) const {
+    return not_a_string_view(static_cast<const char*>(data_) + n, size_ - n);
+  }
+
+  not_a_string_view remove_suffix(size_t n) const {
+    return not_a_string_view(data_, size_ - n);
+  }
+
+  const void* data() const { return data_; }
+  size_t size() const { return size_; }
+
+ private:
+  const void* data_;
+  size_t size_;
+};
+
+bool operator==(not_a_string_view lhs, not_a_string_view rhs) {
+  return lhs.data() == rhs.data() && lhs.size() == rhs.size();
+}
+
+std::ostream& operator<<(std::ostream& s, not_a_string_view rhs) {
+  return s << "{ data: " << rhs.data() << " size: " << rhs.size() << "}";
+}
+
+std::vector<not_a_string_view> ToRawFlats(const CordRepRing* r) {
+  std::vector<not_a_string_view> flats;
+  flats.reserve(r->entries());
+  index_type pos = r->head();
+  do {
+    flats.emplace_back(r->entry_data(pos));
+  } while ((pos = r->advance(pos)) != r->tail());
+  return flats;
+}
+
+// Returns the value contained in the provided CordRepRing
+std::string ToString(const CordRepRing* r) {
+  std::string value;
+  value.reserve(r->length);
+  index_type pos = r->head();
+  do {
+    absl::string_view sv = r->entry_data(pos);
+    value.append(sv.data(), sv.size());
+  } while ((pos = r->advance(pos)) != r->tail());
+  return value;
+}
+
+// Creates a flat for testing
+CordRep* MakeFlat(absl::string_view s, size_t extra = 0) {
+  CordRepFlat* flat = CordRepFlat::New(s.length() + extra);
+  memcpy(flat->Data(), s.data(), s.length());
+  flat->length = s.length();
+  return flat;
+}
+
+// Creates an external node for testing
+CordRepExternal* MakeExternal(absl::string_view s) {
+  struct Rep : public CordRepExternal {
+    std::string s;
+    explicit Rep(absl::string_view s) : s(s) {
+      this->tag = EXTERNAL;
+      this->base = s.data();
+      this->length = s.length();
+      this->releaser_invoker = [](CordRepExternal* self) {
+        delete static_cast<Rep*>(self);
+      };
+    }
+  };
+  return new Rep(s);
+}
+
+CordRepExternal* MakeFakeExternal(size_t length) {
+  struct Rep : public CordRepExternal {
+    std::string s;
+    explicit Rep(size_t len) {
+      this->tag = EXTERNAL;
+      this->base = this->storage;
+      this->length = len;
+      this->releaser_invoker = [](CordRepExternal* self) {
+        delete static_cast<Rep*>(self);
+      };
+    }
+  };
+  return new Rep(length);
+}
+
+// Creates a flat or an external node for testing depending on the size.
+CordRep* MakeLeaf(absl::string_view s, size_t extra = 0) {
+  if (s.size() <= absl::cord_internal::kMaxFlatLength) {
+    return MakeFlat(s, extra);
+  } else {
+    return MakeExternal(s);
+  }
+}
+
+// Creates a substring node
+CordRepSubstring* MakeSubstring(size_t start, size_t len, CordRep* rep) {
+  auto* sub = new CordRepSubstring;
+  sub->tag = SUBSTRING;
+  sub->start = start;
+  sub->length = (len <= 0) ? rep->length - start + len : len;
+  sub->child = rep;
+  return sub;
+}
+
+// Creates a substring node removing the specified prefix
+CordRepSubstring* RemovePrefix(size_t start, CordRep* rep) {
+  return MakeSubstring(start, rep->length - start, rep);
+}
+
+// Creates a substring node removing the specified suffix
+CordRepSubstring* RemoveSuffix(size_t length, CordRep* rep) {
+  return MakeSubstring(0, rep->length - length, rep);
+}
+
+CordRepConcat* MakeConcat(CordRep* left, CordRep* right, int depth = 0) {
+  auto* concat = new CordRepConcat;
+  concat->tag = CONCAT;
+  concat->length = left->length + right->length;
+  concat->left = left;
+  concat->right = right;
+  concat->set_depth(depth);
+  return concat;
+}
+
+enum Composition { kMix, kAppend, kPrepend };
+
+Composition RandomComposition() {
+  RandomEngine rng(testing::GTEST_FLAG(random_seed));
+  return (rng() & 1) ? kMix : ((rng() & 1) ? kAppend : kPrepend);
+}
+
+absl::string_view ToString(Composition composition) {
+  switch (composition) {
+    case kAppend:
+      return "Append";
+    case kPrepend:
+      return "Prepend";
+    case kMix:
+      return "Mix";
+  }
+  assert(false);
+  return "???";
+}
+
+constexpr const char* kFox = "The quick brown fox jumps over the lazy dog";
+constexpr const char* kFoxFlats[] = {"The ", "quick ", "brown ",
+                                     "fox ", "jumps ", "over ",
+                                     "the ", "lazy ",  "dog"};
+constexpr const char* kAlphabet = "abcdefghijklmnopqrstuvwxyz";
+
+CordRepRing* FromFlats(Span<const char* const> flats,
+                       Composition composition = kAppend) {
+  if (flats.empty()) return nullptr;
+  CordRepRing* ring = nullptr;
+  switch (composition) {
+    case kAppend:
+      ring = CordRepRing::Create(MakeLeaf(flats.front()), flats.size() - 1);
+      for (int i = 1; i < flats.size(); ++i) {
+        ring = CordRepRing::Append(ring, MakeLeaf(flats[i]));
+      }
+      break;
+    case kPrepend:
+      ring = CordRepRing::Create(MakeLeaf(flats.back()), flats.size() - 1);
+      for (int i = static_cast<int>(flats.size() - 2); i >= 0; --i) {
+        ring = CordRepRing::Prepend(ring, MakeLeaf(flats[i]));
+      }
+      break;
+    case kMix:
+      size_t middle1 = flats.size() / 2, middle2 = middle1;
+      ring = CordRepRing::Create(MakeLeaf(flats[middle1]), flats.size() - 1);
+      if (!flats.empty()) {
+        if ((flats.size() & 1) == 0) {
+          ring = CordRepRing::Prepend(ring, MakeLeaf(flats[--middle1]));
+        }
+        for (int i = 1; i <= middle1; ++i) {
+          ring = CordRepRing::Prepend(ring, MakeLeaf(flats[middle1 - i]));
+          ring = CordRepRing::Append(ring, MakeLeaf(flats[middle2 + i]));
+        }
+      }
+      break;
+  }
+  EXPECT_THAT(ToFlats(ring), ElementsAreArray(flats));
+  return ring;
+}
+
+std::ostream& operator<<(std::ostream& s, const TestParam& param) {
+  return s << param.ToString();
+}
+
+std::string TestParamToString(const testing::TestParamInfo<TestParam>& info) {
+  return info.param.ToString();
+}
+
+class CordRingTest : public testing::Test {
+ public:
+  ~CordRingTest() override {
+#if ASAN_BUG_177688959_FIXED
+    for (CordRep* rep : unrefs_) {
+      CordRep::Unref(rep);
+    }
+#endif
+  }
+
+  template <typename CordRepType>
+  CordRepType* NeedsUnref(CordRepType* rep) {
+    assert(rep);
+#if ASAN_BUG_177688959_FIXED
+    unrefs_.push_back(rep);
+#endif
+    return rep;
+  }
+
+  template <typename CordRepType>
+  CordRepType* Ref(CordRepType* rep) {
+    CordRep::Ref(rep);
+    return NeedsUnref(rep);
+  }
+
+  void Unref(CordRep* rep) {
+#if !ASAN_BUG_177688959_FIXED
+    CordRep::Unref(rep);
+#endif
+  }
+
+ private:
+#if ASAN_BUG_177688959_FIXED
+  std::vector<CordRep*> unrefs_;
+#endif
+};
+
+class CordRingTestWithParam : public testing::TestWithParam<TestParam> {
+ public:
+  ~CordRingTestWithParam() override {
+#if ASAN_BUG_177688959_FIXED
+    for (CordRep* rep : unrefs_) {
+      CordRep::Unref(rep);
+    }
+#endif
+  }
+
+  CordRepRing* CreateWithCapacity(CordRep* child, size_t extra_capacity) {
+    if (!GetParam().with_capacity) extra_capacity = 0;
+    CordRepRing* ring = CordRepRing::Create(child, extra_capacity);
+    ring->SetCapacityForTesting(1 + extra_capacity);
+    return RefIfShared(ring);
+  }
+
+  bool Shared() const { return !GetParam().refcount_is_one; }
+  bool InputShared() const { return GetParam().input_share_mode == kShared; }
+  bool InputSharedIndirect() const {
+    return GetParam().input_share_mode == kSharedIndirect;
+  }
+
+  template <typename CordRepType>
+  CordRepType* NeedsUnref(CordRepType* rep) {
+    assert(rep);
+#if ASAN_BUG_177688959_FIXED
+    unrefs_.push_back(rep);
+#endif
+    return rep;
+  }
+
+  template <typename CordRepType>
+  CordRepType* Ref(CordRepType* rep) {
+    CordRep::Ref(rep);
+    return NeedsUnref(rep);
+  }
+
+  void Unref(CordRep* rep) {
+#if !ASAN_BUG_177688959_FIXED
+    CordRep::Unref(rep);
+#endif
+  }
+
+  template <typename CordRepType>
+  CordRepType* RefIfShared(CordRepType* rep) {
+    return Shared() ? Ref(rep) : rep;
+  }
+
+  void UnrefIfShared(CordRep* rep) {
+    if (Shared()) Unref(rep);
+  }
+
+  template <typename CordRepType>
+  CordRepType* RefIfInputShared(CordRepType* rep) {
+    return InputShared() ? Ref(rep) : rep;
+  }
+
+  void UnrefIfInputShared(CordRep* rep) {
+    if (InputShared()) Unref(rep);
+  }
+
+  template <typename CordRepType>
+  CordRepType* RefIfInputSharedIndirect(CordRepType* rep) {
+    return InputSharedIndirect() ? Ref(rep) : rep;
+  }
+
+  void UnrefIfInputSharedIndirect(CordRep* rep) {
+    if (InputSharedIndirect()) Unref(rep);
+  }
+
+ private:
+#if ASAN_BUG_177688959_FIXED
+  std::vector<CordRep*> unrefs_;
+#endif
+};
+
+class CordRingCreateTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    params.emplace_back(InputShareMode::kPrivate);
+    params.emplace_back(InputShareMode::kShared);
+    return params;
+  }
+};
+
+class CordRingSubTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    for (bool refcount_is_one : {true, false}) {
+      TestParam param;
+      param.refcount_is_one = refcount_is_one;
+      params.push_back(param);
+    }
+    return params;
+  }
+};
+
+class CordRingBuildTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    for (bool refcount_is_one : {true, false}) {
+      for (bool with_capacity : {true, false}) {
+        TestParam param;
+        param.refcount_is_one = refcount_is_one;
+        param.with_capacity = with_capacity;
+        params.push_back(param);
+      }
+    }
+    return params;
+  }
+};
+
+class CordRingCreateFromTreeTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    params.emplace_back(InputShareMode::kPrivate);
+    params.emplace_back(InputShareMode::kShared);
+    params.emplace_back(InputShareMode::kSharedIndirect);
+    return params;
+  }
+};
+
+class CordRingBuildInputTest : public CordRingTestWithParam {
+ public:
+  static TestParams CreateTestParams() {
+    TestParams params;
+    for (bool refcount_is_one : {true, false}) {
+      for (bool with_capacity : {true, false}) {
+        for (InputShareMode share_mode : {kPrivate, kShared, kSharedIndirect}) {
+          TestParam param;
+          param.refcount_is_one = refcount_is_one;
+          param.with_capacity = with_capacity;
+          param.input_share_mode = share_mode;
+          params.push_back(param);
+        }
+      }
+    }
+    return params;
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(WithParam, CordRingSubTest,
+                        testing::ValuesIn(CordRingSubTest::CreateTestParams()),
+                        TestParamToString);
+
+INSTANTIATE_TEST_CASE_P(
+    WithParam, CordRingCreateTest,
+    testing::ValuesIn(CordRingCreateTest::CreateTestParams()),
+    TestParamToString);
+
+INSTANTIATE_TEST_CASE_P(
+    WithParam, CordRingCreateFromTreeTest,
+    testing::ValuesIn(CordRingCreateFromTreeTest::CreateTestParams()),
+    TestParamToString);
+
+INSTANTIATE_TEST_CASE_P(
+    WithParam, CordRingBuildTest,
+    testing::ValuesIn(CordRingBuildTest::CreateTestParams()),
+    TestParamToString);
+
+INSTANTIATE_TEST_CASE_P(
+    WithParam, CordRingBuildInputTest,
+    testing::ValuesIn(CordRingBuildInputTest::CreateTestParams()),
+    TestParamToString);
+
+TEST_P(CordRingCreateTest, CreateFromFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(MakeFlat(str1)));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1));
+  Unref(result);
+}
+
+TEST_P(CordRingCreateTest, CreateFromRing) {
+  CordRepRing* ring = RefIfShared(FromFlats(kFoxFlats));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(ring));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringRing) {
+  CordRepRing* ring = RefIfInputSharedIndirect(FromFlats(kFoxFlats));
+  CordRep* sub = RefIfInputShared(MakeSubstring(2, 11, ring));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(sub));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfInputPrivate(GetParam(), ring));
+  EXPECT_THAT(ToString(result), string_view(kFox).substr(2, 11));
+  UnrefIfInputSharedIndirect(ring);
+  UnrefIfInputShared(sub);
+  Unref(result);
+}
+
+TEST_F(CordRingTest, CreateWithIllegalExtraCapacity) {
+  CordRep* flat = NeedsUnref(MakeFlat("Hello world"));
+#if defined(ABSL_HAVE_EXCEPTIONS)
+  try {
+    CordRepRing::Create(flat, CordRepRing::kMaxCapacity);
+    GTEST_FAIL() << "expected std::length_error exception";
+  } catch (const std::length_error&) {
+  }
+#elif defined(GTEST_HAS_DEATH_TEST)
+  EXPECT_DEATH(CordRepRing::Create(flat, CordRepRing::kMaxCapacity), ".*");
+#endif
+  Unref(flat);
+}
+
+TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  auto* flat = RefIfInputShared(MakeFlat(str1));
+  auto* child = RefIfInputSharedIndirect(MakeSubstring(4, 20, flat));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(20));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(4, 20)));
+  Unref(result);
+  UnrefIfInputShared(flat);
+  UnrefIfInputSharedIndirect(child);
+}
+
+TEST_P(CordRingCreateTest, CreateFromExternal) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  auto* child = RefIfInputShared(MakeExternal(str1));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1));
+  Unref(result);
+  UnrefIfInputShared(child);
+}
+
+TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfExternal) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  auto* external = RefIfInputShared(MakeExternal(str1));
+  auto* child = RefIfInputSharedIndirect(MakeSubstring(1, 24, external));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(24));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1.substr(1, 24)));
+  Unref(result);
+  UnrefIfInputShared(external);
+  UnrefIfInputSharedIndirect(child);
+}
+
+TEST_P(CordRingCreateFromTreeTest, CreateFromSubstringOfLargeExternal) {
+  auto* external = RefIfInputShared(MakeFakeExternal(1 << 20));
+  auto str = not_a_string_view(external->base, 1 << 20)
+                 .remove_prefix(1 << 19)
+                 .remove_suffix(6);
+  auto* child =
+      RefIfInputSharedIndirect(MakeSubstring(1 << 19, (1 << 19) - 6, external));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str.size()));
+  EXPECT_THAT(ToRawFlats(result), ElementsAre(str));
+  Unref(result);
+  UnrefIfInputShared(external);
+  UnrefIfInputSharedIndirect(child);
+}
+
+TEST_P(CordRingBuildInputTest, CreateFromConcat) {
+  CordRep* flats[] = {MakeFlat("abcdefgh"), MakeFlat("ijklm"),
+                      MakeFlat("nopqrstuv"), MakeFlat("wxyz")};
+  auto* left = MakeConcat(RefIfInputSharedIndirect(flats[0]), flats[1]);
+  auto* right = MakeConcat(flats[2], RefIfInputSharedIndirect(flats[3]));
+  auto* concat = RefIfInputShared(MakeConcat(left, right));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(concat));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(26));
+  EXPECT_THAT(ToString(result), Eq(kAlphabet));
+  UnrefIfInputSharedIndirect(flats[0]);
+  UnrefIfInputSharedIndirect(flats[3]);
+  UnrefIfInputShared(concat);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, CreateFromSubstringConcat) {
+  for (size_t off = 0; off < 26; ++off) {
+    for (size_t len = 1; len < 26 - off; ++len) {
+      CordRep* flats[] = {MakeFlat("abcdefgh"), MakeFlat("ijklm"),
+                          MakeFlat("nopqrstuv"), MakeFlat("wxyz")};
+      auto* left = MakeConcat(RefIfInputSharedIndirect(flats[0]), flats[1]);
+      auto* right = MakeConcat(flats[2], RefIfInputSharedIndirect(flats[3]));
+      auto* concat = MakeConcat(left, right);
+      auto* child = RefIfInputShared(MakeSubstring(off, len, concat));
+      CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+      ASSERT_THAT(result, IsValidRingBuffer());
+      ASSERT_THAT(result->length, Eq(len));
+      ASSERT_THAT(ToString(result), string_view(kAlphabet).substr(off, len));
+      UnrefIfInputSharedIndirect(flats[0]);
+      UnrefIfInputSharedIndirect(flats[3]);
+      UnrefIfInputShared(child);
+      Unref(result);
+    }
+  }
+}
+
+TEST_P(CordRingCreateTest, Properties) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(MakeFlat(str1), 120));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->head(), Eq(0));
+  EXPECT_THAT(result->tail(), Eq(1));
+  EXPECT_THAT(result->capacity(), Ge(120 + 1));
+  EXPECT_THAT(result->capacity(), Le(2 * 120 + 1));
+  EXPECT_THAT(result->entries(), Eq(1));
+  EXPECT_THAT(result->begin_pos(), Eq(0));
+  Unref(result);
+}
+
+TEST_P(CordRingCreateTest, EntryForNewFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  CordRep* child = MakeFlat(str1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child, 120));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->entry_child(0), Eq(child));
+  EXPECT_THAT(result->entry_end_pos(0), Eq(str1.length()));
+  EXPECT_THAT(result->entry_data_offset(0), Eq(0));
+  Unref(result);
+}
+
+TEST_P(CordRingCreateTest, EntryForNewFlatSubstring) {
+  absl::string_view str1 = "1234567890abcdefghijklmnopqrstuvwxyz";
+  CordRep* child = MakeFlat(str1);
+  CordRep* substring = MakeSubstring(10, 26, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(substring, 1));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->entry_child(0), Eq(child));
+  EXPECT_THAT(result->entry_end_pos(0), Eq(26));
+  EXPECT_THAT(result->entry_data_offset(0), Eq(10));
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, MakeFlat(str2)));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, PrependFlat) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, MakeFlat(str2)));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendString) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendStringHavingExtra) {
+  absl::string_view str1 = "1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(str1, 26), 0);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendStringHavingPartialExtra) {
+  absl::string_view str1 = "1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+  // Create flat with at least one extra byte. We don't expect to have sized
+  // alloc and capacity rounding to grant us enough to not make it partial.
+  auto* flat = MakeFlat(str1, 1);
+  size_t avail = flat->flat()->Capacity() - flat->length;
+  ASSERT_THAT(avail, Lt(str2.size())) << " adjust test for larger flats!";
+
+  // Construct the flats we do expect using all of `avail`.
+  absl::string_view str1a = str2.substr(0, avail);
+  absl::string_view str2a = str2.substr(avail);
+
+  CordRepRing* ring = CreateWithCapacity(flat, 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str1, str1a), str2a));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre(str1, str2));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendStringHavingExtraInSubstring) {
+  absl::string_view str1 = "123456789_1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRep* flat = RemovePrefix(10, MakeFlat(str1, 26));
+  CordRepRing* ring = CreateWithCapacity(flat, 0);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(4 + str2.size()));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result), ElementsAre(StrCat("1234", str2)));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendStringHavingSharedExtra) {
+  absl::string_view str1 = "123456789_1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  for (int shared_type = 0; shared_type < 2; ++shared_type) {
+    SCOPED_TRACE(absl::StrCat("Shared extra type ", shared_type));
+
+    // Create a flat that is shared in some way.
+    CordRep* flat = nullptr;
+    CordRep* flat1 = nullptr;
+    if (shared_type == 0) {
+      // Shared flat
+      flat = CordRep::Ref(MakeFlat(str1.substr(10), 100));
+    } else if (shared_type == 1) {
+      // Shared flat inside private substring
+      flat1 = CordRep::Ref(MakeFlat(str1));
+      flat = RemovePrefix(10, flat1);
+    } else {
+      // Private flat inside shared substring
+      flat = CordRep::Ref(RemovePrefix(10, MakeFlat(str1, 100)));
+    }
+
+    CordRepRing* ring = CreateWithCapacity(flat, 1);
+    CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2));
+    ASSERT_THAT(result, IsValidRingBuffer());
+    EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+    EXPECT_THAT(result->length, Eq(4 + str2.size()));
+    EXPECT_THAT(ToFlats(result), ElementsAre("1234", str2));
+    UnrefIfShared(ring);
+    Unref(result);
+
+    CordRep::Unref(shared_type == 1 ? flat1 : flat);
+  }
+}
+
+TEST_P(CordRingBuildTest, AppendStringWithExtra) {
+  absl::string_view str1 = "1234";
+  absl::string_view str2 = "1234567890";
+  absl::string_view str3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, str2, 26));
+  result = CordRepRing::Append(result, str3);
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size()));
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str1, StrCat(str2, str3)));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, PrependString) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  // Use external rep to avoid appending to first flat
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  if (GetParam().with_capacity && GetParam().refcount_is_one) {
+    EXPECT_THAT(result, Eq(ring));
+  } else {
+    EXPECT_THAT(result, Ne(ring));
+  }
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size()));
+  EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, PrependStringHavingExtra) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz1234";
+  absl::string_view str2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRep* flat = RemovePrefix(26, MakeFlat(str1));
+  CordRepRing* ring = CreateWithCapacity(flat, 0);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  EXPECT_THAT(result->length, Eq(4 + str2.size()));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str2, "1234")));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre(str2, "1234"));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, PrependStringHavingSharedExtra) {
+  absl::string_view str1 = "123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  absl::string_view str2 = "abcdefghij";
+  absl::string_view str1a = str1.substr(10);
+  for (int shared_type = 1; shared_type < 2; ++shared_type) {
+    SCOPED_TRACE(absl::StrCat("Shared extra type ", shared_type));
+
+    // Create a flat that is shared in some way.
+    CordRep* flat = nullptr;
+    CordRep* flat1 = nullptr;
+    if (shared_type == 1) {
+      // Shared flat inside private substring
+      flat = RemovePrefix(10, flat1 = CordRep::Ref(MakeFlat(str1)));
+    } else {
+      // Private flat inside shared substring
+      flat = CordRep::Ref(RemovePrefix(10, MakeFlat(str1, 100)));
+    }
+
+    CordRepRing* ring = CreateWithCapacity(flat, 1);
+    CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2));
+    ASSERT_THAT(result, IsValidRingBuffer());
+    EXPECT_THAT(result->length, Eq(str1a.size() + str2.size()));
+    EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+    EXPECT_THAT(ToFlats(result), ElementsAre(str2, str1a));
+    UnrefIfShared(ring);
+    Unref(result);
+    CordRep::Unref(shared_type == 1 ? flat1 : flat);
+  }
+}
+
+TEST_P(CordRingBuildTest, PrependStringWithExtra) {
+  absl::string_view str1 = "1234";
+  absl::string_view str2 = "1234567890";
+  absl::string_view str3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  CordRepRing* ring = CreateWithCapacity(MakeExternal(str1), 1);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, str2, 26));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  result = CordRepRing::Prepend(result, str3);
+  EXPECT_THAT(result->length, Eq(str1.size() + str2.size() + str3.size()));
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre(StrCat(str3, str2), str1));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendPrependStringMix) {
+  const auto& flats = kFoxFlats;
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(flats[4]), 8);
+  CordRepRing* result = ring;
+  for (int i = 1; i <= 4; ++i) {
+    result = CordRepRing::Prepend(result, flats[4 - i]);
+    result = CordRepRing::Append(result, flats[4 + i]);
+  }
+  UnrefIfShared(ring);
+  NeedsUnref(result);
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToString(result), kFox);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendPrependStringMixWithExtra) {
+  const auto& flats = kFoxFlats;
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(flats[4], 100), 8);
+  CordRepRing* result = ring;
+  for (int i = 1; i <= 4; ++i) {
+    result = CordRepRing::Prepend(result, flats[4 - i], 100);
+    result = CordRepRing::Append(result, flats[4 + i], 100);
+  }
+  NeedsUnref(result);
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result),
+                ElementsAre("The quick brown fox ", "jumps over the lazy dog"));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ",
+                                             "over the lazy dog"));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendPrependStringMixWithPrependedExtra) {
+  const auto& flats = kFoxFlats;
+  CordRep* flat = MakeFlat(StrCat(std::string(50, '.'), flats[4]), 50);
+  CordRepRing* ring = CreateWithCapacity(RemovePrefix(50, flat), 0);
+  CordRepRing* result = ring;
+  for (int i = 1; i <= 4; ++i) {
+    result = CordRepRing::Prepend(result, flats[4 - i], 100);
+    result = CordRepRing::Append(result, flats[4 + i], 100);
+  }
+  result = NeedsUnref(result);
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  if (GetParam().refcount_is_one) {
+    EXPECT_THAT(ToFlats(result), ElementsAre(kFox));
+  } else {
+    EXPECT_THAT(ToFlats(result), ElementsAre("The quick brown fox ", "jumps ",
+                                             "over the lazy dog"));
+  }
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingSubTest, SubRing) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  string_view all = kFox;
+  for (size_t offset = 0; offset < all.size() - 1; ++offset) {
+    CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
+    CordRepRing* result = CordRepRing::SubRing(ring, offset, 0);
+    EXPECT_THAT(result, nullptr);
+    UnrefIfShared(ring);
+
+    for (size_t len = 1; len < all.size() - offset; ++len) {
+      ring = RefIfShared(FromFlats(flats, composition));
+      result = NeedsUnref(CordRepRing::SubRing(ring, offset, len));
+      ASSERT_THAT(result, IsValidRingBuffer());
+      ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
+      ASSERT_THAT(ToString(result), Eq(all.substr(offset, len)));
+      UnrefIfShared(ring);
+      Unref(result);
+    }
+  }
+}
+
+TEST_P(CordRingSubTest, SubRingFromLargeExternal) {
+  auto composition = RandomComposition();
+  std::string large_string(1 << 20, '.');
+  const char* flats[] = {
+      "abcdefghijklmnopqrstuvwxyz",
+      large_string.c_str(),
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+  };
+  std::string buffer = absl::StrCat(flats[0], flats[1], flats[2]);
+  absl::string_view all = buffer;
+  for (size_t offset = 0; offset < 30; ++offset) {
+    CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
+    CordRepRing* result = CordRepRing::SubRing(ring, offset, 0);
+    EXPECT_THAT(result, nullptr);
+    UnrefIfShared(ring);
+
+    for (size_t len = all.size() - 30; len < all.size() - offset; ++len) {
+      ring = RefIfShared(FromFlats(flats, composition));
+      result = NeedsUnref(CordRepRing::SubRing(ring, offset, len));
+      ASSERT_THAT(result, IsValidRingBuffer());
+      ASSERT_THAT(result, EqIfPrivate(GetParam(), ring));
+      auto str = ToString(result);
+      ASSERT_THAT(str, SizeIs(len));
+      ASSERT_THAT(str, Eq(all.substr(offset, len)));
+      UnrefIfShared(ring);
+      Unref(result);
+    }
+  }
+}
+
+TEST_P(CordRingSubTest, RemovePrefix) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  string_view all = kFox;
+  CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
+  CordRepRing* result = CordRepRing::RemovePrefix(ring, all.size());
+  EXPECT_THAT(result, nullptr);
+  UnrefIfShared(ring);
+
+  for (size_t len = 1; len < all.size(); ++len) {
+    ring = RefIfShared(FromFlats(flats, composition));
+    result = NeedsUnref(CordRepRing::RemovePrefix(ring, len));
+    ASSERT_THAT(result, IsValidRingBuffer());
+    EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+    EXPECT_THAT(ToString(result), Eq(all.substr(len)));
+    UnrefIfShared(ring);
+    Unref(result);
+  }
+}
+
+TEST_P(CordRingSubTest, RemovePrefixFromLargeExternal) {
+  CordRepExternal* external1 = MakeFakeExternal(1 << 20);
+  CordRepExternal* external2 = MakeFakeExternal(1 << 20);
+  CordRepRing* ring = CordRepRing::Create(external1, 1);
+  ring = CordRepRing::Append(ring, external2);
+  CordRepRing* result = NeedsUnref(CordRepRing::RemovePrefix(ring, 1 << 16));
+  EXPECT_THAT(
+      ToRawFlats(result),
+      ElementsAre(
+          not_a_string_view(external1->base, 1 << 20).remove_prefix(1 << 16),
+          not_a_string_view(external2->base, 1 << 20)));
+  Unref(result);
+}
+
+TEST_P(CordRingSubTest, RemoveSuffix) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  string_view all = kFox;
+  CordRepRing* ring = RefIfShared(FromFlats(flats, composition));
+  CordRepRing* result = CordRepRing::RemoveSuffix(ring, all.size());
+  EXPECT_THAT(result, nullptr);
+  UnrefIfShared(ring);
+
+  for (size_t len = 1; len < all.size(); ++len) {
+    ring = RefIfShared(FromFlats(flats, composition));
+    result = NeedsUnref(CordRepRing::RemoveSuffix(ring, len));
+    ASSERT_THAT(result, IsValidRingBuffer());
+    EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+    EXPECT_THAT(ToString(result), Eq(all.substr(0, all.size() - len)));
+    UnrefIfShared(ring);
+    Unref(result);
+  }
+}
+
+TEST_P(CordRingSubTest, AppendRing) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats).subspan(1);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(kFoxFlats[0]), flats.size());
+  CordRepRing* child = FromFlats(flats, composition);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivate(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, AppendRingWithFlatOffset) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RemovePrefix(10, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Head", "brown ", "fox ", "jumps ",
+                                           "over ", "the ", "lazy ", "dog"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, AppendRingWithBrokenOffset) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RemovePrefix(21, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result),
+              ElementsAre("Head", "umps ", "over ", "the ", "lazy ", "dog"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, AppendRingWithFlatLength) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RemoveSuffix(8, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ",
+                                           "fox ", "jumps ", "over ", "the "));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendRingWithBrokenFlatLength) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RemoveSuffix(15, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Head", "The ", "quick ", "brown ",
+                                           "fox ", "jumps ", "ov"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendRingMiddlePiece) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = MakeSubstring(7, child->length - 27, child);
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result),
+              ElementsAre("Head", "ck ", "brown ", "fox ", "jum"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildTest, AppendRingSinglePiece) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Head"), flats.size());
+  CordRep* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputShared(MakeSubstring(11, 3, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Head", "row"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfInputShared(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, AppendRingSinglePieceWithPrefix) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  size_t extra_capacity = 1 + (GetParam().with_capacity ? flats.size() : 0);
+  CordRepRing* ring = CordRepRing::Create(MakeFlat("Head"), extra_capacity);
+  ring->SetCapacityForTesting(1 + extra_capacity);
+  ring = RefIfShared(CordRepRing::Prepend(ring, MakeFlat("Prepend")));
+  assert(ring->IsValid(std::cout));
+  CordRepRing* child = RefIfInputSharedIndirect(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputShared(MakeSubstring(11, 3, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Append(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("Prepend", "Head", "row"));
+  UnrefIfInputSharedIndirect(child);
+  UnrefIfInputShared(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRing) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto fox = MakeSpan(kFoxFlats);
+  auto flats = MakeSpan(fox).subspan(0, fox.size() - 1);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat(fox.back()), flats.size());
+  CordRepRing* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAreArray(kFoxFlats));
+  UnrefIfInputShared(child);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingWithFlatOffset) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(10, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("brown ", "fox ", "jumps ", "over ",
+                                           "the ", "lazy ", "dog", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingWithBrokenOffset) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(RemovePrefix(21, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result),
+              ElementsAre("umps ", "over ", "the ", "lazy ", "dog", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingWithFlatLength) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(RemoveSuffix(8, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ",
+                                           "jumps ", "over ", "the ", "Tail"));
+  UnrefIfShared(ring);
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingWithBrokenFlatLength) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(RemoveSuffix(15, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("The ", "quick ", "brown ", "fox ",
+                                           "jumps ", "ov", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingMiddlePiece) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped =
+      RefIfInputSharedIndirect(MakeSubstring(7, child->length - 27, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result),
+              ElementsAre("ck ", "brown ", "fox ", "jum", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingSinglePiece) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CreateWithCapacity(MakeFlat("Tail"), flats.size());
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(MakeSubstring(11, 3, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("row", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_P(CordRingBuildInputTest, PrependRingSinglePieceWithPrefix) {
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  auto flats = MakeSpan(kFoxFlats);
+  size_t extra_capacity = 1 + (GetParam().with_capacity ? flats.size() : 0);
+  CordRepRing* ring = CordRepRing::Create(MakeFlat("Tail"), extra_capacity);
+  ring->SetCapacityForTesting(1 + extra_capacity);
+  ring = RefIfShared(CordRepRing::Prepend(ring, MakeFlat("Prepend")));
+  CordRep* child = RefIfInputShared(FromFlats(flats, composition));
+  CordRep* stripped = RefIfInputSharedIndirect(MakeSubstring(11, 3, child));
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, stripped));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  EXPECT_THAT(result, EqIfPrivateAndCapacity(GetParam(), ring));
+  EXPECT_THAT(ToFlats(result), ElementsAre("row", "Prepend", "Tail"));
+  UnrefIfInputShared(child);
+  UnrefIfInputSharedIndirect(stripped);
+  UnrefIfShared(ring);
+  Unref(result);
+}
+
+TEST_F(CordRingTest, Find) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
+  std::string value = ToString(ring);
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position found = ring->Find(i);
+    auto data = ring->entry_data(found.index);
+    ASSERT_THAT(found.offset, Lt(data.length()));
+    ASSERT_THAT(data[found.offset], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindWithHint) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
+  std::string value = ToString(ring);
+
+#if defined(GTEST_HAS_DEATH_TEST)
+  // Test hint beyond valid position
+  index_type head = ring->head();
+  EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head), 0), ".*");
+  EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head), 9), ".*");
+  EXPECT_DEBUG_DEATH(ring->Find(ring->advance(head, 3), 24), ".*");
+#endif
+
+  int flat_pos = 0;
+  size_t flat_offset = 0;
+  for (auto sflat : flats) {
+    string_view flat(sflat);
+    for (int offset = 0; offset < flat.length(); ++offset) {
+      for (int start = 0; start <= flat_pos; ++start) {
+        index_type hint = ring->advance(ring->head(), start);
+        CordRepRing::Position found = ring->Find(hint, flat_offset + offset);
+        ASSERT_THAT(found.index, Eq(ring->advance(ring->head(), flat_pos)));
+        ASSERT_THAT(found.offset, Eq(offset));
+      }
+    }
+    ++flat_pos;
+    flat_offset += flat.length();
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindInLargeRing) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = FromFlats(flats, composition);
+  for (int i = 0; i < 13; ++i) {
+    ring = CordRepRing::Append(ring, FromFlats(flats, composition));
+  }
+  NeedsUnref(ring);
+  std::string value = ToString(ring);
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position pos = ring->Find(i);
+    auto data = ring->entry_data(pos.index);
+    ASSERT_THAT(pos.offset, Lt(data.length()));
+    ASSERT_THAT(data[pos.offset], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindTail) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
+  std::string value = ToString(ring);
+
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position pos = ring->FindTail(i + 1);
+    auto data = ring->entry_data(ring->retreat(pos.index));
+    ASSERT_THAT(pos.offset, Lt(data.length()));
+    ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindTailWithHint) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, composition));
+  std::string value = ToString(ring);
+
+  // Test hint beyond valid position
+#if defined(GTEST_HAS_DEATH_TEST)
+  index_type head = ring->head();
+  EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head), 1), ".*");
+  EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head), 10), ".*");
+  EXPECT_DEBUG_DEATH(ring->FindTail(ring->advance(head, 3), 26), ".*");
+#endif
+
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position pos = ring->FindTail(i + 1);
+    auto data = ring->entry_data(ring->retreat(pos.index));
+    ASSERT_THAT(pos.offset, Lt(data.length()));
+    ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, FindTailInLargeRing) {
+  constexpr const char* flats[] = {
+      "abcdefghij", "klmnopqrst", "uvwxyz",     "ABCDEFGHIJ",
+      "KLMNOPQRST", "UVWXYZ",     "1234567890", "~!@#$%^&*()_",
+      "+-=",        "[]\\{}|;':", ",/<>?",      "."};
+  auto composition = RandomComposition();
+  SCOPED_TRACE(ToString(composition));
+  CordRepRing* ring = FromFlats(flats, composition);
+  for (int i = 0; i < 13; ++i) {
+    ring = CordRepRing::Append(ring, FromFlats(flats, composition));
+  }
+  NeedsUnref(ring);
+  std::string value = ToString(ring);
+  for (int i = 0; i < value.length(); ++i) {
+    CordRepRing::Position pos = ring->FindTail(i + 1);
+    auto data = ring->entry_data(ring->retreat(pos.index));
+    ASSERT_THAT(pos.offset, Lt(data.length()));
+    ASSERT_THAT(data[data.length() - pos.offset - 1], Eq(value[i]));
+  }
+  Unref(ring);
+}
+
+TEST_F(CordRingTest, GetCharacter) {
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = CordRepRing::Create(MakeFlat("Tail"), flats.size());
+  CordRep* child = FromFlats(flats, kAppend);
+  CordRepRing* result = NeedsUnref(CordRepRing::Prepend(ring, child));
+  std::string value = ToString(result);
+  for (int i = 0; i < value.length(); ++i) {
+    ASSERT_THAT(result->GetCharacter(i), Eq(value[i]));
+  }
+  Unref(result);
+}
+
+TEST_F(CordRingTest, GetCharacterWithSubstring) {
+  absl::string_view str1 = "abcdefghijklmnopqrstuvwxyz";
+  auto* child = MakeSubstring(4, 20, MakeFlat(str1));
+  CordRepRing* result = NeedsUnref(CordRepRing::Create(child));
+  ASSERT_THAT(result, IsValidRingBuffer());
+  std::string value = ToString(result);
+  for (int i = 0; i < value.length(); ++i) {
+    ASSERT_THAT(result->GetCharacter(i), Eq(value[i]));
+  }
+  Unref(result);
+}
+
+TEST_F(CordRingTest, Dump) {
+  std::stringstream ss;
+  auto flats = MakeSpan(kFoxFlats);
+  CordRepRing* ring = NeedsUnref(FromFlats(flats, kPrepend));
+  ss << *ring;
+  Unref(ring);
+}
+
+}  // namespace
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/strings/cord_test.cc b/grpc/third_party/abseil-cpp/absl/strings/cord_test.cc
index 4443c82..f998242 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/cord_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/cord_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/cord.h"
 
 #include <algorithm>
@@ -167,6 +181,12 @@
       const Cord& c, absl::FunctionRef<void(absl::string_view)> callback) {
     c.ForEachChunk(callback);
   }
+
+  static bool IsTree(const Cord& c) { return c.contents_.is_tree(); }
+
+  static cord_internal::CordzInfo* GetCordzInfo(const Cord& c) {
+    return c.contents_.cordz_info();
+  }
 };
 
 ABSL_NAMESPACE_END
@@ -351,7 +371,7 @@
     for (size_t end_pos : positions) {
       if (end_pos < pos || end_pos > a.size()) continue;
       absl::Cord sa = a.Subcord(pos, end_pos - pos);
-      EXPECT_EQ(absl::string_view(s).substr(pos, end_pos - pos),
+      ASSERT_EQ(absl::string_view(s).substr(pos, end_pos - pos),
                 std::string(sa))
           << a;
     }
@@ -363,7 +383,7 @@
   for (size_t pos = 0; pos <= sh.size(); ++pos) {
     for (size_t n = 0; n <= sh.size() - pos; ++n) {
       absl::Cord sc = c.Subcord(pos, n);
-      EXPECT_EQ(sh.substr(pos, n), std::string(sc)) << c;
+      ASSERT_EQ(sh.substr(pos, n), std::string(sc)) << c;
     }
   }
 
@@ -373,7 +393,7 @@
   while (sa.size() > 1) {
     sa = sa.Subcord(1, sa.size() - 2);
     ss = ss.substr(1, ss.size() - 2);
-    EXPECT_EQ(ss, std::string(sa)) << a;
+    ASSERT_EQ(ss, std::string(sa)) << a;
     if (HasFailure()) break;  // halt cascade
   }
 
@@ -1613,3 +1633,83 @@
   EXPECT_DEATH_IF_SUPPORTED(static_cast<void>(cord.chunk_end()->empty()), "");
   EXPECT_DEATH_IF_SUPPORTED(++cord.chunk_end(), "");
 }
+
+class AfterExitCordTester {
+ public:
+  bool Set(absl::Cord* cord, absl::string_view expected) {
+    cord_ = cord;
+    expected_ = expected;
+    return true;
+  }
+
+  ~AfterExitCordTester() {
+    EXPECT_EQ(*cord_, expected_);
+  }
+ private:
+  absl::Cord* cord_;
+  absl::string_view expected_;
+};
+
+template <typename Str>
+void TestConstinitConstructor(Str) {
+  const auto expected = Str::value;
+  // Defined before `cord` to be destroyed after it.
+  static AfterExitCordTester exit_tester;  // NOLINT
+  ABSL_CONST_INIT static absl::Cord cord(Str{});  // NOLINT
+  static bool init_exit_tester = exit_tester.Set(&cord, expected);
+  (void)init_exit_tester;
+
+  EXPECT_EQ(cord, expected);
+  // Copy the object and test the copy, and the original.
+  {
+    absl::Cord copy = cord;
+    EXPECT_EQ(copy, expected);
+  }
+  // The original still works
+  EXPECT_EQ(cord, expected);
+
+  // Try making adding more structure to the tree.
+  {
+    absl::Cord copy = cord;
+    std::string expected_copy(expected);
+    for (int i = 0; i < 10; ++i) {
+      copy.Append(cord);
+      absl::StrAppend(&expected_copy, expected);
+      EXPECT_EQ(copy, expected_copy);
+    }
+  }
+
+  // Make sure we are using the right branch during constant evaluation.
+  EXPECT_EQ(absl::CordTestPeer::IsTree(cord), cord.size() >= 16);
+
+  for (int i = 0; i < 10; ++i) {
+    // Make a few more Cords from the same global rep.
+    // This tests what happens when the refcount for it gets below 1.
+    EXPECT_EQ(expected, absl::Cord(Str{}));
+  }
+}
+
+constexpr int SimpleStrlen(const char* p) {
+  return *p ? 1 + SimpleStrlen(p + 1) : 0;
+}
+
+struct ShortView {
+  constexpr absl::string_view operator()() const {
+    return absl::string_view("SSO string", SimpleStrlen("SSO string"));
+  }
+};
+
+struct LongView {
+  constexpr absl::string_view operator()() const {
+    return absl::string_view("String that does not fit SSO.",
+                             SimpleStrlen("String that does not fit SSO."));
+  }
+};
+
+
+TEST(Cord, ConstinitConstructor) {
+  TestConstinitConstructor(
+      absl::strings_internal::MakeStringConstant(ShortView{}));
+  TestConstinitConstructor(
+      absl::strings_internal::MakeStringConstant(LongView{}));
+}
diff --git a/grpc/third_party/abseil-cpp/absl/strings/escaping.cc b/grpc/third_party/abseil-cpp/absl/strings/escaping.cc
index 9fceeef..18b20b8 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/escaping.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/escaping.cc
@@ -137,7 +137,7 @@
             // Copy the escape sequence for the null character
             const ptrdiff_t octal_size = p + 1 - octal_start;
             *d++ = '\\';
-            memcpy(d, octal_start, octal_size);
+            memmove(d, octal_start, octal_size);
             d += octal_size;
             break;
           }
@@ -170,7 +170,7 @@
             // Copy the escape sequence for the null character
             const ptrdiff_t hex_size = p + 1 - hex_start;
             *d++ = '\\';
-            memcpy(d, hex_start, hex_size);
+            memmove(d, hex_start, hex_size);
             d += hex_size;
             break;
           }
@@ -203,7 +203,7 @@
           if ((rune == 0) && leave_nulls_escaped) {
             // Copy the escape sequence for the null character
             *d++ = '\\';
-            memcpy(d, hex_start, 5);  // u0000
+            memmove(d, hex_start, 5);  // u0000
             d += 5;
             break;
           }
@@ -251,7 +251,7 @@
           if ((rune == 0) && leave_nulls_escaped) {
             // Copy the escape sequence for the null character
             *d++ = '\\';
-            memcpy(d, hex_start, 9);  // U00000000
+            memmove(d, hex_start, 9);  // U00000000
             d += 9;
             break;
           }
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc
index 363bcb0..a8b9945 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc
@@ -69,6 +69,61 @@
     // And we should have fully rotated all bits off by now:
     EXPECT_EQ(a, BigUnsigned<84>(0u));
   }
+  {
+    // Bit shifting large and small numbers by large and small offsets.
+    // Intended to exercise bounds-checking corner on ShiftLeft() (directly
+    // and under asan).
+
+    // 2**(32*84)-1
+    const BigUnsigned<84> all_bits_one(
+        "1474444211396924248063325089479706787923460402125687709454567433186613"
+        "6228083464060749874845919674257665016359189106695900028098437021384227"
+        "3285029708032466536084583113729486015826557532750465299832071590813090"
+        "2011853039837649252477307070509704043541368002938784757296893793903797"
+        "8180292336310543540677175225040919704702800559606097685920595947397024"
+        "8303316808753252115729411497720357971050627997031988036134171378490368"
+        "6008000778741115399296162550786288457245180872759047016734959330367829"
+        "5235612397427686310674725251378116268607113017720538636924549612987647"
+        "5767411074510311386444547332882472126067840027882117834454260409440463"
+        "9345147252664893456053258463203120637089916304618696601333953616715125"
+        "2115882482473279040772264257431663818610405673876655957323083702713344"
+        "4201105427930770976052393421467136557055");
+    const BigUnsigned<84> zero(0u);
+    const BigUnsigned<84> one(1u);
+    // in bounds shifts
+    for (int i = 1; i < 84*32; ++i) {
+      // shifting all_bits_one to the left should result in a smaller number,
+      // since the high bits rotate off and the low bits are replaced with
+      // zeroes.
+      BigUnsigned<84> big_shifted = all_bits_one;
+      big_shifted.ShiftLeft(i);
+      EXPECT_GT(all_bits_one, big_shifted);
+      // Shifting 1 to the left should instead result in a larger number.
+      BigUnsigned<84> small_shifted = one;
+      small_shifted.ShiftLeft(i);
+      EXPECT_LT(one, small_shifted);
+    }
+    // Shifting by zero or a negative number has no effect
+    for (int no_op_shift : {0, -1, -84 * 32, std::numeric_limits<int>::min()}) {
+      BigUnsigned<84> big_shifted = all_bits_one;
+      big_shifted.ShiftLeft(no_op_shift);
+      EXPECT_EQ(all_bits_one, big_shifted);
+      BigUnsigned<84> small_shifted = one;
+      big_shifted.ShiftLeft(no_op_shift);
+      EXPECT_EQ(one, small_shifted);
+    }
+    // Shifting by an amount greater than the number of bits should result in
+    // zero.
+    for (int out_of_bounds_shift :
+         {84 * 32, 84 * 32 + 1, std::numeric_limits<int>::max()}) {
+      BigUnsigned<84> big_shifted = all_bits_one;
+      big_shifted.ShiftLeft(out_of_bounds_shift);
+      EXPECT_EQ(zero, big_shifted);
+      BigUnsigned<84> small_shifted = one;
+      small_shifted.ShiftLeft(out_of_bounds_shift);
+      EXPECT_EQ(zero, small_shifted);
+    }
+  }
 }
 
 TEST(BigUnsigned, MultiplyByUint32) {
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc
index fd6d948..8b11868 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc
@@ -246,8 +246,8 @@
 // ConsumeDigits does not protect against overflow on *out; max_digits must
 // be chosen with respect to type T to avoid the possibility of overflow.
 template <int base, typename T>
-std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits,
-                          T* out, bool* dropped_nonzero_digit) {
+int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out,
+                  bool* dropped_nonzero_digit) {
   if (base == 10) {
     assert(max_digits <= std::numeric_limits<T>::digits10);
   } else if (base == 16) {
@@ -282,7 +282,7 @@
     *dropped_nonzero_digit = true;
   }
   *out = accumulator;
-  return begin - original_begin;
+  return static_cast<int>(begin - original_begin);
 }
 
 // Returns true if `v` is one of the chars allowed inside parentheses following
@@ -372,7 +372,7 @@
 
   int exponent_adjustment = 0;
   bool mantissa_is_inexact = false;
-  std::size_t pre_decimal_digits = ConsumeDigits<base>(
+  int pre_decimal_digits = ConsumeDigits<base>(
       begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
   begin += pre_decimal_digits;
   int digits_left;
@@ -398,14 +398,14 @@
       while (begin < end && *begin == '0') {
         ++begin;
       }
-      std::size_t zeros_skipped = begin - begin_zeros;
+      int zeros_skipped = static_cast<int>(begin - begin_zeros);
       if (zeros_skipped >= DigitLimit<base>()) {
         // refuse to parse pathological inputs
         return result;
       }
       exponent_adjustment -= static_cast<int>(zeros_skipped);
     }
-    std::size_t post_decimal_digits = ConsumeDigits<base>(
+    int post_decimal_digits = ConsumeDigits<base>(
         begin, end, digits_left, &mantissa, &mantissa_is_inexact);
     begin += post_decimal_digits;
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/cord_internal.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_internal.cc
new file mode 100644
index 0000000..905ffd0
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_internal.cc
@@ -0,0 +1,83 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/internal/cord_internal.h"
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+ABSL_CONST_INIT std::atomic<bool> cord_ring_buffer_enabled(
+    kCordEnableRingBufferDefault);
+ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled(
+    kCordShallowSubcordsDefault);
+
+void CordRep::Destroy(CordRep* rep) {
+  assert(rep != nullptr);
+
+  absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending;
+  while (true) {
+    assert(!rep->refcount.IsImmortal());
+    if (rep->tag == CONCAT) {
+      CordRepConcat* rep_concat = rep->concat();
+      CordRep* right = rep_concat->right;
+      if (!right->refcount.Decrement()) {
+        pending.push_back(right);
+      }
+      CordRep* left = rep_concat->left;
+      delete rep_concat;
+      rep = nullptr;
+      if (!left->refcount.Decrement()) {
+        rep = left;
+        continue;
+      }
+    } else if (rep->tag == RING) {
+      CordRepRing::Destroy(rep->ring());
+      rep = nullptr;
+    } else if (rep->tag == EXTERNAL) {
+      CordRepExternal::Delete(rep);
+      rep = nullptr;
+    } else if (rep->tag == SUBSTRING) {
+      CordRepSubstring* rep_substring = rep->substring();
+      CordRep* child = rep_substring->child;
+      delete rep_substring;
+      rep = nullptr;
+      if (!child->refcount.Decrement()) {
+        rep = child;
+        continue;
+      }
+    } else {
+      CordRepFlat::Delete(rep);
+      rep = nullptr;
+    }
+
+    if (!pending.empty()) {
+      rep = pending.back();
+      pending.pop_back();
+    } else {
+      break;
+    }
+  }
+}
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/cord_internal.h b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_internal.h
index d456eef..a1ba67f 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/cord_internal.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_internal.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Abseil Authors.
+// Copyright 2021 The Abseil Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -21,7 +21,10 @@
 #include <cstdint>
 #include <type_traits>
 
+#include "absl/base/config.h"
+#include "absl/base/internal/endian.h"
 #include "absl/base/internal/invoke.h"
+#include "absl/base/optimization.h"
 #include "absl/container/internal/compressed_tuple.h"
 #include "absl/meta/type_traits.h"
 #include "absl/strings/string_view.h"
@@ -30,17 +33,55 @@
 ABSL_NAMESPACE_BEGIN
 namespace cord_internal {
 
+class CordzInfo;
+
+// Default feature enable states for cord ring buffers
+enum CordFeatureDefaults {
+  kCordEnableRingBufferDefault = false,
+  kCordShallowSubcordsDefault = false
+};
+
+extern std::atomic<bool> cord_ring_buffer_enabled;
+extern std::atomic<bool> shallow_subcords_enabled;
+
+inline void enable_cord_ring_buffer(bool enable) {
+  cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed);
+}
+
+inline void enable_shallow_subcords(bool enable) {
+  shallow_subcords_enabled.store(enable, std::memory_order_relaxed);
+}
+
+enum Constants {
+  // The inlined size to use with absl::InlinedVector.
+  //
+  // Note: The InlinedVectors in this file (and in cord.h) do not need to use
+  // the same value for their inlined size. The fact that they do is historical.
+  // It may be desirable for each to use a different inlined size optimized for
+  // that InlinedVector's usage.
+  //
+  // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+  // the inlined vector size (47 exists for backward compatibility).
+  kInlinedVectorSize = 47,
+
+  // Prefer copying blocks of at most this size, otherwise reference count.
+  kMaxBytesToCopy = 511
+};
+
 // Wraps std::atomic for reference counting.
 class Refcount {
  public:
-  Refcount() : count_{1} {}
-  ~Refcount() {}
+  constexpr Refcount() : count_{kRefIncrement} {}
+  struct Immortal {};
+  explicit constexpr Refcount(Immortal) : count_(kImmortalTag) {}
 
-  // Increments the reference count by 1. Imposes no memory ordering.
-  inline void Increment() { count_.fetch_add(1, std::memory_order_relaxed); }
+  // Increments the reference count. Imposes no memory ordering.
+  inline void Increment() {
+    count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
+  }
 
   // Asserts that the current refcount is greater than 0. If the refcount is
-  // greater than 1, decrements the reference count by 1.
+  // greater than 1, decrements the reference count.
   //
   // Returns false if there are no references outstanding; true otherwise.
   // Inserts barriers to ensure that state written before this method returns
@@ -48,19 +89,24 @@
   // false.
   inline bool Decrement() {
     int32_t refcount = count_.load(std::memory_order_acquire);
-    assert(refcount > 0);
-    return refcount != 1 && count_.fetch_sub(1, std::memory_order_acq_rel) != 1;
+    assert(refcount > 0 || refcount & kImmortalTag);
+    return refcount != kRefIncrement &&
+           count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) !=
+               kRefIncrement;
   }
 
   // Same as Decrement but expect that refcount is greater than 1.
   inline bool DecrementExpectHighRefcount() {
-    int32_t refcount = count_.fetch_sub(1, std::memory_order_acq_rel);
-    assert(refcount > 0);
-    return refcount != 1;
+    int32_t refcount =
+        count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel);
+    assert(refcount > 0 || refcount & kImmortalTag);
+    return refcount != kRefIncrement;
   }
 
   // Returns the current reference count using acquire semantics.
-  inline int32_t Get() const { return count_.load(std::memory_order_acquire); }
+  inline int32_t Get() const {
+    return count_.load(std::memory_order_acquire) >> kImmortalShift;
+  }
 
   // Returns whether the atomic integer is 1.
   // If the reference count is used in the conventional way, a
@@ -70,9 +116,27 @@
   // performs the memory barrier needed for the owning thread
   // to act on the object, knowing that it has exclusive access to the
   // object.
-  inline bool IsOne() { return count_.load(std::memory_order_acquire) == 1; }
+  inline bool IsOne() {
+    return count_.load(std::memory_order_acquire) == kRefIncrement;
+  }
+
+  bool IsImmortal() const {
+    return (count_.load(std::memory_order_relaxed) & kImmortalTag) != 0;
+  }
 
  private:
+  // We reserve the bottom bit to tag a reference count as immortal.
+  // By making it `1` we ensure that we never reach `0` when adding/subtracting
+  // `2`, thus it never looks as if it should be destroyed.
+  // These are used for the StringConstant constructor where we do not increase
+  // the refcount at construction time (due to constinit requirements) but we
+  // will still decrease it at destruction time to avoid branching on Unref.
+  enum {
+    kImmortalShift = 1,
+    kRefIncrement = 1 << kImmortalShift,
+    kImmortalTag = kRefIncrement - 1
+  };
+
   std::atomic<int32_t> count_;
 };
 
@@ -82,10 +146,33 @@
 // functions in the base class.
 
 struct CordRepConcat;
-struct CordRepSubstring;
 struct CordRepExternal;
+struct CordRepFlat;
+struct CordRepSubstring;
+class CordRepRing;
+
+// Various representations that we allow
+enum CordRepKind {
+  CONCAT = 0,
+  EXTERNAL = 1,
+  SUBSTRING = 2,
+  RING = 3,
+
+  // We have different tags for different sized flat arrays,
+  // starting with FLAT, and limited to MAX_FLAT_TAG. The 224 value is based on
+  // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed
+  // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well
+  // as the Tag <---> Size logic so that FLAT stil represents the minimum flat
+  // allocation size. (32 bytes as of now).
+  FLAT = 4,
+  MAX_FLAT_TAG = 224
+};
 
 struct CordRep {
+  CordRep() = default;
+  constexpr CordRep(Refcount::Immortal immortal, size_t l)
+      : length(l), refcount(immortal), tag(EXTERNAL), storage{} {}
+
   // The following three fields have to be less than 32 bytes since
   // that is the smallest supported flat node size.
   size_t length;
@@ -93,22 +180,40 @@
   // If tag < FLAT, it represents CordRepKind and indicates the type of node.
   // Otherwise, the node type is CordRepFlat and the tag is the encoded size.
   uint8_t tag;
-  char data[1];  // Starting point for flat array: MUST BE LAST FIELD of CordRep
+  char storage[1];  // Starting point for flat array: MUST BE LAST FIELD
 
+  inline CordRepRing* ring();
+  inline const CordRepRing* ring() const;
   inline CordRepConcat* concat();
   inline const CordRepConcat* concat() const;
   inline CordRepSubstring* substring();
   inline const CordRepSubstring* substring() const;
   inline CordRepExternal* external();
   inline const CordRepExternal* external() const;
+  inline CordRepFlat* flat();
+  inline const CordRepFlat* flat() const;
+
+  // --------------------------------------------------------------------
+  // Memory management
+
+  // Destroys the provided `rep`.
+  static void Destroy(CordRep* rep);
+
+  // Increments the reference count of `rep`.
+  // Requires `rep` to be a non-null pointer value.
+  static inline CordRep* Ref(CordRep* rep);
+
+  // Decrements the reference count of `rep`. Destroys rep if count reaches
+  // zero. Requires `rep` to be a non-null pointer value.
+  static inline void Unref(CordRep* rep);
 };
 
 struct CordRepConcat : public CordRep {
   CordRep* left;
   CordRep* right;
 
-  uint8_t depth() const { return static_cast<uint8_t>(data[0]); }
-  void set_depth(uint8_t depth) { data[0] = static_cast<char>(depth); }
+  uint8_t depth() const { return static_cast<uint8_t>(storage[0]); }
+  void set_depth(uint8_t depth) { storage[0] = static_cast<char>(depth); }
 };
 
 struct CordRepSubstring : public CordRep {
@@ -124,9 +229,19 @@
 // External CordReps are allocated together with a type erased releaser. The
 // releaser is stored in the memory directly following the CordRepExternal.
 struct CordRepExternal : public CordRep {
+  CordRepExternal() = default;
+  explicit constexpr CordRepExternal(absl::string_view str)
+      : CordRep(Refcount::Immortal{}, str.size()),
+        base(str.data()),
+        releaser_invoker(nullptr) {}
+
   const char* base;
   // Pointer to function that knows how to call and destroy the releaser.
   ExternalReleaserInvoker releaser_invoker;
+
+  // Deletes (releases) the external rep.
+  // Requires rep != nullptr and rep->tag == EXTERNAL
+  static void Delete(CordRep* rep);
 };
 
 struct Rank1 {};
@@ -167,7 +282,262 @@
   }
 };
 
+inline void CordRepExternal::Delete(CordRep* rep) {
+  assert(rep != nullptr && rep->tag == EXTERNAL);
+  auto* rep_external = static_cast<CordRepExternal*>(rep);
+  assert(rep_external->releaser_invoker != nullptr);
+  rep_external->releaser_invoker(rep_external);
+}
+
+template <typename Str>
+struct ConstInitExternalStorage {
+  ABSL_CONST_INIT static CordRepExternal value;
+};
+
+template <typename Str>
+CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
+
+enum {
+  kMaxInline = 15,
+};
+
+constexpr char GetOrNull(absl::string_view data, size_t pos) {
+  return pos < data.size() ? data[pos] : '\0';
+}
+
+// We store cordz_info as 64 bit pointer value in big endian format. This
+// guarantees that the least significant byte of cordz_info matches the last
+// byte of the inline data representation in as_chars_, which holds the inlined
+// size or the 'is_tree' bit.
+using cordz_info_t = int64_t;
+
+// Assert that the `cordz_info` pointer value perfectly overlaps the last half
+// of `as_chars_` and can hold a pointer value.
+static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
+static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
+
+// BigEndianByte() creates a big endian representation of 'value', i.e.: a big
+// endian value where the last byte in the host's representation holds 'value`,
+// with all other bytes being 0.
+static constexpr cordz_info_t BigEndianByte(unsigned char value) {
+#if defined(ABSL_IS_BIG_ENDIAN)
+  return value;
+#else
+  return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8);
+#endif
+}
+
+class InlineData {
+ public:
+  // kNullCordzInfo holds the big endian representation of intptr_t(1)
+  // This is the 'null' / initial value of 'cordz_info'. The null value
+  // is specifically big endian 1 as with 64-bit pointers, the last
+  // byte of cordz_info overlaps with the last byte holding the tag.
+  static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1);
+
+  // kFakeCordzInfo holds a 'fake', non-null cordz-info value we use to
+  // emulate the previous 'kProfiled' tag logic in 'set_profiled' until
+  // cord code is changed to store cordz_info values in InlineData.
+  static constexpr cordz_info_t kFakeCordzInfo = BigEndianByte(9);
+
+  constexpr InlineData() : as_chars_{0} {}
+  explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {}
+  explicit constexpr InlineData(absl::string_view chars)
+      : as_chars_{
+            GetOrNull(chars, 0),  GetOrNull(chars, 1),
+            GetOrNull(chars, 2),  GetOrNull(chars, 3),
+            GetOrNull(chars, 4),  GetOrNull(chars, 5),
+            GetOrNull(chars, 6),  GetOrNull(chars, 7),
+            GetOrNull(chars, 8),  GetOrNull(chars, 9),
+            GetOrNull(chars, 10), GetOrNull(chars, 11),
+            GetOrNull(chars, 12), GetOrNull(chars, 13),
+            GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {}
+
+  // Returns true if the current instance is empty.
+  // The 'empty value' is an inlined data value of zero length.
+  bool is_empty() const { return tag() == 0; }
+
+  // Returns true if the current instance holds a tree value.
+  bool is_tree() const { return (tag() & 1) != 0; }
+
+  // Returns true if the current instance holds a cordz_info value.
+  // Requires the current instance to hold a tree value.
+  bool is_profiled() const {
+    assert(is_tree());
+    return as_tree_.cordz_info != kNullCordzInfo;
+  }
+
+  // Returns the cordz_info sampling instance for this instance, or nullptr
+  // if the current instance is not sampled and does not have CordzInfo data.
+  // Requires the current instance to hold a tree value.
+  CordzInfo* cordz_info() const {
+    assert(is_tree());
+    intptr_t info =
+        static_cast<intptr_t>(absl::big_endian::ToHost64(as_tree_.cordz_info));
+    assert(info & 1);
+    return reinterpret_cast<CordzInfo*>(info - 1);
+  }
+
+  // Sets the current cordz_info sampling instance for this instance, or nullptr
+  // if the current instance is not sampled and does not have CordzInfo data.
+  // Requires the current instance to hold a tree value.
+  void set_cordz_info(CordzInfo* cordz_info) {
+    assert(is_tree());
+    intptr_t info = reinterpret_cast<intptr_t>(cordz_info) | 1;
+    as_tree_.cordz_info = absl::big_endian::FromHost64(info);
+  }
+
+  // Resets the current cordz_info to null / empty.
+  void clear_cordz_info() {
+    assert(is_tree());
+    as_tree_.cordz_info = kNullCordzInfo;
+  }
+
+  // Returns a read only pointer to the character data inside this instance.
+  // Requires the current instance to hold inline data.
+  const char* as_chars() const {
+    assert(!is_tree());
+    return as_chars_;
+  }
+
+  // Returns a mutable pointer to the character data inside this instance.
+  // Should be used for 'write only' operations setting an inlined value.
+  // Applications can set the value of inlined data either before or after
+  // setting the inlined size, i.e., both of the below are valid:
+  //
+  //   // Set inlined data and inline size
+  //   memcpy(data_.as_chars(), data, size);
+  //   data_.set_inline_size(size);
+  //
+  //   // Set inlined size and inline data
+  //   data_.set_inline_size(size);
+  //   memcpy(data_.as_chars(), data, size);
+  //
+  // It's an error to read from the returned pointer without a preceding write
+  // if the current instance does not hold inline data, i.e.: is_tree() == true.
+  char* as_chars() { return as_chars_; }
+
+  // Returns the tree value of this value.
+  // Requires the current instance to hold a tree value.
+  CordRep* as_tree() const {
+    assert(is_tree());
+    return as_tree_.rep;
+  }
+
+  // Initialize this instance to holding the tree value `rep`,
+  // initializing the cordz_info to null, i.e.: 'not profiled'.
+  void make_tree(CordRep* rep) {
+    as_tree_.rep = rep;
+    as_tree_.cordz_info = kNullCordzInfo;
+  }
+
+  // Set the tree value of this instance to 'rep`.
+  // Requires the current instance to already hold a tree value.
+  // Does not affect the value of cordz_info.
+  void set_tree(CordRep* rep) {
+    assert(is_tree());
+    as_tree_.rep = rep;
+  }
+
+  // Returns the size of the inlined character data inside this instance.
+  // Requires the current instance to hold inline data.
+  size_t inline_size() const {
+    assert(!is_tree());
+    return tag() >> 1;
+  }
+
+  // Sets the size of the inlined character data inside this instance.
+  // Requires `size` to be <= kMaxInline.
+  // See the documentation on 'as_chars()' for more information and examples.
+  void set_inline_size(size_t size) {
+    ABSL_ASSERT(size <= kMaxInline);
+    tag() = static_cast<char>(size << 1);
+  }
+
+  // Sets or unsets the 'is_profiled' state of this instance.
+  // Requires the current instance to hold a tree value.
+  void set_profiled(bool profiled) {
+    assert(is_tree());
+    as_tree_.cordz_info = profiled ? kFakeCordzInfo : kNullCordzInfo;
+  }
+
+ private:
+  // See cordz_info_t for forced alignment and size of `cordz_info` details.
+  struct AsTree {
+    explicit constexpr AsTree(absl::cord_internal::CordRep* tree)
+        : rep(tree), cordz_info(kNullCordzInfo) {}
+    // This union uses up extra space so that whether rep is 32 or 64 bits,
+    // cordz_info will still start at the eighth byte, and the last
+    // byte of cordz_info will still be the last byte of InlineData.
+    union {
+      absl::cord_internal::CordRep* rep;
+      cordz_info_t unused_aligner;
+    };
+    cordz_info_t cordz_info;
+  };
+
+  char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; }
+  char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; }
+
+  // If the data has length <= kMaxInline, we store it in `as_chars_`, and
+  // store the size in the last char of `as_chars_` shifted left + 1.
+  // Else we store it in a tree and store a pointer to that tree in
+  // `as_tree_.rep` and store a tag in `tagged_size`.
+  union  {
+    char as_chars_[kMaxInline + 1];
+    AsTree as_tree_;
+  };
+};
+
+static_assert(sizeof(InlineData) == kMaxInline + 1, "");
+
+inline CordRepConcat* CordRep::concat() {
+  assert(tag == CONCAT);
+  return static_cast<CordRepConcat*>(this);
+}
+
+inline const CordRepConcat* CordRep::concat() const {
+  assert(tag == CONCAT);
+  return static_cast<const CordRepConcat*>(this);
+}
+
+inline CordRepSubstring* CordRep::substring() {
+  assert(tag == SUBSTRING);
+  return static_cast<CordRepSubstring*>(this);
+}
+
+inline const CordRepSubstring* CordRep::substring() const {
+  assert(tag == SUBSTRING);
+  return static_cast<const CordRepSubstring*>(this);
+}
+
+inline CordRepExternal* CordRep::external() {
+  assert(tag == EXTERNAL);
+  return static_cast<CordRepExternal*>(this);
+}
+
+inline const CordRepExternal* CordRep::external() const {
+  assert(tag == EXTERNAL);
+  return static_cast<const CordRepExternal*>(this);
+}
+
+inline CordRep* CordRep::Ref(CordRep* rep) {
+  assert(rep != nullptr);
+  rep->refcount.Increment();
+  return rep;
+}
+
+inline void CordRep::Unref(CordRep* rep) {
+  assert(rep != nullptr);
+  // Expect refcount to be 0. Avoiding the cost of an atomic decrement should
+  // typically outweigh the cost of an extra branch checking for ref == 1.
+  if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) {
+    Destroy(rep);
+  }
+}
+
 }  // namespace cord_internal
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 #endif  // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h
new file mode 100644
index 0000000..a98aa9d
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h
@@ -0,0 +1,146 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+#include "absl/strings/internal/cord_internal.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// Note: all constants below are never ODR used and internal to cord, we define
+// these as static constexpr to avoid 'in struct' definition and usage clutter.
+
+// Largest and smallest flat node lengths we are willing to allocate
+// Flat allocation size is stored in tag, which currently can encode sizes up
+// to 4K, encoded as multiple of either 8 or 32 bytes.
+// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc.
+// kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and
+// ideally a 'nice' size aligning with allocation and cacheline sizes like 32.
+// kMaxFlatSize is bounded by the size resulting in a computed tag no greater
+// than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values.
+static constexpr size_t kFlatOverhead = offsetof(CordRep, storage);
+static constexpr size_t kMinFlatSize = 32;
+static constexpr size_t kMaxFlatSize = 4096;
+static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
+static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
+
+constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) {
+  return static_cast<uint8_t>((size <= 1024) ? size / 8
+                                             : 128 + size / 32 - 1024 / 32);
+}
+
+static_assert(kMinFlatSize / 8 >= FLAT, "");
+static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, "");
+
+// Helper functions for rounded div, and rounding to exact sizes.
+constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
+constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
+
+// Returns the size to the nearest equal or larger value that can be
+// expressed exactly as a tag value.
+inline size_t RoundUpForTag(size_t size) {
+  return RoundUp(size, (size <= 1024) ? 8 : 32);
+}
+
+// Converts the allocated size to a tag, rounding down if the size
+// does not exactly match a 'tag expressible' size value. The result is
+// undefined if the size exceeds the maximum size that can be encoded in
+// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
+inline uint8_t AllocatedSizeToTag(size_t size) {
+  const uint8_t tag = AllocatedSizeToTagUnchecked(size);
+  assert(tag <= MAX_FLAT_TAG);
+  return tag;
+}
+
+// Converts the provided tag to the corresponding allocated size
+constexpr size_t TagToAllocatedSize(uint8_t tag) {
+  return (tag <= 128) ? (tag * 8) : (1024 + (tag - 128) * 32);
+}
+
+// Converts the provided tag to the corresponding available data length
+constexpr size_t TagToLength(uint8_t tag) {
+  return TagToAllocatedSize(tag) - kFlatOverhead;
+}
+
+// Enforce that kMaxFlatSize maps to a well-known exact tag value.
+static_assert(TagToAllocatedSize(224) == kMaxFlatSize, "Bad tag logic");
+
+struct CordRepFlat : public CordRep {
+  // Creates a new flat node.
+  static CordRepFlat* New(size_t len) {
+    if (len <= kMinFlatLength) {
+      len = kMinFlatLength;
+    } else if (len > kMaxFlatLength) {
+      len = kMaxFlatLength;
+    }
+
+    // Round size up so it matches a size we can exactly express in a tag.
+    const size_t size = RoundUpForTag(len + kFlatOverhead);
+    void* const raw_rep = ::operator new(size);
+    CordRepFlat* rep = new (raw_rep) CordRepFlat();
+    rep->tag = AllocatedSizeToTag(size);
+    return rep;
+  }
+
+  // Deletes a CordRepFlat instance created previously through a call to New().
+  // Flat CordReps are allocated and constructed with raw ::operator new and
+  // placement new, and must be destructed and deallocated accordingly.
+  static void Delete(CordRep*rep) {
+    assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG);
+
+#if defined(__cpp_sized_deallocation)
+    size_t size = TagToAllocatedSize(rep->tag);
+    rep->~CordRep();
+    ::operator delete(rep, size);
+#else
+    rep->~CordRep();
+    ::operator delete(rep);
+#endif
+  }
+
+  // Returns a pointer to the data inside this flat rep.
+  char* Data() { return storage; }
+  const char* Data() const { return storage; }
+
+  // Returns the maximum capacity (payload size) of this instance.
+  size_t Capacity() const { return TagToLength(tag); }
+
+  // Returns the allocated size (payload + overhead) of this instance.
+  size_t AllocatedSize() const { return TagToAllocatedSize(tag); }
+};
+
+// Now that CordRepFlat is defined, we can define CordRep's helper casts:
+inline CordRepFlat* CordRep::flat() {
+  assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+  return reinterpret_cast<CordRepFlat*>(this);
+}
+
+inline const CordRepFlat* CordRep::flat() const {
+  assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+  return reinterpret_cast<const CordRepFlat*>(this);
+}
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc
new file mode 100644
index 0000000..4d31d1d
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc
@@ -0,0 +1,897 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 "absl/strings/internal/cord_rep_ring.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iostream>
+#include <limits>
+#include <memory>
+#include <string>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// See https://bugs.llvm.org/show_bug.cgi?id=48477
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wshadow"
+#if __has_warning("-Wshadow-field")
+#pragma clang diagnostic ignored "-Wshadow-field"
+#endif
+#endif
+
+namespace {
+
+using index_type = CordRepRing::index_type;
+
+enum class Direction { kForward, kReversed };
+
+inline bool IsFlatOrExternal(CordRep* rep) {
+  return rep->tag >= FLAT || rep->tag == EXTERNAL;
+}
+
+// Verifies that n + extra <= kMaxCapacity: throws std::length_error otherwise.
+inline void CheckCapacity(size_t n, size_t extra) {
+  if (ABSL_PREDICT_FALSE(extra > CordRepRing::kMaxCapacity - n)) {
+    base_internal::ThrowStdLengthError("Maximum capacity exceeded");
+  }
+}
+
+// Removes a reference from `rep` only.
+// Asserts that the refcount after decrement is not zero.
+inline bool UnrefNeverOne(CordRep* rep) {
+  bool result = rep->refcount.Decrement();
+  assert(result);
+  return result;
+}
+
+// Creates a flat from the provided string data, allocating up to `extra`
+// capacity in the returned flat depending on kMaxFlatLength limitations.
+// Requires `len` to be less or equal to `kMaxFlatLength`
+CordRepFlat* CreateFlat(const char* s, size_t n, size_t extra = 0) {  // NOLINT
+  assert(n <= kMaxFlatLength);
+  auto* rep = CordRepFlat::New(n + extra);
+  rep->length = n;
+  memcpy(rep->Data(), s, n);
+  return rep;
+}
+
+// Unrefs the provided `substring`, and returns `substring->child`
+// Adds or assumes a reference on `substring->child`
+CordRep* ClipSubstring(CordRepSubstring* substring) {
+  CordRep* child = substring->child;
+  if (substring->refcount.IsOne()) {
+    delete substring;
+  } else {
+    CordRep::Ref(child);
+    if (ABSL_PREDICT_FALSE(!substring->refcount.Decrement())) {
+      UnrefNeverOne(child);
+      delete substring;
+    }
+  }
+  return child;
+}
+
+// Unrefs the provided `concat`, and returns `{concat->left, concat->right}`
+// Adds or assumes a reference on `concat->left` and `concat->right`.
+std::pair<CordRep*, CordRep*> ClipConcat(CordRepConcat* concat) {
+  auto result = std::make_pair(concat->left, concat->right);
+  if (concat->refcount.IsOne()) {
+    delete concat;
+  } else {
+    CordRep::Ref(result.first);
+    CordRep::Ref(result.second);
+    if (ABSL_PREDICT_FALSE(!concat->refcount.Decrement())) {
+      UnrefNeverOne(result.first);
+      UnrefNeverOne(result.second);
+      delete concat;
+    }
+  }
+  return result;
+}
+
+// Unrefs the entries in `[head, tail)`.
+// Requires all entries to be a FLAT or EXTERNAL node.
+void UnrefEntries(const CordRepRing* rep, index_type head, index_type tail) {
+  rep->ForEach(head, tail, [rep](index_type ix) {
+    CordRep* child = rep->entry_child(ix);
+    if (!child->refcount.Decrement()) {
+      if (child->tag >= FLAT) {
+        CordRepFlat::Delete(child->flat());
+      } else {
+        CordRepExternal::Delete(child->external());
+      }
+    }
+  });
+}
+
+template <typename F>
+void Consume(Direction direction, CordRep* rep, F&& fn) {
+  size_t offset = 0;
+  size_t length = rep->length;
+  struct Entry {
+    CordRep* rep;
+    size_t offset;
+    size_t length;
+  };
+  absl::InlinedVector<Entry, 40> stack;
+
+  for (;;) {
+    if (rep->tag >= FLAT || rep->tag == EXTERNAL || rep->tag == RING) {
+      fn(rep, offset, length);
+      if (stack.empty()) return;
+
+      rep = stack.back().rep;
+      offset = stack.back().offset;
+      length = stack.back().length;
+      stack.pop_back();
+    } else if (rep->tag == SUBSTRING) {
+      offset += rep->substring()->start;
+      rep = ClipSubstring(rep->substring());
+    } else if (rep->tag == CONCAT) {
+      auto res = ClipConcat(rep->concat());
+      CordRep* left = res.first;
+      CordRep* right = res.second;
+
+      if (left->length <= offset) {
+        // Don't need left node
+        offset -= left->length;
+        CordRep::Unref(left);
+        rep = right;
+        continue;
+      }
+
+      size_t length_left = left->length - offset;
+      if (length_left >= length) {
+        // Don't need right node
+        CordRep::Unref(right);
+        rep = left;
+        continue;
+      }
+
+      // Need both nodes
+      size_t length_right = length - length_left;
+      if (direction == Direction::kReversed) {
+        stack.push_back({left, offset, length_left});
+        rep = right;
+        offset = 0;
+        length = length_right;
+      } else {
+        stack.push_back({right, 0, length_right});
+        rep = left;
+        length = length_left;
+      }
+    } else {
+      assert("Valid tag" == nullptr);
+      return;
+    }
+  }
+}
+
+template <typename F>
+void Consume(CordRep* rep, F&& fn) {
+  return Consume(Direction::kForward, rep, std::forward<F>(fn));
+}
+
+template <typename F>
+void RConsume(CordRep* rep, F&& fn) {
+  return Consume(Direction::kReversed, rep, std::forward<F>(fn));
+}
+
+}  // namespace
+
+std::ostream& operator<<(std::ostream& s, const CordRepRing& rep) {
+  // Note: 'pos' values are defined as size_t (for overflow reasons), but that
+  // prints really awkward for small prepended values such as -5. ssize_t is not
+  // portable (POSIX), so we use ptrdiff_t instead to cast to signed values.
+  s << "  CordRepRing(" << &rep << ", length = " << rep.length
+    << ", head = " << rep.head_ << ", tail = " << rep.tail_
+    << ", cap = " << rep.capacity_ << ", rc = " << rep.refcount.Get()
+    << ", begin_pos_ = " << static_cast<ptrdiff_t>(rep.begin_pos_) << ") {\n";
+  CordRepRing::index_type head = rep.head();
+  do {
+    CordRep* child = rep.entry_child(head);
+    s << " entry[" << head << "] length = " << rep.entry_length(head)
+      << ", child " << child << ", clen = " << child->length
+      << ", tag = " << static_cast<int>(child->tag)
+      << ", rc = " << child->refcount.Get()
+      << ", offset = " << rep.entry_data_offset(head)
+      << ", end_pos = " << static_cast<ptrdiff_t>(rep.entry_end_pos(head))
+      << "\n";
+    head = rep.advance(head);
+  } while (head != rep.tail());
+  return s << "}\n";
+}
+
+void CordRepRing::AddDataOffset(index_type index, size_t n) {
+  entry_data_offset()[index] += static_cast<offset_type>(n);
+}
+
+void CordRepRing::SubLength(index_type index, size_t n) {
+  entry_end_pos()[index] -= n;
+}
+
+class CordRepRing::Filler {
+ public:
+  Filler(CordRepRing* rep, index_type pos) : rep_(rep), head_(pos), pos_(pos) {}
+
+  index_type head() const { return head_; }
+  index_type pos() const { return pos_; }
+
+  void Add(CordRep* child, size_t offset, pos_type end_pos) {
+    rep_->entry_end_pos()[pos_] = end_pos;
+    rep_->entry_child()[pos_] = child;
+    rep_->entry_data_offset()[pos_] = static_cast<offset_type>(offset);
+    pos_ = rep_->advance(pos_);
+  }
+
+ private:
+  CordRepRing* rep_;
+  index_type head_;
+  index_type pos_;
+};
+
+constexpr size_t CordRepRing::kMaxCapacity; // NOLINT: needed for c++11
+
+bool CordRepRing::IsValid(std::ostream& output) const {
+  if (capacity_ == 0) {
+    output << "capacity == 0";
+    return false;
+  }
+
+  if (head_ >= capacity_ || tail_ >= capacity_) {
+    output << "head " << head_ << " and/or tail " << tail_ << "exceed capacity "
+           << capacity_;
+    return false;
+  }
+
+  const index_type back = retreat(tail_);
+  size_t pos_length = Distance(begin_pos_, entry_end_pos(back));
+  if (pos_length != length) {
+    output << "length " << length << " does not match positional length "
+           << pos_length << " from begin_pos " << begin_pos_ << " and entry["
+           << back << "].end_pos " << entry_end_pos(back);
+    return false;
+  }
+
+  index_type head = head_;
+  pos_type begin_pos = begin_pos_;
+  do {
+    pos_type end_pos = entry_end_pos(head);
+    size_t entry_length = Distance(begin_pos, end_pos);
+    if (entry_length == 0) {
+      output << "entry[" << head << "] has an invalid length " << entry_length
+             << " from begin_pos " << begin_pos << " and end_pos " << end_pos;
+      return false;
+    }
+
+    CordRep* child = entry_child(head);
+    if (child == nullptr) {
+      output << "entry[" << head << "].child == nullptr";
+      return false;
+    }
+    if (child->tag < FLAT && child->tag != EXTERNAL) {
+      output << "entry[" << head << "].child has an invalid tag "
+             << static_cast<int>(child->tag);
+      return false;
+    }
+
+    size_t offset = entry_data_offset(head);
+    if (offset >= child->length || entry_length > child->length - offset) {
+      output << "entry[" << head << "] has offset " << offset
+             << " and entry length " << entry_length
+             << " which are outside of the childs length of " << child->length;
+      return false;
+    }
+
+    begin_pos = end_pos;
+    head = advance(head);
+  } while (head != tail_);
+
+  return true;
+}
+
+#ifdef EXTRA_CORD_RING_VALIDATION
+CordRepRing* CordRepRing::Validate(CordRepRing* rep, const char* file,
+                                   int line) {
+  if (!rep->IsValid(std::cerr)) {
+    std::cerr << "\nERROR: CordRepRing corrupted";
+    if (line) std::cerr << " at line " << line;
+    if (file) std::cerr << " in file " << file;
+    std::cerr << "\nContent = " << *rep;
+    abort();
+  }
+  return rep;
+}
+#endif  // EXTRA_CORD_RING_VALIDATION
+
+CordRepRing* CordRepRing::New(size_t capacity, size_t extra) {
+  CheckCapacity(capacity, extra);
+
+  size_t size = AllocSize(capacity += extra);
+  void* mem = ::operator new(size);
+  auto* rep = new (mem) CordRepRing(static_cast<index_type>(capacity));
+  rep->tag = RING;
+  rep->capacity_ = static_cast<index_type>(capacity);
+  rep->begin_pos_ = 0;
+  return rep;
+}
+
+void CordRepRing::SetCapacityForTesting(size_t capacity) {
+  // Adjust for the changed layout
+  assert(capacity <= capacity_);
+  assert(head() == 0 || head() < tail());
+  memmove(Layout::Partial(capacity).Pointer<1>(data_) + head(),
+          Layout::Partial(capacity_).Pointer<1>(data_) + head(),
+          entries() * sizeof(Layout::ElementType<1>));
+  memmove(Layout::Partial(capacity, capacity).Pointer<2>(data_) + head(),
+          Layout::Partial(capacity_, capacity_).Pointer<2>(data_) + head(),
+          entries() * sizeof(Layout::ElementType<2>));
+  capacity_ = static_cast<index_type>(capacity);
+}
+
+void CordRepRing::Delete(CordRepRing* rep) {
+  assert(rep != nullptr && rep->tag == RING);
+#if defined(__cpp_sized_deallocation)
+  size_t size = AllocSize(rep->capacity_);
+  rep->~CordRepRing();
+  ::operator delete(rep, size);
+#else
+  rep->~CordRepRing();
+  ::operator delete(rep);
+#endif
+}
+
+void CordRepRing::Destroy(CordRepRing* rep) {
+  UnrefEntries(rep, rep->head(), rep->tail());
+  Delete(rep);
+}
+
+template <bool ref>
+void CordRepRing::Fill(const CordRepRing* src, index_type head,
+                       index_type tail) {
+  this->length = src->length;
+  head_ = 0;
+  tail_ = advance(0, src->entries(head, tail));
+  begin_pos_ = src->begin_pos_;
+
+  // TODO(mvels): there may be opportunities here for large buffers.
+  auto* dst_pos = entry_end_pos();
+  auto* dst_child = entry_child();
+  auto* dst_offset = entry_data_offset();
+  src->ForEach(head, tail, [&](index_type index) {
+    *dst_pos++ = src->entry_end_pos(index);
+    CordRep* child = src->entry_child(index);
+    *dst_child++ = ref ? CordRep::Ref(child) : child;
+    *dst_offset++ = src->entry_data_offset(index);
+  });
+}
+
+CordRepRing* CordRepRing::Copy(CordRepRing* rep, index_type head,
+                               index_type tail, size_t extra) {
+  CordRepRing* newrep = CordRepRing::New(rep->entries(head, tail), extra);
+  newrep->Fill<true>(rep, head, tail);
+  CordRep::Unref(rep);
+  return newrep;
+}
+
+CordRepRing* CordRepRing::Mutable(CordRepRing* rep, size_t extra) {
+  // Get current number of entries, and check for max capacity.
+  size_t entries = rep->entries();
+
+  size_t min_extra = (std::max)(extra, rep->capacity() * 2 - entries);
+  if (!rep->refcount.IsOne()) {
+    return Copy(rep, rep->head(), rep->tail(), min_extra);
+  } else if (entries + extra > rep->capacity()) {
+    CordRepRing* newrep = CordRepRing::New(entries, min_extra);
+    newrep->Fill<false>(rep, rep->head(), rep->tail());
+    CordRepRing::Delete(rep);
+    return newrep;
+  } else {
+    return rep;
+  }
+}
+
+Span<char> CordRepRing::GetAppendBuffer(size_t size) {
+  assert(refcount.IsOne());
+  index_type back = retreat(tail_);
+  CordRep* child = entry_child(back);
+  if (child->tag >= FLAT && child->refcount.IsOne()) {
+    size_t capacity = child->flat()->Capacity();
+    pos_type end_pos = entry_end_pos(back);
+    size_t data_offset = entry_data_offset(back);
+    size_t entry_length = Distance(entry_begin_pos(back), end_pos);
+    size_t used = data_offset + entry_length;
+    if (size_t n = (std::min)(capacity - used, size)) {
+      child->length = data_offset + entry_length + n;
+      entry_end_pos()[back] = end_pos + n;
+      this->length += n;
+      return {child->flat()->Data() + used, n};
+    }
+  }
+  return {nullptr, 0};
+}
+
+Span<char> CordRepRing::GetPrependBuffer(size_t size) {
+  assert(refcount.IsOne());
+  CordRep* child = entry_child(head_);
+  size_t data_offset = entry_data_offset(head_);
+  if (data_offset && child->refcount.IsOne() && child->tag >= FLAT) {
+    size_t n = (std::min)(data_offset, size);
+    this->length += n;
+    begin_pos_ -= n;
+    data_offset -= n;
+    entry_data_offset()[head_] = static_cast<offset_type>(data_offset);
+    return {child->flat()->Data() + data_offset, n};
+  }
+  return {nullptr, 0};
+}
+
+CordRepRing* CordRepRing::CreateFromLeaf(CordRep* child, size_t offset,
+                                         size_t length, size_t extra) {
+  CordRepRing* rep = CordRepRing::New(1, extra);
+  rep->head_ = 0;
+  rep->tail_ = rep->advance(0);
+  rep->length = length;
+  rep->entry_end_pos()[0] = length;
+  rep->entry_child()[0] = child;
+  rep->entry_data_offset()[0] = static_cast<offset_type>(offset);
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::CreateSlow(CordRep* child, size_t extra) {
+  CordRepRing* rep = nullptr;
+  Consume(child, [&](CordRep* child, size_t offset, size_t length) {
+    if (IsFlatOrExternal(child)) {
+      rep = rep ? AppendLeaf(rep, child, offset, length)
+                : CreateFromLeaf(child, offset, length, extra);
+    } else if (rep) {
+      rep = AddRing<AddMode::kAppend>(rep, child->ring(), offset, length);
+    } else if (offset == 0 && child->length == length) {
+      rep = Mutable(child->ring(), extra);
+    } else {
+      rep = SubRing(child->ring(), offset, length, extra);
+    }
+  });
+  return Validate(rep, nullptr, __LINE__);
+}
+
+CordRepRing* CordRepRing::Create(CordRep* child, size_t extra) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return CreateFromLeaf(child, 0, length, extra);
+  }
+  if (child->tag == RING) {
+    return Mutable(child->ring(), extra);
+  }
+  return CreateSlow(child, extra);
+}
+
+template <CordRepRing::AddMode mode>
+CordRepRing* CordRepRing::AddRing(CordRepRing* rep, CordRepRing* ring,
+                                  size_t offset, size_t length) {
+  assert(offset < ring->length);
+  constexpr bool append = mode == AddMode::kAppend;
+  Position head = ring->Find(offset);
+  Position tail = ring->FindTail(head.index, offset + length);
+  const index_type entries = ring->entries(head.index, tail.index);
+
+  rep = Mutable(rep, entries);
+
+  // The delta for making ring[head].end_pos into 'len - offset'
+  const pos_type delta_length =
+      (append ? rep->begin_pos_ + rep->length : rep->begin_pos_ - length) -
+      ring->entry_begin_pos(head.index) - head.offset;
+
+  // Start filling at `tail`, or `entries` before `head`
+  Filler filler(rep, append ? rep->tail_ : rep->retreat(rep->head_, entries));
+
+  if (ring->refcount.IsOne()) {
+    // Copy entries from source stealing the ref and adjusting the end position.
+    // Commit the filler as this is no-op.
+    ring->ForEach(head.index, tail.index, [&](index_type ix) {
+      filler.Add(ring->entry_child(ix), ring->entry_data_offset(ix),
+                 ring->entry_end_pos(ix) + delta_length);
+    });
+
+    // Unref entries we did not copy over, and delete source.
+    if (head.index != ring->head_) UnrefEntries(ring, ring->head_, head.index);
+    if (tail.index != ring->tail_) UnrefEntries(ring, tail.index, ring->tail_);
+    CordRepRing::Delete(ring);
+  } else {
+    ring->ForEach(head.index, tail.index, [&](index_type ix) {
+      CordRep* child = ring->entry_child(ix);
+      filler.Add(child, ring->entry_data_offset(ix),
+                 ring->entry_end_pos(ix) + delta_length);
+      CordRep::Ref(child);
+    });
+    CordRepRing::Unref(ring);
+  }
+
+  if (head.offset) {
+    // Increase offset of first 'source' entry appended or prepended.
+    // This is always the entry in `filler.head()`
+    rep->AddDataOffset(filler.head(), head.offset);
+  }
+
+  if (tail.offset) {
+    // Reduce length of last 'source' entry appended or prepended.
+    // This is always the entry tailed by `filler.pos()`
+    rep->SubLength(rep->retreat(filler.pos()), tail.offset);
+  }
+
+  // Commit changes
+  rep->length += length;
+  if (append) {
+    rep->tail_ = filler.pos();
+  } else {
+    rep->head_ = filler.head();
+    rep->begin_pos_ -= length;
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::AppendSlow(CordRepRing* rep, CordRep* child) {
+  Consume(child, [&rep](CordRep* child, size_t offset, size_t length) {
+    if (child->tag == RING) {
+      rep = AddRing<AddMode::kAppend>(rep, child->ring(), offset, length);
+    } else {
+      rep = AppendLeaf(rep, child, offset, length);
+    }
+  });
+  return rep;
+}
+
+CordRepRing* CordRepRing::AppendLeaf(CordRepRing* rep, CordRep* child,
+                                     size_t offset, size_t length) {
+  rep = Mutable(rep, 1);
+  index_type back = rep->tail_;
+  const pos_type begin_pos = rep->begin_pos_ + rep->length;
+  rep->tail_ = rep->advance(rep->tail_);
+  rep->length += length;
+  rep->entry_end_pos()[back] = begin_pos + length;
+  rep->entry_child()[back] = child;
+  rep->entry_data_offset()[back] = static_cast<offset_type>(offset);
+  return Validate(rep, nullptr, __LINE__);
+}
+
+CordRepRing* CordRepRing::Append(CordRepRing* rep, CordRep* child) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return AppendLeaf(rep, child, 0, length);
+  }
+  if (child->tag == RING) {
+    return AddRing<AddMode::kAppend>(rep, child->ring(), 0, length);
+  }
+  return AppendSlow(rep, child);
+}
+
+CordRepRing* CordRepRing::PrependSlow(CordRepRing* rep, CordRep* child) {
+  RConsume(child, [&](CordRep* child, size_t offset, size_t length) {
+    if (IsFlatOrExternal(child)) {
+      rep = PrependLeaf(rep, child, offset, length);
+    } else {
+      rep = AddRing<AddMode::kPrepend>(rep, child->ring(), offset, length);
+    }
+  });
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::PrependLeaf(CordRepRing* rep, CordRep* child,
+                                      size_t offset, size_t length) {
+  rep = Mutable(rep, 1);
+  index_type head = rep->retreat(rep->head_);
+  pos_type end_pos = rep->begin_pos_;
+  rep->head_ = head;
+  rep->length += length;
+  rep->begin_pos_ -= length;
+  rep->entry_end_pos()[head] = end_pos;
+  rep->entry_child()[head] = child;
+  rep->entry_data_offset()[head] = static_cast<offset_type>(offset);
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::Prepend(CordRepRing* rep, CordRep* child) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return PrependLeaf(rep, child, 0, length);
+  }
+  if (child->tag == RING) {
+    return AddRing<AddMode::kPrepend>(rep, child->ring(), 0, length);
+  }
+  return PrependSlow(rep, child);
+}
+
+CordRepRing* CordRepRing::Append(CordRepRing* rep, absl::string_view data,
+                                 size_t extra) {
+  if (rep->refcount.IsOne()) {
+    Span<char> avail = rep->GetAppendBuffer(data.length());
+    if (!avail.empty()) {
+      memcpy(avail.data(), data.data(), avail.length());
+      data.remove_prefix(avail.length());
+    }
+  }
+  if (data.empty()) return Validate(rep);
+
+  const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
+  rep = Mutable(rep, flats);
+
+  Filler filler(rep, rep->tail_);
+  pos_type pos = rep->begin_pos_ + rep->length;
+
+  while (data.length() >= kMaxFlatLength) {
+    auto* flat = CreateFlat(data.data(), kMaxFlatLength);
+    filler.Add(flat, 0, pos += kMaxFlatLength);
+    data.remove_prefix(kMaxFlatLength);
+  }
+
+  if (data.length()) {
+    auto* flat = CreateFlat(data.data(), data.length(), extra);
+    filler.Add(flat, 0, pos += data.length());
+  }
+
+  rep->length = pos - rep->begin_pos_;
+  rep->tail_ = filler.pos();
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::Prepend(CordRepRing* rep, absl::string_view data,
+                                  size_t extra) {
+  if (rep->refcount.IsOne()) {
+    Span<char> avail = rep->GetPrependBuffer(data.length());
+    if (!avail.empty()) {
+      const char* tail = data.data() + data.length() - avail.length();
+      memcpy(avail.data(), tail, avail.length());
+      data.remove_suffix(avail.length());
+    }
+  }
+  if (data.empty()) return rep;
+
+  const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
+  rep = Mutable(rep, flats);
+  pos_type pos = rep->begin_pos_;
+  Filler filler(rep, rep->retreat(rep->head_, static_cast<index_type>(flats)));
+
+  size_t first_size = data.size() - (flats - 1) * kMaxFlatLength;
+  CordRepFlat* flat = CordRepFlat::New(first_size + extra);
+  flat->length = first_size + extra;
+  memcpy(flat->Data() + extra, data.data(), first_size);
+  data.remove_prefix(first_size);
+  filler.Add(flat, extra, pos);
+  pos -= first_size;
+
+  while (!data.empty()) {
+    assert(data.size() >= kMaxFlatLength);
+    flat = CreateFlat(data.data(), kMaxFlatLength);
+    filler.Add(flat, 0, pos);
+    pos -= kMaxFlatLength;
+    data.remove_prefix(kMaxFlatLength);
+  }
+
+  rep->head_ = filler.head();
+  rep->length += rep->begin_pos_ - pos;
+  rep->begin_pos_ = pos;
+
+  return Validate(rep);
+}
+
+// 32 entries is 32 * sizeof(pos_type) = 4 cache lines on x86
+static constexpr index_type kBinarySearchThreshold = 32;
+static constexpr index_type kBinarySearchEndCount = 8;
+
+template <bool wrap>
+CordRepRing::index_type CordRepRing::FindBinary(index_type head,
+                                                index_type tail,
+                                                size_t offset) const {
+  index_type count = tail + (wrap ? capacity_ : 0) - head;
+  do {
+    count = (count - 1) / 2;
+    assert(count < entries(head, tail_));
+    index_type mid = wrap ? advance(head, count) : head + count;
+    index_type after_mid = wrap ? advance(mid) : mid + 1;
+    bool larger = (offset >= entry_end_offset(mid));
+    head = larger ? after_mid : head;
+    tail = larger ? tail : mid;
+    assert(head != tail);
+  } while (ABSL_PREDICT_TRUE(count > kBinarySearchEndCount));
+  return head;
+}
+
+CordRepRing::Position CordRepRing::FindSlow(index_type head,
+                                            size_t offset) const {
+  index_type tail = tail_;
+
+  // Binary search until we are good for linear search
+  // Optimize for branchless / non wrapping ops
+  if (tail > head) {
+    index_type count = tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<false>(head, tail, offset);
+    }
+  } else {
+    index_type count = capacity_ + tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<true>(head, tail, offset);
+    }
+  }
+
+  pos_type pos = entry_begin_pos(head);
+  pos_type end_pos = entry_end_pos(head);
+  while (offset >= Distance(begin_pos_, end_pos)) {
+    head = advance(head);
+    pos = end_pos;
+    end_pos = entry_end_pos(head);
+  }
+
+  return {head, offset - Distance(begin_pos_, pos)};
+}
+
+CordRepRing::Position CordRepRing::FindTailSlow(index_type head,
+                                                size_t offset) const {
+  index_type tail = tail_;
+  const size_t tail_offset = offset - 1;
+
+  // Binary search until we are good for linear search
+  // Optimize for branchless / non wrapping ops
+  if (tail > head) {
+    index_type count = tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<false>(head, tail, tail_offset);
+    }
+  } else {
+    index_type count = capacity_ + tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<true>(head, tail, tail_offset);
+    }
+  }
+
+  size_t end_offset = entry_end_offset(head);
+  while (tail_offset >= end_offset) {
+    head = advance(head);
+    end_offset = entry_end_offset(head);
+  }
+
+  return {advance(head), end_offset - offset};
+}
+
+char CordRepRing::GetCharacter(size_t offset) const {
+  assert(offset < length);
+
+  Position pos = Find(offset);
+  size_t data_offset = entry_data_offset(pos.index) + pos.offset;
+  return GetRepData(entry_child(pos.index))[data_offset];
+}
+
+CordRepRing* CordRepRing::SubRing(CordRepRing* rep, size_t offset,
+                                  size_t length, size_t extra) {
+  assert(offset <= rep->length);
+  assert(offset <= rep->length - length);
+
+  if (length == 0) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  // Find position of first byte
+  Position head = rep->Find(offset);
+  Position tail = rep->FindTail(head.index, offset + length);
+  const size_t new_entries = rep->entries(head.index, tail.index);
+
+  if (rep->refcount.IsOne() && extra <= (rep->capacity() - new_entries)) {
+    // We adopt a privately owned rep and no extra entries needed.
+    if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
+    if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
+    rep->head_ = head.index;
+    rep->tail_ = tail.index;
+  } else {
+    // Copy subset to new rep
+    rep = Copy(rep, head.index, tail.index, extra);
+    head.index = rep->head_;
+    tail.index = rep->tail_;
+  }
+
+  // Adjust begin_pos and length
+  rep->length = length;
+  rep->begin_pos_ += offset;
+
+  // Adjust head and tail blocks
+  if (head.offset) {
+    rep->AddDataOffset(head.index, head.offset);
+  }
+  if (tail.offset) {
+    rep->SubLength(rep->retreat(tail.index), tail.offset);
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::RemovePrefix(CordRepRing* rep, size_t len,
+                                       size_t extra) {
+  assert(len <= rep->length);
+  if (len == rep->length) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  Position head = rep->Find(len);
+  if (rep->refcount.IsOne()) {
+    if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
+    rep->head_ = head.index;
+  } else {
+    rep = Copy(rep, head.index, rep->tail_, extra);
+    head.index = rep->head_;
+  }
+
+  // Adjust begin_pos and length
+  rep->length -= len;
+  rep->begin_pos_ += len;
+
+  // Adjust head block
+  if (head.offset) {
+    rep->AddDataOffset(head.index, head.offset);
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::RemoveSuffix(CordRepRing* rep, size_t len,
+                                       size_t extra) {
+  assert(len <= rep->length);
+
+  if (len == rep->length) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  Position tail = rep->FindTail(rep->length - len);
+  if (rep->refcount.IsOne()) {
+    // We adopt a privately owned rep, scrub.
+    if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
+    rep->tail_ = tail.index;
+  } else {
+    // Copy subset to new rep
+    rep = Copy(rep, rep->head_, tail.index, extra);
+    tail.index = rep->tail_;
+  }
+
+  // Adjust length
+  rep->length -= len;
+
+  // Adjust tail block
+  if (tail.offset) {
+    rep->SubLength(rep->retreat(tail.index), tail.offset);
+  }
+
+  return Validate(rep);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h
new file mode 100644
index 0000000..c74d335
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h
@@ -0,0 +1,589 @@
+// Copyright 2020 The Abseil 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
+//
+//     https://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 ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iosfwd>
+#include <limits>
+#include <memory>
+
+#include "absl/container/internal/layout.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// See https://bugs.llvm.org/show_bug.cgi?id=48477
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wshadow"
+#if __has_warning("-Wshadow-field")
+#pragma clang diagnostic ignored "-Wshadow-field"
+#endif
+#endif
+
+// All operations modifying a ring buffer are implemented as static methods
+// requiring a CordRepRing instance with a reference adopted by the method.
+//
+// The methods return the modified ring buffer, which may be equal to the input
+// if the input was not shared, and having large enough capacity to accommodate
+// any newly added node(s). Otherwise, a copy of the input rep with the new
+// node(s) added is returned.
+//
+// Any modification on non shared ring buffers with enough capacity will then
+// require minimum atomic operations. Caller should where possible provide
+// reasonable `extra` hints for both anticipated extra `flat` byte space, as
+// well as anticipated extra nodes required for complex operations.
+//
+// Example of code creating a ring buffer, adding some data to it,
+// and discarding the buffer when done:
+//
+//   void FunWithRings() {
+//     // Create ring with 3 flats
+//     CordRep* flat = CreateFlat("Hello");
+//     CordRepRing* ring = CordRepRing::Create(flat, 2);
+//     ring = CordRepRing::Append(ring, CreateFlat(" "));
+//     ring = CordRepRing::Append(ring, CreateFlat("world"));
+//     DoSomethingWithRing(ring);
+//     CordRep::Unref(ring);
+//   }
+//
+// Example of code Copying an existing ring buffer and modifying it:
+//
+//   void MoreFunWithRings(CordRepRing* src) {
+//     CordRepRing* ring = CordRep::Ref(src)->ring();
+//     ring = CordRepRing::Append(ring, CreateFlat("Hello"));
+//     ring = CordRepRing::Append(ring, CreateFlat(" "));
+//     ring = CordRepRing::Append(ring, CreateFlat("world"));
+//     DoSomethingWithRing(ring);
+//     CordRep::Unref(ring);
+//   }
+//
+class CordRepRing : public CordRep {
+ public:
+  // `pos_type` represents a 'logical position'. A CordRepRing instance has a
+  // `begin_pos` (default 0), and each node inside the buffer will have an
+  // `end_pos` which is the `end_pos` of the previous node (or `begin_pos`) plus
+  // this node's length. The purpose is to allow for a binary search on this
+  // position, while allowing O(1) prepend and append operations.
+  using pos_type = size_t;
+
+  // `index_type` is the type for the `head`, `tail` and `capacity` indexes.
+  // Ring buffers are limited to having no more than four billion entries.
+  using index_type = uint32_t;
+
+  // `offset_type` is the type for the data offset inside a child rep's data.
+  using offset_type = uint32_t;
+
+  // Position holds the node index and relative offset into the node for
+  // some physical offset in the contained data as returned by the Find()
+  // and FindTail() methods.
+  struct Position {
+    index_type index;
+    size_t offset;
+  };
+
+  // The maximum # of child nodes that can be hosted inside a CordRepRing.
+  static constexpr size_t kMaxCapacity = (std::numeric_limits<uint32_t>::max)();
+
+  // CordRepring can not be default constructed, moved, copied or assigned.
+  CordRepRing() = delete;
+  CordRepRing(const CordRepRing&) = delete;
+  CordRepRing& operator=(const CordRepRing&) = delete;
+
+  // Returns true if this instance is valid, false if some or all of the
+  // invariants are broken. Intended for debug purposes only.
+  // `output` receives an explanation of the broken invariants.
+  bool IsValid(std::ostream& output) const;
+
+  // Returns the size in bytes for a CordRepRing with `capacity' entries.
+  static constexpr size_t AllocSize(size_t capacity);
+
+  // Returns the distance in bytes from `pos` to `end_pos`.
+  static constexpr size_t Distance(pos_type pos, pos_type end_pos);
+
+  // Creates a new ring buffer from the provided `rep`. Adopts a reference
+  // on `rep`. The returned ring buffer has a capacity of at least `extra + 1`
+  static CordRepRing* Create(CordRep* child, size_t extra = 0);
+
+  // `head`, `tail` and `capacity` indexes defining the ring buffer boundaries.
+  index_type head() const { return head_; }
+  index_type tail() const { return tail_; }
+  index_type capacity() const { return capacity_; }
+
+  // Returns the number of entries in this instance.
+  index_type entries() const { return entries(head_, tail_); }
+
+  // Returns the logical begin position of this instance.
+  pos_type begin_pos() const { return begin_pos_; }
+
+  // Returns the number of entries for a given head-tail range.
+  // Requires `head` and `tail` values to be less than `capacity()`.
+  index_type entries(index_type head, index_type tail) const {
+    assert(head < capacity_ && tail < capacity_);
+    return tail - head + ((tail > head) ? 0 : capacity_);
+  }
+
+  // Returns the logical end position of entry `index`.
+  pos_type const& entry_end_pos(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial().Pointer<0>(data_)[index];
+  }
+
+  // Returns the child pointer of entry `index`.
+  CordRep* const& entry_child(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial(capacity()).Pointer<1>(data_)[index];
+  }
+
+  // Returns the data offset of entry `index`
+  offset_type const& entry_data_offset(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial(capacity(), capacity()).Pointer<2>(data_)[index];
+  }
+
+  // Appends the provided child node to the `rep` instance.
+  // Adopts a reference from `rep` and `child` which may not be null.
+  // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
+  // containing a FLAT or EXTERNAL node, then flat or external the node is added
+  // 'as is', with an offset added for the SUBSTRING case.
+  // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING or
+  // CONCAT tree, then all child nodes not excluded by any start offset or
+  // length values are added recursively.
+  static CordRepRing* Append(CordRepRing* rep, CordRep* child);
+
+  // Appends the provided string data to the `rep` instance.
+  // This function will attempt to utilize any remaining capacity in the last
+  // node of the input if that node is not shared (directly or indirectly), and
+  // of type FLAT. Remaining data will be added as one or more FLAT nodes.
+  // Any last node added to the ring buffer will be allocated with up to
+  // `extra` bytes of capacity for (anticipated) subsequent append actions.
+  static CordRepRing* Append(CordRepRing* rep, string_view data,
+                             size_t extra = 0);
+
+  // Prepends the provided child node to the `rep` instance.
+  // Adopts a reference from `rep` and `child` which may not be null.
+  // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
+  // containing a FLAT or EXTERNAL node, then flat or external the node is
+  // prepended 'as is', with an optional offset added for the SUBSTRING case.
+  // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING
+  // or CONCAT tree, then all child nodes not excluded by any start offset or
+  // length values are added recursively.
+  static CordRepRing* Prepend(CordRepRing* rep, CordRep* child);
+
+  // Prepends the provided string data to the `rep` instance.
+  // This function will attempt to utilize any remaining capacity in the first
+  // node of the input if that node is not shared (directly or indirectly), and
+  // of type FLAT. Remaining data will be added as one or more FLAT nodes.
+  // Any first node prepnded to the ring buffer will be allocated with up to
+  // `extra` bytes of capacity for (anticipated) subsequent prepend actions.
+  static CordRepRing* Prepend(CordRepRing* rep, string_view data,
+                              size_t extra = 0);
+
+  // Returns a span referencing potentially unused capacity in the last node.
+  // The returned span may be empty if no such capacity is available, or if the
+  // current instance is shared. Else, a span of size `n <= size` is returned.
+  // If non empty, the ring buffer is adjusted to the new length, with the newly
+  // added capacity left uninitialized. Callers should assign a value to the
+  // entire span before any other operations on this instance.
+  Span<char> GetAppendBuffer(size_t size);
+
+  // Returns a span referencing potentially unused capacity in the first node.
+  // This function is identical to GetAppendBuffer except that it returns a span
+  // referencing up to `size` capacity directly before the existing data.
+  Span<char> GetPrependBuffer(size_t size);
+
+  // Returns a cord ring buffer containing `length` bytes of data starting at
+  // `offset`. If the input is not shared, this function will remove all head
+  // and tail child nodes outside of the requested range, and adjust the new
+  // head and tail nodes as required. If the input is shared, this function
+  // returns a new instance sharing some or all of the nodes from the input.
+  static CordRepRing* SubRing(CordRepRing* r, size_t offset, size_t length,
+                              size_t extra = 0);
+
+  // Returns a cord ring buffer with the first `length` bytes removed.
+  // If the input is not shared, this function will remove all head child nodes
+  // fully inside the first `length` bytes, and adjust the new head as required.
+  // If the input is shared, this function returns a new instance sharing some
+  // or all of the nodes from the input.
+  static CordRepRing* RemoveSuffix(CordRepRing* r, size_t length,
+                                   size_t extra = 0);
+
+  // Returns a cord ring buffer with the last `length` bytes removed.
+  // If the input is not shared, this function will remove all head child nodes
+  // fully inside the first `length` bytes, and adjust the new head as required.
+  // If the input is shared, this function returns a new instance sharing some
+  // or all of the nodes from the input.
+  static CordRepRing* RemovePrefix(CordRepRing* r, size_t len,
+                                   size_t extra = 0);
+
+  // Returns the character at `offset`. Requires that `offset < length`.
+  char GetCharacter(size_t offset) const;
+
+  // Testing only: set capacity to requested capacity.
+  void SetCapacityForTesting(size_t capacity);
+
+  // Returns the CordRep data pointer for the provided CordRep.
+  // Requires that the provided `rep` is either a FLAT or EXTERNAL CordRep.
+  static const char* GetLeafData(const CordRep* rep);
+
+  // Returns the CordRep data pointer for the provided CordRep.
+  // Requires that `rep` is either a FLAT, EXTERNAL, or SUBSTRING CordRep.
+  static const char* GetRepData(const CordRep* rep);
+
+  // Advances the provided position, wrapping around capacity as needed.
+  // Requires `index` < capacity()
+  inline index_type advance(index_type index) const;
+
+  // Advances the provided position by 'n`, wrapping around capacity as needed.
+  // Requires `index` < capacity() and `n` <= capacity.
+  inline index_type advance(index_type index, index_type n) const;
+
+  // Retreats the provided position, wrapping around 0 as needed.
+  // Requires `index` < capacity()
+  inline index_type retreat(index_type index) const;
+
+  // Retreats the provided position by 'n', wrapping around 0 as needed.
+  // Requires `index` < capacity()
+  inline index_type retreat(index_type index, index_type n) const;
+
+  // Returns the logical begin position of entry `index`
+  pos_type const& entry_begin_pos(index_type index) const {
+    return (index == head_) ? begin_pos_ : entry_end_pos(retreat(index));
+  }
+
+  // Returns the physical start offset of entry `index`
+  size_t entry_start_offset(index_type index) const {
+    return Distance(begin_pos_, entry_begin_pos(index));
+  }
+
+  // Returns the physical end offset of entry `index`
+  size_t entry_end_offset(index_type index) const {
+    return Distance(begin_pos_, entry_end_pos(index));
+  }
+
+  // Returns the data length for entry `index`
+  size_t entry_length(index_type index) const {
+    return Distance(entry_begin_pos(index), entry_end_pos(index));
+  }
+
+  // Returns the data for entry `index`
+  absl::string_view entry_data(index_type index) const;
+
+  // Returns the position for `offset` as {index, prefix}. `index` holds the
+  // index of the entry at the specified offset and `prefix` holds the relative
+  // offset inside that entry.
+  // Requires `offset` < length.
+  //
+  // For example we can implement GetCharacter(offset) as:
+  //   char GetCharacter(size_t offset) {
+  //     Position pos = this->Find(offset);
+  //     return this->entry_data(pos.pos)[pos.offset];
+  //   }
+  inline Position Find(size_t offset) const;
+
+  // Find starting at `head`
+  inline Position Find(index_type head, size_t offset) const;
+
+  // Returns the tail position for `offset` as {tail index, suffix}.
+  // `tail index` holds holds the index of the entry holding the offset directly
+  // before 'offset` advanced by one. 'suffix` holds the relative offset from
+  // that relative offset in the entry to the end of the entry.
+  // For example, FindTail(length) will return {tail(), 0}, FindTail(length - 5)
+  // will return {retreat(tail), 5)} provided the preceding entry contains at
+  // least 5 bytes of data.
+  // Requires offset >= 1 && offset <= length.
+  //
+  // This function is very useful in functions that need to clip the end of some
+  // ring buffer such as 'RemovePrefix'.
+  // For example, we could implement RemovePrefix for non shared instances as:
+  //   void RemoveSuffix(size_t n) {
+  //     Position pos = FindTail(length - n);
+  //     UnrefEntries(pos.pos, this->tail_);
+  //     this->tail_ = pos.pos;
+  //     entry(retreat(pos.pos)).end_pos -= pos.offset;
+  //   }
+  inline Position FindTail(size_t offset) const;
+
+  // Find tail starting at `head`
+  inline Position FindTail(index_type head, size_t offset) const;
+
+  // Invokes f(index_type index) for each entry inside the range [head, tail>
+  template <typename F>
+  void ForEach(index_type head, index_type tail, F&& f) const {
+    index_type n1 = (tail > head) ? tail : capacity_;
+    for (index_type i = head; i < n1; ++i) f(i);
+    if (tail <= head) {
+      for (index_type i = 0; i < tail; ++i) f(i);
+    }
+  }
+
+  // Invokes f(index_type index) for each entry inside this instance.
+  template <typename F>
+  void ForEach(F&& f) const {
+    ForEach(head_, tail_, std::forward<F>(f));
+  }
+
+  // Dump this instance's data tp stream `s` in human readable format, excluding
+  // the actual data content itself. Intended for debug purposes only.
+  friend std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
+
+ private:
+  enum class AddMode { kAppend, kPrepend };
+
+  using Layout = container_internal::Layout<pos_type, CordRep*, offset_type>;
+
+  class Filler;
+  class Transaction;
+  class CreateTransaction;
+
+  static constexpr size_t kLayoutAlignment = Layout::Partial().Alignment();
+
+  // Creates a new CordRepRing.
+  explicit CordRepRing(index_type capacity) : capacity_(capacity) {}
+
+  // Returns true if `index` is a valid index into this instance.
+  bool IsValidIndex(index_type index) const;
+
+  // Debug use only: validates the provided CordRepRing invariants.
+  // Verification of all CordRepRing methods can be enabled by defining
+  // EXTRA_CORD_RING_VALIDATION, i.e.: `--copts=-DEXTRA_CORD_RING_VALIDATION`
+  // Verification is VERY expensive, so only do it for debugging purposes.
+  static CordRepRing* Validate(CordRepRing* rep, const char* file = nullptr,
+                               int line = 0);
+
+  // Allocates a CordRepRing large enough to hold `capacity + extra' entries.
+  // The returned capacity may be larger if the allocated memory allows for it.
+  // The maximum capacity of a CordRepRing is capped at kMaxCapacity.
+  // Throws `std::length_error` if `capacity + extra' exceeds kMaxCapacity.
+  static CordRepRing* New(size_t capacity, size_t extra);
+
+  // Deallocates (but does not destroy) the provided ring buffer.
+  static void Delete(CordRepRing* rep);
+
+  // Destroys the provided ring buffer, decrementing the reference count of all
+  // contained child CordReps. The provided 1\`rep` should have a ref count of
+  // one (pre decrement destroy call observing `refcount.IsOne()`) or zero (post
+  // decrement destroy call observing `!refcount.Decrement()`).
+  static void Destroy(CordRepRing* rep);
+
+  // Returns a mutable reference to the logical end position array.
+  pos_type* entry_end_pos() {
+    return Layout::Partial().Pointer<0>(data_);
+  }
+
+  // Returns a mutable reference to the child pointer array.
+  CordRep** entry_child() {
+    return Layout::Partial(capacity()).Pointer<1>(data_);
+  }
+
+  // Returns a mutable reference to the data offset array.
+  offset_type* entry_data_offset() {
+    return Layout::Partial(capacity(), capacity()).Pointer<2>(data_);
+  }
+
+  // Find implementations for the non fast path 0 / length cases.
+  Position FindSlow(index_type head, size_t offset) const;
+  Position FindTailSlow(index_type head, size_t offset) const;
+
+  // Finds the index of the first node that is inside a reasonable distance
+  // of the node at `offset` from which we can continue with a linear search.
+  template <bool wrap>
+  index_type FindBinary(index_type head, index_type tail, size_t offset) const;
+
+  // Fills the current (initialized) instance from the provided source, copying
+  // entries [head, tail). Adds a reference to copied entries if `ref` is true.
+  template <bool ref>
+  void Fill(const CordRepRing* src, index_type head, index_type tail);
+
+  // Create a copy of 'rep', copying all entries [head, tail), allocating room
+  // for `extra` entries. Adds a reference on all copied entries.
+  static CordRepRing* Copy(CordRepRing* rep, index_type head, index_type tail,
+                           size_t extra = 0);
+
+  // Returns a Mutable CordRepRing reference from `rep` with room for at least
+  // `extra` additional nodes. Adopts a reference count from `rep`.
+  // This function will return `rep` if, and only if:
+  // - rep.entries + extra <= rep.capacity
+  // - rep.refcount == 1
+  // Otherwise, this function will create a new copy of `rep` with additional
+  // capacity to satisfy `extra` extra nodes, and unref the old `rep` instance.
+  //
+  // If a new CordRepRing can not be allocated, or the new capacity would exceed
+  // the maxmimum capacity, then the input is consumed only, and an exception is
+  // thrown.
+  static CordRepRing* Mutable(CordRepRing* rep, size_t extra);
+
+  // Slow path for Append(CordRepRing* rep, CordRep* child). This function is
+  // exercised if the provided `child` in Append() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* AppendSlow(CordRepRing* rep, CordRep* child);
+
+  // Appends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
+  static CordRepRing* AppendLeaf(CordRepRing* rep, CordRep* child,
+                                 size_t offset, size_t length);
+
+  // Prepends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
+  static CordRepRing* PrependLeaf(CordRepRing* rep, CordRep* child,
+                                  size_t offset, size_t length);
+
+  // Slow path for Prepend(CordRepRing* rep, CordRep* child). This function is
+  // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* PrependSlow(CordRepRing* rep, CordRep* child);
+
+  // Slow path for Create(CordRep* child, size_t extra). This function is
+  // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* CreateSlow(CordRep* child, size_t extra);
+
+  // Creates a new ring buffer from the provided `child` leaf node. Requires
+  // `child` to be FLAT or EXTERNAL. on `rep`.
+  // The returned ring buffer has a capacity of at least `1 + extra`
+  static CordRepRing* CreateFromLeaf(CordRep* child, size_t offset,
+                                     size_t length, size_t extra);
+
+  // Appends or prepends (depending on AddMode) the ring buffer in `ring' to
+  // `rep` starting at `offset` with length `length`.
+  template <AddMode mode>
+  static CordRepRing* AddRing(CordRepRing* rep, CordRepRing* ring,
+                              size_t offset, size_t length);
+
+  // Increases the data offset for entry `index` by `n`.
+  void AddDataOffset(index_type index, size_t n);
+
+  // Descreases the length for entry `index` by `n`.
+  void SubLength(index_type index, size_t n);
+
+  index_type head_;
+  index_type tail_;
+  index_type capacity_;
+  pos_type begin_pos_;
+
+  alignas(kLayoutAlignment) char data_[kLayoutAlignment];
+
+  friend struct CordRep;
+};
+
+constexpr size_t CordRepRing::AllocSize(size_t capacity) {
+  return sizeof(CordRepRing) - sizeof(data_) +
+         Layout(capacity, capacity, capacity).AllocSize();
+}
+
+inline constexpr size_t CordRepRing::Distance(pos_type pos, pos_type end_pos) {
+  return (end_pos - pos);
+}
+
+inline const char* CordRepRing::GetLeafData(const CordRep* rep) {
+  return rep->tag != EXTERNAL ? rep->flat()->Data() : rep->external()->base;
+}
+
+inline const char* CordRepRing::GetRepData(const CordRep* rep) {
+  if (rep->tag >= FLAT) return rep->flat()->Data();
+  if (rep->tag == EXTERNAL) return rep->external()->base;
+  return GetLeafData(rep->substring()->child) + rep->substring()->start;
+}
+
+inline CordRepRing::index_type CordRepRing::advance(index_type index) const {
+  assert(index < capacity_);
+  return ++index == capacity_ ? 0 : index;
+}
+
+inline CordRepRing::index_type CordRepRing::advance(index_type index,
+                                                    index_type n) const {
+  assert(index < capacity_ && n <= capacity_);
+  return (index += n) >= capacity_ ? index - capacity_ : index;
+}
+
+inline CordRepRing::index_type CordRepRing::retreat(index_type index) const {
+  assert(index < capacity_);
+  return (index > 0 ? index : capacity_) - 1;
+}
+
+inline CordRepRing::index_type CordRepRing::retreat(index_type index,
+                                                    index_type n) const {
+  assert(index < capacity_ && n <= capacity_);
+  return index >= n ? index - n : capacity_ - n + index;
+}
+
+inline absl::string_view CordRepRing::entry_data(index_type index) const {
+  size_t data_offset = entry_data_offset(index);
+  return {GetRepData(entry_child(index)) + data_offset, entry_length(index)};
+}
+
+inline bool CordRepRing::IsValidIndex(index_type index) const {
+  if (index >= capacity_) return false;
+  return (tail_ > head_) ? (index >= head_ && index < tail_)
+                         : (index >= head_ || index < tail_);
+}
+
+#ifndef EXTRA_CORD_RING_VALIDATION
+inline CordRepRing* CordRepRing::Validate(CordRepRing* rep,
+                                          const char* /*file*/, int /*line*/) {
+  return rep;
+}
+#endif
+
+inline CordRepRing::Position CordRepRing::Find(size_t offset) const {
+  assert(offset < length);
+  return (offset == 0) ? Position{head_, 0} : FindSlow(head_, offset);
+}
+
+inline CordRepRing::Position CordRepRing::Find(index_type head,
+                                               size_t offset) const {
+  assert(offset < length);
+  assert(IsValidIndex(head) && offset >= entry_start_offset(head));
+  return (offset == 0) ? Position{head_, 0} : FindSlow(head, offset);
+}
+
+inline CordRepRing::Position CordRepRing::FindTail(size_t offset) const {
+  assert(offset > 0 && offset <= length);
+  return (offset == length) ? Position{tail_, 0} : FindTailSlow(head_, offset);
+}
+
+inline CordRepRing::Position CordRepRing::FindTail(index_type head,
+                                                   size_t offset) const {
+  assert(offset > 0 && offset <= length);
+  assert(IsValidIndex(head) && offset >= entry_start_offset(head) + 1);
+  return (offset == length) ? Position{tail_, 0} : FindTailSlow(head, offset);
+}
+
+// Now that CordRepRing is defined, we can define CordRep's helper casts:
+inline CordRepRing* CordRep::ring() {
+  assert(tag == RING);
+  return static_cast<CordRepRing*>(this);
+}
+
+inline const CordRepRing* CordRep::ring() const {
+  assert(tag == RING);
+  return static_cast<const CordRepRing*>(this);
+}
+
+std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h
new file mode 100644
index 0000000..396c0e2
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h
@@ -0,0 +1,114 @@
+// Copyright 2021 The Abseil 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
+//
+//     https://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 ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// CordRepRingReader provides basic navigation over CordRepRing data.
+class CordRepRingReader {
+ public:
+  // Returns true if this instance is not empty.
+  explicit operator bool() const { return ring_ != nullptr; }
+
+  // Returns the ring buffer reference for this instance, or nullptr if empty.
+  CordRepRing* ring() const { return ring_; }
+
+  // Returns the current node index inside the ring buffer for this instance.
+  // The returned value is undefined if this instance is empty.
+  CordRepRing::index_type index() const { return index_; }
+
+  // Returns the length of the referenced ring buffer.
+  // Requires the current instance to be non empty.
+  size_t length() const {
+    assert(ring_);
+    return ring_->length;
+  }
+
+  // Returns the end offset of the last navigated-to chunk, which represents the
+  // total bytes 'consumed' relative to the start of the ring. The returned
+  // value is never zero. For example, initializing a reader with a ring buffer
+  // with a first chunk of 19 bytes will return consumed() = 19.
+  // Requires the current instance to be non empty.
+  size_t consumed() const {
+    assert(ring_);
+    return ring_->entry_end_offset(index_);
+  }
+
+  // Returns the number of bytes remaining beyond the last navigated-to chunk.
+  // Requires the current instance to be non empty.
+  size_t remaining() const {
+    assert(ring_);
+    return length() - consumed();
+  }
+
+  // Resets this instance to an empty value
+  void Reset() { ring_ = nullptr; }
+
+  // Resets this instance to the start of `ring`. `ring` must not be null.
+  // Returns a reference into the first chunk of the provided ring.
+  absl::string_view Reset(CordRepRing* ring) {
+    assert(ring);
+    ring_ = ring;
+    index_ = ring_->head();
+    return ring_->entry_data(index_);
+  }
+
+  // Navigates to the next chunk inside the reference ring buffer.
+  // Returns a reference into the navigated-to chunk.
+  // Requires remaining() to be non zero.
+  absl::string_view Next() {
+    assert(remaining());
+    index_ = ring_->advance(index_);
+    return ring_->entry_data(index_);
+  }
+
+  // Navigates to the chunk at offset `offset`.
+  // Returns a reference into the navigated-to chunk, adjusted for the relative
+  // position of `offset` into that chunk. For example, calling Seek(13) on a
+  // ring buffer containing 2 chunks of 10 and 20 bytes respectively will return
+  // a string view into the second chunk starting at offset 3 with a size of 17.
+  // Requires `offset` to be less than `length()`
+  absl::string_view Seek(size_t offset) {
+    assert(offset < length());
+    size_t current = ring_->entry_end_offset(index_);
+    CordRepRing::index_type hint = (offset >= current) ? index_ : ring_->head();
+    const CordRepRing::Position head = ring_->Find(hint, offset);
+    index_ = head.index;
+    auto data = ring_->entry_data(head.index);
+    data.remove_prefix(head.offset);
+    return data;
+  }
+
+ private:
+  CordRepRing* ring_ = nullptr;
+  CordRepRing::index_type index_;
+};
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc
index 9feb224..e28a29b 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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.
+
 //
 // POSIX spec:
 //   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h
index 3dbc152..7040c86 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg_test.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg_test.cc
index f53fd6b..1261937 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/arg_test.cc
@@ -6,6 +6,12 @@
 //
 //      https://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 "absl/strings/internal/str_format/arg.h"
 
 #include <ostream>
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
index 6980ed1..4e68b90 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/internal/str_format/bind.h"
 
 #include <cerrno>
@@ -221,7 +235,7 @@
     errno = sink.error();
     return -1;
   }
-  if (sink.count() > std::numeric_limits<int>::max()) {
+  if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
     errno = EFBIG;
     return -1;
   }
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h
index 585246e..267cc0e 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 
@@ -119,10 +133,11 @@
 
 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 
-  template <FormatConversionCharSet... C,
-            typename = typename std::enable_if<
-                AllOf(sizeof...(C) == sizeof...(Args), Contains(Args,
-                                                                C)...)>::type>
+  template <
+      FormatConversionCharSet... C,
+      typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,
+      typename = typename std::enable_if<AllOf(Contains(Args,
+                                                        C)...)>::type>
   FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
       : Base(&pc) {}
 };
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
index 64790a8..1eef9c4 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/internal/str_format/bind.h"
 
 #include <string.h>
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h
index 424c51f..2a2601e 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc
index a76d70b..7c70f47 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 <string>
 
 #include "gmock/gmock.h"
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
index 634ee78..926283c 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -540,7 +554,8 @@
 }
 
 template <typename Floating>
-void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats) {
+void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats,
+                                   const std::set<Floating> &skip_verify) {
   const NativePrintfTraits &native_traits = VerifyNativeImplementation();
   // Reserve the space to ensure we don't allocate memory in the output itself.
   std::string str_format_result;
@@ -588,7 +603,16 @@
           AppendPack(&str_format_result, format, absl::MakeSpan(args));
         }
 
-        if (string_printf_result != str_format_result) {
+#ifdef _MSC_VER
+        // MSVC has a different rounding policy than us so we can't test our
+        // implementation against the native one there.
+        continue;
+#elif defined(__APPLE__)
+        // Apple formats NaN differently (+nan) vs. (nan)
+        if (std::isnan(d)) continue;
+#endif
+        if (string_printf_result != str_format_result &&
+            skip_verify.find(d) == skip_verify.end()) {
           // We use ASSERT_EQ here because failures are usually correlated and a
           // bug would print way too many failed expectations causing the test
           // to time out.
@@ -602,12 +626,6 @@
 }
 
 TEST_F(FormatConvertTest, Float) {
-#ifdef _MSC_VER
-  // MSVC has a different rounding policy than us so we can't test our
-  // implementation against the native one there.
-  return;
-#endif  // _MSC_VER
-
   std::vector<float> floats = {0.0f,
                                -0.0f,
                                .9999999f,
@@ -621,7 +639,8 @@
                                std::numeric_limits<float>::epsilon(),
                                std::numeric_limits<float>::epsilon() + 1.0f,
                                std::numeric_limits<float>::infinity(),
-                               -std::numeric_limits<float>::infinity()};
+                               -std::numeric_limits<float>::infinity(),
+                               std::nanf("")};
 
   // Some regression tests.
   floats.push_back(0.999999989f);
@@ -650,21 +669,14 @@
   std::sort(floats.begin(), floats.end());
   floats.erase(std::unique(floats.begin(), floats.end()), floats.end());
 
-#ifndef __APPLE__
-  // Apple formats NaN differently (+nan) vs. (nan)
-  floats.push_back(std::nan(""));
-#endif
-
-  TestWithMultipleFormatsHelper(floats);
+  TestWithMultipleFormatsHelper(floats, {});
 }
 
 TEST_F(FormatConvertTest, Double) {
-#ifdef _MSC_VER
-  // MSVC has a different rounding policy than us so we can't test our
-  // implementation against the native one there.
-  return;
-#endif  // _MSC_VER
-
+  // For values that we know won't match the standard library implementation we
+  // skip verification, but still run the algorithm to catch asserts/sanitizer
+  // bugs.
+  std::set<double> skip_verify;
   std::vector<double> doubles = {0.0,
                                  -0.0,
                                  .99999999999999,
@@ -678,7 +690,8 @@
                                  std::numeric_limits<double>::epsilon(),
                                  std::numeric_limits<double>::epsilon() + 1,
                                  std::numeric_limits<double>::infinity(),
-                                 -std::numeric_limits<double>::infinity()};
+                                 -std::numeric_limits<double>::infinity(),
+                                 std::nan("")};
 
   // Some regression tests.
   doubles.push_back(0.99999999999999989);
@@ -708,33 +721,29 @@
       "5084551339423045832369032229481658085593321233482747978262041447231"
       "68738177180919299881250404026184124858368.000000";
 
-  if (!gcc_bug_22142) {
-    for (int exp = -300; exp <= 300; ++exp) {
-      const double all_ones_mantissa = 0x1fffffffffffff;
-      doubles.push_back(std::ldexp(all_ones_mantissa, exp));
+  for (int exp = -300; exp <= 300; ++exp) {
+    const double all_ones_mantissa = 0x1fffffffffffff;
+    doubles.push_back(std::ldexp(all_ones_mantissa, exp));
+    if (gcc_bug_22142) {
+      skip_verify.insert(doubles.back());
     }
   }
 
   if (gcc_bug_22142) {
-    for (auto &d : doubles) {
-      using L = std::numeric_limits<double>;
-      double d2 = std::abs(d);
-      if (d2 == L::max() || d2 == L::min() || d2 == L::denorm_min()) {
-        d = 0;
-      }
-    }
+    using L = std::numeric_limits<double>;
+    skip_verify.insert(L::max());
+    skip_verify.insert(L::min());  // NOLINT
+    skip_verify.insert(L::denorm_min());
+    skip_verify.insert(-L::max());
+    skip_verify.insert(-L::min());  // NOLINT
+    skip_verify.insert(-L::denorm_min());
   }
 
   // Remove duplicates to speed up the logic below.
   std::sort(doubles.begin(), doubles.end());
   doubles.erase(std::unique(doubles.begin(), doubles.end()), doubles.end());
 
-#ifndef __APPLE__
-  // Apple formats NaN differently (+nan) vs. (nan)
-  doubles.push_back(std::nan(""));
-#endif
-
-  TestWithMultipleFormatsHelper(doubles);
+  TestWithMultipleFormatsHelper(doubles, skip_verify);
 }
 
 TEST_F(FormatConvertTest, DoubleRound) {
@@ -1055,11 +1064,6 @@
 }
 
 TEST_F(FormatConvertTest, LongDouble) {
-#ifdef _MSC_VER
-  // MSVC has a different rounding policy than us so we can't test our
-  // implementation against the native one there.
-  return;
-#endif  // _MSC_VER
   const NativePrintfTraits &native_traits = VerifyNativeImplementation();
   const char *const kFormats[] = {"%",    "%.3", "%8.5", "%9",  "%.5000",
                                   "%.60", "%+",  "% ",   "%-10"};
@@ -1120,10 +1124,18 @@
       for (auto d : doubles) {
         FormatArgImpl arg(d);
         UntypedFormatSpecImpl format(fmt_str);
+        std::string result = FormatPack(format, {&arg, 1});
+
+#ifdef _MSC_VER
+        // MSVC has a different rounding policy than us so we can't test our
+        // implementation against the native one there.
+        continue;
+#endif  // _MSC_VER
+
         // We use ASSERT_EQ here because failures are usually correlated and a
         // bug would print way too many failed expectations causing the test to
         // time out.
-        ASSERT_EQ(StrPrint(fmt_str.c_str(), d), FormatPack(format, {&arg, 1}))
+        ASSERT_EQ(StrPrint(fmt_str.c_str(), d), result)
             << fmt_str << " " << StrPrint("%.18Lg", d) << " "
             << StrPrint("%La", d) << " " << StrPrint("%.1080Lf", d);
       }
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
index 20aeada..b1c4068 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/internal/str_format/float_conversion.h"
 
 #include <string.h>
@@ -10,11 +24,12 @@
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
-#include "absl/base/internal/bits.h"
 #include "absl/base/optimization.h"
 #include "absl/functional/function_ref.h"
 #include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
+#include "absl/numeric/internal/representation.h"
 #include "absl/strings/numbers.h"
 #include "absl/types/optional.h"
 #include "absl/types/span.h"
@@ -25,6 +40,8 @@
 
 namespace {
 
+using ::absl::numeric_internal::IsDoubleDouble;
+
 // The code below wants to avoid heap allocations.
 // To do so it needs to allocate memory on the stack.
 // `StackArray` will allocate memory on the stack in the form of a uint32_t
@@ -98,12 +115,15 @@
   return next_carry % divisor;
 }
 
+using MaxFloatType =
+    typename std::conditional<IsDoubleDouble(), double, long double>::type;
+
 // Generates the decimal representation for an integer of the form `v * 2^exp`,
 // where `v` and `exp` are both positive integers.
 // It generates the digits from the left (ie the most significant digit first)
 // to allow for direct printing into the sink.
 //
-// Requires `0 <= exp` and `exp <= numeric_limits<long double>::max_exponent`.
+// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::max_exponent`.
 class BinaryToDecimal {
   static constexpr int ChunksNeeded(int exp) {
     // We will left shift a uint128 by `exp` bits, so we need `128+exp` total
@@ -118,10 +138,10 @@
   static void RunConversion(uint128 v, int exp,
                             absl::FunctionRef<void(BinaryToDecimal)> f) {
     assert(exp > 0);
-    assert(exp <= std::numeric_limits<long double>::max_exponent);
+    assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent);
     static_assert(
-        StackArray::kMaxCapacity >=
-            ChunksNeeded(std::numeric_limits<long double>::max_exponent),
+        static_cast<int>(StackArray::kMaxCapacity) >=
+            ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent),
         "");
 
     StackArray::RunWithCapacity(
@@ -218,14 +238,14 @@
 
 // Converts a value of the form `x * 2^-exp` into a sequence of decimal digits.
 // Requires `-exp < 0` and
-// `-exp >= limits<long double>::min_exponent - limits<long double>::digits`.
+// `-exp >= limits<MaxFloatType>::min_exponent - limits<MaxFloatType>::digits`.
 class FractionalDigitGenerator {
  public:
   // Run the conversion for `v * 2^exp` and call `f(generator)`.
   // This function will allocate enough stack space to perform the conversion.
   static void RunConversion(
       uint128 v, int exp, absl::FunctionRef<void(FractionalDigitGenerator)> f) {
-    using Limits = std::numeric_limits<long double>;
+    using Limits = std::numeric_limits<MaxFloatType>;
     assert(-exp < 0);
     assert(-exp >= Limits::min_exponent - 128);
     static_assert(StackArray::kMaxCapacity >=
@@ -301,12 +321,11 @@
 };
 
 // Count the number of leading zero bits.
-int LeadingZeros(uint64_t v) { return base_internal::CountLeadingZeros64(v); }
+int LeadingZeros(uint64_t v) { return countl_zero(v); }
 int LeadingZeros(uint128 v) {
   auto high = static_cast<uint64_t>(v >> 64);
   auto low = static_cast<uint64_t>(v);
-  return high != 0 ? base_internal::CountLeadingZeros64(high)
-                   : 64 + base_internal::CountLeadingZeros64(low);
+  return high != 0 ? countl_zero(high) : 64 + countl_zero(low);
 }
 
 // Round up the text digits starting at `p`.
@@ -858,10 +877,10 @@
   // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the
   // size with long double which is the largest of the floats.
   constexpr size_t kBufSizeForHexFloatRepr =
-      2                                               // 0x
-      + std::numeric_limits<long double>::digits / 4  // number of hex digits
-      + 1                                             // round up
-      + 1;                                            // "." (dot)
+      2                                                // 0x
+      + std::numeric_limits<MaxFloatType>::digits / 4  // number of hex digits
+      + 1                                              // round up
+      + 1;                                             // "." (dot)
   char digits_buffer[kBufSizeForHexFloatRepr];
   char *digits_iter = digits_buffer;
   const char *const digits =
@@ -1380,10 +1399,9 @@
 
 bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink) {
-  if (std::numeric_limits<long double>::digits ==
-      2 * std::numeric_limits<double>::digits) {
-    // This is the `double-double` representation of `long double`.
-    // We do not handle it natively. Fallback to snprintf.
+  if (IsDoubleDouble()) {
+    // This is the `double-double` representation of `long double`. We do not
+    // handle it natively. Fallback to snprintf.
     return FallbackToSnprintf(v, conv, sink);
   }
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h
index e78bc19..71100e7 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc
index cc55dfa..f308d02 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/internal/str_format/parser.h"
 
 #include <assert.h>
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h
index fffed04..6504dd3 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc
index 5aced98..a5fa1c7 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/internal/str_format/parser.h"
 
 #include <string.h>
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/str_split_internal.h b/grpc/third_party/abseil-cpp/absl/strings/internal/str_split_internal.h
index 6f5bc09..a2f41c1 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/internal/str_split_internal.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/str_split_internal.h
@@ -51,9 +51,9 @@
 namespace strings_internal {
 
 // This class is implicitly constructible from everything that absl::string_view
-// is implicitly constructible from. If it's constructed from a temporary
-// string, the data is moved into a data member so its lifetime matches that of
-// the ConvertibleToStringView instance.
+// is implicitly constructible from, except for rvalue strings.  This means it
+// can be used as a function parameter in places where passing a temporary
+// string might cause memory lifetime issues.
 class ConvertibleToStringView {
  public:
   ConvertibleToStringView(const char* s)  // NOLINT(runtime/explicit)
@@ -65,41 +65,12 @@
       : value_(s) {}
 
   // Matches rvalue strings and moves their data to a member.
-  ConvertibleToStringView(std::string&& s)  // NOLINT(runtime/explicit)
-      : copy_(std::move(s)), value_(copy_) {}
-
-  ConvertibleToStringView(const ConvertibleToStringView& other)
-      : copy_(other.copy_),
-        value_(other.IsSelfReferential() ? copy_ : other.value_) {}
-
-  ConvertibleToStringView(ConvertibleToStringView&& other) {
-    StealMembers(std::move(other));
-  }
-
-  ConvertibleToStringView& operator=(ConvertibleToStringView other) {
-    StealMembers(std::move(other));
-    return *this;
-  }
+  ConvertibleToStringView(std::string&& s) = delete;
+  ConvertibleToStringView(const std::string&& s) = delete;
 
   absl::string_view value() const { return value_; }
 
  private:
-  // Returns true if ctsp's value refers to its internal copy_ member.
-  bool IsSelfReferential() const { return value_.data() == copy_.data(); }
-
-  void StealMembers(ConvertibleToStringView&& other) {
-    if (other.IsSelfReferential()) {
-      copy_ = std::move(other.copy_);
-      value_ = copy_;
-      other.value_ = other.copy_;
-    } else {
-      value_ = other.value_;
-    }
-  }
-
-  // Holds the data moved from temporary std::string arguments. Declared first
-  // so that 'value' can refer to 'copy_'.
-  std::string copy_;
   absl::string_view value_;
 };
 
@@ -273,7 +244,11 @@
 // the split strings: only strings for which the predicate returns true will be
 // kept. A Predicate object is any unary functor that takes an absl::string_view
 // and returns bool.
-template <typename Delimiter, typename Predicate>
+//
+// The StringType parameter can be either string_view or string, depending on
+// whether the Splitter refers to a string stored elsewhere, or if the string
+// resides inside the Splitter itself.
+template <typename Delimiter, typename Predicate, typename StringType>
 class Splitter {
  public:
   using DelimiterType = Delimiter;
@@ -281,12 +256,12 @@
   using const_iterator = strings_internal::SplitIterator<Splitter>;
   using value_type = typename std::iterator_traits<const_iterator>::value_type;
 
-  Splitter(ConvertibleToStringView input_text, Delimiter d, Predicate p)
+  Splitter(StringType input_text, Delimiter d, Predicate p)
       : text_(std::move(input_text)),
         delimiter_(std::move(d)),
         predicate_(std::move(p)) {}
 
-  absl::string_view text() const { return text_.value(); }
+  absl::string_view text() const { return text_; }
   const Delimiter& delimiter() const { return delimiter_; }
   const Predicate& predicate() const { return predicate_; }
 
@@ -336,7 +311,7 @@
     Container operator()(const Splitter& splitter) const {
       Container c;
       auto it = std::inserter(c, c.end());
-      for (const auto sp : splitter) {
+      for (const auto& sp : splitter) {
         *it++ = ValueType(sp);
       }
       return c;
@@ -401,7 +376,7 @@
       Container m;
       typename Container::iterator it;
       bool insert = true;
-      for (const auto sp : splitter) {
+      for (const auto& sp : splitter) {
         if (insert) {
           it = Inserter<Container>::Insert(&m, First(sp), Second());
         } else {
@@ -443,7 +418,7 @@
     };
   };
 
-  ConvertibleToStringView text_;
+  StringType text_;
   Delimiter delimiter_;
   Predicate predicate_;
 };
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/string_constant.h b/grpc/third_party/abseil-cpp/absl/strings/internal/string_constant.h
new file mode 100644
index 0000000..a11336b
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/string_constant.h
@@ -0,0 +1,64 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// StringConstant<T> represents a compile time string constant.
+// It can be accessed via its `absl::string_view value` static member.
+// It is guaranteed that the `string_view` returned has constant `.data()`,
+// constant `.size()` and constant `value[i]` for all `0 <= i < .size()`
+//
+// The `T` is an opaque type. It is guaranteed that different string constants
+// will have different values of `T`. This allows users to associate the string
+// constant with other static state at compile time.
+//
+// Instances should be made using the `MakeStringConstant()` factory function
+// below.
+template <typename T>
+struct StringConstant {
+  static constexpr absl::string_view value = T{}();
+  constexpr absl::string_view operator()() const { return value; }
+
+  // Check to be sure `view` points to constant data.
+  // Otherwise, it can't be constant evaluated.
+  static_assert(value.empty() || 2 * value[0] != 1,
+                "The input string_view must point to constant data.");
+};
+
+template <typename T>
+constexpr absl::string_view StringConstant<T>::value;  // NOLINT
+
+// Factory function for `StringConstant` instances.
+// It supports callables that have a constexpr default constructor and a
+// constexpr operator().
+// It must return an `absl::string_view` or `const char*` pointing to constant
+// data. This is validated at compile time.
+template <typename T>
+constexpr StringConstant<T> MakeStringConstant(T) {
+  return {};
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
diff --git a/grpc/third_party/abseil-cpp/absl/strings/internal/string_constant_test.cc b/grpc/third_party/abseil-cpp/absl/strings/internal/string_constant_test.cc
new file mode 100644
index 0000000..392833c
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/strings/internal/string_constant_test.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/internal/string_constant.h"
+
+#include "absl/meta/type_traits.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::strings_internal::MakeStringConstant;
+
+struct Callable {
+  constexpr absl::string_view operator()() const {
+    return absl::string_view("Callable", 8);
+  }
+};
+
+TEST(StringConstant, Traits) {
+  constexpr auto str = MakeStringConstant(Callable{});
+  using T = decltype(str);
+
+  EXPECT_TRUE(std::is_empty<T>::value);
+  EXPECT_TRUE(std::is_trivial<T>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<T>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<T>::value);
+  EXPECT_TRUE(absl::is_trivially_move_constructible<T>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<T>::value);
+}
+
+TEST(StringConstant, MakeFromCallable) {
+  constexpr auto str = MakeStringConstant(Callable{});
+  using T = decltype(str);
+  EXPECT_EQ(Callable{}(), T::value);
+  EXPECT_EQ(Callable{}(), str());
+}
+
+TEST(StringConstant, MakeFromStringConstant) {
+  // We want to make sure the StringConstant itself is a valid input to the
+  // factory function.
+  constexpr auto str = MakeStringConstant(Callable{});
+  constexpr auto str2 = MakeStringConstant(str);
+  using T = decltype(str2);
+  EXPECT_EQ(Callable{}(), T::value);
+  EXPECT_EQ(Callable{}(), str2());
+}
+
+}  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/strings/match.cc b/grpc/third_party/abseil-cpp/absl/strings/match.cc
index 8127cb0..2d67250 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/match.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/match.cc
@@ -19,19 +19,22 @@
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
-bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) {
+bool EqualsIgnoreCase(absl::string_view piece1,
+                      absl::string_view piece2) noexcept {
   return (piece1.size() == piece2.size() &&
           0 == absl::strings_internal::memcasecmp(piece1.data(), piece2.data(),
                                                   piece1.size()));
   // memcasecmp uses absl::ascii_tolower().
 }
 
-bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) {
+bool StartsWithIgnoreCase(absl::string_view text,
+                          absl::string_view prefix) noexcept {
   return (text.size() >= prefix.size()) &&
          EqualsIgnoreCase(text.substr(0, prefix.size()), prefix);
 }
 
-bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) {
+bool EndsWithIgnoreCase(absl::string_view text,
+                        absl::string_view suffix) noexcept {
   return (text.size() >= suffix.size()) &&
          EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix);
 }
diff --git a/grpc/third_party/abseil-cpp/absl/strings/match.h b/grpc/third_party/abseil-cpp/absl/strings/match.h
index 90fca98..038cbb3 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/match.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/match.h
@@ -43,14 +43,20 @@
 // StrContains()
 //
 // Returns whether a given string `haystack` contains the substring `needle`.
-inline bool StrContains(absl::string_view haystack, absl::string_view needle) {
+inline bool StrContains(absl::string_view haystack,
+                        absl::string_view needle) noexcept {
   return haystack.find(needle, 0) != haystack.npos;
 }
 
+inline bool StrContains(absl::string_view haystack, char needle) noexcept {
+  return haystack.find(needle) != haystack.npos;
+}
+
 // StartsWith()
 //
 // Returns whether a given string `text` begins with `prefix`.
-inline bool StartsWith(absl::string_view text, absl::string_view prefix) {
+inline bool StartsWith(absl::string_view text,
+                       absl::string_view prefix) noexcept {
   return prefix.empty() ||
          (text.size() >= prefix.size() &&
           memcmp(text.data(), prefix.data(), prefix.size()) == 0);
@@ -59,7 +65,8 @@
 // EndsWith()
 //
 // Returns whether a given string `text` ends with `suffix`.
-inline bool EndsWith(absl::string_view text, absl::string_view suffix) {
+inline bool EndsWith(absl::string_view text,
+                     absl::string_view suffix) noexcept {
   return suffix.empty() ||
          (text.size() >= suffix.size() &&
           memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
@@ -70,19 +77,22 @@
 //
 // Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring
 // case in the comparison.
-bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2);
+bool EqualsIgnoreCase(absl::string_view piece1,
+                      absl::string_view piece2) noexcept;
 
 // StartsWithIgnoreCase()
 //
 // Returns whether a given ASCII string `text` starts with `prefix`,
 // ignoring case in the comparison.
-bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix);
+bool StartsWithIgnoreCase(absl::string_view text,
+                          absl::string_view prefix) noexcept;
 
 // EndsWithIgnoreCase()
 //
 // Returns whether a given ASCII string `text` ends with `suffix`, ignoring
 // case in the comparison.
-bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix);
+bool EndsWithIgnoreCase(absl::string_view text,
+                        absl::string_view suffix) noexcept;
 
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/strings/match_test.cc b/grpc/third_party/abseil-cpp/absl/strings/match_test.cc
index 4c313dd..5841bc1 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/match_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/match_test.cc
@@ -66,6 +66,23 @@
   EXPECT_FALSE(absl::StrContains("", "a"));
 }
 
+TEST(MatchTest, ContainsChar) {
+  absl::string_view a("abcdefg");
+  absl::string_view b("abcd");
+  EXPECT_TRUE(absl::StrContains(a, 'a'));
+  EXPECT_TRUE(absl::StrContains(a, 'b'));
+  EXPECT_TRUE(absl::StrContains(a, 'e'));
+  EXPECT_FALSE(absl::StrContains(a, 'h'));
+
+  EXPECT_TRUE(absl::StrContains(b, 'a'));
+  EXPECT_TRUE(absl::StrContains(b, 'b'));
+  EXPECT_FALSE(absl::StrContains(b, 'e'));
+  EXPECT_FALSE(absl::StrContains(b, 'h'));
+
+  EXPECT_FALSE(absl::StrContains("", 'a'));
+  EXPECT_FALSE(absl::StrContains("", 'a'));
+}
+
 TEST(MatchTest, ContainsNull) {
   const std::string s = "foo";
   const char* cs = "foo";
diff --git a/grpc/third_party/abseil-cpp/absl/strings/numbers.cc b/grpc/third_party/abseil-cpp/absl/strings/numbers.cc
index 68c26dd..966d94b 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/numbers.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/numbers.cc
@@ -31,8 +31,8 @@
 #include <utility>
 
 #include "absl/base/attributes.h"
-#include "absl/base/internal/bits.h"
 #include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/bits.h"
 #include "absl/strings/ascii.h"
 #include "absl/strings/charconv.h"
 #include "absl/strings/escaping.h"
@@ -46,8 +46,13 @@
 bool SimpleAtof(absl::string_view str, float* out) {
   *out = 0.0;
   str = StripAsciiWhitespace(str);
+  // std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one
+  // is present, skip it, while avoiding accepting "+-0" as valid.
   if (!str.empty() && str[0] == '+') {
     str.remove_prefix(1);
+    if (!str.empty() && str[0] == '-') {
+      return false;
+    }
   }
   auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
   if (result.ec == std::errc::invalid_argument) {
@@ -72,8 +77,13 @@
 bool SimpleAtod(absl::string_view str, double* out) {
   *out = 0.0;
   str = StripAsciiWhitespace(str);
+  // std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one
+  // is present, skip it, while avoiding accepting "+-0" as valid.
   if (!str.empty() && str[0] == '+') {
     str.remove_prefix(1);
+    if (!str.empty() && str[0] == '-') {
+      return false;
+    }
   }
   auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
   if (result.ec == std::errc::invalid_argument) {
@@ -303,7 +313,7 @@
   uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
   if (bits128_up == 0) return {bits64_127, bits0_63};
 
-  int shift = 64 - base_internal::CountLeadingZeros64(bits128_up);
+  auto shift = static_cast<unsigned>(bit_width(bits128_up));
   uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift));
   uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift));
   return {hi, lo};
@@ -334,7 +344,7 @@
       5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
       5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
   result = Mul32(result, powers_of_five[expfive & 15]);
-  int shift = base_internal::CountLeadingZeros64(result.first);
+  int shift = countl_zero(result.first);
   if (shift != 0) {
     result.first = (result.first << shift) + (result.second >> (64 - shift));
     result.second = (result.second << shift);
@@ -736,9 +746,18 @@
         X / 35, X / 36,                                                   \
   }
 
+// This kVmaxOverBase is generated with
+//  for (int base = 2; base < 37; ++base) {
+//    absl::uint128 max = std::numeric_limits<absl::uint128>::max();
+//    auto result = max / base;
+//    std::cout << "    MakeUint128(" << absl::Uint128High64(result) << "u, "
+//              << absl::Uint128Low64(result) << "u),\n";
+//  }
+// See https://godbolt.org/z/aneYsb
+//
 // uint128& operator/=(uint128) is not constexpr, so hardcode the resulting
 // array to avoid a static initializer.
-template <>
+template<>
 const uint128 LookupTables<uint128>::kVmaxOverBase[] = {
     0,
     0,
@@ -779,6 +798,111 @@
     MakeUint128(512409557603043100u, 8198552921648689607u),
 };
 
+// This kVmaxOverBase generated with
+//   for (int base = 2; base < 37; ++base) {
+//    absl::int128 max = std::numeric_limits<absl::int128>::max();
+//    auto result = max / base;
+//    std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
+//              << absl::Int128Low64(result) << "u),\n";
+//  }
+// See https://godbolt.org/z/7djYWz
+//
+// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
+// to avoid a static initializer.
+template<>
+const int128 LookupTables<int128>::kVmaxOverBase[] = {
+    0,
+    0,
+    MakeInt128(4611686018427387903, 18446744073709551615u),
+    MakeInt128(3074457345618258602, 12297829382473034410u),
+    MakeInt128(2305843009213693951, 18446744073709551615u),
+    MakeInt128(1844674407370955161, 11068046444225730969u),
+    MakeInt128(1537228672809129301, 6148914691236517205u),
+    MakeInt128(1317624576693539401, 2635249153387078802u),
+    MakeInt128(1152921504606846975, 18446744073709551615u),
+    MakeInt128(1024819115206086200, 16397105843297379214u),
+    MakeInt128(922337203685477580, 14757395258967641292u),
+    MakeInt128(838488366986797800, 13415813871788764811u),
+    MakeInt128(768614336404564650, 12297829382473034410u),
+    MakeInt128(709490156681136600, 11351842506898185609u),
+    MakeInt128(658812288346769700, 10540996613548315209u),
+    MakeInt128(614891469123651720, 9838263505978427528u),
+    MakeInt128(576460752303423487, 18446744073709551615u),
+    MakeInt128(542551296285575047, 9765923333140350855u),
+    MakeInt128(512409557603043100, 8198552921648689607u),
+    MakeInt128(485440633518672410, 17475862806672206794u),
+    MakeInt128(461168601842738790, 7378697629483820646u),
+    MakeInt128(439208192231179800, 7027331075698876806u),
+    MakeInt128(419244183493398900, 6707906935894382405u),
+    MakeInt128(401016175515425035, 2406097053092550210u),
+    MakeInt128(384307168202282325, 6148914691236517205u),
+    MakeInt128(368934881474191032, 5902958103587056517u),
+    MakeInt128(354745078340568300, 5675921253449092804u),
+    MakeInt128(341606371735362066, 17763531330238827482u),
+    MakeInt128(329406144173384850, 5270498306774157604u),
+    MakeInt128(318047311615681924, 7633135478776366185u),
+    MakeInt128(307445734561825860, 4919131752989213764u),
+    MakeInt128(297528130221121800, 4760450083537948804u),
+    MakeInt128(288230376151711743, 18446744073709551615u),
+    MakeInt128(279496122328932600, 4471937957262921603u),
+    MakeInt128(271275648142787523, 14106333703424951235u),
+    MakeInt128(263524915338707880, 4216398645419326083u),
+    MakeInt128(256204778801521550, 4099276460824344803u),
+};
+
+// This kVminOverBase generated with
+//  for (int base = 2; base < 37; ++base) {
+//    absl::int128 min = std::numeric_limits<absl::int128>::min();
+//    auto result = min / base;
+//    std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
+//              << absl::Int128Low64(result) << "u),\n";
+//  }
+//
+// See https://godbolt.org/z/7djYWz
+//
+// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
+// to avoid a static initializer.
+template<>
+const int128 LookupTables<int128>::kVminOverBase[] = {
+    0,
+    0,
+    MakeInt128(-4611686018427387904, 0u),
+    MakeInt128(-3074457345618258603, 6148914691236517206u),
+    MakeInt128(-2305843009213693952, 0u),
+    MakeInt128(-1844674407370955162, 7378697629483820647u),
+    MakeInt128(-1537228672809129302, 12297829382473034411u),
+    MakeInt128(-1317624576693539402, 15811494920322472814u),
+    MakeInt128(-1152921504606846976, 0u),
+    MakeInt128(-1024819115206086201, 2049638230412172402u),
+    MakeInt128(-922337203685477581, 3689348814741910324u),
+    MakeInt128(-838488366986797801, 5030930201920786805u),
+    MakeInt128(-768614336404564651, 6148914691236517206u),
+    MakeInt128(-709490156681136601, 7094901566811366007u),
+    MakeInt128(-658812288346769701, 7905747460161236407u),
+    MakeInt128(-614891469123651721, 8608480567731124088u),
+    MakeInt128(-576460752303423488, 0u),
+    MakeInt128(-542551296285575048, 8680820740569200761u),
+    MakeInt128(-512409557603043101, 10248191152060862009u),
+    MakeInt128(-485440633518672411, 970881267037344822u),
+    MakeInt128(-461168601842738791, 11068046444225730970u),
+    MakeInt128(-439208192231179801, 11419412998010674810u),
+    MakeInt128(-419244183493398901, 11738837137815169211u),
+    MakeInt128(-401016175515425036, 16040647020617001406u),
+    MakeInt128(-384307168202282326, 12297829382473034411u),
+    MakeInt128(-368934881474191033, 12543785970122495099u),
+    MakeInt128(-354745078340568301, 12770822820260458812u),
+    MakeInt128(-341606371735362067, 683212743470724134u),
+    MakeInt128(-329406144173384851, 13176245766935394012u),
+    MakeInt128(-318047311615681925, 10813608594933185431u),
+    MakeInt128(-307445734561825861, 13527612320720337852u),
+    MakeInt128(-297528130221121801, 13686293990171602812u),
+    MakeInt128(-288230376151711744, 0u),
+    MakeInt128(-279496122328932601, 13974806116446630013u),
+    MakeInt128(-271275648142787524, 4340410370284600381u),
+    MakeInt128(-263524915338707881, 14230345428290225533u),
+    MakeInt128(-256204778801521551, 14347467612885206813u),
+};
+
 template <typename IntType>
 const IntType LookupTables<IntType>::kVmaxOverBase[] =
     X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max());
@@ -948,6 +1072,10 @@
   return safe_int_internal<int64_t>(text, value, base);
 }
 
+bool safe_strto128_base(absl::string_view text, int128* value, int base) {
+  return safe_int_internal<absl::int128>(text, value, base);
+}
+
 bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) {
   return safe_uint_internal<uint32_t>(text, value, base);
 }
diff --git a/grpc/third_party/abseil-cpp/absl/strings/numbers.h b/grpc/third_party/abseil-cpp/absl/strings/numbers.h
index d872cca..1780bb4 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/numbers.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/numbers.h
@@ -1,4 +1,3 @@
-//
 // Copyright 2017 The Abseil Authors.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -37,7 +36,6 @@
 #include <type_traits>
 
 #include "absl/base/config.h"
-#include "absl/base/internal/bits.h"
 #ifdef __SSE4_2__
 // TODO(jorg): Remove this when we figure out the right way
 // to swap bytes on SSE 4.2 that works with the compilers
@@ -48,6 +46,7 @@
 #endif
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
+#include "absl/numeric/bits.h"
 #include "absl/numeric/int128.h"
 #include "absl/strings/string_view.h"
 
@@ -125,8 +124,11 @@
 }
 
 // safe_strto?() functions for implementing SimpleAtoi()
+
 bool safe_strto32_base(absl::string_view text, int32_t* value, int base);
 bool safe_strto64_base(absl::string_view text, int64_t* value, int base);
+bool safe_strto128_base(absl::string_view text, absl::int128* value,
+                         int base);
 bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base);
 bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base);
 bool safe_strtou128_base(absl::string_view text, absl::uint128* value,
@@ -238,24 +240,22 @@
   }
 #endif
   // | 0x1 so that even 0 has 1 digit.
-  return 16 - absl::base_internal::CountLeadingZeros64(val | 0x1) / 4;
+  return 16 - countl_zero(val | 0x1) / 4;
 }
 
 }  // namespace numbers_internal
 
-// SimpleAtoi()
-//
-// Converts a string to an integer, using `safe_strto?()` functions for actual
-// parsing, returning `true` if successful. The `safe_strto?()` functions apply
-// strict checking; the string must be a base-10 integer, optionally followed or
-// preceded by ASCII whitespace, with a value in the range of the corresponding
-// integer type.
 template <typename int_type>
 ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) {
   return numbers_internal::safe_strtoi_base(str, out, 10);
 }
 
 ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
+                                            absl::int128* out) {
+  return numbers_internal::safe_strto128_base(str, out, 10);
+}
+
+ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
                                             absl::uint128* out) {
   return numbers_internal::safe_strtou128_base(str, out, 10);
 }
diff --git a/grpc/third_party/abseil-cpp/absl/strings/numbers_test.cc b/grpc/third_party/abseil-cpp/absl/strings/numbers_test.cc
index c2f03b6..f310310 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/numbers_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/numbers_test.cc
@@ -46,6 +46,7 @@
 
 namespace {
 
+using absl::SimpleAtoi;
 using absl::numbers_internal::kSixDigitsToBufferSize;
 using absl::numbers_internal::safe_strto32_base;
 using absl::numbers_internal::safe_strto64_base;
@@ -55,7 +56,6 @@
 using absl::strings_internal::Itoa;
 using absl::strings_internal::strtouint32_test_cases;
 using absl::strings_internal::strtouint64_test_cases;
-using absl::SimpleAtoi;
 using testing::Eq;
 using testing::MatchesRegex;
 
@@ -251,7 +251,7 @@
 template <typename int_type, typename in_val_type>
 void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
   std::string s;
-  // uint128 can be streamed but not StrCat'd
+  // (u)int128 can be streamed but not StrCat'd.
   absl::strings_internal::OStringStream(&s) << in_value;
   int_type x = static_cast<int_type>(~exp_value);
   EXPECT_TRUE(SimpleAtoi(s, &x))
@@ -264,7 +264,9 @@
 
 template <typename int_type, typename in_val_type>
 void VerifySimpleAtoiBad(in_val_type in_value) {
-  std::string s = absl::StrCat(in_value);
+  std::string s;
+  // (u)int128 can be streamed but not StrCat'd.
+  absl::strings_internal::OStringStream(&s) << in_value;
   int_type x;
   EXPECT_FALSE(SimpleAtoi(s, &x));
   EXPECT_FALSE(SimpleAtoi(s.c_str(), &x));
@@ -347,13 +349,38 @@
       std::numeric_limits<absl::uint128>::max(),
       std::numeric_limits<absl::uint128>::max());
 
+  // SimpleAtoi(absl::string_view, absl::int128)
+  VerifySimpleAtoiGood<absl::int128>(0, 0);
+  VerifySimpleAtoiGood<absl::int128>(42, 42);
+  VerifySimpleAtoiGood<absl::int128>(-42, -42);
+
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int32_t>::min(),
+                                      std::numeric_limits<int32_t>::min());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int32_t>::max(),
+                                      std::numeric_limits<int32_t>::max());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<uint32_t>::max(),
+                                      std::numeric_limits<uint32_t>::max());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int64_t>::min(),
+                                      std::numeric_limits<int64_t>::min());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int64_t>::max(),
+                                      std::numeric_limits<int64_t>::max());
+  VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<uint64_t>::max(),
+                                      std::numeric_limits<uint64_t>::max());
+  VerifySimpleAtoiGood<absl::int128>(
+      std::numeric_limits<absl::int128>::min(),
+      std::numeric_limits<absl::int128>::min());
+  VerifySimpleAtoiGood<absl::int128>(
+      std::numeric_limits<absl::int128>::max(),
+      std::numeric_limits<absl::int128>::max());
+  VerifySimpleAtoiBad<absl::int128>(std::numeric_limits<absl::uint128>::max());
+
   // Some other types
   VerifySimpleAtoiGood<int>(-42, -42);
   VerifySimpleAtoiGood<int32_t>(-42, -42);
   VerifySimpleAtoiGood<uint32_t>(42, 42);
   VerifySimpleAtoiGood<unsigned int>(42, 42);
   VerifySimpleAtoiGood<int64_t>(-42, -42);
-  VerifySimpleAtoiGood<long>(-42, -42);  // NOLINT(runtime/int)
+  VerifySimpleAtoiGood<long>(-42, -42);  // NOLINT: runtime-int
   VerifySimpleAtoiGood<uint64_t>(42, 42);
   VerifySimpleAtoiGood<size_t>(42, 42);
   VerifySimpleAtoiGood<std::string::size_type>(42, 42);
@@ -365,6 +392,28 @@
   EXPECT_TRUE(std::isnan(d));
 }
 
+TEST(NumbersTest, Prefixes) {
+  double d;
+  EXPECT_FALSE(absl::SimpleAtod("++1", &d));
+  EXPECT_FALSE(absl::SimpleAtod("+-1", &d));
+  EXPECT_FALSE(absl::SimpleAtod("-+1", &d));
+  EXPECT_FALSE(absl::SimpleAtod("--1", &d));
+  EXPECT_TRUE(absl::SimpleAtod("-1", &d));
+  EXPECT_EQ(d, -1.);
+  EXPECT_TRUE(absl::SimpleAtod("+1", &d));
+  EXPECT_EQ(d, +1.);
+
+  float f;
+  EXPECT_FALSE(absl::SimpleAtof("++1", &f));
+  EXPECT_FALSE(absl::SimpleAtof("+-1", &f));
+  EXPECT_FALSE(absl::SimpleAtof("-+1", &f));
+  EXPECT_FALSE(absl::SimpleAtof("--1", &f));
+  EXPECT_TRUE(absl::SimpleAtof("-1", &f));
+  EXPECT_EQ(f, -1.f);
+  EXPECT_TRUE(absl::SimpleAtof("+1", &f));
+  EXPECT_EQ(f, +1.f);
+}
+
 TEST(NumbersTest, Atoenum) {
   enum E01 {
     E01_zero = 0,
@@ -725,6 +774,51 @@
     EXPECT_FALSE(parse_func(s, &parsed_value, base));
   }
 }
+TEST(stringtest, safe_strto128_random) {
+  // random number generators don't work for int128, and
+  // int128 can be streamed but not StrCat'd, so this code must be custom
+  // implemented for int128, but is generally the same as what's above.
+  // test_random_integer_parse_base<absl::int128>(
+  //     &absl::numbers_internal::safe_strto128_base);
+  using RandomEngine = std::minstd_rand0;
+  using IntType = absl::int128;
+  constexpr auto parse_func = &absl::numbers_internal::safe_strto128_base;
+
+  std::random_device rd;
+  RandomEngine rng(rd());
+  std::uniform_int_distribution<int64_t> random_int64(
+      std::numeric_limits<int64_t>::min());
+  std::uniform_int_distribution<uint64_t> random_uint64(
+      std::numeric_limits<uint64_t>::min());
+  std::uniform_int_distribution<int> random_base(2, 35);
+
+  for (size_t i = 0; i < kNumRandomTests; ++i) {
+    int64_t high = random_int64(rng);
+    uint64_t low = random_uint64(rng);
+    IntType value = absl::MakeInt128(high, low);
+
+    int base = random_base(rng);
+    std::string str_value;
+    EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+    IntType parsed_value;
+
+    // Test successful parse
+    EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+    EXPECT_EQ(parsed_value, value);
+
+    // Test overflow
+    std::string s;
+    absl::strings_internal::OStringStream(&s)
+        << std::numeric_limits<IntType>::max() << value;
+    EXPECT_FALSE(parse_func(s, &parsed_value, base));
+
+    // Test underflow
+    s.clear();
+    absl::strings_internal::OStringStream(&s)
+        << std::numeric_limits<IntType>::min() << value;
+    EXPECT_FALSE(parse_func(s, &parsed_value, base));
+  }
+}
 
 TEST(stringtest, safe_strtou32_base) {
   for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {
diff --git a/grpc/third_party/abseil-cpp/absl/strings/str_format_test.cc b/grpc/third_party/abseil-cpp/absl/strings/str_format_test.cc
index d9fb25a..c60027a 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/str_format_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/str_format_test.cc
@@ -1,3 +1,16 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 "absl/strings/str_format.h"
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/str_join.h b/grpc/third_party/abseil-cpp/absl/strings/str_join.h
index ae5731a..3353453 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/str_join.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/str_join.h
@@ -144,7 +144,7 @@
       std::forward<Formatter>(f));
 }
 
-// Function overload of `DererefenceFormatter()` for using a default
+// Function overload of `DereferenceFormatter()` for using a default
 // `AlphaNumFormatter()`.
 inline strings_internal::DereferenceFormatterImpl<
     strings_internal::AlphaNumFormatterImpl>
diff --git a/grpc/third_party/abseil-cpp/absl/strings/str_split.h b/grpc/third_party/abseil-cpp/absl/strings/str_split.h
index 1ce17f3..bfbca42 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/str_split.h
+++ b/grpc/third_party/abseil-cpp/absl/strings/str_split.h
@@ -369,6 +369,12 @@
   }
 };
 
+template <typename T>
+using EnableSplitIfString =
+    typename std::enable_if<std::is_same<T, std::string>::value ||
+                            std::is_same<T, const std::string>::value,
+                            int>::type;
+
 //------------------------------------------------------------------------------
 //                                  StrSplit()
 //------------------------------------------------------------------------------
@@ -489,22 +495,50 @@
 // Try not to depend on this distinction because the bug may one day be fixed.
 template <typename Delimiter>
 strings_internal::Splitter<
-    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty>
+    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
+    absl::string_view>
 StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) {
   using DelimiterType =
       typename strings_internal::SelectDelimiter<Delimiter>::type;
-  return strings_internal::Splitter<DelimiterType, AllowEmpty>(
+  return strings_internal::Splitter<DelimiterType, AllowEmpty,
+                                    absl::string_view>(
+      text.value(), DelimiterType(d), AllowEmpty());
+}
+
+template <typename Delimiter, typename StringType,
+          EnableSplitIfString<StringType> = 0>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
+    std::string>
+StrSplit(StringType&& text, Delimiter d) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, AllowEmpty, std::string>(
       std::move(text), DelimiterType(d), AllowEmpty());
 }
 
 template <typename Delimiter, typename Predicate>
 strings_internal::Splitter<
-    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate>
+    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
+    absl::string_view>
 StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
          Predicate p) {
   using DelimiterType =
       typename strings_internal::SelectDelimiter<Delimiter>::type;
-  return strings_internal::Splitter<DelimiterType, Predicate>(
+  return strings_internal::Splitter<DelimiterType, Predicate,
+                                    absl::string_view>(
+      text.value(), DelimiterType(d), std::move(p));
+}
+
+template <typename Delimiter, typename Predicate, typename StringType,
+          EnableSplitIfString<StringType> = 0>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
+    std::string>
+StrSplit(StringType&& text, Delimiter d, Predicate p) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, Predicate, std::string>(
       std::move(text), DelimiterType(d), std::move(p));
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/strings/str_split_test.cc b/grpc/third_party/abseil-cpp/absl/strings/str_split_test.cc
index b5ce68d..7f7c097 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/str_split_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/str_split_test.cc
@@ -367,7 +367,7 @@
 TEST(Splitter, RangeIterators) {
   auto splitter = absl::StrSplit("a,b,c", ',');
   std::vector<absl::string_view> output;
-  for (const absl::string_view p : splitter) {
+  for (const absl::string_view& p : splitter) {
     output.push_back(p);
   }
   EXPECT_THAT(output, ElementsAre("a", "b", "c"));
diff --git a/grpc/third_party/abseil-cpp/absl/strings/string_view_test.cc b/grpc/third_party/abseil-cpp/absl/strings/string_view_test.cc
index dcebb15..643af8f 100644
--- a/grpc/third_party/abseil-cpp/absl/strings/string_view_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/strings/string_view_test.cc
@@ -915,9 +915,9 @@
   EXPECT_EQ(abc.at(1), 'b');
   EXPECT_EQ(abc.at(2), 'c');
 #ifdef ABSL_HAVE_EXCEPTIONS
-  EXPECT_THROW(abc.at(3), std::out_of_range);
+  EXPECT_THROW((void)abc.at(3), std::out_of_range);
 #else
-  ABSL_EXPECT_DEATH_IF_SUPPORTED(abc.at(3), "absl::string_view::at");
+  ABSL_EXPECT_DEATH_IF_SUPPORTED((void)abc.at(3), "absl::string_view::at");
 #endif
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
index 4d4d680..5ce1695 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
@@ -73,15 +73,14 @@
         "internal/create_thread_identity.cc",
         "internal/per_thread_sem.cc",
         "internal/waiter.cc",
+        "mutex.cc",
         "notification.cc",
-    ] + select({
-        "//conditions:default": ["mutex.cc"],
-    }),
+    ],
     hdrs = [
         "barrier.h",
         "blocking_counter.h",
         "internal/create_thread_identity.h",
-        "internal/mutex_nonprod.inc",
+        "internal/futex.h",
         "internal/per_thread_sem.h",
         "internal/waiter.h",
         "mutex.h",
@@ -89,7 +88,8 @@
     ],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = select({
-        "//absl:windows": [],
+        "//absl:msvc_compiler": [],
+        "//absl:clang-cl_compiler": [],
         "//absl:wasm": [],
         "//conditions:default": ["-pthread"],
     }) + ABSL_DEFAULT_LINKOPTS,
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
index e5bc52f..e633d0b 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
@@ -52,7 +52,7 @@
     "barrier.h"
     "blocking_counter.h"
     "internal/create_thread_identity.h"
-    "internal/mutex_nonprod.inc"
+    "internal/futex.h"
     "internal/per_thread_sem.h"
     "internal/waiter.h"
     "mutex.h"
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/futex.h b/grpc/third_party/abseil-cpp/absl/synchronization/internal/futex.h
new file mode 100644
index 0000000..06fbd6d
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/internal/futex.h
@@ -0,0 +1,154 @@
+// Copyright 2020 The Abseil 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
+//
+//      https://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 ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/optimization.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+#error ABSL_INTERNAL_HAVE_FUTEX may not be set on the command line
+#elif defined(__BIONIC__)
+// Bionic supports all the futex operations we need even when some of the futex
+// definitions are missing.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
+// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// Some Android headers are missing these definitions even though they
+// support these futex operations.
+#ifdef __BIONIC__
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#ifndef FUTEX_WAIT_BITSET
+#define FUTEX_WAIT_BITSET 9
+#endif
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+#ifndef FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+#ifndef FUTEX_BITSET_MATCH_ANY
+#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
+#endif
+#endif
+
+#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
+#define SYS_futex_time64 __NR_futex_time64
+#endif
+
+#if defined(SYS_futex_time64) && !defined(SYS_futex)
+#define SYS_futex SYS_futex_time64
+#endif
+
+class FutexImpl {
+ public:
+  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
+                       KernelTimeout t) {
+    int err = 0;
+    if (t.has_timeout()) {
+      // https://locklessinc.com/articles/futex_cheat_sheet/
+      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
+      struct timespec abs_timeout = t.MakeAbsTimespec();
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
+      err = syscall(
+          SYS_futex, reinterpret_cast<int32_t *>(v),
+          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
+          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+    } else {
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until woken by FUTEX_WAKE.
+      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
+    }
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int WaitBitsetAbsoluteTimeout(std::atomic<int32_t> *v, int32_t val,
+                                       int32_t bits,
+                                       const struct timespec *abstime) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime,
+                      nullptr, bits);
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int Wake(std::atomic<int32_t> *v, int32_t count) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  // FUTEX_WAKE_BITSET
+  static int WakeBitset(std::atomic<int32_t> *v, int32_t count, int32_t bits) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr,
+                      nullptr, bits);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+};
+
+class Futex : public FutexImpl {};
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_FUTEX
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc b/grpc/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc
index 19f9aab..27fec21 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc
@@ -37,6 +37,7 @@
 
 #include <algorithm>
 #include <array>
+#include <limits>
 #include "absl/base/internal/hide_ptr.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/spinlock.h"
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h b/grpc/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
index 1084e1e..bbd4d2d 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
@@ -26,6 +26,7 @@
 #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
 
 #include <time.h>
+
 #include <algorithm>
 #include <limits>
 
@@ -142,7 +143,7 @@
 
   struct timespec abstime;
   int64_t seconds = (std::min)(n / kNanosPerSecond,
-                             int64_t{(std::numeric_limits<time_t>::max)()});
+                               int64_t{(std::numeric_limits<time_t>::max)()});
   abstime.tv_sec = static_cast<time_t>(seconds);
   abstime.tv_nsec = static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
   return abstime;
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.cc b/grpc/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.cc
deleted file mode 100644
index 334c3bc..0000000
--- a/grpc/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.cc
+++ /dev/null
@@ -1,325 +0,0 @@
-// Copyright 2017 The Abseil 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
-//
-//      https://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.
-
-// Implementation of a small subset of Mutex and CondVar functionality
-// for platforms where the production implementation hasn't been fully
-// ported yet.
-
-#include "absl/synchronization/mutex.h"
-
-#if defined(_WIN32)
-#include <chrono>  // NOLINT(build/c++11)
-#else
-#include <sys/time.h>
-#include <time.h>
-#endif
-
-#include <algorithm>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
-#include "absl/time/time.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-void SetMutexDeadlockDetectionMode(OnDeadlockCycle) {}
-void EnableMutexInvariantDebugging(bool) {}
-
-namespace synchronization_internal {
-
-namespace {
-
-// Return the current time plus the timeout.
-absl::Time DeadlineFromTimeout(absl::Duration timeout) {
-  return absl::Now() + timeout;
-}
-
-// Limit the deadline to a positive, 32-bit time_t value to accommodate
-// implementation restrictions.  This also deals with InfinitePast and
-// InfiniteFuture.
-absl::Time LimitedDeadline(absl::Time deadline) {
-  deadline = std::max(absl::FromTimeT(0), deadline);
-  deadline = std::min(deadline, absl::FromTimeT(0x7fffffff));
-  return deadline;
-}
-
-}  // namespace
-
-#if defined(_WIN32)
-
-MutexImpl::MutexImpl() {}
-
-MutexImpl::~MutexImpl() {
-  if (locked_) {
-    std_mutex_.unlock();
-  }
-}
-
-void MutexImpl::Lock() {
-  std_mutex_.lock();
-  locked_ = true;
-}
-
-bool MutexImpl::TryLock() {
-  bool locked = std_mutex_.try_lock();
-  if (locked) locked_ = true;
-  return locked;
-}
-
-void MutexImpl::Unlock() {
-  locked_ = false;
-  released_.SignalAll();
-  std_mutex_.unlock();
-}
-
-CondVarImpl::CondVarImpl() {}
-
-CondVarImpl::~CondVarImpl() {}
-
-void CondVarImpl::Signal() { std_cv_.notify_one(); }
-
-void CondVarImpl::SignalAll() { std_cv_.notify_all(); }
-
-void CondVarImpl::Wait(MutexImpl* mu) {
-  mu->released_.SignalAll();
-  std_cv_.wait(mu->std_mutex_);
-}
-
-bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
-  mu->released_.SignalAll();
-  time_t when = ToTimeT(deadline);
-  int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when));
-  std::chrono::system_clock::time_point deadline_tp =
-      std::chrono::system_clock::from_time_t(when) +
-      std::chrono::duration_cast<std::chrono::system_clock::duration>(
-          std::chrono::nanoseconds(nanos));
-  auto deadline_since_epoch =
-      std::chrono::duration_cast<std::chrono::duration<double>>(
-          deadline_tp - std::chrono::system_clock::from_time_t(0));
-  return std_cv_.wait_until(mu->std_mutex_, deadline_tp) ==
-         std::cv_status::timeout;
-}
-
-#else  // ! _WIN32
-
-MutexImpl::MutexImpl() {
-  ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0,
-                 "pthread error");
-}
-
-MutexImpl::~MutexImpl() {
-  if (locked_) {
-    ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
-  }
-  ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error");
-}
-
-void MutexImpl::Lock() {
-  ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error");
-  locked_ = true;
-}
-
-bool MutexImpl::TryLock() {
-  bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_));
-  if (locked) locked_ = true;
-  return locked;
-}
-
-void MutexImpl::Unlock() {
-  locked_ = false;
-  released_.SignalAll();
-  ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
-}
-
-CondVarImpl::CondVarImpl() {
-  ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0,
-                 "pthread error");
-}
-
-CondVarImpl::~CondVarImpl() {
-  ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error");
-}
-
-void CondVarImpl::Signal() {
-  ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error");
-}
-
-void CondVarImpl::SignalAll() {
-  ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error");
-}
-
-void CondVarImpl::Wait(MutexImpl* mu) {
-  mu->released_.SignalAll();
-  ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0,
-                 "pthread error");
-}
-
-bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
-  mu->released_.SignalAll();
-  struct timespec ts = ToTimespec(deadline);
-  int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts);
-  if (rc == ETIMEDOUT) return true;
-  ABSL_RAW_CHECK(rc == 0, "pthread error");
-  return false;
-}
-
-#endif  // ! _WIN32
-
-void MutexImpl::Await(const Condition& cond) {
-  if (cond.Eval()) return;
-  released_.SignalAll();
-  do {
-    released_.Wait(this);
-  } while (!cond.Eval());
-}
-
-bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
-  if (cond.Eval()) return true;
-  released_.SignalAll();
-  while (true) {
-    if (released_.WaitWithDeadline(this, deadline)) return false;
-    if (cond.Eval()) return true;
-  }
-}
-
-}  // namespace synchronization_internal
-
-Mutex::Mutex() {}
-
-Mutex::~Mutex() {}
-
-void Mutex::Lock() { impl()->Lock(); }
-
-void Mutex::Unlock() { impl()->Unlock(); }
-
-bool Mutex::TryLock() { return impl()->TryLock(); }
-
-void Mutex::ReaderLock() { Lock(); }
-
-void Mutex::ReaderUnlock() { Unlock(); }
-
-void Mutex::Await(const Condition& cond) { impl()->Await(cond); }
-
-void Mutex::LockWhen(const Condition& cond) {
-  Lock();
-  Await(cond);
-}
-
-bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
-  return impl()->AwaitWithDeadline(
-      cond, synchronization_internal::LimitedDeadline(deadline));
-}
-
-bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
-  return AwaitWithDeadline(
-      cond, synchronization_internal::DeadlineFromTimeout(timeout));
-}
-
-bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) {
-  Lock();
-  return AwaitWithDeadline(cond, deadline);
-}
-
-bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) {
-  return LockWhenWithDeadline(
-      cond, synchronization_internal::DeadlineFromTimeout(timeout));
-}
-
-void Mutex::ReaderLockWhen(const Condition& cond) {
-  ReaderLock();
-  Await(cond);
-}
-
-bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond,
-                                      absl::Duration timeout) {
-  return LockWhenWithTimeout(cond, timeout);
-}
-bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond,
-                                       absl::Time deadline) {
-  return LockWhenWithDeadline(cond, deadline);
-}
-
-void Mutex::EnableDebugLog(const char*) {}
-void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {}
-void Mutex::ForgetDeadlockInfo() {}
-void Mutex::AssertHeld() const {}
-void Mutex::AssertReaderHeld() const {}
-void Mutex::AssertNotHeld() const {}
-
-CondVar::CondVar() {}
-
-CondVar::~CondVar() {}
-
-void CondVar::Signal() { impl()->Signal(); }
-
-void CondVar::SignalAll() { impl()->SignalAll(); }
-
-void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); }
-
-bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) {
-  return impl()->WaitWithDeadline(
-      mu->impl(), synchronization_internal::LimitedDeadline(deadline));
-}
-
-bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
-  return WaitWithDeadline(mu, absl::Now() + timeout);
-}
-
-void CondVar::EnableDebugLog(const char*) {}
-
-#ifdef ABSL_HAVE_THREAD_SANITIZER
-extern "C" void __tsan_read1(void *addr);
-#else
-#define __tsan_read1(addr)  // do nothing if TSan not enabled
-#endif
-
-// A function that just returns its argument, dereferenced
-static bool Dereference(void *arg) {
-  // ThreadSanitizer does not instrument this file for memory accesses.
-  // This function dereferences a user variable that can participate
-  // in a data race, so we need to manually tell TSan about this memory access.
-  __tsan_read1(arg);
-  return *(static_cast<bool *>(arg));
-}
-
-Condition::Condition() {}   // null constructor, used for kTrue only
-const Condition Condition::kTrue;
-
-Condition::Condition(bool (*func)(void *), void *arg)
-    : eval_(&CallVoidPtrFunction),
-      function_(func),
-      method_(nullptr),
-      arg_(arg) {}
-
-bool Condition::CallVoidPtrFunction(const Condition *c) {
-  return (*c->function_)(c->arg_);
-}
-
-Condition::Condition(const bool *cond)
-    : eval_(CallVoidPtrFunction),
-      function_(Dereference),
-      method_(nullptr),
-      // const_cast is safe since Dereference does not modify arg
-      arg_(const_cast<bool *>(cond)) {}
-
-bool Condition::Eval() const {
-  // eval_ == null for kTrue
-  return (this->eval_ == nullptr) || (*this->eval_)(this);
-}
-
-void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
-
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc b/grpc/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc
deleted file mode 100644
index d83bc8a..0000000
--- a/grpc/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc
+++ /dev/null
@@ -1,249 +0,0 @@
-// Do not include.  This is an implementation detail of base/mutex.h.
-//
-// Declares three classes:
-//
-// base::internal::MutexImpl - implementation helper for Mutex
-// base::internal::CondVarImpl - implementation helper for CondVar
-// base::internal::SynchronizationStorage<T> - implementation helper for
-//                                             Mutex, CondVar
-
-#include <type_traits>
-
-#if defined(_WIN32)
-#include <condition_variable>
-#include <mutex>
-#else
-#include <pthread.h>
-#endif
-
-#include "absl/base/call_once.h"
-#include "absl/time/time.h"
-
-// Declare that Mutex::ReaderLock is actually Lock().  Intended primarily
-// for tests, and even then as a last resort.
-#ifdef ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE
-#error ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE cannot be directly set
-#else
-#define ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE 1
-#endif
-
-// Declare that Mutex::EnableInvariantDebugging is not implemented.
-// Intended primarily for tests, and even then as a last resort.
-#ifdef ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED
-#error ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED cannot be directly set
-#else
-#define ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED 1
-#endif
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-class Condition;
-
-namespace synchronization_internal {
-
-class MutexImpl;
-
-// Do not use this implementation detail of CondVar. Provides most of the
-// implementation, but should not be placed directly in static storage
-// because it will not linker initialize properly. See
-// SynchronizationStorage<T> below for what we mean by linker
-// initialization.
-class CondVarImpl {
- public:
-  CondVarImpl();
-  CondVarImpl(const CondVarImpl&) = delete;
-  CondVarImpl& operator=(const CondVarImpl&) = delete;
-  ~CondVarImpl();
-
-  void Signal();
-  void SignalAll();
-  void Wait(MutexImpl* mutex);
-  bool WaitWithDeadline(MutexImpl* mutex, absl::Time deadline);
-
- private:
-#if defined(_WIN32)
-  std::condition_variable_any std_cv_;
-#else
-  pthread_cond_t pthread_cv_;
-#endif
-};
-
-// Do not use this implementation detail of Mutex. Provides most of the
-// implementation, but should not be placed directly in static storage
-// because it will not linker initialize properly. See
-// SynchronizationStorage<T> below for what we mean by linker
-// initialization.
-class MutexImpl {
- public:
-  MutexImpl();
-  MutexImpl(const MutexImpl&) = delete;
-  MutexImpl& operator=(const MutexImpl&) = delete;
-  ~MutexImpl();
-
-  void Lock();
-  bool TryLock();
-  void Unlock();
-  void Await(const Condition& cond);
-  bool AwaitWithDeadline(const Condition& cond, absl::Time deadline);
-
- private:
-  friend class CondVarImpl;
-
-#if defined(_WIN32)
-  std::mutex std_mutex_;
-#else
-  pthread_mutex_t pthread_mutex_;
-#endif
-
-  // True if the underlying mutex is locked.  If the destructor is entered
-  // while locked_, the underlying mutex is unlocked.  Mutex supports
-  // destruction while locked, but the same is undefined behavior for both
-  // pthread_mutex_t and std::mutex.
-  bool locked_ = false;
-
-  // Signaled before releasing the lock, in support of Await.
-  CondVarImpl released_;
-};
-
-// Do not use this implementation detail of CondVar and Mutex.  A storage
-// space for T that supports a LinkerInitialized constructor. T must
-// have a default constructor, which is called by the first call to
-// get(). T's destructor is never called if the LinkerInitialized
-// constructor is called.
-//
-// Objects constructed with the default constructor are constructed and
-// destructed like any other object, and should never be allocated in
-// static storage.
-//
-// Objects constructed with the LinkerInitialized constructor should
-// always be in static storage. For such objects, calls to get() are always
-// valid, except from signal handlers.
-//
-// Note that this implementation relies on undefined language behavior that
-// are known to hold for the set of supported compilers. An analysis
-// follows.
-//
-// From the C++11 standard:
-//
-// [basic.life] says an object has non-trivial initialization if it is of
-// class type and it is initialized by a constructor other than a trivial
-// default constructor.  (the LinkerInitialized constructor is
-// non-trivial)
-//
-// [basic.life] says the lifetime of an object with a non-trivial
-// constructor begins when the call to the constructor is complete.
-//
-// [basic.life] says the lifetime of an object with non-trivial destructor
-// ends when the call to the destructor begins.
-//
-// [basic.life] p5 specifies undefined behavior when accessing non-static
-// members of an instance outside its
-// lifetime. (SynchronizationStorage::get() access non-static members)
-//
-// So, LinkerInitialized object of SynchronizationStorage uses a
-// non-trivial constructor, which is called at some point during dynamic
-// initialization, and is therefore subject to order of dynamic
-// initialization bugs, where get() is called before the object's
-// constructor is, resulting in undefined behavior.
-//
-// Similarly, a LinkerInitialized SynchronizationStorage object has a
-// non-trivial destructor, and so its lifetime ends at some point during
-// destruction of objects with static storage duration [basic.start.term]
-// p4. There is a window where other exit code could call get() after this
-// occurs, resulting in undefined behavior.
-//
-// Combined, these statements imply that LinkerInitialized instances
-// of SynchronizationStorage<T> rely on undefined behavior.
-//
-// However, in practice, the implementation works on all supported
-// compilers. Specifically, we rely on:
-//
-// a) zero-initialization being sufficient to initialize
-// LinkerInitialized instances for the purposes of calling
-// get(), regardless of when the constructor is called. This is
-// because the is_dynamic_ boolean is correctly zero-initialized to
-// false.
-//
-// b) the LinkerInitialized constructor is a NOP, and immaterial to
-// even to concurrent calls to get().
-//
-// c) the destructor being a NOP for LinkerInitialized objects
-// (guaranteed by a check for !is_dynamic_), and so any concurrent and
-// subsequent calls to get() functioning as if the destructor were not
-// called, by virtue of the instances' storage remaining valid after the
-// destructor runs.
-//
-// d) That a-c apply transitively when SynchronizationStorage<T> is the
-// only member of a class allocated in static storage.
-//
-// Nothing in the language standard guarantees that a-d hold.  In practice,
-// these hold in all supported compilers.
-//
-// Future direction:
-//
-// Ideally, we would simply use std::mutex or a similar class, which when
-// allocated statically would support use immediately after static
-// initialization up until static storage is reclaimed (i.e. the properties
-// we require of all "linker initialized" instances).
-//
-// Regarding construction in static storage, std::mutex is required to
-// provide a constexpr default constructor [thread.mutex.class], which
-// ensures the instance's lifetime begins with static initialization
-// [basic.start.init], and so is immune to any problems caused by the order
-// of dynamic initialization. However, as of this writing Microsoft's
-// Visual Studio does not provide a constexpr constructor for std::mutex.
-// See
-// https://blogs.msdn.microsoft.com/vcblog/2015/06/02/constexpr-complete-for-vs-2015-rtm-c11-compiler-c17-stl/
-//
-// Regarding destruction of instances in static storage, [basic.life] does
-// say an object ends when storage in which the occupies is released, in
-// the case of non-trivial destructor. However, std::mutex is not specified
-// to have a trivial destructor.
-//
-// So, we would need a class with a constexpr default constructor and a
-// trivial destructor. Today, we can achieve neither desired property using
-// std::mutex directly.
-template <typename T>
-class SynchronizationStorage {
- public:
-  // Instances allocated on the heap or on the stack should use the default
-  // constructor.
-  SynchronizationStorage()
-      : destruct_(true), once_() {}
-
-  constexpr explicit SynchronizationStorage(absl::ConstInitType)
-      : destruct_(false), once_(), space_{{0}} {}
-
-  SynchronizationStorage(SynchronizationStorage&) = delete;
-  SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
-
-  ~SynchronizationStorage() {
-    if (destruct_) {
-      get()->~T();
-    }
-  }
-
-  // Retrieve the object in storage. This is fast and thread safe, but does
-  // incur the cost of absl::call_once().
-  T* get() {
-    absl::call_once(once_, SynchronizationStorage::Construct, this);
-    return reinterpret_cast<T*>(&space_);
-  }
-
- private:
-  static void Construct(SynchronizationStorage<T>* self) {
-    new (&self->space_) T();
-  }
-
-  // When true, T's destructor is run when this is destructed.
-  const bool destruct_;
-
-  absl::once_flag once_;
-
-  // An aligned space for the T.
-  alignas(T) unsigned char space_[sizeof(T)];
-};
-
-}  // namespace synchronization_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc b/grpc/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc
index 821ca9b..a603178 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc
@@ -68,12 +68,12 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalPerThreadSemPost(
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(
     absl::base_internal::ThreadIdentity *identity) {
   absl::synchronization_internal::Waiter::GetWaiter(identity)->Post();
 }
 
-ABSL_ATTRIBUTE_WEAK bool AbslInternalPerThreadSemWait(
+ABSL_ATTRIBUTE_WEAK bool ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(
     absl::synchronization_internal::KernelTimeout t) {
   bool timeout = false;
   absl::base_internal::ThreadIdentity *identity;
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h b/grpc/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h
index 2228b6e..7beae8e 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h
@@ -96,20 +96,20 @@
 // By changing our extension points to be extern "C", we dodge this
 // check.
 extern "C" {
-void AbslInternalPerThreadSemPost(
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(
     absl::base_internal::ThreadIdentity* identity);
-bool AbslInternalPerThreadSemWait(
+bool ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(
     absl::synchronization_internal::KernelTimeout t);
 }  // extern "C"
 
 void absl::synchronization_internal::PerThreadSem::Post(
     absl::base_internal::ThreadIdentity* identity) {
-  AbslInternalPerThreadSemPost(identity);
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(identity);
 }
 
 bool absl::synchronization_internal::PerThreadSem::Wait(
     absl::synchronization_internal::KernelTimeout t) {
-  return AbslInternalPerThreadSemWait(t);
+  return ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(t);
 }
 
 #endif  // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc b/grpc/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc
index b6150b9..2123be6 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc
@@ -48,6 +48,7 @@
 #include "absl/base/optimization.h"
 #include "absl/synchronization/internal/kernel_timeout.h"
 
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace synchronization_internal {
@@ -66,71 +67,6 @@
 
 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
 
-// Some Android headers are missing these definitions even though they
-// support these futex operations.
-#ifdef __BIONIC__
-#ifndef SYS_futex
-#define SYS_futex __NR_futex
-#endif
-#ifndef FUTEX_WAIT_BITSET
-#define FUTEX_WAIT_BITSET 9
-#endif
-#ifndef FUTEX_PRIVATE_FLAG
-#define FUTEX_PRIVATE_FLAG 128
-#endif
-#ifndef FUTEX_CLOCK_REALTIME
-#define FUTEX_CLOCK_REALTIME 256
-#endif
-#ifndef FUTEX_BITSET_MATCH_ANY
-#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
-#endif
-#endif
-
-#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
-#define SYS_futex_time64 __NR_futex_time64
-#endif
-
-#if defined(SYS_futex_time64) && !defined(SYS_futex)
-#define SYS_futex SYS_futex_time64
-#endif
-
-class Futex {
- public:
-  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
-                       KernelTimeout t) {
-    int err = 0;
-    if (t.has_timeout()) {
-      // https://locklessinc.com/articles/futex_cheat_sheet/
-      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
-      struct timespec abs_timeout = t.MakeAbsTimespec();
-      // Atomically check that the futex value is still 0, and if it
-      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
-      err = syscall(
-          SYS_futex, reinterpret_cast<int32_t *>(v),
-          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
-          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
-    } else {
-      // Atomically check that the futex value is still 0, and if it
-      // is, sleep until woken by FUTEX_WAKE.
-      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
-                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
-    }
-    if (err != 0) {
-      err = -errno;
-    }
-    return err;
-  }
-
-  static int Wake(std::atomic<int32_t> *v, int32_t count) {
-    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
-                      FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
-    if (ABSL_PREDICT_FALSE(err < 0)) {
-      err = -errno;
-    }
-    return err;
-  }
-};
-
 Waiter::Waiter() {
   futex_.store(0, std::memory_order_relaxed);
 }
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/internal/waiter.h b/grpc/third_party/abseil-cpp/absl/synchronization/internal/waiter.h
index 887f9b1..be3df18 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/internal/waiter.h
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/internal/waiter.h
@@ -36,6 +36,7 @@
 #include <cstdint>
 
 #include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/futex.h"
 #include "absl/synchronization/internal/kernel_timeout.h"
 
 // May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index>
@@ -48,12 +49,7 @@
 #define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
 #elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
-#elif defined(__BIONIC__)
-// Bionic supports all the futex operations we need even when some of the futex
-// definitions are missing.
-#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
-#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
-// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
+#elif defined(ABSL_INTERNAL_HAVE_FUTEX)
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
 #elif defined(ABSL_HAVE_SEMAPHORE_H)
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/mutex.cc b/grpc/third_party/abseil-cpp/absl/synchronization/mutex.cc
index ad13567..76ad41f 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/mutex.cc
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/mutex.cc
@@ -70,7 +70,9 @@
 using absl::synchronization_internal::PerThreadSem;
 
 extern "C" {
-ABSL_ATTRIBUTE_WEAK void AbslInternalMutexYield() { std::this_thread::yield(); }
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)() {
+  std::this_thread::yield();
+}
 }  // extern "C"
 
 namespace absl {
@@ -89,8 +91,8 @@
 ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
 
 ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
-    absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
-        submit_profile_data;
+absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
+    submit_profile_data;
 ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)(
     const char *msg, const void *obj, int64_t wait_cycles)>
     mutex_tracer;
@@ -124,35 +126,44 @@
   symbolizer.Store(fn);
 }
 
+namespace {
+// Represents the strategy for spin and yield.
+// See the comment in GetMutexGlobals() for more information.
+enum DelayMode { AGGRESSIVE, GENTLE };
+
 struct ABSL_CACHELINE_ALIGNED MutexGlobals {
   absl::once_flag once;
-  int num_cpus = 0;
   int spinloop_iterations = 0;
+  int32_t mutex_sleep_limit[2] = {};
 };
 
-static const MutexGlobals& GetMutexGlobals() {
+const MutexGlobals &GetMutexGlobals() {
   ABSL_CONST_INIT static MutexGlobals data;
   absl::base_internal::LowLevelCallOnce(&data.once, [&]() {
-    data.num_cpus = absl::base_internal::NumCPUs();
-    data.spinloop_iterations = data.num_cpus > 1 ? 1500 : 0;
+    const int num_cpus = absl::base_internal::NumCPUs();
+    data.spinloop_iterations = num_cpus > 1 ? 1500 : 0;
+    // If this a uniprocessor, only yield/sleep.  Otherwise, if the mode is
+    // aggressive then spin many times before yielding.  If the mode is
+    // gentle then spin only a few times before yielding.  Aggressive spinning
+    // is used to ensure that an Unlock() call, which must get the spin lock
+    // for any thread to make progress gets it without undue delay.
+    if (num_cpus > 1) {
+      data.mutex_sleep_limit[AGGRESSIVE] = 5000;
+      data.mutex_sleep_limit[GENTLE] = 250;
+    } else {
+      data.mutex_sleep_limit[AGGRESSIVE] = 0;
+      data.mutex_sleep_limit[GENTLE] = 0;
+    }
   });
   return data;
 }
-
-// Spinlock delay on iteration c.  Returns new c.
-namespace {
-  enum DelayMode { AGGRESSIVE, GENTLE };
-};
+}  // namespace
 
 namespace synchronization_internal {
+// Returns the Mutex delay on iteration `c` depending on the given `mode`.
+// The returned value should be used as `c` for the next call to `MutexDelay`.
 int MutexDelay(int32_t c, int mode) {
-  // If this a uniprocessor, only yield/sleep.  Otherwise, if the mode is
-  // aggressive then spin many times before yielding.  If the mode is
-  // gentle then spin only a few times before yielding.  Aggressive spinning is
-  // used to ensure that an Unlock() call, which  must get the spin lock for
-  // any thread to make progress gets it without undue delay.
-  const int32_t limit =
-      GetMutexGlobals().num_cpus > 1 ? (mode == AGGRESSIVE ? 5000 : 250) : 0;
+  const int32_t limit = GetMutexGlobals().mutex_sleep_limit[mode];
   if (c < limit) {
     // Spin.
     c++;
@@ -161,7 +172,7 @@
     ABSL_TSAN_MUTEX_PRE_DIVERT(nullptr, 0);
     if (c == limit) {
       // Yield once.
-      AbslInternalMutexYield();
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)();
       c++;
     } else {
       // Then wait.
@@ -492,7 +503,7 @@
   std::atomic<intptr_t> *cv_word;
 
   int64_t contention_start_cycles;  // Time (in cycles) when this thread started
-                                  // to contend for the mutex.
+                                    // to contend for the mutex.
 };
 
 struct SynchLocksHeld {
@@ -548,7 +559,7 @@
 }
 
 // Post on "w"'s associated PerThreadSem.
-inline void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) {
+void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) {
   if (mu) {
     ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
   }
@@ -752,11 +763,13 @@
   synch_deadlock_detection.store(mode, std::memory_order_release);
 }
 
-// Return true iff threads x and y are waiting on the same condition for the
-// same type of lock.  Requires that x and y be waiting on the same Mutex
-// queue.
-static bool MuSameCondition(PerThreadSynch *x, PerThreadSynch *y) {
-  return x->waitp->how == y->waitp->how &&
+// Return true iff threads x and y are part of the same equivalence
+// class of waiters. An equivalence class is defined as the set of
+// waiters with the same condition, type of lock, and thread priority.
+//
+// Requires that x and y be waiting on the same Mutex queue.
+static bool MuEquivalentWaiter(PerThreadSynch *x, PerThreadSynch *y) {
+  return x->waitp->how == y->waitp->how && x->priority == y->priority &&
          Condition::GuaranteedEqual(x->waitp->cond, y->waitp->cond);
 }
 
@@ -775,18 +788,19 @@
 //     - invalid (iff x is not in a Mutex wait queue),
 //     - null, or
 //     - a pointer to a distinct thread waiting later in the same Mutex queue
-//       such that all threads in [x, x->skip] have the same condition and
-//       lock type (MuSameCondition() is true for all pairs in [x, x->skip]).
+//       such that all threads in [x, x->skip] have the same condition, priority
+//       and lock type (MuEquivalentWaiter() is true for all pairs in [x,
+//       x->skip]).
 // In addition, if x->skip is  valid, (x->may_skip || x->skip == null)
 //
-// By the spec of MuSameCondition(), it is not necessary when removing the
+// By the spec of MuEquivalentWaiter(), it is not necessary when removing the
 // first runnable thread y from the front a Mutex queue to adjust the skip
 // field of another thread x because if x->skip==y, x->skip must (have) become
 // invalid before y is removed.  The function TryRemove can remove a specified
 // thread from an arbitrary position in the queue whether runnable or not, so
 // it fixes up skip fields that would otherwise be left dangling.
 // The statement
-//     if (x->may_skip && MuSameCondition(x, x->next)) { x->skip = x->next; }
+//     if (x->may_skip && MuEquivalentWaiter(x, x->next)) { x->skip = x->next; }
 // maintains the invariant provided x is not the last waiter in a Mutex queue
 // The statement
 //          if (x->skip != null) { x->skip = x->skip->skip; }
@@ -920,24 +934,17 @@
     if (s->priority > head->priority) {  // s's priority is above head's
       // try to put s in priority-fifo order, or failing that at the front.
       if (!head->maybe_unlocking) {
-        // No unlocker can be scanning the queue, so we can insert between
-        // skip-chains, and within a skip-chain if it has the same condition as
-        // s.  We insert in priority-fifo order, examining the end of every
-        // skip-chain, plus every element with the same condition as s.
+        // No unlocker can be scanning the queue, so we can insert into the
+        // middle of the queue.
+        //
+        // Within a skip chain, all waiters have the same priority, so we can
+        // skip forward through the chains until we find one with a lower
+        // priority than the waiter to be enqueued.
         PerThreadSynch *advance_to = head;    // next value of enqueue_after
-        PerThreadSynch *cur;                  // successor of enqueue_after
         do {
           enqueue_after = advance_to;
-          cur = enqueue_after->next;  // this advance ensures progress
-          advance_to = Skip(cur);   // normally, advance to end of skip chain
-                                    // (side-effect: optimizes skip chain)
-          if (advance_to != cur && s->priority > advance_to->priority &&
-              MuSameCondition(s, cur)) {
-            // but this skip chain is not a singleton, s has higher priority
-            // than its tail and has the same condition as the chain,
-            // so we can insert within the skip-chain
-            advance_to = cur;         // advance by just one
-          }
+          // (side-effect: optimizes skip chain)
+          advance_to = Skip(enqueue_after->next);
         } while (s->priority <= advance_to->priority);
               // termination guaranteed because s->priority > head->priority
               // and head is the end of a skip chain
@@ -956,21 +963,21 @@
 
       // enqueue_after can be: head, Skip(...), or cur.
       // The first two imply enqueue_after->skip == nullptr, and
-      // the last is used only if MuSameCondition(s, cur).
+      // the last is used only if MuEquivalentWaiter(s, cur).
       // We require this because clearing enqueue_after->skip
       // is impossible; enqueue_after's predecessors might also
       // incorrectly skip over s if we were to allow other
       // insertion points.
-      ABSL_RAW_CHECK(
-          enqueue_after->skip == nullptr || MuSameCondition(enqueue_after, s),
-          "Mutex Enqueue failure");
+      ABSL_RAW_CHECK(enqueue_after->skip == nullptr ||
+                         MuEquivalentWaiter(enqueue_after, s),
+                     "Mutex Enqueue failure");
 
       if (enqueue_after != head && enqueue_after->may_skip &&
-          MuSameCondition(enqueue_after, enqueue_after->next)) {
+          MuEquivalentWaiter(enqueue_after, enqueue_after->next)) {
         // enqueue_after can skip to its new successor, s
         enqueue_after->skip = enqueue_after->next;
       }
-      if (MuSameCondition(s, s->next)) {  // s->may_skip is known to be true
+      if (MuEquivalentWaiter(s, s->next)) {  // s->may_skip is known to be true
         s->skip = s->next;                // s may skip to its successor
       }
     } else {   // enqueue not done any other way, so
@@ -980,7 +987,7 @@
       head->next = s;
       s->readers = head->readers;  // reader count is from previous head
       s->maybe_unlocking = head->maybe_unlocking;  // same for unlock hint
-      if (head->may_skip && MuSameCondition(head, s)) {
+      if (head->may_skip && MuEquivalentWaiter(head, s)) {
         // head now has successor; may skip
         head->skip = s;
       }
@@ -1000,7 +1007,7 @@
   pw->next = w->next;         // snip w out of list
   if (head == w) {            // we removed the head
     head = (pw == w) ? nullptr : pw;  // either emptied list, or pw is new head
-  } else if (pw != head && MuSameCondition(pw, pw->next)) {
+  } else if (pw != head && MuEquivalentWaiter(pw, pw->next)) {
     // pw can skip to its new successor
     if (pw->next->skip !=
         nullptr) {  // either skip to its successors skip target
@@ -1070,11 +1077,13 @@
       PerThreadSynch *w;
       if ((w = pw->next) != s) {  // search for thread,
         do {                      // processing at least one element
-          if (!MuSameCondition(s, w)) {  // seeking different condition
+          // If the current element isn't equivalent to the waiter to be
+          // removed, we can skip the entire chain.
+          if (!MuEquivalentWaiter(s, w)) {
             pw = Skip(w);                // so skip all that won't match
             // we don't have to worry about dangling skip fields
             // in the threads we skipped; none can point to s
-            // because their condition differs from s
+            // because they are in a different equivalence class.
           } else {          // seeking same condition
             FixSkip(w, s);  // fix up any skip pointer from w to s
             pw = w;
@@ -1365,7 +1374,9 @@
           len += static_cast<int>(strlen(&b->buf[len]));
         }
       }
-      ABSL_RAW_LOG(ERROR, "Acquiring %p    Mutexes held: %s",
+      ABSL_RAW_LOG(ERROR,
+                   "Acquiring absl::Mutex %p while holding %s; a cycle in the "
+                   "historical lock ordering graph has been observed",
                    static_cast<void *>(mu), b->buf);
       ABSL_RAW_LOG(ERROR, "Cycle: ");
       int path_len = deadlock_graph->FindPath(
@@ -2139,7 +2150,7 @@
           !old_h->may_skip) {                  // we used old_h as a terminator
         old_h->may_skip = true;                // allow old_h to skip once more
         ABSL_RAW_CHECK(old_h->skip == nullptr, "illegal skip from head");
-        if (h != old_h && MuSameCondition(old_h, old_h->next)) {
+        if (h != old_h && MuEquivalentWaiter(old_h, old_h->next)) {
           old_h->skip = old_h->next;  // old_h not head & can skip to successor
         }
       }
@@ -2312,7 +2323,8 @@
     if (!cond_waiter) {
       // Sample lock contention events only if the (first) waiter was trying to
       // acquire the lock, not waiting on a condition variable or Condition.
-      int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp;
+      int64_t wait_cycles =
+          base_internal::CycleClock::Now() - enqueue_timestamp;
       mutex_tracer("slow release", this, wait_cycles);
       ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
       submit_profile_data(enqueue_timestamp);
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/mutex.h b/grpc/third_party/abseil-cpp/absl/synchronization/mutex.h
index 52401fe..f49e0c8 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/mutex.h
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/mutex.h
@@ -31,22 +31,23 @@
 //
 //  MutexLock - An RAII wrapper to acquire and release a `Mutex` for exclusive/
 //              write access within the current scope.
+//
 //  ReaderMutexLock
 //            - An RAII wrapper to acquire and release a `Mutex` for shared/read
 //              access within the current scope.
 //
 //  WriterMutexLock
-//            - Alias for `MutexLock` above, designed for use in distinguishing
-//              reader and writer locks within code.
+//            - Effectively an alias for `MutexLock` above, designed for use in
+//              distinguishing reader and writer locks within code.
 //
 // In addition to simple mutex locks, this file also defines ways to perform
 // locking under certain conditions.
 //
-//  Condition   - (Preferred) Used to wait for a particular predicate that
-//                depends on state protected by the `Mutex` to become true.
-//  CondVar     - A lower-level variant of `Condition` that relies on
-//                application code to explicitly signal the `CondVar` when
-//                a condition has been met.
+//  Condition - (Preferred) Used to wait for a particular predicate that
+//              depends on state protected by the `Mutex` to become true.
+//  CondVar   - A lower-level variant of `Condition` that relies on
+//              application code to explicitly signal the `CondVar` when
+//              a condition has been met.
 //
 // See below for more information on using `Condition` or `CondVar`.
 //
@@ -72,15 +73,6 @@
 #include "absl/synchronization/internal/per_thread_sem.h"
 #include "absl/time/time.h"
 
-// Decide if we should use the non-production implementation because
-// the production implementation hasn't been fully ported yet.
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-#error ABSL_INTERNAL_USE_NONPROD_MUTEX cannot be directly set
-#elif defined(ABSL_LOW_LEVEL_ALLOC_MISSING)
-#define ABSL_INTERNAL_USE_NONPROD_MUTEX 1
-#include "absl/synchronization/internal/mutex_nonprod.inc"
-#endif
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
@@ -155,7 +147,7 @@
   //
   // Example usage:
   //   namespace foo {
-  //   ABSL_CONST_INIT Mutex mu(absl::kConstInit);
+  //   ABSL_CONST_INIT absl::Mutex mu(absl::kConstInit);
   //   }
   explicit constexpr Mutex(absl::ConstInitType);
 
@@ -170,7 +162,7 @@
   // Mutex::Unlock()
   //
   // Releases this `Mutex` and returns it from the exclusive/write state to the
-  // free state. Caller must hold the `Mutex` exclusively.
+  // free state. Calling thread must hold the `Mutex` exclusively.
   void Unlock() ABSL_UNLOCK_FUNCTION();
 
   // Mutex::TryLock()
@@ -461,24 +453,13 @@
   static void InternalAttemptToUseMutexInFatalSignalHandler();
 
  private:
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-  friend class CondVar;
-
-  synchronization_internal::MutexImpl *impl() { return impl_.get(); }
-
-  synchronization_internal::SynchronizationStorage<
-      synchronization_internal::MutexImpl>
-      impl_;
-#else
   std::atomic<intptr_t> mu_;  // The Mutex state.
 
   // Post()/Wait() versus associated PerThreadSem; in class for required
   // friendship with PerThreadSem.
-  static inline void IncrementSynchSem(Mutex *mu,
-                                       base_internal::PerThreadSynch *w);
-  static inline bool DecrementSynchSem(
-      Mutex *mu, base_internal::PerThreadSynch *w,
-      synchronization_internal::KernelTimeout t);
+  static void IncrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w);
+  static bool DecrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w,
+                                synchronization_internal::KernelTimeout t);
 
   // slow path acquire
   void LockSlowLoop(SynchWaitParams *waitp, int flags);
@@ -504,7 +485,6 @@
   void Trans(MuHow how);  // used for CondVar->Mutex transfer
   void Fer(
       base_internal::PerThreadSynch *w);  // used for CondVar->Mutex transfer
-#endif
 
   // Catch the error of writing Mutex when intending MutexLock.
   Mutex(const volatile Mutex * /*ignored*/) {}  // NOLINT(runtime/explicit)
@@ -525,22 +505,36 @@
 // Example:
 //
 // Class Foo {
-//
+//  public:
 //   Foo::Bar* Baz() {
-//     MutexLock l(&lock_);
+//     MutexLock lock(&mu_);
 //     ...
 //     return bar;
 //   }
 //
 // private:
-//   Mutex lock_;
+//   Mutex mu_;
 // };
 class ABSL_SCOPED_LOCKABLE MutexLock {
  public:
+  // Constructors
+
+  // Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is
+  // guaranteed to be locked when this object is constructed. Requires that
+  // `mu` be dereferenceable.
   explicit MutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
     this->mu_->Lock();
   }
 
+  // Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to
+  // the above, the condition given by `cond` is also guaranteed to hold when
+  // this object is constructed.
+  explicit MutexLock(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_->LockWhen(cond);
+  }
+
   MutexLock(const MutexLock &) = delete;  // NOLINT(runtime/mutex)
   MutexLock(MutexLock&&) = delete;  // NOLINT(runtime/mutex)
   MutexLock& operator=(const MutexLock&) = delete;
@@ -562,6 +556,12 @@
     mu->ReaderLock();
   }
 
+  explicit ReaderMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_SHARED_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu->ReaderLockWhen(cond);
+  }
+
   ReaderMutexLock(const ReaderMutexLock&) = delete;
   ReaderMutexLock(ReaderMutexLock&&) = delete;
   ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
@@ -584,6 +584,12 @@
     mu->WriterLock();
   }
 
+  explicit WriterMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu->WriterLockWhen(cond);
+  }
+
   WriterMutexLock(const WriterMutexLock&) = delete;
   WriterMutexLock(WriterMutexLock&&) = delete;
   WriterMutexLock& operator=(const WriterMutexLock&) = delete;
@@ -622,16 +628,26 @@
 // `noexcept`; until then this requirement cannot be enforced in the
 // type system.)
 //
-// Note: to use a `Condition`, you need only construct it and pass it within the
-// appropriate `Mutex' member function, such as `Mutex::Await()`.
+// Note: to use a `Condition`, you need only construct it and pass it to a
+// suitable `Mutex' member function, such as `Mutex::Await()`, or to the
+// constructor of one of the scope guard classes.
 //
-// Example:
+// Example using LockWhen/Unlock:
 //
 //   // assume count_ is not internal reference count
 //   int count_ ABSL_GUARDED_BY(mu_);
+//   Condition count_is_zero(+[](int *count) { return *count == 0; }, &count_);
 //
-//   mu_.LockWhen(Condition(+[](int* count) { return *count == 0; },
-//         &count_));
+//   mu_.LockWhen(count_is_zero);
+//   // ...
+//   mu_.Unlock();
+//
+// Example using a scope guard:
+//
+//   {
+//     MutexLock lock(&mu_, count_is_zero);
+//     // ...
+//   }
 //
 // When multiple threads are waiting on exactly the same condition, make sure
 // that they are constructed with the same parameters (same pointer to function
@@ -686,10 +702,10 @@
   //   };
   //   mu_.Await(Condition(&reached));
   //
-  // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReadHeld()" in the
-  // lambda as it may be called when the mutex is being unlocked from a scope
-  // holding only a reader lock, which will make the assertion not fulfilled and
-  // crash the binary.
+  // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in
+  // the lambda as it may be called when the mutex is being unlocked from a
+  // scope holding only a reader lock, which will make the assertion not
+  // fulfilled and crash the binary.
 
   // See class comment for performance advice. In particular, if there
   // might be more than one waiter for the same condition, make sure
@@ -838,17 +854,10 @@
   void EnableDebugLog(const char *name);
 
  private:
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-  synchronization_internal::CondVarImpl *impl() { return impl_.get(); }
-  synchronization_internal::SynchronizationStorage<
-      synchronization_internal::CondVarImpl>
-      impl_;
-#else
   bool WaitCommon(Mutex *mutex, synchronization_internal::KernelTimeout t);
   void Remove(base_internal::PerThreadSynch *s);
   void Wakeup(base_internal::PerThreadSynch *w);
   std::atomic<intptr_t> cv_;  // Condition variable state.
-#endif
   CondVar(const CondVar&) = delete;
   CondVar& operator=(const CondVar&) = delete;
 };
@@ -870,6 +879,15 @@
       this->mu_->Lock();
     }
   }
+
+  explicit MutexLockMaybe(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    if (this->mu_ != nullptr) {
+      this->mu_->LockWhen(cond);
+    }
+  }
+
   ~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() {
     if (this->mu_ != nullptr) { this->mu_->Unlock(); }
   }
@@ -892,6 +910,13 @@
       : mu_(mu) {
     this->mu_->Lock();
   }
+
+  explicit ReleasableMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_->LockWhen(cond);
+  }
+
   ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
     if (this->mu_ != nullptr) { this->mu_->Unlock(); }
   }
@@ -906,12 +931,6 @@
   ReleasableMutexLock& operator=(ReleasableMutexLock&&) = delete;
 };
 
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-
-inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {}
-
-#else
-
 inline Mutex::Mutex() : mu_(0) {
   ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
 }
@@ -920,8 +939,6 @@
 
 inline CondVar::CondVar() : cv_(0) {}
 
-#endif  // ABSL_INTERNAL_USE_NONPROD_MUTEX
-
 // static
 template <typename T>
 bool Condition::CastAndCallMethod(const Condition *c) {
@@ -988,7 +1005,7 @@
 //
 // This has the same memory ordering concerns as RegisterMutexProfiler() above.
 void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
-                              int64_t wait_cycles));
+                                    int64_t wait_cycles));
 
 // TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer()
 // into a single interface, since they are only ever called in pairs.
@@ -1059,7 +1076,7 @@
 // By changing our extension points to be extern "C", we dodge this
 // check.
 extern "C" {
-void AbslInternalMutexYield();
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)();
 }  // extern "C"
 
 #endif  // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc b/grpc/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc
index 933ea14..e35aed8 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc
@@ -61,8 +61,124 @@
   std::mutex* mu_;
 };
 
+// RAII object to change the Mutex priority of the running thread.
+class ScopedThreadMutexPriority {
+ public:
+  explicit ScopedThreadMutexPriority(int priority) {
+    absl::base_internal::ThreadIdentity* identity =
+        absl::synchronization_internal::GetOrCreateCurrentThreadIdentity();
+    identity->per_thread_synch.priority = priority;
+    // Bump next_priority_read_cycles to the infinite future so that the
+    // implementation doesn't re-read the thread's actual scheduler priority
+    // and replace our temporary scoped priority.
+    identity->per_thread_synch.next_priority_read_cycles =
+        std::numeric_limits<int64_t>::max();
+  }
+  ~ScopedThreadMutexPriority() {
+    // Reset the "next priority read time" back to the infinite past so that
+    // the next time the Mutex implementation wants to know this thread's
+    // priority, it re-reads it from the OS instead of using our overridden
+    // priority.
+    absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()
+        ->per_thread_synch.next_priority_read_cycles =
+        std::numeric_limits<int64_t>::min();
+  }
+};
+
+void BM_MutexEnqueue(benchmark::State& state) {
+  // In the "multiple priorities" variant of the benchmark, one of the
+  // threads runs with Mutex priority 0 while the rest run at elevated priority.
+  // This benchmarks the performance impact of the presence of a low priority
+  // waiter when a higher priority waiter adds itself of the queue
+  // (b/175224064).
+  //
+  // NOTE: The actual scheduler priority is not modified in this benchmark:
+  // all of the threads get CPU slices with the same priority. Only the
+  // Mutex queueing behavior is modified.
+  const bool multiple_priorities = state.range(0);
+  ScopedThreadMutexPriority priority_setter(
+      (multiple_priorities && state.thread_index != 0) ? 1 : 0);
+
+  struct Shared {
+    absl::Mutex mu;
+    std::atomic<int> looping_threads{0};
+    std::atomic<int> blocked_threads{0};
+    std::atomic<bool> thread_has_mutex{false};
+  };
+  static Shared* shared = new Shared;
+
+  // Set up 'blocked_threads' to count how many threads are currently blocked
+  // in Abseil synchronization code.
+  //
+  // NOTE: Blocking done within the Google Benchmark library itself (e.g.
+  // the barrier which synchronizes threads entering and exiting the benchmark
+  // loop) does _not_ get registered in this counter. This is because Google
+  // Benchmark uses its own synchronization primitives based on std::mutex, not
+  // Abseil synchronization primitives. If at some point the benchmark library
+  // merges into Abseil, this code may break.
+  absl::synchronization_internal::PerThreadSem::SetThreadBlockedCounter(
+      &shared->blocked_threads);
+
+  // The benchmark framework may run several iterations in the same process,
+  // reusing the same static-initialized 'shared' object. Given the semantics
+  // of the members, here, we expect everything to be reset to zero by the
+  // end of any iteration. Assert that's the case, just to be sure.
+  ABSL_RAW_CHECK(
+      shared->looping_threads.load(std::memory_order_relaxed) == 0 &&
+          shared->blocked_threads.load(std::memory_order_relaxed) == 0 &&
+          !shared->thread_has_mutex.load(std::memory_order_relaxed),
+      "Shared state isn't zeroed at start of benchmark iteration");
+
+  static constexpr int kBatchSize = 1000;
+  while (state.KeepRunningBatch(kBatchSize)) {
+    shared->looping_threads.fetch_add(1);
+    for (int i = 0; i < kBatchSize; i++) {
+      {
+        absl::MutexLock l(&shared->mu);
+        shared->thread_has_mutex.store(true, std::memory_order_relaxed);
+        // Spin until all other threads are either out of the benchmark loop
+        // or blocked on the mutex. This ensures that the mutex queue is kept
+        // at its maximal length to benchmark the performance of queueing on
+        // a highly contended mutex.
+        while (shared->looping_threads.load(std::memory_order_relaxed) -
+                   shared->blocked_threads.load(std::memory_order_relaxed) !=
+               1) {
+        }
+        shared->thread_has_mutex.store(false);
+      }
+      // Spin until some other thread has acquired the mutex before we block
+      // again. This ensures that we always go through the slow (queueing)
+      // acquisition path rather than reacquiring the mutex we just released.
+      while (!shared->thread_has_mutex.load(std::memory_order_relaxed) &&
+             shared->looping_threads.load(std::memory_order_relaxed) > 1) {
+      }
+    }
+    // The benchmark framework uses a barrier to ensure that all of the threads
+    // complete their benchmark loop together before any of the threads exit
+    // the loop. So, we need to remove ourselves from the "looping threads"
+    // counter here before potentially blocking on that barrier. Otherwise,
+    // another thread spinning above might wait forever for this thread to
+    // block on the mutex while we in fact are waiting to exit.
+    shared->looping_threads.fetch_add(-1);
+  }
+  absl::synchronization_internal::PerThreadSem::SetThreadBlockedCounter(
+      nullptr);
+}
+
+BENCHMARK(BM_MutexEnqueue)
+    ->Threads(4)
+    ->Threads(64)
+    ->Threads(128)
+    ->Threads(512)
+    ->ArgName("multiple_priorities")
+    ->Arg(false)
+    ->Arg(true);
+
 template <typename MutexType>
 void BM_Contended(benchmark::State& state) {
+  int priority = state.thread_index % state.range(1);
+  ScopedThreadMutexPriority priority_setter(priority);
+
   struct Shared {
     MutexType mu;
     int data = 0;
@@ -85,81 +201,51 @@
     DelayNs(state.range(0), &shared->data);
   }
 }
+void SetupBenchmarkArgs(benchmark::internal::Benchmark* bm,
+                        bool do_test_priorities) {
+  const int max_num_priorities = do_test_priorities ? 2 : 1;
+  bm->UseRealTime()
+      // ThreadPerCpu poorly handles non-power-of-two CPU counts.
+      ->Threads(1)
+      ->Threads(2)
+      ->Threads(4)
+      ->Threads(6)
+      ->Threads(8)
+      ->Threads(12)
+      ->Threads(16)
+      ->Threads(24)
+      ->Threads(32)
+      ->Threads(48)
+      ->Threads(64)
+      ->Threads(96)
+      ->Threads(128)
+      ->Threads(192)
+      ->Threads(256)
+      ->ArgNames({"cs_ns", "num_prios"});
+  // Some empirically chosen amounts of work in critical section.
+  // 1 is low contention, 2000 is high contention and few values in between.
+  for (int critical_section_ns : {1, 20, 50, 200, 2000}) {
+    for (int num_priorities = 1; num_priorities <= max_num_priorities;
+         num_priorities++) {
+      bm->ArgPair(critical_section_ns, num_priorities);
+    }
+  }
+}
 
 BENCHMARK_TEMPLATE(BM_Contended, absl::Mutex)
-    ->UseRealTime()
-    // ThreadPerCpu poorly handles non-power-of-two CPU counts.
-    ->Threads(1)
-    ->Threads(2)
-    ->Threads(4)
-    ->Threads(6)
-    ->Threads(8)
-    ->Threads(12)
-    ->Threads(16)
-    ->Threads(24)
-    ->Threads(32)
-    ->Threads(48)
-    ->Threads(64)
-    ->Threads(96)
-    ->Threads(128)
-    ->Threads(192)
-    ->Threads(256)
-    // Some empirically chosen amounts of work in critical section.
-    // 1 is low contention, 200 is high contention and few values in between.
-    ->Arg(1)
-    ->Arg(20)
-    ->Arg(50)
-    ->Arg(200);
+    ->Apply([](benchmark::internal::Benchmark* bm) {
+      SetupBenchmarkArgs(bm, /*do_test_priorities=*/true);
+    });
 
 BENCHMARK_TEMPLATE(BM_Contended, absl::base_internal::SpinLock)
-    ->UseRealTime()
-    // ThreadPerCpu poorly handles non-power-of-two CPU counts.
-    ->Threads(1)
-    ->Threads(2)
-    ->Threads(4)
-    ->Threads(6)
-    ->Threads(8)
-    ->Threads(12)
-    ->Threads(16)
-    ->Threads(24)
-    ->Threads(32)
-    ->Threads(48)
-    ->Threads(64)
-    ->Threads(96)
-    ->Threads(128)
-    ->Threads(192)
-    ->Threads(256)
-    // Some empirically chosen amounts of work in critical section.
-    // 1 is low contention, 200 is high contention and few values in between.
-    ->Arg(1)
-    ->Arg(20)
-    ->Arg(50)
-    ->Arg(200);
+    ->Apply([](benchmark::internal::Benchmark* bm) {
+      SetupBenchmarkArgs(bm, /*do_test_priorities=*/false);
+    });
 
 BENCHMARK_TEMPLATE(BM_Contended, std::mutex)
-    ->UseRealTime()
-    // ThreadPerCpu poorly handles non-power-of-two CPU counts.
-    ->Threads(1)
-    ->Threads(2)
-    ->Threads(4)
-    ->Threads(6)
-    ->Threads(8)
-    ->Threads(12)
-    ->Threads(16)
-    ->Threads(24)
-    ->Threads(32)
-    ->Threads(48)
-    ->Threads(64)
-    ->Threads(96)
-    ->Threads(128)
-    ->Threads(192)
-    ->Threads(256)
-    // Some empirically chosen amounts of work in critical section.
-    // 1 is low contention, 200 is high contention and few values in between.
-    ->Arg(1)
-    ->Arg(20)
-    ->Arg(50)
-    ->Arg(200);
+    ->Apply([](benchmark::internal::Benchmark* bm) {
+      SetupBenchmarkArgs(bm, /*do_test_priorities=*/false);
+    });
 
 // Measure the overhead of conditions on mutex release (when they must be
 // evaluated).  Mutex has (some) support for equivalence classes allowing
diff --git a/grpc/third_party/abseil-cpp/absl/synchronization/mutex_test.cc b/grpc/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
index 16fc905..f8fbf94 100644
--- a/grpc/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/synchronization/mutex_test.cc
@@ -707,6 +707,40 @@
   t.join();
 }
 
+TEST(Mutex, LockWhenGuard) {
+  absl::Mutex mu;
+  int n = 30;
+  bool done = false;
+
+  // We don't inline the lambda because the conversion is ambiguous in MSVC.
+  bool (*cond_eq_10)(int *) = [](int *p) { return *p == 10; };
+  bool (*cond_lt_10)(int *) = [](int *p) { return *p < 10; };
+
+  std::thread t1([&mu, &n, &done, cond_eq_10]() {
+    absl::ReaderMutexLock lock(&mu, absl::Condition(cond_eq_10, &n));
+    done = true;
+  });
+
+  std::thread t2[10];
+  for (std::thread &t : t2) {
+    t = std::thread([&mu, &n, cond_lt_10]() {
+      absl::WriterMutexLock lock(&mu, absl::Condition(cond_lt_10, &n));
+      ++n;
+    });
+  }
+
+  {
+    absl::MutexLock lock(&mu);
+    n = 0;
+  }
+
+  for (std::thread &t : t2) t.join();
+  t1.join();
+
+  EXPECT_TRUE(done);
+  EXPECT_EQ(n, 10);
+}
+
 // --------------------------------------------------------
 // The following test requires Mutex::ReaderLock to be a real shared
 // lock, which is not the case in all builds.
@@ -818,7 +852,7 @@
 // held and then destroyed (w/o unlocking).
 #ifdef ABSL_HAVE_THREAD_SANITIZER
 // TSAN reports errors when locked Mutexes are destroyed.
-TEST(Mutex, DISABLED_LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, DISABLED_LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
 #else
 TEST(Mutex, LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
 #endif
@@ -1002,9 +1036,6 @@
   x.mu0.Unlock();
 }
 
-// The deadlock detector is not part of non-prod builds, so do not test it.
-#if !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
-
 TEST(Mutex, DeadlockDetector) {
   absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
 
@@ -1122,7 +1153,7 @@
 
 #ifdef ABSL_HAVE_THREAD_SANITIZER
 // TSAN reports errors when locked Mutexes are destroyed.
-TEST(Mutex, DISABLED_DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, DISABLED_DeadlockIdBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
 #else
 TEST(Mutex, DeadlockIdBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
 #endif
@@ -1158,7 +1189,6 @@
   c.Lock();
   c.Unlock();
 }
-#endif  // !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
 
 // --------------------------------------------------------
 // Test for timeouts/deadlines on condition waits that are specified using
diff --git a/grpc/third_party/abseil-cpp/absl/time/BUILD.bazel b/grpc/third_party/abseil-cpp/absl/time/BUILD.bazel
index 991241a..3e25ca2 100644
--- a/grpc/third_party/abseil-cpp/absl/time/BUILD.bazel
+++ b/grpc/third_party/abseil-cpp/absl/time/BUILD.bazel
@@ -119,6 +119,7 @@
         ":time",
         "//absl/base",
         "//absl/base:core_headers",
+        "//absl/flags:flag",
         "//absl/hash",
         "@com_github_google_benchmark//:benchmark_main",
     ],
diff --git a/grpc/third_party/abseil-cpp/absl/time/clock.cc b/grpc/third_party/abseil-cpp/absl/time/clock.cc
index e5c423c..7b204c4 100644
--- a/grpc/third_party/abseil-cpp/absl/time/clock.cc
+++ b/grpc/third_party/abseil-cpp/absl/time/clock.cc
@@ -15,6 +15,7 @@
 #include "absl/time/clock.h"
 
 #include "absl/base/attributes.h"
+#include "absl/base/optimization.h"
 
 #ifdef _WIN32
 #include <windows.h>
@@ -74,9 +75,7 @@
 #if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
 namespace absl {
 ABSL_NAMESPACE_BEGIN
-int64_t GetCurrentTimeNanos() {
-  return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
-}
+int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
 ABSL_NAMESPACE_END
 }  // namespace absl
 #else  // Use the cyclecounter-based implementation below.
@@ -87,13 +86,6 @@
   ::absl::time_internal::UnscaledCycleClockWrapperForGetCurrentTime::Now()
 #endif
 
-// The following counters are used only by the test code.
-static int64_t stats_initializations;
-static int64_t stats_reinitializations;
-static int64_t stats_calibrations;
-static int64_t stats_slow_paths;
-static int64_t stats_fast_slow_paths;
-
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace time_internal {
@@ -107,72 +99,6 @@
 
 // uint64_t is used in this module to provide an extra bit in multiplications
 
-// Return the time in ns as told by the kernel interface.  Place in *cycleclock
-// the value of the cycleclock at about the time of the syscall.
-// This call represents the time base that this module synchronizes to.
-// Ensures that *cycleclock does not step back by up to (1 << 16) from
-// last_cycleclock, to discard small backward counter steps.  (Larger steps are
-// assumed to be complete resyncs, which shouldn't happen.  If they do, a full
-// reinitialization of the outer algorithm should occur.)
-static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock,
-                                             uint64_t *cycleclock) {
-  // We try to read clock values at about the same time as the kernel clock.
-  // This value gets adjusted up or down as estimate of how long that should
-  // take, so we can reject attempts that take unusually long.
-  static std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000};
-
-  uint64_t local_approx_syscall_time_in_cycles =  // local copy
-      approx_syscall_time_in_cycles.load(std::memory_order_relaxed);
-
-  int64_t current_time_nanos_from_system;
-  uint64_t before_cycles;
-  uint64_t after_cycles;
-  uint64_t elapsed_cycles;
-  int loops = 0;
-  do {
-    before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
-    current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
-    after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
-    // elapsed_cycles is unsigned, so is large on overflow
-    elapsed_cycles = after_cycles - before_cycles;
-    if (elapsed_cycles >= local_approx_syscall_time_in_cycles &&
-        ++loops == 20) {  // clock changed frequencies?  Back off.
-      loops = 0;
-      if (local_approx_syscall_time_in_cycles < 1000 * 1000) {
-        local_approx_syscall_time_in_cycles =
-            (local_approx_syscall_time_in_cycles + 1) << 1;
-      }
-      approx_syscall_time_in_cycles.store(
-          local_approx_syscall_time_in_cycles,
-          std::memory_order_relaxed);
-    }
-  } while (elapsed_cycles >= local_approx_syscall_time_in_cycles ||
-           last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16));
-
-  // Number of times in a row we've seen a kernel time call take substantially
-  // less than approx_syscall_time_in_cycles.
-  static std::atomic<uint32_t> seen_smaller{ 0 };
-
-  // Adjust approx_syscall_time_in_cycles to be within a factor of 2
-  // of the typical time to execute one iteration of the loop above.
-  if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) {
-    // measured time is no smaller than half current approximation
-    seen_smaller.store(0, std::memory_order_relaxed);
-  } else if (seen_smaller.fetch_add(1, std::memory_order_relaxed) >= 3) {
-    // smaller delays several times in a row; reduce approximation by 12.5%
-    const uint64_t new_approximation =
-        local_approx_syscall_time_in_cycles -
-        (local_approx_syscall_time_in_cycles >> 3);
-    approx_syscall_time_in_cycles.store(new_approximation,
-                                        std::memory_order_relaxed);
-    seen_smaller.store(0, std::memory_order_relaxed);
-  }
-
-  *cycleclock = after_cycles;
-  return current_time_nanos_from_system;
-}
-
-
 // ---------------------------------------------------------------------
 // An implementation of reader-write locks that use no atomic ops in the read
 // case.  This is a generalization of Lamport's method for reading a multiword
@@ -224,32 +150,110 @@
                kMinNSBetweenSamples,
                "cannot represent kMaxBetweenSamplesNSScaled");
 
-// A reader-writer lock protecting the static locations below.
-// See SeqAcquire() and SeqRelease() above.
-ABSL_CONST_INIT static absl::base_internal::SpinLock lock(
-    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
-ABSL_CONST_INIT static std::atomic<uint64_t> seq(0);
-
 // data from a sample of the kernel's time value
 struct TimeSampleAtomic {
-  std::atomic<uint64_t> raw_ns;              // raw kernel time
-  std::atomic<uint64_t> base_ns;             // our estimate of time
-  std::atomic<uint64_t> base_cycles;         // cycle counter reading
-  std::atomic<uint64_t> nsscaled_per_cycle;  // cycle period
+  std::atomic<uint64_t> raw_ns{0};              // raw kernel time
+  std::atomic<uint64_t> base_ns{0};             // our estimate of time
+  std::atomic<uint64_t> base_cycles{0};         // cycle counter reading
+  std::atomic<uint64_t> nsscaled_per_cycle{0};  // cycle period
   // cycles before we'll sample again (a scaled reciprocal of the period,
   // to avoid a division on the fast path).
-  std::atomic<uint64_t> min_cycles_per_sample;
+  std::atomic<uint64_t> min_cycles_per_sample{0};
 };
 // Same again, but with non-atomic types
 struct TimeSample {
-  uint64_t raw_ns;                 // raw kernel time
-  uint64_t base_ns;                // our estimate of time
-  uint64_t base_cycles;            // cycle counter reading
-  uint64_t nsscaled_per_cycle;     // cycle period
-  uint64_t min_cycles_per_sample;  // approx cycles before next sample
+  uint64_t raw_ns = 0;                 // raw kernel time
+  uint64_t base_ns = 0;                // our estimate of time
+  uint64_t base_cycles = 0;            // cycle counter reading
+  uint64_t nsscaled_per_cycle = 0;     // cycle period
+  uint64_t min_cycles_per_sample = 0;  // approx cycles before next sample
 };
 
-static struct TimeSampleAtomic last_sample;   // the last sample; under seq
+struct ABSL_CACHELINE_ALIGNED TimeState {
+  std::atomic<uint64_t> seq{0};
+  TimeSampleAtomic last_sample;  // the last sample; under seq
+
+  // The following counters are used only by the test code.
+  int64_t stats_initializations{0};
+  int64_t stats_reinitializations{0};
+  int64_t stats_calibrations{0};
+  int64_t stats_slow_paths{0};
+  int64_t stats_fast_slow_paths{0};
+
+  uint64_t last_now_cycles ABSL_GUARDED_BY(lock){0};
+
+  // Used by GetCurrentTimeNanosFromKernel().
+  // We try to read clock values at about the same time as the kernel clock.
+  // This value gets adjusted up or down as estimate of how long that should
+  // take, so we can reject attempts that take unusually long.
+  std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000};
+  // Number of times in a row we've seen a kernel time call take substantially
+  // less than approx_syscall_time_in_cycles.
+  std::atomic<uint32_t> kernel_time_seen_smaller{0};
+
+  // A reader-writer lock protecting the static locations below.
+  // See SeqAcquire() and SeqRelease() above.
+  absl::base_internal::SpinLock lock{absl::kConstInit,
+                                     base_internal::SCHEDULE_KERNEL_ONLY};
+};
+ABSL_CONST_INIT static TimeState time_state{};
+
+// Return the time in ns as told by the kernel interface.  Place in *cycleclock
+// the value of the cycleclock at about the time of the syscall.
+// This call represents the time base that this module synchronizes to.
+// Ensures that *cycleclock does not step back by up to (1 << 16) from
+// last_cycleclock, to discard small backward counter steps.  (Larger steps are
+// assumed to be complete resyncs, which shouldn't happen.  If they do, a full
+// reinitialization of the outer algorithm should occur.)
+static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock,
+                                             uint64_t *cycleclock)
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
+  uint64_t local_approx_syscall_time_in_cycles =  // local copy
+      time_state.approx_syscall_time_in_cycles.load(std::memory_order_relaxed);
+
+  int64_t current_time_nanos_from_system;
+  uint64_t before_cycles;
+  uint64_t after_cycles;
+  uint64_t elapsed_cycles;
+  int loops = 0;
+  do {
+    before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+    current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
+    after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+    // elapsed_cycles is unsigned, so is large on overflow
+    elapsed_cycles = after_cycles - before_cycles;
+    if (elapsed_cycles >= local_approx_syscall_time_in_cycles &&
+        ++loops == 20) {  // clock changed frequencies?  Back off.
+      loops = 0;
+      if (local_approx_syscall_time_in_cycles < 1000 * 1000) {
+        local_approx_syscall_time_in_cycles =
+            (local_approx_syscall_time_in_cycles + 1) << 1;
+      }
+      time_state.approx_syscall_time_in_cycles.store(
+          local_approx_syscall_time_in_cycles, std::memory_order_relaxed);
+    }
+  } while (elapsed_cycles >= local_approx_syscall_time_in_cycles ||
+           last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16));
+
+  // Adjust approx_syscall_time_in_cycles to be within a factor of 2
+  // of the typical time to execute one iteration of the loop above.
+  if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) {
+    // measured time is no smaller than half current approximation
+    time_state.kernel_time_seen_smaller.store(0, std::memory_order_relaxed);
+  } else if (time_state.kernel_time_seen_smaller.fetch_add(
+                 1, std::memory_order_relaxed) >= 3) {
+    // smaller delays several times in a row; reduce approximation by 12.5%
+    const uint64_t new_approximation =
+        local_approx_syscall_time_in_cycles -
+        (local_approx_syscall_time_in_cycles >> 3);
+    time_state.approx_syscall_time_in_cycles.store(new_approximation,
+                                                   std::memory_order_relaxed);
+    time_state.kernel_time_seen_smaller.store(0, std::memory_order_relaxed);
+  }
+
+  *cycleclock = after_cycles;
+  return current_time_nanos_from_system;
+}
 
 static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD;
 
@@ -317,14 +321,15 @@
   // Acquire pairs with the barrier in SeqRelease - if this load sees that
   // store, the shared-data reads necessarily see that SeqRelease's updates
   // to the same shared data.
-  seq_read0 = seq.load(std::memory_order_acquire);
+  seq_read0 = time_state.seq.load(std::memory_order_acquire);
 
-  base_ns = last_sample.base_ns.load(std::memory_order_relaxed);
-  base_cycles = last_sample.base_cycles.load(std::memory_order_relaxed);
+  base_ns = time_state.last_sample.base_ns.load(std::memory_order_relaxed);
+  base_cycles =
+      time_state.last_sample.base_cycles.load(std::memory_order_relaxed);
   nsscaled_per_cycle =
-      last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
-  min_cycles_per_sample =
-      last_sample.min_cycles_per_sample.load(std::memory_order_relaxed);
+      time_state.last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
+  min_cycles_per_sample = time_state.last_sample.min_cycles_per_sample.load(
+      std::memory_order_relaxed);
 
   // This acquire fence pairs with the release fence in SeqAcquire.  Since it
   // is sequenced between reads of shared data and seq_read1, the reads of
@@ -335,7 +340,7 @@
   // shared-data writes are effectively release ordered. Therefore if our
   // shared-data reads see any of a particular update's shared-data writes,
   // seq_read1 is guaranteed to see that update's SeqAcquire.
-  seq_read1 = seq.load(std::memory_order_relaxed);
+  seq_read1 = time_state.seq.load(std::memory_order_relaxed);
 
   // Fast path.  Return if min_cycles_per_sample has not yet elapsed since the
   // last sample, and we read a consistent sample.  The fast path activates
@@ -348,9 +353,9 @@
   // last_sample was updated). This is harmless, because delta_cycles will wrap
   // and report a time much much bigger than min_cycles_per_sample. In that case
   // we will take the slow path.
-  uint64_t delta_cycles = now_cycles - base_cycles;
+  uint64_t delta_cycles;
   if (seq_read0 == seq_read1 && (seq_read0 & 1) == 0 &&
-      delta_cycles < min_cycles_per_sample) {
+      (delta_cycles = now_cycles - base_cycles) < min_cycles_per_sample) {
     return base_ns + ((delta_cycles * nsscaled_per_cycle) >> kScale);
   }
   return GetCurrentTimeNanosSlowPath();
@@ -390,24 +395,25 @@
 // TODO(absl-team): Remove this attribute when our compiler is smart enough
 // to do the right thing.
 ABSL_ATTRIBUTE_NOINLINE
-static int64_t GetCurrentTimeNanosSlowPath() ABSL_LOCKS_EXCLUDED(lock) {
+static int64_t GetCurrentTimeNanosSlowPath()
+    ABSL_LOCKS_EXCLUDED(time_state.lock) {
   // Serialize access to slow-path.  Fast-path readers are not blocked yet, and
   // code below must not modify last_sample until the seqlock is acquired.
-  lock.Lock();
+  time_state.lock.Lock();
 
   // Sample the kernel time base.  This is the definition of
   // "now" if we take the slow path.
-  static uint64_t last_now_cycles;  // protected by lock
   uint64_t now_cycles;
-  uint64_t now_ns = GetCurrentTimeNanosFromKernel(last_now_cycles, &now_cycles);
-  last_now_cycles = now_cycles;
+  uint64_t now_ns =
+      GetCurrentTimeNanosFromKernel(time_state.last_now_cycles, &now_cycles);
+  time_state.last_now_cycles = now_cycles;
 
   uint64_t estimated_base_ns;
 
   // ----------
   // Read the "last_sample" values again; this time holding the write lock.
   struct TimeSample sample;
-  ReadTimeSampleAtomic(&last_sample, &sample);
+  ReadTimeSampleAtomic(&time_state.last_sample, &sample);
 
   // ----------
   // Try running the fast path again; another thread may have updated the
@@ -418,13 +424,13 @@
     // so that blocked readers can make progress without blocking new readers.
     estimated_base_ns = sample.base_ns +
         ((delta_cycles * sample.nsscaled_per_cycle) >> kScale);
-    stats_fast_slow_paths++;
+    time_state.stats_fast_slow_paths++;
   } else {
     estimated_base_ns =
         UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample);
   }
 
-  lock.Unlock();
+  time_state.lock.Unlock();
 
   return estimated_base_ns;
 }
@@ -435,9 +441,10 @@
 static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
                                  uint64_t delta_cycles,
                                  const struct TimeSample *sample)
-    ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock) {
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
   uint64_t estimated_base_ns = now_ns;
-  uint64_t lock_value = SeqAcquire(&seq);  // acquire seqlock to block readers
+  uint64_t lock_value =
+      SeqAcquire(&time_state.seq);  // acquire seqlock to block readers
 
   // The 5s in the next if-statement limits the time for which we will trust
   // the cycle counter and our last sample to give a reasonable result.
@@ -447,12 +454,16 @@
       sample->raw_ns + static_cast<uint64_t>(5) * 1000 * 1000 * 1000 < now_ns ||
       now_ns < sample->raw_ns || now_cycles < sample->base_cycles) {
     // record this sample, and forget any previously known slope.
-    last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
-    last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed);
-    last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed);
-    last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed);
-    last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed);
-    stats_initializations++;
+    time_state.last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+    time_state.last_sample.base_ns.store(estimated_base_ns,
+                                         std::memory_order_relaxed);
+    time_state.last_sample.base_cycles.store(now_cycles,
+                                             std::memory_order_relaxed);
+    time_state.last_sample.nsscaled_per_cycle.store(0,
+                                                    std::memory_order_relaxed);
+    time_state.last_sample.min_cycles_per_sample.store(
+        0, std::memory_order_relaxed);
+    time_state.stats_initializations++;
   } else if (sample->raw_ns + 500 * 1000 * 1000 < now_ns &&
              sample->base_cycles + 50 < now_cycles) {
     // Enough time has passed to compute the cycle time.
@@ -495,28 +506,32 @@
     if (new_nsscaled_per_cycle != 0 &&
         diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) {
       // record the cycle time measurement
-      last_sample.nsscaled_per_cycle.store(
+      time_state.last_sample.nsscaled_per_cycle.store(
           new_nsscaled_per_cycle, std::memory_order_relaxed);
       uint64_t new_min_cycles_per_sample =
           SafeDivideAndScale(kMinNSBetweenSamples, new_nsscaled_per_cycle);
-      last_sample.min_cycles_per_sample.store(
+      time_state.last_sample.min_cycles_per_sample.store(
           new_min_cycles_per_sample, std::memory_order_relaxed);
-      stats_calibrations++;
+      time_state.stats_calibrations++;
     } else {  // something went wrong; forget the slope
-      last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed);
-      last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed);
+      time_state.last_sample.nsscaled_per_cycle.store(
+          0, std::memory_order_relaxed);
+      time_state.last_sample.min_cycles_per_sample.store(
+          0, std::memory_order_relaxed);
       estimated_base_ns = now_ns;
-      stats_reinitializations++;
+      time_state.stats_reinitializations++;
     }
-    last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
-    last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed);
-    last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed);
+    time_state.last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+    time_state.last_sample.base_ns.store(estimated_base_ns,
+                                         std::memory_order_relaxed);
+    time_state.last_sample.base_cycles.store(now_cycles,
+                                             std::memory_order_relaxed);
   } else {
     // have a sample, but no slope; waiting for enough time for a calibration
-    stats_slow_paths++;
+    time_state.stats_slow_paths++;
   }
 
-  SeqRelease(&seq, lock_value);  // release the readers
+  SeqRelease(&time_state.seq, lock_value);  // release the readers
 
   return estimated_base_ns;
 }
@@ -558,7 +573,8 @@
 
 extern "C" {
 
-ABSL_ATTRIBUTE_WEAK void AbslInternalSleepFor(absl::Duration duration) {
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(
+    absl::Duration duration) {
   while (duration > absl::ZeroDuration()) {
     absl::Duration to_sleep = std::min(duration, absl::MaxSleep());
     absl::SleepOnce(to_sleep);
diff --git a/grpc/third_party/abseil-cpp/absl/time/clock.h b/grpc/third_party/abseil-cpp/absl/time/clock.h
index 27764a9..5fe244d 100644
--- a/grpc/third_party/abseil-cpp/absl/time/clock.h
+++ b/grpc/third_party/abseil-cpp/absl/time/clock.h
@@ -64,11 +64,11 @@
 // By changing our extension points to be extern "C", we dodge this
 // check.
 extern "C" {
-void AbslInternalSleepFor(absl::Duration duration);
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(absl::Duration duration);
 }  // extern "C"
 
 inline void absl::SleepFor(absl::Duration duration) {
-  AbslInternalSleepFor(duration);
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(duration);
 }
 
 #endif  // ABSL_TIME_CLOCK_H_
diff --git a/grpc/third_party/abseil-cpp/absl/time/duration.cc b/grpc/third_party/abseil-cpp/absl/time/duration.cc
index 952cc09..4443109 100644
--- a/grpc/third_party/abseil-cpp/absl/time/duration.cc
+++ b/grpc/third_party/abseil-cpp/absl/time/duration.cc
@@ -356,7 +356,7 @@
 // the remainder.  If it does not saturate, the remainder remain accurate,
 // but the returned quotient will over/underflow int64_t and should not be used.
 int64_t IDivDuration(bool satq, const Duration num, const Duration den,
-                   Duration* rem) {
+                     Duration* rem) {
   int64_t q = 0;
   if (IDivFastPath(num, den, &q, rem)) {
     return q;
@@ -763,7 +763,8 @@
 //   form "72h3m0.5s". Leading zero units are omitted.  As a special
 //   case, durations less than one second format use a smaller unit
 //   (milli-, micro-, or nanoseconds) to ensure that the leading digit
-//   is non-zero.  The zero duration formats as 0, with no unit.
+//   is non-zero.
+// Unlike Go, we format the zero duration as 0, with no unit.
 std::string FormatDuration(Duration d) {
   const Duration min_duration = Seconds(kint64min);
   if (d == min_duration) {
diff --git a/grpc/third_party/abseil-cpp/absl/time/duration_benchmark.cc b/grpc/third_party/abseil-cpp/absl/time/duration_benchmark.cc
index 83a836c..56820f3 100644
--- a/grpc/third_party/abseil-cpp/absl/time/duration_benchmark.cc
+++ b/grpc/third_party/abseil-cpp/absl/time/duration_benchmark.cc
@@ -18,9 +18,14 @@
 #include <string>
 
 #include "absl/base/attributes.h"
+#include "absl/flags/flag.h"
 #include "absl/time/time.h"
 #include "benchmark/benchmark.h"
 
+ABSL_FLAG(absl::Duration, absl_duration_flag_for_benchmark,
+          absl::Milliseconds(1),
+          "Flag to use for benchmarking duration flag access speed.");
+
 namespace {
 
 //
@@ -425,4 +430,15 @@
 }
 BENCHMARK(BM_Duration_ParseDuration)->DenseRange(0, kNumDurations - 1);
 
+//
+// Flag access
+//
+void BM_Duration_GetFlag(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(
+        absl::GetFlag(FLAGS_absl_duration_flag_for_benchmark));
+  }
+}
+BENCHMARK(BM_Duration_GetFlag);
+
 }  // namespace
diff --git a/grpc/third_party/abseil-cpp/absl/time/duration_test.cc b/grpc/third_party/abseil-cpp/absl/time/duration_test.cc
index 4d85a2c..fb28fa9 100644
--- a/grpc/third_party/abseil-cpp/absl/time/duration_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/time/duration_test.cc
@@ -1369,10 +1369,13 @@
   EXPECT_THAT(ToTimeval(absl::Nanoseconds(2000)), TimevalMatcher(tv));
 }
 
-void VerifySameAsMul(double time_as_seconds, int* const misses) {
+void VerifyApproxSameAsMul(double time_as_seconds, int* const misses) {
   auto direct_seconds = absl::Seconds(time_as_seconds);
   auto mul_by_one_second = time_as_seconds * absl::Seconds(1);
-  if (direct_seconds != mul_by_one_second) {
+  // These are expected to differ by up to one tick due to fused multiply/add
+  // contraction.
+  if (absl::AbsDuration(direct_seconds - mul_by_one_second) >
+      absl::time_internal::MakeDuration(0, 1u)) {
     if (*misses > 10) return;
     ASSERT_LE(++(*misses), 10) << "Too many errors, not reporting more.";
     EXPECT_EQ(direct_seconds, mul_by_one_second)
@@ -1384,7 +1387,8 @@
 // For a variety of interesting durations, we find the exact point
 // where one double converts to that duration, and the very next double
 // converts to the next duration.  For both of those points, verify that
-// Seconds(point) returns the same duration as point * Seconds(1.0)
+// Seconds(point) returns a duration near point * Seconds(1.0). (They may
+// not be exactly equal due to fused multiply/add contraction.)
 TEST(Duration, ToDoubleSecondsCheckEdgeCases) {
   constexpr uint32_t kTicksPerSecond = absl::time_internal::kTicksPerSecond;
   constexpr auto duration_tick = absl::time_internal::MakeDuration(0, 1u);
@@ -1423,8 +1427,8 @@
         }
         // Now low_edge is the highest double that converts to Duration d,
         // and high_edge is the lowest double that converts to Duration after_d.
-        VerifySameAsMul(low_edge, &misses);
-        VerifySameAsMul(high_edge, &misses);
+        VerifyApproxSameAsMul(low_edge, &misses);
+        VerifyApproxSameAsMul(high_edge, &misses);
       }
     }
   }
@@ -1444,8 +1448,8 @@
   int misses = 0;
   for (int i = 0; i < 1000000; ++i) {
     double d = std::exp(uniform(gen));
-    VerifySameAsMul(d, &misses);
-    VerifySameAsMul(-d, &misses);
+    VerifyApproxSameAsMul(d, &misses);
+    VerifyApproxSameAsMul(-d, &misses);
   }
 }
 
diff --git a/grpc/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/grpc/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h
index d1b4222..8aadde5 100644
--- a/grpc/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+++ b/grpc/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -416,16 +416,10 @@
 
   // Assigning arithmetic.
   CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
-    f_ = step(T{}, f_, n);
-    return *this;
+    return *this = *this + n;
   }
   CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
-    if (n != (std::numeric_limits<diff_t>::min)()) {
-      f_ = step(T{}, f_, -n);
-    } else {
-      f_ = step(T{}, step(T{}, f_, -(n + 1)), 1);
-    }
-    return *this;
+    return *this = *this - n;
   }
   CONSTEXPR_M civil_time& operator++() noexcept { return *this += 1; }
   CONSTEXPR_M civil_time operator++(int) noexcept {
@@ -442,13 +436,15 @@
 
   // Binary arithmetic operators.
   friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept {
-    return a += n;
+    return civil_time(step(T{}, a.f_, n));
   }
   friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept {
-    return a += n;
+    return a + n;
   }
   friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept {
-    return a -= n;
+    return n != (std::numeric_limits<diff_t>::min)()
+               ? civil_time(step(T{}, a.f_, -n))
+               : civil_time(step(T{}, step(T{}, a.f_, -(n + 1)), 1));
   }
   friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
     return difference(T{}, lhs.f_, rhs.f_);
diff --git a/grpc/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc b/grpc/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
index a14982a..887dd09 100644
--- a/grpc/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/grpc/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -27,6 +27,12 @@
 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
 
+#if defined(_AIX)
+extern "C" {
+extern long altzone;
+}
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace time_internal {
@@ -44,7 +50,7 @@
   const bool is_dst = tm.tm_isdst > 0;
   return _tzname[is_dst];
 }
-#elif defined(__sun)
+#elif defined(__sun) || defined(_AIX)
 // Uses the globals: 'timezone', 'altzone' and 'tzname'.
 auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
   const bool is_dst = tm.tm_isdst > 0;
diff --git a/grpc/third_party/abseil-cpp/absl/time/internal/cctz/src/tzfile.h b/grpc/third_party/abseil-cpp/absl/time/internal/cctz/src/tzfile.h
index 659f84c..269fa36 100644
--- a/grpc/third_party/abseil-cpp/absl/time/internal/cctz/src/tzfile.h
+++ b/grpc/third_party/abseil-cpp/absl/time/internal/cctz/src/tzfile.h
@@ -108,15 +108,15 @@
 #ifndef TZ_MAX_TYPES
 /* This must be at least 17 for Europe/Samara and Europe/Vilnius.  */
 #define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
-#endif /* !defined TZ_MAX_TYPES */
+#endif                   /* !defined TZ_MAX_TYPES */
 
 #ifndef TZ_MAX_CHARS
 #define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
-/* (limited by what unsigned chars can hold) */
-#endif /* !defined TZ_MAX_CHARS */
+                        /* (limited by what unsigned chars can hold) */
+#endif                  /* !defined TZ_MAX_CHARS */
 
 #ifndef TZ_MAX_LEAPS
 #define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
-#endif /* !defined TZ_MAX_LEAPS */
+#endif                  /* !defined TZ_MAX_LEAPS */
 
 #endif /* !defined TZFILE_H */
diff --git a/grpc/third_party/abseil-cpp/absl/time/time.cc b/grpc/third_party/abseil-cpp/absl/time/time.cc
index 6bb36cb..1ec2026 100644
--- a/grpc/third_party/abseil-cpp/absl/time/time.cc
+++ b/grpc/third_party/abseil-cpp/absl/time/time.cc
@@ -60,9 +60,10 @@
 inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
   absl::Duration rem;
   int64_t q = absl::IDivDuration(d, unit, &rem);
-  return (q > 0 ||
-          rem >= ZeroDuration() ||
-          q == std::numeric_limits<int64_t>::min()) ? q : q - 1;
+  return (q > 0 || rem >= ZeroDuration() ||
+          q == std::numeric_limits<int64_t>::min())
+             ? q
+             : q - 1;
 }
 
 inline absl::Time::Breakdown InfiniteFutureBreakdown() {
diff --git a/grpc/third_party/abseil-cpp/absl/time/time.h b/grpc/third_party/abseil-cpp/absl/time/time.h
index 37f6131..2df6858 100644
--- a/grpc/third_party/abseil-cpp/absl/time/time.h
+++ b/grpc/third_party/abseil-cpp/absl/time/time.h
@@ -458,12 +458,12 @@
 //
 //   absl::Duration d = absl::Milliseconds(1500);
 //   int64_t isec = absl::ToInt64Seconds(d);  // isec == 1
-int64_t ToInt64Nanoseconds(Duration d);
-int64_t ToInt64Microseconds(Duration d);
-int64_t ToInt64Milliseconds(Duration d);
-int64_t ToInt64Seconds(Duration d);
-int64_t ToInt64Minutes(Duration d);
-int64_t ToInt64Hours(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Nanoseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Microseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Seconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Minutes(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Hours(Duration d);
 
 // ToDoubleNanoSeconds()
 // ToDoubleMicroseconds()
@@ -480,12 +480,12 @@
 //
 //   absl::Duration d = absl::Milliseconds(1500);
 //   double dsec = absl::ToDoubleSeconds(d);  // dsec == 1.5
-double ToDoubleNanoseconds(Duration d);
-double ToDoubleMicroseconds(Duration d);
-double ToDoubleMilliseconds(Duration d);
-double ToDoubleSeconds(Duration d);
-double ToDoubleMinutes(Duration d);
-double ToDoubleHours(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleNanoseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMicroseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMilliseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleSeconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMinutes(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleHours(Duration d);
 
 // FromChrono()
 //
@@ -639,7 +639,7 @@
   // Deprecated. Use `absl::TimeZone::CivilInfo`.
   struct
       Breakdown {
-    int64_t year;          // year (e.g., 2013)
+    int64_t year;        // year (e.g., 2013)
     int month;           // month of year [1:12]
     int day;             // day of month [1:31]
     int hour;            // hour of day [0:23]
@@ -1180,11 +1180,15 @@
 //
 // Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and
 // `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3)
-// for a description of the expected values of the tm fields. If the indicated
-// time instant is not unique (see `absl::TimeZone::At(absl::CivilSecond)`
-// above), the `tm_isdst` field is consulted to select the desired instant
-// (`tm_isdst` > 0 means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0
-// means use the post-transition offset).
+// for a description of the expected values of the tm fields. If the civil time
+// is unique (see `absl::TimeZone::At(absl::CivilSecond)` above), the matching
+// time instant is returned.  Otherwise, the `tm_isdst` field is consulted to
+// choose between the possible results.  For a repeated civil time, `tm_isdst !=
+// 0` returns the matching DST instant, while `tm_isdst == 0` returns the
+// matching non-DST instant.  For a skipped civil time there is no matching
+// instant, so `tm_isdst != 0` returns the DST instant, and `tm_isdst == 0`
+// returns the non-DST instant, that would have matched if the transition never
+// happened.
 Time FromTM(const struct tm& tm, TimeZone tz);
 
 // ToTM()
@@ -1494,12 +1498,10 @@
 constexpr bool operator<(Duration lhs, Duration rhs) {
   return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
              ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
-             : time_internal::GetRepHi(lhs) ==
-                       (std::numeric_limits<int64_t>::min)()
-                   ? time_internal::GetRepLo(lhs) + 1 <
-                         time_internal::GetRepLo(rhs) + 1
-                   : time_internal::GetRepLo(lhs) <
-                         time_internal::GetRepLo(rhs);
+         : time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)()
+             ? time_internal::GetRepLo(lhs) + 1 <
+                   time_internal::GetRepLo(rhs) + 1
+             : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs);
 }
 
 constexpr bool operator==(Duration lhs, Duration rhs) {
diff --git a/grpc/third_party/abseil-cpp/absl/time/time_test.cc b/grpc/third_party/abseil-cpp/absl/time/time_test.cc
index b28a99f..cde9423 100644
--- a/grpc/third_party/abseil-cpp/absl/time/time_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/time/time_test.cc
@@ -1070,7 +1070,8 @@
   EXPECT_EQ("292277026596-12-04T15:30:07+00:00",
             absl::FormatTime(absl::RFC3339_full, t, utc));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
+      t);
 
   // Checks that we can also get the maximal Time value for a far-east zone.
   const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60);
@@ -1078,7 +1079,8 @@
   EXPECT_EQ("292277026596-12-05T05:30:07+14:00",
             absl::FormatTime(absl::RFC3339_full, t, plus14));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
+      t);
 
   // One second later should push us to infinity.
   t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc);
@@ -1092,7 +1094,8 @@
   EXPECT_EQ("-292277022657-01-27T08:29:52+00:00",
             absl::FormatTime(absl::RFC3339_full, t, utc));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
+      t);
 
   // Checks that we can also get the minimal Time value for a far-west zone.
   const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60);
@@ -1101,7 +1104,8 @@
   EXPECT_EQ("-292277022657-01-26T20:29:52-12:00",
             absl::FormatTime(absl::RFC3339_full, t, minus12));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
+      t);
 
   // One second before should push us to -infinity.
   t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc);
diff --git a/grpc/third_party/abseil-cpp/absl/types/CMakeLists.txt b/grpc/third_party/abseil-cpp/absl/types/CMakeLists.txt
index 3f99ad8..c356b21 100644
--- a/grpc/third_party/abseil-cpp/absl/types/CMakeLists.txt
+++ b/grpc/third_party/abseil-cpp/absl/types/CMakeLists.txt
@@ -353,9 +353,6 @@
     gmock_main
 )
 
-# TODO(cohenjon,zhangxy) Figure out why this test is failing on gcc 4.8
-if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
-else()
 absl_cc_test(
   NAME
     variant_exception_safety_test
@@ -370,4 +367,3 @@
     absl::memory
     gmock_main
 )
-endif()
diff --git a/grpc/third_party/abseil-cpp/absl/types/internal/variant.h b/grpc/third_party/abseil-cpp/absl/types/internal/variant.h
index d404e80..772008c 100644
--- a/grpc/third_party/abseil-cpp/absl/types/internal/variant.h
+++ b/grpc/third_party/abseil-cpp/absl/types/internal/variant.h
@@ -45,7 +45,7 @@
 template <class... Types>
 class variant;
 
-ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
+ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1));
 
 template <class T>
 struct variant_size;
diff --git a/grpc/third_party/abseil-cpp/absl/types/variant.h b/grpc/third_party/abseil-cpp/absl/types/variant.h
index 776d19a..ac93464 100644
--- a/grpc/third_party/abseil-cpp/absl/types/variant.h
+++ b/grpc/third_party/abseil-cpp/absl/types/variant.h
@@ -604,7 +604,10 @@
 
   // emplace() Functions
 
-  // Constructs a value of the given alternative type T within the variant.
+  // Constructs a value of the given alternative type T within the variant. The
+  // existing value of the variant is destroyed first (provided that
+  // `absl::valueless_by_exception()` is false). Requires that T is unambiguous
+  // in the variant.
   //
   // Example:
   //
@@ -624,7 +627,9 @@
   }
 
   // Constructs a value of the given alternative type T within the variant using
-  // an initializer list.
+  // an initializer list. The existing value of the variant is destroyed first
+  // (provided that `absl::valueless_by_exception()` is false). Requires that T
+  // is unambiguous in the variant.
   //
   // Example:
   //
@@ -643,7 +648,7 @@
   }
 
   // Destroys the current value of the variant (provided that
-  // `absl::valueless_by_exception()` is false, and constructs a new value at
+  // `absl::valueless_by_exception()` is false) and constructs a new value at
   // the given index.
   //
   // Example:
@@ -662,7 +667,7 @@
   }
 
   // Destroys the current value of the variant (provided that
-  // `absl::valueless_by_exception()` is false, and constructs a new value at
+  // `absl::valueless_by_exception()` is false) and constructs a new value at
   // the given index using an initializer list and the provided arguments.
   //
   // Example:
diff --git a/grpc/third_party/abseil-cpp/absl/types/variant_test.cc b/grpc/third_party/abseil-cpp/absl/types/variant_test.cc
index cf8f7f3..cf23733 100644
--- a/grpc/third_party/abseil-cpp/absl/types/variant_test.cc
+++ b/grpc/third_party/abseil-cpp/absl/types/variant_test.cc
@@ -2311,7 +2311,8 @@
   ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
   EXPECT_EQ(42, absl::get<int32_t>(variant2));
 
-  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+  variant2 =
+      ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
   ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
   EXPECT_EQ(42, absl::get<uint32_t>(variant2));
 #endif  // !ABSL_USES_STD_VARIANT
@@ -2453,7 +2454,8 @@
       ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
   EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
 
-  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+  variant2 =
+      ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
   EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
 #endif
 
diff --git a/grpc/third_party/abseil-cpp/ci/cmake_common.sh b/grpc/third_party/abseil-cpp/ci/cmake_common.sh
new file mode 100644
index 0000000..aec8a11
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/ci/cmake_common.sh
@@ -0,0 +1,25 @@
+# Copyright 2020 The Abseil 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
+#
+#    https://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.
+
+# The commit of GoogleTest to be used in the CMake tests in this directory.
+# Keep this in sync with the commit in the WORKSPACE file.
+readonly ABSL_GOOGLETEST_COMMIT="8567b09290fe402cf01923e2131c5635b8ed851b"
+
+# Avoid depending on GitHub by looking for a cached copy of the commit first.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip" ]]; then
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/${ABSL_GOOGLETEST_COMMIT}.zip"
+else
+  ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/archive/${ABSL_GOOGLETEST_COMMIT}.zip"
+fi
diff --git a/grpc/third_party/abseil-cpp/ci/cmake_install_test.sh b/grpc/third_party/abseil-cpp/ci/cmake_install_test.sh
index b31e4b8..ffc6b51 100755
--- a/grpc/third_party/abseil-cpp/ci/cmake_install_test.sh
+++ b/grpc/third_party/abseil-cpp/ci/cmake_install_test.sh
@@ -20,16 +20,24 @@
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
+if [[ -z ${LINK_TYPE:-} ]]; then
+  LINK_TYPE="STATIC DYNAMIC"
+fi
+
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
 source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
 readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
 
-time docker run \
-    --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
-    --workdir=/abseil-cpp \
+for link_type in ${LINK_TYPE}; do
+  time docker run \
+    --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
     --tmpfs=/buildfs:exec \
+    --tmpfs=/abseil-cpp:exec \
+    --workdir=/abseil-cpp \
     --cap-add=SYS_PTRACE \
+    -e "LINK_TYPE=${link_type}" \
     --rm \
-    -e CFLAGS="-Werror" \
-    -e CXXFLAGS="-Werror" \
     ${DOCKER_CONTAINER} \
-    /bin/bash CMake/install_test_project/test.sh $@
+    /bin/bash -c "cp -r /abseil-cpp-ro/* . && CMake/install_test_project/test.sh"
+done
diff --git a/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh b/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh
index 2aed43c..ffbb832 100755
--- a/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -42,7 +42,7 @@
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
 if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -55,7 +55,7 @@
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
 if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
 
@@ -64,12 +64,11 @@
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CC="/opt/llvm/clang/bin/clang" \
-        -e BAZEL_COMPILER="llvm" \
         -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
         -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \
         -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \
diff --git a/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh b/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh
index eb04e69..f6a2221 100755
--- a/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh
@@ -42,7 +42,7 @@
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
 if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -55,7 +55,7 @@
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
 if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
 
@@ -64,13 +64,12 @@
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp-ro:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
         --tmpfs=/abseil-cpp \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CC="/opt/llvm/clang/bin/clang" \
-        -e BAZEL_COMPILER="llvm" \
         -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
         -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \
         -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \
diff --git a/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh
index b39eaf7..e70e821 100755
--- a/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -42,7 +42,7 @@
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
 if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -55,7 +55,7 @@
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
 if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
 
@@ -64,12 +64,11 @@
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CC="/opt/llvm/clang/bin/clang" \
-        -e BAZEL_COMPILER="llvm" \
         -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
         -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx-tsan/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib" \
         -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx-tsan/include/c++/v1" \
diff --git a/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh b/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh
index 4e49067..0986ff4 100755
--- a/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -42,7 +42,7 @@
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
 if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -55,7 +55,7 @@
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
 if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
 
@@ -64,12 +64,11 @@
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CC="/opt/llvm/clang/bin/clang" \
-        -e BAZEL_COMPILER="llvm" \
         -e BAZEL_CXXOPTS="-std=${std}" \
         ${DOCKER_EXTRA_ARGS:-} \
         ${DOCKER_CONTAINER} \
diff --git a/grpc/third_party/abseil-cpp/ci/linux_docker_containers.sh b/grpc/third_party/abseil-cpp/ci/linux_docker_containers.sh
index e42fa58..1c29d9a 100644
--- a/grpc/third_party/abseil-cpp/ci/linux_docker_containers.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_docker_containers.sh
@@ -15,7 +15,7 @@
 # The file contains Docker container identifiers currently used by test scripts.
 # Test scripts should source this file to get the identifiers.
 
-readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20191016"
-readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20200909"
-readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20200909"
-readonly LINUX_GCC_49_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20191018"
+readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026"
+readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
+readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
+readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015"
diff --git a/grpc/third_party/abseil-cpp/ci/linux_gcc-4.9_libstdcxx_bazel.sh b/grpc/third_party/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh
similarity index 96%
rename from grpc/third_party/abseil-cpp/ci/linux_gcc-4.9_libstdcxx_bazel.sh
rename to grpc/third_party/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh
index 8e6540c..224aef8 100755
--- a/grpc/third_party/abseil-cpp/ci/linux_gcc-4.9_libstdcxx_bazel.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright 2019 The Abseil Authors.
+# Copyright 2020 The Abseil Authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@
 fi
 
 source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
-readonly DOCKER_CONTAINER=${LINUX_GCC_49_CONTAINER}
+readonly DOCKER_CONTAINER=${LINUX_GCC_FLOOR_CONTAINER}
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
@@ -68,7 +68,7 @@
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
         --rm \
-        -e CC="/usr/bin/gcc-4.9" \
+        -e CC="/usr/local/bin/gcc" \
         -e BAZEL_CXXOPTS="-std=${std}" \
         ${DOCKER_EXTRA_ARGS:-} \
         ${DOCKER_CONTAINER} \
diff --git a/grpc/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh b/grpc/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh
index b327405..37d89d9 100755
--- a/grpc/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -42,7 +42,7 @@
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
 if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
   # Bazel doesn't track changes to tools outside of the workspace
   # (e.g. /usr/bin/gcc), so by appending the docker container to the
   # remote_http_cache url, we make changes to the container part of
@@ -55,7 +55,7 @@
 # external dependencies first.
 # https://docs.bazel.build/versions/master/guide.html#distdir
 if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
-  DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
   BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
 fi
 
@@ -64,7 +64,7 @@
     for exceptions_mode in ${EXCEPTIONS_MODE}; do
       echo "--------------------------------------------------------------------"
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp-ro:ro" \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
         --tmpfs=/abseil-cpp \
         --workdir=/abseil-cpp \
         --cap-add=SYS_PTRACE \
diff --git a/grpc/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_cmake.sh b/grpc/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_cmake.sh
index 26415e2..ab06aa0 100755
--- a/grpc/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -14,18 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# TODO(absl-team): This script isn't fully hermetic because
-# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
-# version of GoogleTest. This means that an upstream change to GoogleTest could
-# break this test. Fix this by allowing this script to pin to a known-good
-# version of GoogleTest.
-
 set -euox pipefail
 
 if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
 if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="11 14 17 20"
 fi
@@ -45,20 +41,20 @@
   for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
     for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
-        --workdir=/abseil-cpp \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
         --tmpfs=/buildfs:exec \
+        --workdir=/buildfs \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CFLAGS="-Werror" \
         -e CXXFLAGS="-Werror" \
-        ${DOCKER_CONTAINER} \
+        ${DOCKER_EXTRA_ARGS:-} \
+        "${DOCKER_CONTAINER}" \
         /bin/bash -c "
-          cd /buildfs && \
           cmake /abseil-cpp \
-            -DABSL_USE_GOOGLETEST_HEAD=ON \
-            -DABSL_RUN_TESTS=ON \
+            -DABSL_GOOGLETEST_DOWNLOAD_URL=${ABSL_GOOGLETEST_DOWNLOAD_URL} \
             -DBUILD_SHARED_LIBS=${build_shared} \
+            -DBUILD_TESTING=ON \
             -DCMAKE_BUILD_TYPE=${compilation_mode} \
             -DCMAKE_CXX_STANDARD=${std} \
             -DCMAKE_MODULE_LINKER_FLAGS=\"-Wl,--no-undefined\" && \
diff --git a/grpc/third_party/abseil-cpp/ci/linux_gcc_alpine_cmake.sh b/grpc/third_party/abseil-cpp/ci/linux_gcc_alpine_cmake.sh
index b3b8e7a..bce27d2 100755
--- a/grpc/third_party/abseil-cpp/ci/linux_gcc_alpine_cmake.sh
+++ b/grpc/third_party/abseil-cpp/ci/linux_gcc_alpine_cmake.sh
@@ -14,18 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# TODO(absl-team): This script isn't fully hermetic because
-# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
-# version of GoogleTest. This means that an upstream change to GoogleTest could
-# break this test. Fix this by allowing this script to pin to a known-good
-# version of GoogleTest.
-
 set -euox pipefail
 
 if [[ -z ${ABSEIL_ROOT:-} ]]; then
   ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
 fi
 
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
 if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="11 14 17"
 fi
@@ -45,19 +41,19 @@
   for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
     for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
       time docker run \
-        --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
-        --workdir=/abseil-cpp \
+        --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
         --tmpfs=/buildfs:exec \
+        --workdir=/buildfs \
         --cap-add=SYS_PTRACE \
         --rm \
         -e CFLAGS="-Werror" \
         -e CXXFLAGS="-Werror" \
+        ${DOCKER_EXTRA_ARGS:-} \
         "${DOCKER_CONTAINER}" \
         /bin/sh -c "
-          cd /buildfs && \
           cmake /abseil-cpp \
-            -DABSL_USE_GOOGLETEST_HEAD=ON \
-            -DABSL_RUN_TESTS=ON \
+            -DABSL_GOOGLETEST_DOWNLOAD_URL=${ABSL_GOOGLETEST_DOWNLOAD_URL} \
+            -DBUILD_TESTING=ON \
             -DCMAKE_BUILD_TYPE=${compilation_mode} \
             -DCMAKE_CXX_STANDARD=${std} \
             -DCMAKE_MODULE_LINKER_FLAGS=\"-Wl,--no-undefined\" && \
diff --git a/grpc/third_party/abseil-cpp/ci/macos_xcode_cmake.sh b/grpc/third_party/abseil-cpp/ci/macos_xcode_cmake.sh
index d90e273..2a870cf 100755
--- a/grpc/third_party/abseil-cpp/ci/macos_xcode_cmake.sh
+++ b/grpc/third_party/abseil-cpp/ci/macos_xcode_cmake.sh
@@ -14,9 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# This script is invoked on Kokoro to test Abseil on macOS.
-# It is not hermetic and may break when Kokoro is updated.
-
 set -euox pipefail
 
 if [[ -z ${ABSEIL_ROOT:-} ]]; then
@@ -24,6 +21,13 @@
 fi
 ABSEIL_ROOT=$(realpath ${ABSEIL_ROOT})
 
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+# The MacOS build doesn't run in a docker container, so we have to override ABSL_GOOGLETEST_DOWNLOAD_URL.
+if [[ -r "${KOKORO_GFILE_DIR}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file://${KOKORO_GFILE_DIR}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip"
+fi
+
 if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug"
 fi
@@ -41,11 +45,11 @@
     time cmake ${ABSEIL_ROOT} \
       -GXcode \
       -DBUILD_SHARED_LIBS=${build_shared} \
+      -DBUILD_TESTING=ON \
       -DCMAKE_BUILD_TYPE=${compilation_mode} \
       -DCMAKE_CXX_STANDARD=11 \
       -DCMAKE_MODULE_LINKER_FLAGS="-Wl,--no-undefined" \
-      -DABSL_USE_GOOGLETEST_HEAD=ON \
-      -DABSL_RUN_TESTS=ON
+      -DABSL_GOOGLETEST_DOWNLOAD_URL="${ABSL_GOOGLETEST_DOWNLOAD_URL}"
     time cmake --build .
     time ctest -C ${compilation_mode} --output-on-failure
   done
diff --git a/grpc/third_party/abseil-cpp/conanfile.py b/grpc/third_party/abseil-cpp/conanfile.py
old mode 100644
new mode 100755
diff --git a/grpc/third_party/abseil-cpp/create_lts.py b/grpc/third_party/abseil-cpp/create_lts.py
new file mode 100755
index 0000000..a98c76b
--- /dev/null
+++ b/grpc/third_party/abseil-cpp/create_lts.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright 2021 The Abseil 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
+#
+#      https://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.
+"""A script to do source transformations to create a new LTS release.
+
+   Usage: ./create_lts.py YYYYMMDD
+"""
+
+import sys
+
+
+def ReplaceStringsInFile(filename, replacement_dict):
+  """Performs textual replacements in a file.
+
+  Rewrites filename with the keys in replacement_dict replaced with
+  their values. This function assumes the file can fit in memory.
+
+  Args:
+    filename: the filename to perform the replacement on
+    replacement_dict: a dictionary of key strings to be replaced with their
+      values
+
+  Raises:
+    Exception: A failure occured
+  """
+  f = open(filename, 'r')
+  content = f.read()
+  f.close()
+
+  for key, value in replacement_dict.items():
+    original = content
+    content = content.replace(key, value)
+    if content == original:
+      raise Exception('Failed to find {} in {}'.format(key, filename))
+
+  f = open(filename, 'w')
+  f.write(content)
+  f.close()
+
+
+def StripContentBetweenTags(filename, strip_begin_tag, strip_end_tag):
+  """Strip contents from a file.
+
+  Rewrites filename with by removing all content between
+  strip_begin_tag and strip_end_tag, including the tags themselves.
+
+  Args:
+    filename: the filename to perform the replacement on
+    strip_begin_tag: the start of the content to be removed
+    strip_end_tag: the end of the content to be removed
+
+  Raises:
+    Exception: A failure occured
+  """
+  f = open(filename, 'r')
+  content = f.read()
+  f.close()
+
+  while True:
+    begin = content.find(strip_begin_tag)
+    if begin == -1:
+      break
+    end = content.find(strip_end_tag, begin + len(strip_begin_tag))
+    if end == -1:
+      raise Exception('{}: imbalanced strip begin ({}) and '
+                      'end ({}) tags'.format(filename, strip_begin_tag,
+                                             strip_end_tag))
+    content = content.replace(content[begin:end + len(strip_end_tag)], '')
+
+  f = open(filename, 'w')
+  f.write(content)
+  f.close()
+
+
+def main(argv):
+  if len(argv) != 2:
+    print('Usage: {} YYYYMMDD'.format(sys.argv[0], file=sys.stderr))
+    sys.exit(1)
+
+  datestamp = sys.argv[1]
+  if len(datestamp) != 8 or not datestamp.isdigit():
+    raise Exception(
+        'datestamp={} is not in the YYYYMMDD format'.format(datestamp))
+
+  # Replacement directives go here.
+  ReplaceStringsInFile(
+      'absl/base/options.h', {
+          '#define ABSL_OPTION_USE_INLINE_NAMESPACE 0':
+              '#define ABSL_OPTION_USE_INLINE_NAMESPACE 1',
+          '#define ABSL_OPTION_INLINE_NAMESPACE_NAME head':
+              '#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_{}'.format(
+                  datestamp)
+      })
+  ReplaceStringsInFile(
+      'CMakeLists.txt', {
+          'project(absl LANGUAGES CXX)':
+              'project(absl LANGUAGES CXX VERSION {})'.format(datestamp)
+      })
+  # Set the SOVERSION to YYYYMMDD.0.0 - The first 0 means we only have
+  # ABI compatible changes, and the second 0 means we can increment it
+  # to mark changes as ABI-compatible, for patch releases.
+  ReplaceStringsInFile('CMake/AbseilHelpers.cmake',
+                       {'SOVERSION 0': 'SOVERSION "{}.0.0"'.format(datestamp)})
+  StripContentBetweenTags('CMakeLists.txt', '# absl:lts-remove-begin',
+                          '# absl:lts-remove-end')
+
+
+if __name__ == '__main__':
+  main(sys.argv)
diff --git a/grpc/third_party/protobuf.patch b/grpc/third_party/protobuf.patch
index 0b302e4..f7ff1dd 100644
--- a/grpc/third_party/protobuf.patch
+++ b/grpc/third_party/protobuf.patch
@@ -5,7 +5,7 @@
 @@ -31,3 +31,9 @@
  # Copyright 2007 Google Inc. All Rights Reserved.
 
- __version__ = '3.14.0'
+ __version__ = '3.15.8'
 +
 +if __name__ != '__main__':
 +  try:
diff --git a/grpc/third_party/py/BUILD b/grpc/third_party/py/BUILD
index e69de29..6ab5124 100644
--- a/grpc/third_party/py/BUILD
+++ b/grpc/third_party/py/BUILD
@@ -0,0 +1,5 @@
+exports_files([
+    "BUILD.tpl",
+    "python_configure.bzl",
+    "variety.tpl"
+])
diff --git a/grpc/third_party/py/python_configure.bzl b/grpc/third_party/py/python_configure.bzl
index 88fcb10..fa47d89 100644
--- a/grpc/third_party/py/python_configure.bzl
+++ b/grpc/third_party/py/python_configure.bzl
@@ -348,7 +348,7 @@
         repository_ctx,
         "_python2",
         _PYTHON2_BIN_PATH,
-        "python",
+        "python2",
         _PYTHON2_LIB_PATH,
         True
     )
diff --git a/grpc/third_party/xxhash/.gitattributes b/grpc/third_party/xxhash/.gitattributes
new file mode 100644
index 0000000..fbcf75b
--- /dev/null
+++ b/grpc/third_party/xxhash/.gitattributes
@@ -0,0 +1,10 @@
+# Set the default behavior
+* text eol=lf
+
+# Explicitly declare source files
+*.c text eol=lf
+*.h text eol=lf
+
+# Denote files that should not be modified.
+*.odt binary
+
diff --git a/grpc/third_party/xxhash/.gitignore b/grpc/third_party/xxhash/.gitignore
new file mode 100644
index 0000000..d0ce9aa
--- /dev/null
+++ b/grpc/third_party/xxhash/.gitignore
@@ -0,0 +1,47 @@
+# objects
+*.o
+*.obj
+*.s
+
+# libraries
+libxxhash.*
+!libxxhash.pc.in
+
+# Executables
+*.exe
+xxh32sum
+xxh64sum
+xxh128sum
+xxhsum
+xxhsum32
+xxhsum_privateXXH
+xxhsum_inlinedXXH
+dispatch
+tests/generate_unicode_test
+
+# compilation chain
+.clang_complete
+
+# Mac OS-X artefacts
+*.dSYM
+.DS_Store
+
+# Wasm / emcc / emscripten artefacts
+*.html
+*.wasm
+*.js
+
+# CMake build directories
+build*/
+
+# project managers artifacts
+.projectile
+
+# analyzer artifacts
+infer-out
+
+# test artifacts
+.test*
+tmp*
+tests/*.unicode
+tests/unicode_test*
diff --git a/grpc/third_party/xxhash/.travis.yml b/grpc/third_party/xxhash/.travis.yml
new file mode 100644
index 0000000..8347686
--- /dev/null
+++ b/grpc/third_party/xxhash/.travis.yml
@@ -0,0 +1,138 @@
+language: c
+
+# Dump CPU info before start
+before_install:
+  - cat /proc/cpuinfo || echo /proc/cpuinfo is not present
+
+matrix:
+  fast_finish: true
+  include:
+
+    - name: General linux x64 tests
+      arch: amd64
+      addons:
+        apt:
+          packages:
+            - g++-multilib
+            - gcc-multilib
+            - cppcheck
+      script:
+        - make -B test-all
+        - make clean
+        - CFLAGS="-Werror" MOREFLAGS="-Wno-sign-conversion" make dispatch  # removing sign conversion warnings due to a bug in gcc-5's definition of some AVX512 intrinsics
+        - make clean
+        - CC=g++ CFLAGS="-O1 -mavx512f -Werror" make
+        - make clean
+        - CC=g++ CFLAGS="-Wall -Wextra -Werror" make DISPATCH=1
+
+
+    - name: Check results consistency on x64
+      arch: amd64
+      script:
+        - CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR make check   # Scalar code path
+        - make clean
+        - CPPFLAGS=-DXXH_VECTOR=XXH_SSE2 make check   # SSE2 code path
+        - make clean
+        - CPPFLAGS="-mavx2 -DXXH_VECTOR=XXH_AVX2" make check   # AVX2 code path
+        - make clean
+        - CPPFLAGS="-mavx512f -DXXH_VECTOR=XXH_AVX512" make check   # AVX512 code path
+        - make clean
+        - CPPFLAGS=-DXXH_REROLL=1 make check   # reroll code path (#240)
+        - make -C tests/bench
+
+    - name: macOS General Test
+      os: osx
+      compiler: clang
+      script:
+        - CFLAGS="-Werror" make   # test library build
+        - make clean
+        - make test MOREFLAGS='-Werror' | tee # test scenario where `stdout` is not the console
+
+    - name: ARM compilation and consistency checks (Qemu)
+      dist: xenial
+      arch: amd64
+      addons:
+        apt:
+          packages:
+            - qemu-system-arm
+            - qemu-user-static
+            - gcc-arm-linux-gnueabi
+            - libc6-dev-armel-cross
+      script:
+        # arm (32-bit)
+        - CC=arm-linux-gnueabi-gcc CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR LDFLAGS=-static RUN_ENV=qemu-arm-static make check   # Scalar code path
+        - make clean
+        # NEON (32-bit)
+        - CC=arm-linux-gnueabi-gcc CPPFLAGS=-DXXH_VECTOR=XXH_NEON CFLAGS="-O3 -march=armv7-a -fPIC -mfloat-abi=softfp -mfpu=neon-vfpv4" LDFLAGS=-static RUN_ENV=qemu-arm-static make check   # NEON code path
+
+    - name: aarch64 compilation and consistency checks
+      dist: xenial
+      arch: arm64
+      script:
+        # aarch64
+        - CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR make check   # Scalar code path
+        # NEON (64-bit)
+        - make clean
+        - CPPFLAGS=-DXXH_VECTOR=XXH_NEON make check   # NEON code path
+        # clang
+        - make clean
+        - CC=clang CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR make check   # Scalar code path
+        # clang + NEON
+        - make clean
+        - CC=clang CPPFLAGS=-DXXH_VECTOR=XXH_NEON make check   # NEON code path
+
+    # We need Bionic here because the QEMU versions shipped in the older repos
+    # do not support POWER8 emulation, and compiling QEMU from source is a pain.
+    - name: PowerPC + PPC64 compilation and consistency checks (Qemu on Bionic)
+      dist: bionic
+      arch: amd64
+      addons:
+        apt:
+          packages:
+            - qemu-system-ppc
+            - qemu-user-static
+            - gcc-powerpc-linux-gnu
+            - gcc-powerpc64-linux-gnu
+            - libc6-dev-powerpc-cross
+            - libc6-dev-ppc64-cross
+      script:
+        - CC=powerpc-linux-gnu-gcc RUN_ENV=qemu-ppc-static LDFLAGS=-static make check   # Scalar code path
+        - make clean
+        - CC=powerpc64-linux-gnu-gcc RUN_ENV=qemu-ppc64-static CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR CFLAGS="-O3" LDFLAGS="-static -m64" make check   # Scalar code path
+        # VSX code
+        - make clean
+        - CC=powerpc64-linux-gnu-gcc RUN_ENV="qemu-ppc64-static -cpu power8" CPPFLAGS=-DXXH_VECTOR=XXH_VSX CFLAGS="-O3 -maltivec -mvsx -mcpu=power8 -mpower8-vector" LDFLAGS="-static -m64" make check   # VSX code path
+        # altivec.h redefinition issue #426
+        - make clean
+        - CC=powerpc64-linux-gnu-gcc CPPFLAGS=-DXXH_VECTOR=XXH_VSX CFLAGS="-maltivec -mvsx -mcpu=power8 -mpower8-vector" make -C tests test_ppc_redefine
+
+    - name: PPC64LE compilation and consistency checks
+      dist: xenial
+      arch: ppc64le
+      script:
+        # Scalar (universal) code path
+        - CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR LDFLAGS=-static make check
+        # VSX code path (64-bit)
+        - make clean
+        - CPPFLAGS=-DXXH_VECTOR=XXH_VSX CFLAGS="-O3 -maltivec -mvsx -mpower8-vector -mcpu=power8" LDFLAGS="-static" make check
+        # altivec.h redefinition issue #426
+        - make clean
+        - CPPFLAGS=-DXXH_VECTOR=XXH_VSX CFLAGS="-maltivec -mvsx -mcpu=power8 -mpower8-vector" make -C tests test_ppc_redefine
+
+    - name: IBM s390x compilation and consistency checks
+      dist: bionic
+      arch: s390x
+      script:
+        # Scalar (universal) code path
+        - CPPFLAGS=-DXXH_VECTOR=XXH_SCALAR LDFLAGS=-static make check
+        # s390x code path (64-bit)
+        - make clean
+        - CPPFLAGS=-DXXH_VECTOR=XXH_VSX CFLAGS="-O3 -march=arch11 -mzvector" LDFLAGS="-static" make check
+
+    - name: cmake build test
+      script:
+        - cd cmake_unofficial
+        - mkdir build
+        - cd build
+        - cmake ..
+        - CFLAGS=-Werror make
diff --git a/grpc/third_party/xxhash/BUILD b/grpc/third_party/xxhash/BUILD
new file mode 100644
index 0000000..91d7bd0
--- /dev/null
+++ b/grpc/third_party/xxhash/BUILD
@@ -0,0 +1,12 @@
+# TODO(donnadionne): describe this package.
+cc_library(
+    name = "xxhash",
+    hdrs = [
+        "xxhash.h",
+    ],
+    # Must specify the includes so that the header file can be found.
+    includes = [
+        "",
+    ],
+    visibility = ["//visibility:public"],
+)
diff --git a/grpc/third_party/xxhash/CHANGELOG b/grpc/third_party/xxhash/CHANGELOG
new file mode 100644
index 0000000..2387075
--- /dev/null
+++ b/grpc/third_party/xxhash/CHANGELOG
@@ -0,0 +1,52 @@
+v0.8.0
+- api : stabilize XXH3
+- cli : xxhsum can parse BSD-style --check lines, by @WayneD
+- cli : `xxhsum -` accepts console input, requested by @jaki
+- cli : xxhsum accepts -- separator, by @jaki
+- cli : fix : print correct default algo for symlinked helpers, by @martinetd
+- install: improved pkgconfig script, allowing custom install locations, requested by @ellert
+
+v0.7.4
+- perf: automatic vector detection and selection at runtime (`xxh_x86dispatch.h`), initiated by @easyaspi314
+- perf: added AVX512 support, by @gzm55
+- api : new: secret generator `XXH_generateSecret()`, suggested by @koraa
+- api : fix: XXH3_state_t is movable, identified by @koraa
+- api : fix: state is correctly aligned in AVX mode (unlike `malloc()`), by @easyaspi314
+- api : fix: streaming generated wrong values in some combination of random ingestion lengths, reported by @WayneD
+- cli : fix unicode print on Windows, by @easyaspi314
+- cli : can `-c` check file generated by sfv
+- build: `make DISPATCH=1` generates `xxhsum` and `libxxhash` with runtime vector detection (x86/x64 only)
+- install: cygwin installation support
+- doc : Cryptol specification of XXH32 and XXH64, by @weaversa
+
+v0.7.3
+- perf: improved speed for large inputs (~+20%)
+- perf: improved latency for small inputs (~10%)
+- perf: s390x Vectorial code, by @easyaspi314
+- cli: improved support for Unicode filenames on Windows, thanks to @easyaspi314 and @t-mat
+- api: `xxhash.h` can now be included in any order, with and without `XXH_STATIC_LINKING_ONLY` and `XXH_INLINE_ALL`
+- build: xxHash's implementation transferred into `xxhash.h`. No more need to have `xxhash.c` in the `/include` directory for `XXH_INLINE_ALL` to work
+- install: created pkg-config file, by @bket
+- install: VCpkg installation instructions, by @LilyWangL
+- doc: Highly improved code documentation, by @easyaspi314
+- misc: New test tool in `/tests/collisions`: brute force collision tester for 64-bit hashes
+
+v0.7.2
+- Fixed collision ratio of `XXH128` for some specific input lengths, reported by @svpv
+- Improved `VSX` and `NEON` variants, by @easyaspi314
+- Improved performance of scalar code path (`XXH_VECTOR=0`), by @easyaspi314
+- `xxhsum`: can generate 128-bit hashes with the `-H2` option (note: for experimental purposes only! `XXH128` is not yet frozen)
+- `xxhsum`: option `-q` removes status notifications
+
+v0.7.1
+- Secret first: the algorithm computation can be altered by providing a "secret", which is any blob of bytes, of size >= `XXH3_SECRET_SIZE_MIN`.
+- `seed` is still available, and acts as a secret generator
+- updated `ARM NEON` variant by @easyaspi314
+- Streaming implementation is available
+- Improve compatibility and performance with Visual Studio, with help from @aras-p
+- Better integration when using `XXH_INLINE_ALL`: do not pollute host namespace, use its own macros, such as `XXH_ASSERT()`, `XXH_ALIGN`, etc.
+- 128-bit variant provides helper functions for comparison of hashes.
+- Better `clang` generation of `rotl` instruction, thanks to @easyaspi314
+- `XXH_REROLL` build macro to reduce binary size, by @easyaspi314
+- Improved `cmake` script, by @Mezozoysky
+- Full benchmark program provided in `/tests/bench`
diff --git a/grpc/third_party/xxhash/Doxyfile b/grpc/third_party/xxhash/Doxyfile
new file mode 100644
index 0000000..634e1e1
--- /dev/null
+++ b/grpc/third_party/xxhash/Doxyfile
@@ -0,0 +1,58 @@
+# Doxygen config for xxHash
+DOXYFILE_ENCODING      = UTF-8
+
+PROJECT_NAME           = "xxHash"
+PROJECT_NUMBER         = "0.8.0"
+PROJECT_BRIEF          = "Extremely fast non-cryptographic hash function"
+OUTPUT_DIRECTORY       = doxygen
+OUTPUT_LANGUAGE        = English
+
+# We already separate the internal docs.
+INTERNAL_DOCS          = YES
+# Consistency
+SORT_MEMBER_DOCS       = NO
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+
+# Warnings
+QUIET                  = YES
+# Until we document everything
+WARN_IF_UNDOCUMENTED   = NO
+
+# TODO: Add the other files. It is just xxhash.h for now.
+FILE_PATTERNS          = xxhash.h xxh_x86dispatch.c
+# Note: xxHash's source files are technically ASCII only.
+INPUT_ENCODING         = UTF-8
+TAB_SIZE               = 4
+MARKDOWN_SUPPORT       = YES
+
+# xxHash is a C library
+OPTIMIZE_OUTPUT_FOR_C  = YES
+# So we can document the internals
+EXTRACT_STATIC         = YES
+# Document the macros
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = YES
+# Predefine some macros to clean up the output.
+PREDEFINED             = "XXH_DOXYGEN=" \
+                         "XXH_PUBLIC_API=" \
+                         "XXH_FORCE_INLINE=static inline" \
+                         "XXH_NO_INLINE=static" \
+                         "XXH_RESTRICT=restrict" \
+                         "XSUM_API=" \
+                         "XXH_STATIC_LINKING_ONLY" \
+                         "XXH_IMPLEMENTATION" \
+                         "XXH_ALIGN(N)=alignas(N)" \
+                         "XXH_ALIGN_MEMBER(align,type)=alignas(align) type"
+
+# We want HTML docs
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+# Tweak the colors a bit
+HTML_COLORSTYLE_HUE    = 220
+HTML_COLORSTYLE_GAMMA  = 100
+HTML_COLORSTYLE_SAT    = 100
+
+# We don't want LaTeX.
+GENERATE_LATEX         = NO
diff --git a/grpc/third_party/xxhash/LICENSE b/grpc/third_party/xxhash/LICENSE
new file mode 100644
index 0000000..fa20595
--- /dev/null
+++ b/grpc/third_party/xxhash/LICENSE
@@ -0,0 +1,48 @@
+xxHash Library
+Copyright (c) 2012-2020 Yann Collet
+All rights reserved.
+
+BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------
+
+xxhsum command line interface
+Copyright (c) 2013-2020 Yann Collet
+All rights reserved.
+
+GPL v2 License
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
diff --git a/grpc/third_party/xxhash/Makefile b/grpc/third_party/xxhash/Makefile
new file mode 100644
index 0000000..23cf4a8
--- /dev/null
+++ b/grpc/third_party/xxhash/Makefile
@@ -0,0 +1,506 @@
+# ################################################################
+# xxHash Makefile
+# Copyright (C) 2012-2020 Yann Collet
+#
+# GPL v2 License
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# You can contact the author at:
+#   - xxHash homepage: https://www.xxhash.com
+#   - xxHash source repository: https://github.com/Cyan4973/xxHash
+# ################################################################
+# xxhsum: provides 32/64 bits hash of one or multiple files, or stdin
+# ################################################################
+Q = $(if $(filter 1,$(V) $(VERBOSE)),,@)
+
+# Version numbers
+SED ?= sed
+SED_ERE_OPT ?= -E
+LIBVER_MAJOR_SCRIPT:=`$(SED) -n '/define XXH_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
+LIBVER_MINOR_SCRIPT:=`$(SED) -n '/define XXH_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
+LIBVER_PATCH_SCRIPT:=`$(SED) -n '/define XXH_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < xxhash.h`
+LIBVER_MAJOR := $(shell echo $(LIBVER_MAJOR_SCRIPT))
+LIBVER_MINOR := $(shell echo $(LIBVER_MINOR_SCRIPT))
+LIBVER_PATCH := $(shell echo $(LIBVER_PATCH_SCRIPT))
+LIBVER := $(LIBVER_MAJOR).$(LIBVER_MINOR).$(LIBVER_PATCH)
+
+CFLAGS ?= -O3
+DEBUGFLAGS+=-Wall -Wextra -Wconversion -Wcast-qual -Wcast-align -Wshadow \
+            -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
+            -Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \
+            -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
+            -Wredundant-decls -Wstrict-overflow=2
+CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
+FLAGS   = $(CFLAGS) $(CPPFLAGS)
+XXHSUM_VERSION = $(LIBVER)
+UNAME := $(shell uname)
+
+# Define *.exe as extension for Windows systems
+ifneq (,$(filter Windows%,$(OS)))
+EXT =.exe
+else
+EXT =
+endif
+
+# OS X linker doesn't support -soname, and use different extension
+# see: https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html
+ifeq ($(UNAME), Darwin)
+	SHARED_EXT = dylib
+	SHARED_EXT_MAJOR = $(LIBVER_MAJOR).$(SHARED_EXT)
+	SHARED_EXT_VER = $(LIBVER).$(SHARED_EXT)
+	SONAME_FLAGS = -install_name $(LIBDIR)/libxxhash.$(SHARED_EXT_MAJOR) -compatibility_version $(LIBVER_MAJOR) -current_version $(LIBVER)
+else
+	SONAME_FLAGS = -Wl,-soname=libxxhash.$(SHARED_EXT).$(LIBVER_MAJOR)
+	SHARED_EXT = so
+	SHARED_EXT_MAJOR = $(SHARED_EXT).$(LIBVER_MAJOR)
+	SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER)
+endif
+
+LIBXXH = libxxhash.$(SHARED_EXT_VER)
+
+XXHSUM_SRC_DIR = cli
+XXHSUM_SPLIT_SRCS = $(XXHSUM_SRC_DIR)/xsum_os_specific.c \
+                    $(XXHSUM_SRC_DIR)/xsum_output.c \
+                    $(XXHSUM_SRC_DIR)/xsum_sanity_check.c
+XXHSUM_SPLIT_OBJS = $(XXHSUM_SPLIT_SRCS:.c=.o)
+XXHSUM_HEADERS = $(XXHSUM_SRC_DIR)/xsum_config.h \
+                 $(XXHSUM_SRC_DIR)/xsum_arch.h \
+                 $(XXHSUM_SRC_DIR)/xsum_os_specific.h \
+                 $(XXHSUM_SRC_DIR)/xsum_output.h \
+                 $(XXHSUM_SRC_DIR)/xsum_sanity_check.h
+
+## generate CLI and libraries in release mode (default for `make`)
+.PHONY: default
+default: DEBUGFLAGS=
+default: lib xxhsum_and_links
+
+.PHONY: all
+all: lib xxhsum xxhsum_inlinedXXH
+
+## xxhsum is the command line interface (CLI)
+ifeq ($(DISPATCH),1)
+xxhsum: CPPFLAGS += -DXXHSUM_DISPATCH=1
+xxhsum: xxh_x86dispatch.o
+endif
+xxhsum: xxhash.o xxhsum.o $(XXHSUM_SPLIT_OBJS)
+	$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
+
+xxhsum32: CFLAGS += -m32  ## generate CLI in 32-bits mode
+xxhsum32: xxhash.c xxhsum.c $(XXHSUM_SPLIT_SRCS) ## do not generate object (avoid mixing different ABI)
+	$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
+
+## dispatch only works for x86/x64 systems
+dispatch: CPPFLAGS += -DXXHSUM_DISPATCH=1
+dispatch: xxhash.o xxh_x86dispatch.o xxhsum.c $(XXHSUM_SPLIT_SRCS)
+	$(CC) $(FLAGS) $^ $(LDFLAGS) -o $@$(EXT)
+
+xxhash.o: xxhash.c xxhash.h
+xxhsum.o: xxhsum.c $(XXHSUM_HEADERS) \
+    xxhash.h xxh_x86dispatch.h
+xxh_x86dispatch.o: xxh_x86dispatch.c xxh_x86dispatch.h xxhash.h
+
+.PHONY: xxhsum_and_links
+xxhsum_and_links: xxhsum xxh32sum xxh64sum xxh128sum
+
+xxh32sum xxh64sum xxh128sum: xxhsum
+	ln -sf $<$(EXT) $@$(EXT)
+
+xxhsum_inlinedXXH: CPPFLAGS += -DXXH_INLINE_ALL
+xxhsum_inlinedXXH: xxhsum.c $(XXHSUM_SPLIT_SRCS)
+	$(CC) $(FLAGS) $< -o $@$(EXT)
+
+
+# library
+
+libxxhash.a: ARFLAGS = rcs
+libxxhash.a: xxhash.o
+	$(AR) $(ARFLAGS) $@ $^
+
+$(LIBXXH): LDFLAGS += -shared
+ifeq (,$(filter Windows%,$(OS)))
+$(LIBXXH): CFLAGS += -fPIC
+endif
+ifeq ($(DISPATCH),1)
+$(LIBXXH): xxh_x86dispatch.c
+endif
+$(LIBXXH): xxhash.c
+	$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@
+	ln -sf $@ libxxhash.$(SHARED_EXT_MAJOR)
+	ln -sf $@ libxxhash.$(SHARED_EXT)
+
+.PHONY: libxxhash
+libxxhash:  ## generate dynamic xxhash library
+libxxhash: $(LIBXXH)
+
+.PHONY: lib
+lib:  ## generate static and dynamic xxhash libraries
+lib: libxxhash.a libxxhash
+
+# helper targets
+
+AWK = awk
+GREP = grep
+SORT = sort
+
+.PHONY: list
+list:  ## list all Makefile targets
+	$(Q)$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | $(AWK) -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | $(SORT) | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
+
+.PHONY: help
+help:  ## list documented targets
+	$(Q)$(GREP) -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
+	$(SORT) | \
+	$(AWK) 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+
+.PHONY: clean
+clean:  ## remove all build artifacts
+	$(Q)$(RM) -r *.dSYM   # Mac OS-X specific
+	$(Q)$(RM) core *.o *.obj *.$(SHARED_EXT) *.$(SHARED_EXT).* *.a libxxhash.pc
+	$(Q)$(RM) xxhsum$(EXT) xxhsum32$(EXT) xxhsum_inlinedXXH$(EXT) dispatch$(EXT)
+	$(Q)$(RM) xxh32sum$(EXT) xxh64sum$(EXT) xxh128sum$(EXT)
+	$(Q)$(RM) $(XXHSUM_SRC_DIR)/*.o $(XXHSUM_SRC_DIR)/*.obj
+	@echo cleaning completed
+
+
+# =================================================
+# tests
+# =================================================
+
+# make check can be run with cross-compiled binaries on emulated environments (qemu user mode)
+# by setting $(RUN_ENV) to the target emulation environment
+.PHONY: check
+check: xxhsum   ## basic tests for xxhsum CLI, set RUN_ENV for emulated environments
+	# stdin
+	$(RUN_ENV) ./xxhsum$(EXT) < xxhash.c
+	# multiple files
+	$(RUN_ENV) ./xxhsum$(EXT) xxhash.* xxhsum.*
+	# internal bench
+	$(RUN_ENV) ./xxhsum$(EXT) -bi0
+	# long bench command
+	$(RUN_ENV) ./xxhsum$(EXT) --benchmark-all -i0
+	# bench multiple variants
+	$(RUN_ENV) ./xxhsum$(EXT) -b1,2,3 -i0
+	# file bench
+	$(RUN_ENV) ./xxhsum$(EXT) -bi0 xxhash.c
+	# 32-bit
+	$(RUN_ENV) ./xxhsum$(EXT) -H0 xxhash.c
+	# 128-bit
+	$(RUN_ENV) ./xxhsum$(EXT) -H2 xxhash.c
+	# request incorrect variant
+	$(RUN_ENV) ./xxhsum$(EXT) -H9 xxhash.c ; test $$? -eq 1
+	@printf "\n .......   checks completed successfully   ....... \n"
+
+.PHONY: test-unicode
+test-unicode:
+	$(MAKE) -C tests test_unicode
+
+.PHONY: test-mem
+VALGRIND = valgrind --leak-check=yes --error-exitcode=1
+test-mem: RUN_ENV = $(VALGRIND)
+test-mem: xxhsum check
+
+.PHONY: test32
+test32: clean xxhsum32
+	@echo ---- test 32-bit ----
+	./xxhsum32 -bi1 xxhash.c
+
+.PHONY: test-xxhsum-c
+test-xxhsum-c: xxhsum
+	# xxhsum to/from pipe
+	./xxhsum xxh* | ./xxhsum -c -
+	./xxhsum -H0 xxh* | ./xxhsum -c -
+	# xxhsum -q does not display "Loading" message into stderr (#251)
+	! ./xxhsum -q xxh* 2>&1 | grep Loading
+	# xxhsum does not display "Loading" message into stderr either
+	! ./xxhsum xxh* 2>&1 | grep Loading
+	# Check that xxhsum do display filename that it failed to open.
+	LC_ALL=C ./xxhsum nonexistent 2>&1 | grep "Error: Could not open 'nonexistent'"
+	# xxhsum to/from file, shell redirection
+	./xxhsum xxh* > .test.xxh64
+	./xxhsum --tag xxh* > .test.xxh64_tag
+	./xxhsum --little-endian xxh* > .test.le_xxh64
+	./xxhsum --tag --little-endian xxh* > .test.le_xxh64_tag
+	./xxhsum -H0 xxh* > .test.xxh32
+	./xxhsum -H0 --tag xxh* > .test.xxh32_tag
+	./xxhsum -H0 --little-endian xxh* > .test.le_xxh32
+	./xxhsum -H0 --tag --little-endian xxh* > .test.le_xxh32_tag
+	./xxhsum -H2 xxh* > .test.xxh128
+	./xxhsum -H2 --tag xxh* > .test.xxh128_tag
+	./xxhsum -H2 --little-endian xxh* > .test.le_xxh128
+	./xxhsum -H2 --tag --little-endian xxh* > .test.le_xxh128_tag
+	./xxhsum -c .test.xxh*
+	./xxhsum -c --little-endian .test.le_xxh*
+	./xxhsum -c .test.*_tag
+	# read list of files from stdin
+	./xxhsum -c < .test.xxh64
+	./xxhsum -c < .test.xxh32
+	cat .test.xxh* | ./xxhsum -c -
+	# check variant with '*' marker as second separator
+	$(SED) 's/  / \*/' .test.xxh32 | ./xxhsum -c
+	# bsd-style output
+	./xxhsum --tag xxhsum* | $(GREP) XXH64
+	./xxhsum --tag -H0 xxhsum* | $(GREP) XXH32
+	./xxhsum --tag -H1 xxhsum* | $(GREP) XXH64
+	./xxhsum --tag -H2 xxhsum* | $(GREP) XXH128
+	./xxhsum --tag -H32 xxhsum* | $(GREP) XXH32
+	./xxhsum --tag -H64 xxhsum* | $(GREP) XXH64
+	./xxhsum --tag -H128 xxhsum* | $(GREP) XXH128
+	./xxhsum --tag -H0 --little-endian xxhsum* | $(GREP) XXH32_LE
+	./xxhsum --tag -H1 --little-endian xxhsum* | $(GREP) XXH64_LE
+	./xxhsum --tag -H2 --little-endian xxhsum* | $(GREP) XXH128_LE
+	./xxhsum --tag -H32 --little-endian xxhsum* | $(GREP) XXH32_LE
+	./xxhsum --tag -H64 --little-endian xxhsum* | $(GREP) XXH64_LE
+	./xxhsum --tag -H128 --little-endian xxhsum* | $(GREP) XXH128_LE
+	# check bsd-style
+	./xxhsum --tag xxhsum* | ./xxhsum -c
+	./xxhsum --tag -H32 --little-endian xxhsum* | ./xxhsum -c
+	# xxhsum -c warns improperly format lines.
+	echo '12345678 ' >>.test.xxh32
+	./xxhsum -c .test.xxh32 | $(GREP) improperly
+	echo '123456789  file' >>.test.xxh64
+	./xxhsum -c .test.xxh64 | $(GREP) improperly
+	# Expects "FAILED"
+	echo "0000000000000000  LICENSE" | ./xxhsum -c -; test $$? -eq 1
+	echo "00000000  LICENSE" | ./xxhsum -c -; test $$? -eq 1
+	# Expects "FAILED open or read"
+	echo "0000000000000000  test-expects-file-not-found" | ./xxhsum -c -; test $$? -eq 1
+	echo "00000000  test-expects-file-not-found" | ./xxhsum -c -; test $$? -eq 1
+	@$(RM) .test.*
+
+.PHONY: armtest
+armtest: clean
+	@echo ---- test ARM compilation ----
+	CC=arm-linux-gnueabi-gcc MOREFLAGS="-Werror -static" $(MAKE) xxhsum
+
+.PHONY: clangtest
+clangtest: clean
+	@echo ---- test clang compilation ----
+	CC=clang MOREFLAGS="-Werror -Wconversion -Wno-sign-conversion" $(MAKE) all
+
+.PHONY: cxxtest
+cxxtest: clean
+	@echo ---- test C++ compilation ----
+	CC="$(CXX) -Wno-deprecated" $(MAKE) all CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror -fPIC"
+
+.PHONY: c90test
+ifeq ($(NO_C90_TEST),true)
+c90test:
+	@echo no c90 compatibility test
+else
+c90test: CPPFLAGS += -DXXH_NO_LONG_LONG
+c90test: CFLAGS += -std=c90 -Werror -pedantic
+c90test: xxhash.c
+	@echo ---- test strict C90 compilation [xxh32 only] ----
+	$(RM) xxhash.o
+	$(CC) $(FLAGS) $^ $(LDFLAGS) -c
+	$(RM) xxhash.o
+endif
+
+.PHONY: usan
+usan: CC=clang
+usan: CXX=clang++
+usan:  ## check CLI runtime for undefined behavior, using clang's sanitizer
+	@echo ---- check undefined behavior - sanitize ----
+	$(MAKE) clean
+	$(MAKE) test CC=$(CC) CXX=$(CXX) MOREFLAGS="-g -fsanitize=undefined -fno-sanitize-recover=all"
+
+.PHONY: staticAnalyze
+SCANBUILD ?= scan-build
+staticAnalyze: clean  ## check C source files using $(SCANBUILD) static analyzer
+	@echo ---- static analyzer - $(SCANBUILD) ----
+	CFLAGS="-g -Werror" $(SCANBUILD) --status-bugs -v $(MAKE) all
+
+CPPCHECK ?= cppcheck
+.PHONY: cppcheck
+cppcheck:  ## check C source files using $(CPPCHECK) static analyzer
+	@echo ---- static analyzer - $(CPPCHECK) ----
+	$(CPPCHECK) . --force --enable=warning,portability,performance,style --error-exitcode=1 > /dev/null
+
+.PHONY: namespaceTest
+namespaceTest:  ## ensure XXH_NAMESPACE redefines all public symbols
+	$(CC) -c xxhash.c
+	$(CC) -DXXH_NAMESPACE=TEST_ -c xxhash.c -o xxhash2.o
+	$(CC) xxhash.o xxhash2.o xxhsum.c $(XXHSUM_SPLIT_SRCS)  -o xxhsum2  # will fail if one namespace missing (symbol collision)
+	$(RM) *.o xxhsum2  # clean
+
+MD2ROFF ?= ronn
+MD2ROFF_FLAGS ?= --roff --warnings --manual="User Commands" --organization="xxhsum $(XXHSUM_VERSION)"
+xxhsum.1: xxhsum.1.md xxhash.h
+	cat $< | $(MD2ROFF) $(MD2ROFF_FLAGS) | $(SED) -n '/^\.\\\".*/!p' > $@
+
+.PHONY: man
+man: xxhsum.1  ## generate man page from markdown source
+
+.PHONY: clean-man
+clean-man:
+	$(RM) xxhsum.1
+
+.PHONY: preview-man
+preview-man: man
+	man ./xxhsum.1
+
+.PHONY: test
+test: DEBUGFLAGS += -DXXH_DEBUGLEVEL=1
+test: all namespaceTest check test-xxhsum-c c90test test-tools
+
+.PHONY: test-inline
+test-inline:
+	$(MAKE) -C tests test_multiInclude
+
+.PHONY: test-all
+test-all: CFLAGS += -Werror
+test-all: test test32 clangtest cxxtest usan test-inline listL120 trailingWhitespace test-unicode
+
+.PHONY: test-tools
+test-tools:
+	CFLAGS=-Werror $(MAKE) -C tests/bench
+	CFLAGS=-Werror $(MAKE) -C tests/collisions
+
+.PHONY: listL120
+listL120:  # extract lines >= 120 characters in *.{c,h}, by Takayuki Matsuoka (note: $$, for Makefile compatibility)
+	find . -type f -name '*.c' -o -name '*.h' | while read -r filename; do awk 'length > 120 {print FILENAME "(" FNR "): " $$0}' $$filename; done
+
+.PHONY: trailingWhitespace
+trailingWhitespace:
+	! $(GREP) -E "`printf '[ \\t]$$'`" xxhsum.1 *.c *.h LICENSE Makefile cmake_unofficial/CMakeLists.txt
+
+
+# =========================================================
+# make install is validated only for the following targets
+# =========================================================
+ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU Haiku OpenBSD FreeBSD NetBSD DragonFly SunOS CYGWIN% , $(UNAME)))
+
+DESTDIR     ?=
+# directory variables: GNU conventions prefer lowercase
+# see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html
+# support both lower and uppercase (BSD), use uppercase in script
+prefix      ?= /usr/local
+PREFIX      ?= $(prefix)
+exec_prefix ?= $(PREFIX)
+EXEC_PREFIX ?= $(exec_prefix)
+libdir      ?= $(EXEC_PREFIX)/lib
+LIBDIR      ?= $(libdir)
+includedir  ?= $(PREFIX)/include
+INCLUDEDIR  ?= $(includedir)
+bindir      ?= $(EXEC_PREFIX)/bin
+BINDIR      ?= $(bindir)
+datarootdir ?= $(PREFIX)/share
+mandir      ?= $(datarootdir)/man
+man1dir     ?= $(mandir)/man1
+
+ifneq (,$(filter $(UNAME),FreeBSD NetBSD DragonFly))
+PKGCONFIGDIR ?= $(PREFIX)/libdata/pkgconfig
+else
+PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig
+endif
+
+ifneq (,$(filter $(UNAME),OpenBSD FreeBSD NetBSD DragonFly SunOS))
+MANDIR  ?= $(PREFIX)/man/man1
+else
+MANDIR  ?= $(man1dir)
+endif
+
+ifneq (,$(filter $(UNAME),SunOS))
+INSTALL ?= ginstall
+else
+INSTALL ?= install
+endif
+
+INSTALL_PROGRAM ?= $(INSTALL)
+INSTALL_DATA    ?= $(INSTALL) -m 644
+
+
+PCLIBDIR ?= $(shell echo "$(LIBDIR)"     | $(SED) -n $(SED_ERE_OPT) -e "s@^$(EXEC_PREFIX)(/|$$)@@p")
+PCINCDIR ?= $(shell echo "$(INCLUDEDIR)" | $(SED) -n $(SED_ERE_OPT) -e "s@^$(PREFIX)(/|$$)@@p")
+PCEXECDIR?= $(if $(filter $(PREFIX),$(EXEC_PREFIX)),$$\{prefix\},$(EXEC_PREFIX))
+
+ifeq (,$(PCLIBDIR))
+# Additional prefix check is required, since the empty string is technically a
+# valid PCLIBDIR
+ifeq (,$(shell echo "$(LIBDIR)" | $(SED) -n $(SED_ERE_OPT) -e "\\@^$(EXEC_PREFIX)(/|$$)@ p"))
+$(error configured libdir ($(LIBDIR)) is outside of exec_prefix ($(EXEC_PREFIX)), can't generate pkg-config file)
+endif
+endif
+
+ifeq (,$(PCINCDIR))
+# Additional prefix check is required, since the empty string is technically a
+# valid PCINCDIR
+ifeq (,$(shell echo "$(INCLUDEDIR)" | $(SED) -n $(SED_ERE_OPT) -e "\\@^$(PREFIX)(/|$$)@ p"))
+$(error configured includedir ($(INCLUDEDIR)) is outside of prefix ($(PREFIX)), can't generate pkg-config file)
+endif
+endif
+
+libxxhash.pc: libxxhash.pc.in
+	@echo creating pkgconfig
+	$(Q)$(SED) $(SED_ERE_OPT) -e 's|@PREFIX@|$(PREFIX)|' \
+          -e 's|@EXECPREFIX@|$(PCEXECDIR)|' \
+          -e 's|@LIBDIR@|$(PCLIBDIR)|' \
+          -e 's|@INCLUDEDIR@|$(PCINCDIR)|' \
+          -e 's|@VERSION@|$(LIBVER)|' \
+          $< > $@
+
+
+.PHONY: install
+install: lib libxxhash.pc xxhsum  ## install libraries, CLI, links and man page
+	@echo Installing libxxhash
+	$(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)
+	$(Q)$(INSTALL_DATA) libxxhash.a $(DESTDIR)$(LIBDIR)
+	$(Q)$(INSTALL_PROGRAM) $(LIBXXH) $(DESTDIR)$(LIBDIR)
+	$(Q)ln -sf $(LIBXXH) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT_MAJOR)
+	$(Q)ln -sf $(LIBXXH) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT)
+	$(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)   # includes
+	$(Q)$(INSTALL_DATA) xxhash.h $(DESTDIR)$(INCLUDEDIR)
+	$(Q)$(INSTALL_DATA) xxh3.h $(DESTDIR)$(INCLUDEDIR) # for compatibility, will be removed in v0.9.0
+ifeq ($(DISPATCH),1)
+	$(Q)$(INSTALL_DATA) xxh_x86dispatch.h $(DESTDIR)$(INCLUDEDIR)
+endif
+	@echo Installing pkgconfig
+	$(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR)/
+	$(Q)$(INSTALL_DATA) libxxhash.pc $(DESTDIR)$(PKGCONFIGDIR)/
+	@echo Installing xxhsum
+	$(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)/ $(DESTDIR)$(MANDIR)/
+	$(Q)$(INSTALL_PROGRAM) xxhsum $(DESTDIR)$(BINDIR)/xxhsum
+	$(Q)ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh32sum
+	$(Q)ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh64sum
+	$(Q)ln -sf xxhsum $(DESTDIR)$(BINDIR)/xxh128sum
+	@echo Installing man pages
+	$(Q)$(INSTALL_DATA) xxhsum.1 $(DESTDIR)$(MANDIR)/xxhsum.1
+	$(Q)ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh32sum.1
+	$(Q)ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh64sum.1
+	$(Q)ln -sf xxhsum.1 $(DESTDIR)$(MANDIR)/xxh128sum.1
+	@echo xxhash installation completed
+
+.PHONY: uninstall
+uninstall:  ## uninstall libraries, CLI, links and man page
+	$(Q)$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.a
+	$(Q)$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT)
+	$(Q)$(RM) $(DESTDIR)$(LIBDIR)/libxxhash.$(SHARED_EXT_MAJOR)
+	$(Q)$(RM) $(DESTDIR)$(LIBDIR)/$(LIBXXH)
+	$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/xxhash.h
+	$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/xxh3.h
+	$(Q)$(RM) $(DESTDIR)$(INCLUDEDIR)/xxh_x86dispatch.h
+	$(Q)$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libxxhash.pc
+	$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxh32sum
+	$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxh64sum
+	$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxh128sum
+	$(Q)$(RM) $(DESTDIR)$(BINDIR)/xxhsum
+	$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxh32sum.1
+	$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxh64sum.1
+	$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxh128sum.1
+	$(Q)$(RM) $(DESTDIR)$(MANDIR)/xxhsum.1
+	@echo xxhsum successfully uninstalled
+
+endif
diff --git a/grpc/third_party/xxhash/README.md b/grpc/third_party/xxhash/README.md
new file mode 100644
index 0000000..7d9ae9d
--- /dev/null
+++ b/grpc/third_party/xxhash/README.md
@@ -0,0 +1,235 @@
+
+xxHash - Extremely fast hash algorithm
+======================================
+
+xxHash is an Extremely fast Hash algorithm, running at RAM speed limits.
+It successfully completes the [SMHasher](https://code.google.com/p/smhasher/wiki/SMHasher) test suite
+which evaluates collision, dispersion and randomness qualities of hash functions.
+Code is highly portable, and hashes are identical across all platforms (little / big endian).
+
+|Branch      |Status   |
+|------------|---------|
+|dev         | [![Build Status](https://travis-ci.org/Cyan4973/xxHash.svg?branch=dev)](https://travis-ci.org/Cyan4973/xxHash?branch=dev) |
+
+
+Benchmarks
+-------------------------
+
+The reference system uses an Intel i7-9700K cpu, and runs Ubuntu x64 20.04.
+The [open source benchmark program] is compiled with `clang` v10.0 using `-O3` flag.
+
+| Hash Name     | Width | Bandwidth (GB/s) | Small Data Velocity | Quality | Comment |
+| ---------     | ----- | ---------------- | ----- | --- | --- |
+| __XXH3__ (SSE2) |  64 | 31.5 GB/s        | 133.1 | 10
+| __XXH128__ (SSE2) | 128 | 29.6 GB/s      | 118.1 | 10
+| _RAM sequential read_ | N/A | 28.0 GB/s  |   N/A | N/A | _for reference_
+| City64        |    64 | 22.0 GB/s        |  76.6 | 10
+| T1ha2         |    64 | 22.0 GB/s        |  99.0 |  9 | Slightly worse [collisions]
+| City128       |   128 | 21.7 GB/s        |  57.7 | 10
+| __XXH64__     |    64 | 19.4 GB/s        |  71.0 | 10
+| SpookyHash    |    64 | 19.3 GB/s        |  53.2 | 10
+| Mum           |    64 | 18.0 GB/s        |  67.0 |  9 | Slightly worse [collisions]
+| __XXH32__     |    32 |  9.7 GB/s        |  71.9 | 10
+| City32        |    32 |  9.1 GB/s        |  66.0 | 10
+| Murmur3       |    32 |  3.9 GB/s        |  56.1 | 10
+| SipHash       |    64 |  3.0 GB/s        |  43.2 | 10
+| FNV64         |    64 |  1.2 GB/s        |  62.7 |  5 | Poor avalanche properties
+| Blake2        |   256 |  1.1 GB/s        |   5.1 | 10 | Cryptographic
+| SHA1          |   160 |  0.8 GB/s        |   5.6 | 10 | Cryptographic but broken
+| MD5           |   128 |  0.6 GB/s        |   7.8 | 10 | Cryptographic but broken
+
+[open source benchmark program]: https://github.com/Cyan4973/xxHash/tree/release/tests/bench
+[collisions]: https://github.com/Cyan4973/xxHash/wiki/Collision-ratio-comparison#collision-study
+
+note 1: Small data velocity is a _rough_ evaluation of algorithm's efficiency on small data. For more detailed analysis, please refer to next paragraph.
+
+note 2: some algorithms feature _faster than RAM_ speed. In which case, they can only reach their full speed when input data is already in CPU cache (L3 or better). Otherwise, they max out on RAM speed limit.
+
+### Small data
+
+Performance on large data is only one part of the picture.
+Hashing is also very useful in constructions like hash tables and bloom filters.
+In these use cases, it's frequent to hash a lot of small data (starting at a few bytes).
+Algorithm's performance can be very different for such scenarios, since parts of the algorithm,
+such as initialization or finalization, become fixed cost.
+The impact of branch mis-prediction also becomes much more present.
+
+XXH3 has been designed for excellent performance on both long and small inputs,
+which can be observed in the following graph:
+
+![XXH3, latency, random size](https://user-images.githubusercontent.com/750081/61976089-aedeab00-af9f-11e9-9239-e5375d6c080f.png)
+
+For a more detailed analysis, visit the wiki :
+https://github.com/Cyan4973/xxHash/wiki/Performance-comparison#benchmarks-concentrating-on-small-data-
+
+Quality
+-------------------------
+
+Speed is not the only property that matters.
+Produced hash values must respect excellent dispersion and randomness properties,
+so that any sub-section of it can be used to maximally spread out a table or index,
+as well as reduce the amount of collisions to the minimal theoretical level, following the [birthday paradox].
+
+`xxHash` has been tested with Austin Appleby's excellent SMHasher test suite,
+and passes all tests, ensuring reasonable quality levels.
+It also passes extended tests from [newer forks of SMHasher], featuring additional scenarios and conditions.
+
+Finally, xxHash provides its own [massive collision tester](https://github.com/Cyan4973/xxHash/tree/dev/tests/collisions),
+able to generate and compare billions of hash to test the limits of 64-bit hash algorithms.
+On this front too, xxHash features good results, in line with the [birthday paradox].
+A more detailed analysis is documented [in the wiki](https://github.com/Cyan4973/xxHash/wiki/Collision-ratio-comparison).
+
+[birthday paradox]: https://en.wikipedia.org/wiki/Birthday_problem
+[newer forks of SMHasher]: https://github.com/rurban/smhasher
+
+
+### Build modifiers
+
+The following macros can be set at compilation time to modify libxxhash's behavior. They are generally disabled by default.
+
+- `XXH_INLINE_ALL`: Make all functions `inline`, with implementations being directly included within `xxhash.h`.
+                    Inlining functions is beneficial for speed on small keys.
+                    It's _extremely effective_ when key length is expressed as _a compile time constant_,
+                    with performance improvements observed in the +200% range .
+                    See [this article](https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html) for details.
+- `XXH_PRIVATE_API`: same outcome as `XXH_INLINE_ALL`. Still available for legacy support.
+                     The name underlines that `XXH_*` symbols will not be exported.
+- `XXH_NAMESPACE`: Prefixes all symbols with the value of `XXH_NAMESPACE`.
+                   This macro can only use compilable character set.
+                   Useful to evade symbol naming collisions,
+                   in case of multiple inclusions of xxHash's source code.
+                   Client applications still use the regular function names,
+                   as symbols are automatically translated through `xxhash.h`.
+- `XXH_FORCE_MEMORY_ACCESS`: The default method `0` uses a portable `memcpy()` notation.
+                             Method `1` uses a gcc-specific `packed` attribute, which can provide better performance for some targets.
+                             Method `2` forces unaligned reads, which is not standards compliant, but might sometimes be the only way to extract better read performance.
+                             Method `3` uses a byteshift operation, which is best for old compilers which don't inline `memcpy()` or big-endian systems without a byteswap instruction
+- `XXH_FORCE_ALIGN_CHECK`: Use a faster direct read path when input is aligned.
+                           This option can result in dramatic performance improvement when input to hash is aligned on 32 or 64-bit boundaries,
+                           when running on architectures unable to load memory from unaligned addresses, or suffering a performance penalty from it.
+                           It is (slightly) detrimental on platform with good unaligned memory access performance (same instruction for both aligned and unaligned accesses).
+                           This option is automatically disabled on `x86`, `x64` and `aarch64`, and enabled on all other platforms.
+- `XXH_VECTOR` : manually select a vector instruction set (default: auto-selected at compilation time). Available instruction sets are `XXH_SCALAR`, `XXH_SSE2`, `XXH_AVX2`, `XXH_AVX512`, `XXH_NEON` and `XXH_VSX`. Compiler may require additional flags to ensure proper support (for example, `gcc` on linux will require `-mavx2` for AVX2, and `-mavx512f` for AVX512).
+- `XXH_NO_PREFETCH` : disable prefetching. XXH3 only.
+- `XXH_PREFETCH_DIST` : select prefecting distance. XXH3 only.
+- `XXH_NO_INLINE_HINTS`: By default, xxHash uses `__attribute__((always_inline))` and `__forceinline` to improve performance at the cost of code size.
+                         Defining this macro to 1 will mark all internal functions as `static`, allowing the compiler to decide whether to inline a function or not.
+                         This is very useful when optimizing for smallest binary size,
+                         and is automatically defined when compiling with `-O0`, `-Os`, `-Oz`, or `-fno-inline` on GCC and Clang.
+                         This may also increase performance depending on compiler and architecture.
+- `XXH_REROLL`: Reduces the size of the generated code by not unrolling some loops.
+                Impact on performance may vary, depending on platform and algorithm.
+- `XXH_ACCEPT_NULL_INPUT_POINTER`: if set to `1`, when input is a `NULL` pointer,
+                                   xxHash'd result is the same as a zero-length input
+                                   (instead of a dereference segfault).
+                                   Adds one branch at the beginning of each hash.
+- `XXH_STATIC_LINKING_ONLY`: gives access to the state declaration for static allocation.
+                             Incompatible with dynamic linking, due to risks of ABI changes.
+- `XXH_NO_LONG_LONG`: removes compilation of algorithms relying on 64-bit types (XXH3 and XXH64). Only XXH32 will be compiled.
+                      Useful for targets (architectures and compilers) without 64-bit support.
+- `XXH_IMPORT`: MSVC specific: should only be defined for dynamic linking, as it prevents linkage errors.
+- `XXH_CPU_LITTLE_ENDIAN`: By default, endianess is determined by a runtime test resolved at compile time.
+                           If, for some reason, the compiler cannot simplify the runtime test, it can cost performance.
+                           It's possible to skip auto-detection and simply state that the architecture is little-endian by setting this macro to 1.
+                           Setting it to 0 states big-endian.
+
+For the Command Line Interface `xxhsum`, the following environment variables can also be set :
+- `DISPATCH=1` : use `xxh_x86dispatch.c`, to automatically select between `scalar`, `sse2`, `avx2` or `avx512` instruction set at runtime, depending on local host. This option is only valid for `x86`/`x64` systems.
+
+
+### Building xxHash - Using vcpkg
+
+You can download and install xxHash using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
+
+    git clone https://github.com/Microsoft/vcpkg.git
+    cd vcpkg
+    ./bootstrap-vcpkg.sh
+    ./vcpkg integrate install
+    ./vcpkg install xxhash
+
+The xxHash port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
+
+
+### Example
+
+The simplest example calls xxhash 64-bit variant as a one-shot function
+generating a hash value from a single buffer, and invoked from a C/C++ program:
+
+```C
+#include "xxhash.h"
+
+    (...)
+    XXH64_hash_t hash = XXH64(buffer, size, seed);
+}
+```
+
+Streaming variant is more involved, but makes it possible to provide data incrementally:
+
+```C
+#include "stdlib.h"   /* abort() */
+#include "xxhash.h"
+
+
+XXH64_hash_t calcul_hash_streaming(FileHandler fh)
+{
+    /* create a hash state */
+    XXH64_state_t* const state = XXH64_createState();
+    if (state==NULL) abort();
+
+    size_t const bufferSize = SOME_SIZE;
+    void* const buffer = malloc(bufferSize);
+    if (buffer==NULL) abort();
+
+    /* Initialize state with selected seed */
+    XXH64_hash_t const seed = 0;   /* or any other value */
+    if (XXH64_reset(state, seed) == XXH_ERROR) abort();
+
+    /* Feed the state with input data, any size, any number of times */
+    (...)
+    while ( /* some data left */ ) {
+        size_t const length = get_more_data(buffer, bufferSize, fh);
+        if (XXH64_update(state, buffer, length) == XXH_ERROR) abort();
+        (...)
+    }
+    (...)
+
+    /* Produce the final hash value */
+    XXH64_hash_t const hash = XXH64_digest(state);
+
+    /* State could be re-used; but in this example, it is simply freed  */
+    free(buffer);
+    XXH64_freeState(state);
+
+    return hash;
+}
+```
+
+
+### License
+
+The library files `xxhash.c` and `xxhash.h` are BSD licensed.
+The utility `xxhsum` is GPL licensed.
+
+
+### Other programming languages
+
+Beyond the C reference version,
+xxHash is also available from many different programming languages,
+thanks to great contributors.
+They are [listed here](http://www.xxhash.com/#other-languages).
+
+
+### Packaging status
+
+Many distributions bundle a package manager
+which allows easy xxhash installation as both a `libxxhash` library
+and `xxhsum` command line interface.
+
+[![Packaging status](https://repology.org/badge/vertical-allrepos/xxhash.svg)](https://repology.org/project/xxhash/versions)
+
+
+### Special Thanks
+
+- Takayuki Matsuoka, aka @t-mat, for creating `xxhsum -c` and great support during early xxh releases
+- Mathias Westerdahl, aka @JCash, for introducing the first version of `XXH64`
+- Devin Hussey, aka @easyaspi314, for incredible low-level optimizations on `XXH3` and `XXH128`
diff --git a/grpc/third_party/xxhash/appveyor.yml b/grpc/third_party/xxhash/appveyor.yml
new file mode 100644
index 0000000..850f48b
--- /dev/null
+++ b/grpc/third_party/xxhash/appveyor.yml
@@ -0,0 +1,111 @@
+#---------------------------------#
+#      general configuration      #
+#---------------------------------#
+version: 1.0.{build}
+max_jobs: 2
+
+#---------------------------------#
+#    environment configuration    #
+#---------------------------------#
+clone_depth: 2
+environment:
+  matrix:
+  - COMPILER: "visual"
+    ARCH: "x64"
+    TEST_XXHSUM: "true"
+  - COMPILER: "visual"
+    ARCH: "x64"
+    APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+    TEST_XXHSUM: "true"
+  - COMPILER: "visual"
+    ARCH: "Win32"
+    TEST_XXHSUM: "true"
+  - COMPILER: "visual"
+    ARCH: "Win32"
+    APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+    TEST_XXHSUM: "true"
+  - COMPILER: "visual"
+    ARCH: "ARM"
+  - COMPILER: "visual"
+    ARCH: "ARM64"
+    APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+    # note: ARM64 is not available with Visual Studio 14 2015, which is default for Appveyor
+  - COMPILER: "gcc"
+    PLATFORM: "mingw64"
+  - COMPILER: "gcc"
+    PLATFORM: "mingw32"
+  - COMPILER: "gcc"
+    PLATFORM: "clang"
+
+install:
+  - ECHO Installing %COMPILER% %PLATFORM% %ARCH%
+  - MKDIR bin
+  - if [%COMPILER%]==[gcc] SET PATH_ORIGINAL=%PATH%
+  - if [%COMPILER%]==[gcc] (
+      SET "PATH_MINGW32=c:\MinGW\bin;c:\MinGW\usr\bin" &&
+      SET "PATH_MINGW64=c:\msys64\mingw64\bin;c:\msys64\usr\bin" &&
+      COPY C:\MinGW\bin\mingw32-make.exe C:\MinGW\bin\make.exe &&
+      COPY C:\MinGW\bin\gcc.exe C:\MinGW\bin\cc.exe
+    )
+
+#---------------------------------#
+#       build configuration       #
+#---------------------------------#
+build_script:
+  - if [%PLATFORM%]==[mingw32] SET PATH=%PATH_MINGW32%;%PATH_ORIGINAL%
+  - if [%PLATFORM%]==[mingw64] SET PATH=%PATH_MINGW64%;%PATH_ORIGINAL%
+  - if [%PLATFORM%]==[clang]   SET PATH=%PATH_MINGW64%;%PATH_ORIGINAL%
+  - ECHO ***
+  - ECHO Building %COMPILER% %PLATFORM% %ARCH%
+  - ECHO ***
+
+  - if [%COMPILER%]==[gcc] (
+      if [%PLATFORM%]==[clang] (
+        clang -v
+      ) ELSE (
+        gcc -v
+      )
+    )
+  - if [%COMPILER%]==[gcc] (
+      echo ----- &&
+      make -v &&
+      echo ----- &&
+      if not [%PLATFORM%]==[clang] (
+        if [%PLATFORM%]==[mingw32] ( SET CPPFLAGS=-DPOOL_MT=0 ) &&
+        make -B clean test MOREFLAGS=-Werror
+      ) ELSE (
+        SET CXXFLAGS=--std=c++14 &&
+        make -B clean test CC=clang CXX=clang++ MOREFLAGS="--target=x86_64-w64-mingw32 -Werror -Wno-pass-failed" NO_C90_TEST=true
+      ) &&
+      make -C tests/bench
+    )
+    # note 1: strict c90 tests with clang fail, due to (erroneous) presence on `inline` keyword in some included system file
+    # note 2: multi-threading code doesn't work with mingw32, disabled through POOL_MT=0
+    # note 3: clang requires C++14 to compile sort because its own code contains c++14-only code
+
+  - if [%COMPILER%]==[visual] (
+      cd cmake_unofficial &&
+      cmake . -DCMAKE_BUILD_TYPE=Release -A %ARCH% -DXXHASH_C_FLAGS="/WX" &&
+      cmake --build . --config Release
+    )
+
+#---------------------------------#
+#       tests configuration       #
+#---------------------------------#
+test_script:
+  # note: can only run x86 and x64 binaries on Appveyor
+  # note: if %COMPILER%==gcc, xxhsum was already tested within `make test`
+  - if [%TEST_XXHSUM%]==[true] (
+      ECHO ***  &&
+      ECHO Testing %COMPILER% %PLATFORM% %ARCH%  &&
+      ECHO ***  &&
+      cd Release &&
+      xxhsum.exe -bi1 &&
+      ECHO ------- xxhsum tested -------
+    )
+
+
+#---------------------------------#
+#      artifacts configuration    #
+#---------------------------------#
+# none yet
diff --git a/grpc/third_party/xxhash/cli/xsum_arch.h b/grpc/third_party/xxhash/cli/xsum_arch.h
new file mode 100644
index 0000000..cc39297
--- /dev/null
+++ b/grpc/third_party/xxhash/cli/xsum_arch.h
@@ -0,0 +1,153 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+/*
+ * Checks for predefined macros by the compiler to try and get both the arch
+ * and the compiler version.
+ */
+#ifndef XSUM_ARCH_H
+#define XSUM_ARCH_H
+
+#include "xsum_config.h"
+
+#define XSUM_LIB_VERSION XXH_VERSION_MAJOR.XXH_VERSION_MINOR.XXH_VERSION_RELEASE
+#define XSUM_QUOTE(str) #str
+#define XSUM_EXPAND_AND_QUOTE(str) XSUM_QUOTE(str)
+#define XSUM_PROGRAM_VERSION XSUM_EXPAND_AND_QUOTE(XSUM_LIB_VERSION)
+
+
+/* Show compiler versions in WELCOME_MESSAGE. XSUM_CC_VERSION_FMT will return the printf specifiers,
+ * and VERSION will contain the comma separated list of arguments to the XSUM_CC_VERSION_FMT string. */
+#if defined(__clang_version__)
+/* Clang does its own thing. */
+#  ifdef __apple_build_version__
+#    define XSUM_CC_VERSION_FMT "Apple Clang %s"
+#  else
+#    define XSUM_CC_VERSION_FMT "Clang %s"
+#  endif
+#  define XSUM_CC_VERSION  __clang_version__
+#elif defined(__VERSION__)
+/* GCC and ICC */
+#  define XSUM_CC_VERSION_FMT "%s"
+#  ifdef __INTEL_COMPILER /* icc adds its prefix */
+#    define XSUM_CC_VERSION __VERSION__
+#  else /* assume GCC */
+#    define XSUM_CC_VERSION "GCC " __VERSION__
+#  endif
+#elif defined(_MSC_FULL_VER) && defined(_MSC_BUILD)
+/*
+ * MSVC
+ *  "For example, if the version number of the Visual C++ compiler is
+ *   15.00.20706.01, the _MSC_FULL_VER macro evaluates to 150020706."
+ *
+ *   https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017
+ */
+#  define XSUM_CC_VERSION_FMT "MSVC %02i.%02i.%05i.%02i"
+#  define XSUM_CC_VERSION  _MSC_FULL_VER / 10000000 % 100, _MSC_FULL_VER / 100000 % 100, _MSC_FULL_VER % 100000, _MSC_BUILD
+#elif defined(_MSC_VER) /* old MSVC */
+#  define XSUM_CC_VERSION_FMT "MSVC %02i.%02i"
+#  define XSUM_CC_VERSION _MSC_VER / 100, _MSC_VER % 100
+#elif defined(__TINYC__)
+/* tcc stores its version in the __TINYC__ macro. */
+#  define XSUM_CC_VERSION_FMT "tcc %i.%i.%i"
+#  define XSUM_CC_VERSION __TINYC__ / 10000 % 100, __TINYC__ / 100 % 100, __TINYC__ % 100
+#else
+#  define XSUM_CC_VERSION_FMT "%s"
+#  define XSUM_CC_VERSION "unknown compiler"
+#endif
+
+/* makes the next part easier */
+#if defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
+#   define XSUM_ARCH_X64 1
+#   define XSUM_ARCH_X86 "x86_64"
+#elif defined(__i386__) || defined(_M_IX86) || defined(_M_IX86_FP)
+#   define XSUM_ARCH_X86 "i386"
+#endif
+
+/* Try to detect the architecture. */
+#if defined(XSUM_ARCH_X86)
+#  if defined(XXHSUM_DISPATCH)
+#    define XSUM_ARCH XSUM_ARCH_X86 " autoVec"
+#  elif defined(__AVX512F__)
+#    define XSUM_ARCH XSUM_ARCH_X86 " + AVX512"
+#  elif defined(__AVX2__)
+#    define XSUM_ARCH XSUM_ARCH_X86 " + AVX2"
+#  elif defined(__AVX__)
+#    define XSUM_ARCH XSUM_ARCH_X86 " + AVX"
+#  elif defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) \
+      || defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP == 2)
+#     define XSUM_ARCH XSUM_ARCH_X86 " + SSE2"
+#  else
+#     define XSUM_ARCH XSUM_ARCH_X86
+#  endif
+#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
+#  define XSUM_ARCH "aarch64 + NEON"
+#elif defined(__arm__) || defined(__thumb__) || defined(__thumb2__) || defined(_M_ARM)
+/* ARM has a lot of different features that can change xxHash significantly. */
+#  if defined(__thumb2__) || (defined(__thumb__) && (__thumb__ == 2 || __ARM_ARCH >= 7))
+#    define XSUM_ARCH_THUMB " Thumb-2"
+#  elif defined(__thumb__)
+#    define XSUM_ARCH_THUMB " Thumb-1"
+#  else
+#    define XSUM_ARCH_THUMB ""
+#  endif
+/* ARMv7 has unaligned by default */
+#  if defined(__ARM_FEATURE_UNALIGNED) || __ARM_ARCH >= 7 || defined(_M_ARMV7VE)
+#    define XSUM_ARCH_UNALIGNED " + unaligned"
+#  else
+#    define XSUM_ARCH_UNALIGNED ""
+#  endif
+#  if defined(__ARM_NEON) || defined(__ARM_NEON__)
+#    define XSUM_ARCH_NEON " + NEON"
+#  else
+#    define XSUM_ARCH_NEON ""
+#  endif
+#  define XSUM_ARCH "ARMv" XSUM_EXPAND_AND_QUOTE(__ARM_ARCH) XSUM_ARCH_THUMB XSUM_ARCH_NEON XSUM_ARCH_UNALIGNED
+#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
+#  if defined(__GNUC__) && defined(__POWER9_VECTOR__)
+#    define XSUM_ARCH "ppc64 + POWER9 vector"
+#  elif defined(__GNUC__) && defined(__POWER8_VECTOR__)
+#    define XSUM_ARCH "ppc64 + POWER8 vector"
+#  else
+#    define XSUM_ARCH "ppc64"
+#  endif
+#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)
+#  define XSUM_ARCH "ppc"
+#elif defined(__AVR)
+#  define XSUM_ARCH "AVR"
+#elif defined(__mips64)
+#  define XSUM_ARCH "mips64"
+#elif defined(__mips)
+#  define XSUM_ARCH "mips"
+#elif defined(__s390x__)
+#  define XSUM_ARCH "s390x"
+#elif defined(__s390__)
+#  define XSUM_ARCH "s390"
+#else
+#  define XSUM_ARCH "unknown"
+#endif
+
+
+#endif /* XSUM_ARCH_H */
diff --git a/grpc/third_party/xxhash/cli/xsum_config.h b/grpc/third_party/xxhash/cli/xsum_config.h
new file mode 100644
index 0000000..9222144
--- /dev/null
+++ b/grpc/third_party/xxhash/cli/xsum_config.h
@@ -0,0 +1,205 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+/*
+ * This contains various configuration parameters and feature detection for
+ * xxhsum.
+ *
+ * Similar to config.h in Autotools, this should be the first header included.
+ */
+
+#ifndef XSUM_CONFIG_H
+#define XSUM_CONFIG_H
+
+
+/* ************************************
+ *  Compiler Options
+ **************************************/
+/*
+ * Disable Visual C's warnings when using the "insecure" CRT functions instead
+ * of the "secure" _s functions.
+ *
+ * These functions are not portable, and aren't necessary if you are using the
+ * original functions properly.
+ */
+#if defined(_MSC_VER) || defined(_WIN32)
+#  ifndef _CRT_SECURE_NO_WARNINGS
+#    define _CRT_SECURE_NO_WARNINGS
+#  endif
+#endif
+
+/* Under Linux at least, pull in the *64 commands */
+#ifndef _LARGEFILE64_SOURCE
+#  define _LARGEFILE64_SOURCE
+#endif
+#ifndef _FILE_OFFSET_BITS
+#  define _FILE_OFFSET_BITS 64
+#endif
+
+/*
+ * So we can use __attribute__((__format__))
+ */
+#ifdef __GNUC__
+#  define XSUM_ATTRIBUTE(x) __attribute__(x)
+#else
+#  define XSUM_ATTRIBUTE(x)
+#endif
+
+#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) /* UNIX-like OS */ \
+   || defined(__midipix__) || defined(__VMS))
+#  if (defined(__APPLE__) && defined(__MACH__)) || defined(__SVR4) || defined(_AIX) || defined(__hpux) /* POSIX.1-2001 (SUSv3) conformant */ \
+     || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)  /* BSD distros */
+#    define XSUM_PLATFORM_POSIX_VERSION 200112L
+#  else
+#    if defined(__linux__) || defined(__linux)
+#      ifndef _POSIX_C_SOURCE
+#        define _POSIX_C_SOURCE 200112L  /* use feature test macro */
+#      endif
+#    endif
+#    include <unistd.h>  /* declares _POSIX_VERSION */
+#    if defined(_POSIX_VERSION)  /* POSIX compliant */
+#      define XSUM_PLATFORM_POSIX_VERSION _POSIX_VERSION
+#    else
+#      define XSUM_PLATFORM_POSIX_VERSION 0
+#    endif
+#  endif
+#endif
+#if !defined(XSUM_PLATFORM_POSIX_VERSION)
+#  define XSUM_PLATFORM_POSIX_VERSION -1
+#endif
+
+#if !defined(S_ISREG)
+#  define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
+#endif
+
+
+/* ************************************
+ * Windows helpers
+ **************************************/
+
+/*
+ * Whether to use the Windows UTF-16 APIs instead of the portable libc 8-bit
+ * ("ANSI") APIs.
+ *
+ * Windows is not UTF-8 clean by default, and the only way to access every file
+ * on the OS is to use UTF-16.
+ *
+ * Do note that xxhsum uses UTF-8 internally and only uses UTF-16 for command
+ * line arguments, console I/O, and opening files.
+ *
+ * Additionally, this guarantees all piped output is UTF-8.
+ */
+#if defined(XSUM_WIN32_USE_WCHAR) && !defined(_WIN32)
+/* We use Windows APIs, only use this on Windows. */
+#  undef XSUM_WIN32_USE_WCHAR
+#endif
+
+#ifndef XSUM_WIN32_USE_WCHAR
+#  if defined(_WIN32)
+#    include <wchar.h>
+#    if WCHAR_MAX == 0xFFFFU /* UTF-16 wchar_t */
+#       define XSUM_WIN32_USE_WCHAR 1
+#    else
+#       define XSUM_WIN32_USE_WCHAR 0
+#    endif
+#  else
+#    define XSUM_WIN32_USE_WCHAR 0
+#  endif
+#endif
+
+#if !XSUM_WIN32_USE_WCHAR
+/*
+ * It doesn't make sense to have one without the other.
+ * Due to XSUM_WIN32_USE_WCHAR being undef'd, this also handles
+ * non-WIN32 platforms.
+ */
+#  undef  XSUM_WIN32_USE_WMAIN
+#  define XSUM_WIN32_USE_WMAIN 0
+#else
+/*
+ * Whether to use wmain() or main().
+ *
+ * wmain() is preferred because we don't have to mess with internal hidden
+ * APIs.
+ *
+ * It always works on MSVC, but in MinGW, it only works on MinGW-w64 with the
+ * -municode flag.
+ *
+ * Therefore we have to use main() -- there is no better option.
+ */
+#  ifndef XSUM_WIN32_USE_WMAIN
+#    if defined(_UNICODE) || defined(UNICODE) /* MinGW -municode */ \
+        || defined(_MSC_VER) /* MSVC */
+#      define XSUM_WIN32_USE_WMAIN 1
+#    else
+#      define XSUM_WIN32_USE_WMAIN 0
+#    endif
+#  endif
+/*
+ * It is always good practice to define these to prevent accidental use of the
+ * ANSI APIs, even if the program primarily uses UTF-8.
+ */
+#  ifndef _UNICODE
+#    define _UNICODE
+#  endif
+#  ifndef UNICODE
+#    define UNICODE
+#  endif
+#endif /* XSUM_WIN32_USE_WCHAR */
+
+#ifndef XSUM_API
+#  ifdef XXH_INLINE_ALL
+#    define XSUM_API static
+#  else
+#    define XSUM_API
+#  endif
+#endif
+
+#ifndef XSUM_NO_TESTS
+#  define XSUM_NO_TESTS 0
+#endif
+
+/* ***************************
+ * Basic types
+ * ***************************/
+
+#if defined(__cplusplus) /* C++ */ \
+ || (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)  /* C99 */
+#  include <stdint.h>
+    typedef uint8_t  XSUM_U8;
+    typedef uint32_t XSUM_U32;
+    typedef uint64_t XSUM_U64;
+# else
+#   include <limits.h>
+    typedef unsigned char      XSUM_U8;
+#   if UINT_MAX == 0xFFFFFFFFUL
+      typedef unsigned int     XSUM_U32;
+#   else
+      typedef unsigned long    XSUM_U32;
+#   endif
+    typedef unsigned long long XSUM_U64;
+#endif /* not C++/C99 */
+
+#endif /* XSUM_CONFIG_H */
diff --git a/grpc/third_party/xxhash/cli/xsum_os_specific.c b/grpc/third_party/xxhash/cli/xsum_os_specific.c
new file mode 100644
index 0000000..8f48ce0
--- /dev/null
+++ b/grpc/third_party/xxhash/cli/xsum_os_specific.c
@@ -0,0 +1,487 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#include "xsum_config.h"
+#include "xsum_os_specific.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>  /* struct stat / __wstat64 */
+#include <sys/stat.h>   /* stat() / _stat64() */
+
+/*
+ * This file contains all of the ugly boilerplate to make xxhsum work across
+ * platforms.
+ */
+#if defined(_MSC_VER) || XSUM_WIN32_USE_WCHAR
+    typedef struct __stat64 XSUM_stat_t;
+# if defined(_MSC_VER)
+    typedef int mode_t;
+# endif
+#else
+    typedef struct stat XSUM_stat_t;
+#endif
+
+#if (defined(__linux__) && (XSUM_PLATFORM_POSIX_VERSION >= 1)) \
+ || (XSUM_PLATFORM_POSIX_VERSION >= 200112L) \
+ || defined(__DJGPP__) \
+ || defined(__MSYS__)
+#  include <unistd.h>   /* isatty */
+#  define XSUM_IS_CONSOLE(stdStream) isatty(fileno(stdStream))
+#elif defined(MSDOS) || defined(OS2)
+#  include <io.h>       /* _isatty */
+#  define XSUM_IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
+#elif defined(WIN32) || defined(_WIN32)
+#  include <io.h>      /* _isatty */
+#  include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */
+#  include <stdio.h>   /* FILE */
+static __inline int XSUM_IS_CONSOLE(FILE* stdStream)
+{
+    DWORD dummy;
+    return _isatty(_fileno(stdStream)) && GetConsoleMode((HANDLE)_get_osfhandle(_fileno(stdStream)), &dummy);
+}
+#else
+#  define XSUM_IS_CONSOLE(stdStream) 0
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32)
+#  include <fcntl.h>   /* _O_BINARY */
+#  include <io.h>      /* _setmode, _fileno, _get_osfhandle */
+#  if !defined(__DJGPP__)
+#    include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */
+#    include <winioctl.h> /* FSCTL_SET_SPARSE */
+#    define XSUM_SET_BINARY_MODE(file) { int const unused=_setmode(_fileno(file), _O_BINARY); (void)unused; }
+#  else
+#    define XSUM_SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#  endif
+#else
+#  define XSUM_SET_BINARY_MODE(file) ((void)file)
+#endif
+
+XSUM_API int XSUM_isConsole(FILE* stream)
+{
+    return XSUM_IS_CONSOLE(stream);
+}
+
+XSUM_API void XSUM_setBinaryMode(FILE* stream)
+{
+    XSUM_SET_BINARY_MODE(stream);
+}
+
+#if !XSUM_WIN32_USE_WCHAR
+
+XSUM_API FILE* XSUM_fopen(const char* filename, const char* mode)
+{
+    return fopen(filename, mode);
+}
+XSUM_ATTRIBUTE((__format__(__printf__, 2, 0)))
+XSUM_API int XSUM_vfprintf(FILE* stream, const char* format, va_list ap)
+{
+    return vfprintf(stream, format, ap);
+}
+
+static int XSUM_stat(const char* infilename, XSUM_stat_t* statbuf)
+{
+#if defined(_MSC_VER)
+    return _stat64(infilename, statbuf);
+#else
+    return stat(infilename, statbuf);
+#endif
+}
+
+#ifndef XSUM_NO_MAIN
+int main(int argc, char* argv[])
+{
+    return XSUM_main(argc, argv);
+}
+#endif
+
+/* Unicode helpers for Windows to make UTF-8 act as it should. */
+#else
+#  include <windows.h>
+#  include <wchar.h>
+
+/*****************************************************************************
+ *                       Unicode conversion tools
+ *****************************************************************************/
+
+/*
+ * Converts a UTF-8 string to UTF-16. Acts like strdup. The string must be freed afterwards.
+ * This version allows keeping the output length.
+ */
+static wchar_t* XSUM_widenString(const char* str, int* lenOut)
+{
+    int const len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+    if (lenOut != NULL) *lenOut = len;
+    if (len == 0) return NULL;
+    {   wchar_t* buf = (wchar_t*)malloc((size_t)len * sizeof(wchar_t));
+        if (buf != NULL) {
+            if (MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len) == 0) {
+                free(buf);
+                return NULL;
+       }    }
+       return buf;
+    }
+}
+
+/*
+ * Converts a UTF-16 string to UTF-8. Acts like strdup. The string must be freed afterwards.
+ * This version allows keeping the output length.
+ */
+static char* XSUM_narrowString(const wchar_t *str, int *lenOut)
+{
+    int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
+    if (lenOut != NULL) *lenOut = len;
+    if (len == 0) return NULL;
+    {   char* const buf = (char*)malloc((size_t)len * sizeof(char));
+        if (buf != NULL) {
+            if (WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL) == 0) {
+                free(buf);
+                return NULL;
+        }    }
+        return buf;
+    }
+}
+
+
+
+/*****************************************************************************
+ *                             File helpers
+ *****************************************************************************/
+/*
+ * fopen wrapper that supports UTF-8
+ *
+ * fopen will only accept ANSI filenames, which means that we can't open Unicode filenames.
+ *
+ * In order to open a Unicode filename, we need to convert filenames to UTF-16 and use _wfopen.
+ */
+XSUM_API FILE* XSUM_fopen(const char* filename, const char* mode)
+{
+    FILE* f = NULL;
+    wchar_t* const wide_filename = XSUM_widenString(filename, NULL);
+    if (wide_filename != NULL) {
+        wchar_t* const wide_mode = XSUM_widenString(mode, NULL);
+        if (wide_mode != NULL) {
+            f = _wfopen(wide_filename, wide_mode);
+            free(wide_mode);
+        }
+        free(wide_filename);
+    }
+    return f;
+}
+
+/*
+ * stat() wrapper which supports UTF-8 filenames.
+ */
+static int XSUM_stat(const char* infilename, XSUM_stat_t* statbuf)
+{
+    int r = -1;
+    wchar_t* const wide_filename = XSUM_widenString(infilename, NULL);
+    if (wide_filename != NULL) {
+        r = _wstat64(wide_filename, statbuf);
+        free(wide_filename);
+    }
+    return r;
+}
+
+/*
+ * In case it isn't available, this is what MSVC 2019 defines in stdarg.h.
+ */
+#if defined(_MSC_VER) && !defined(__clang__) && !defined(va_copy)
+#  define XSUM_va_copy(destination, source) ((destination) = (source))
+#else
+#  define XSUM_va_copy(destination, source) va_copy(destination, source)
+#endif
+
+/*
+ * vasprintf for Windows.
+ */
+XSUM_ATTRIBUTE((__format__(__printf__, 2, 0)))
+static int XSUM_vasprintf(char** strp, const char* format, va_list ap)
+{
+    int ret;
+    int size;
+    va_list copy;
+    /*
+     * To be safe, make a va_copy.
+     *
+     * Note that Microsoft doesn't use va_copy in its sample code:
+     *   https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsprintf-vsprintf-l-vswprintf-vswprintf-l-vswprintf-l?view=vs-2019
+     */
+    XSUM_va_copy(copy, ap);
+    /* Calculate how many characters we need */
+    size = _vscprintf(format, ap);
+    va_end(copy);
+
+    if (size < 0) {
+        *strp = NULL;
+        return size;
+    } else {
+        *strp = (char*) malloc((size_t)size + 1);
+        if (*strp == NULL) {
+            return -1;
+        }
+        /* vsprintf into the new buffer */
+        ret = vsprintf(*strp, format, ap);
+        if (ret < 0) {
+            free(*strp);
+            *strp = NULL;
+        }
+        return ret;
+    }
+}
+
+/*
+ * fprintf wrapper that supports UTF-8.
+ *
+ * fprintf doesn't properly handle Unicode on Windows.
+ *
+ * Additionally, it is codepage sensitive on console and may crash the program.
+ *
+ * Instead, we use vsnprintf, and either print with fwrite or convert to UTF-16
+ * for console output and use the codepage-independent WriteConsoleW.
+ *
+ * Credit to t-mat: https://github.com/t-mat/xxHash/commit/5691423
+ */
+XSUM_ATTRIBUTE((__format__(__printf__, 2, 0)))
+XSUM_API int XSUM_vfprintf(FILE *stream, const char *format, va_list ap)
+{
+    int result;
+    char* u8_str = NULL;
+
+    /*
+     * Generate the UTF-8 output string with vasprintf.
+     */
+    result = XSUM_vasprintf(&u8_str, format, ap);
+
+    if (result >= 0) {
+        const size_t nchar = (size_t)result + 1;
+
+        /*
+         * Check if we are outputting to a console. Don't use XSUM_isConsole
+         * directly -- we don't need to call _get_osfhandle twice.
+         */
+        int fileNb = _fileno(stream);
+        intptr_t handle_raw = _get_osfhandle(fileNb);
+        HANDLE handle = (HANDLE)handle_raw;
+        DWORD dwTemp;
+
+        if (handle_raw < 0) {
+             result = -1;
+        } else if (_isatty(fileNb) && GetConsoleMode(handle, &dwTemp)) {
+            /*
+             * Convert to UTF-16 and output with WriteConsoleW.
+             *
+             * This is codepage independent and works on Windows XP's default
+             * msvcrt.dll.
+             */
+            int len;
+            wchar_t* const u16_buf = XSUM_widenString(u8_str, &len);
+            if (u16_buf == NULL) {
+                result = -1;
+            } else {
+                if (WriteConsoleW(handle, u16_buf, (DWORD)len - 1, &dwTemp, NULL)) {
+                    result = (int)dwTemp;
+                } else {
+                    result = -1;
+                }
+                free(u16_buf);
+            }
+        } else {
+            /* fwrite the UTF-8 string if we are printing to a file */
+            result = (int)fwrite(u8_str, 1, nchar - 1, stream);
+            if (result == 0) {
+                result = -1;
+            }
+        }
+        free(u8_str);
+    }
+    return result;
+}
+
+#ifndef XSUM_NO_MAIN
+/*****************************************************************************
+ *                    Command Line argument parsing
+ *****************************************************************************/
+
+/* Converts a UTF-16 argv to UTF-8. */
+static char** XSUM_convertArgv(int argc, wchar_t* utf16_argv[])
+{
+    char** const utf8_argv = (char**)malloc((size_t)(argc + 1) * sizeof(char*));
+    if (utf8_argv != NULL) {
+        int i;
+        for (i = 0; i < argc; i++) {
+            utf8_argv[i] = XSUM_narrowString(utf16_argv[i], NULL);
+            if (utf8_argv[i] == NULL) {
+                /* Out of memory, whoops. */
+                while (i-- > 0) {
+                    free(utf8_argv[i]);
+                }
+                free(utf8_argv);
+                return NULL;
+            }
+        }
+        utf8_argv[argc] = NULL;
+    }
+    return utf8_argv;
+}
+/* Frees arguments returned by XSUM_convertArgv */
+static void XSUM_freeArgv(int argc, char** argv)
+{
+    int i;
+    if (argv == NULL) {
+        return;
+    }
+    for (i = 0; i < argc; i++) {
+        free(argv[i]);
+    }
+    free(argv);
+}
+
+static int XSUM_wmain(int argc, wchar_t* utf16_argv[])
+{
+    /* Convert the UTF-16 arguments to UTF-8. */
+    char** utf8_argv = XSUM_convertArgv(argc, utf16_argv);
+
+    if (utf8_argv == NULL) {
+        /* An unfortunate but incredibly unlikely error. */
+        fprintf(stderr, "xxhsum: error converting command line arguments!\n");
+        abort();
+    } else {
+        int ret;
+
+        /*
+         * MinGW's terminal uses full block buffering for stderr.
+         *
+         * This is nonstandard behavior and causes text to not display until
+         * the buffer fills.
+         *
+         * `setvbuf()` can easily correct this to make text display instantly.
+         */
+        setvbuf(stderr, NULL, _IONBF, 0);
+
+        /* Call our real main function */
+        ret = XSUM_main(argc, utf8_argv);
+
+        /* Cleanup */
+        XSUM_freeArgv(argc, utf8_argv);
+        return ret;
+    }
+}
+
+#if XSUM_WIN32_USE_WMAIN
+
+/*
+ * The preferred method of obtaining the real UTF-16 arguments. Always works
+ * on MSVC, sometimes works on MinGW-w64 depending on the compiler flags.
+ */
+#ifdef __cplusplus
+extern "C"
+#endif
+int __cdecl wmain(int argc, wchar_t* utf16_argv[])
+{
+    return XSUM_wmain(argc, utf16_argv);
+}
+#else /* !XSUM_WIN32_USE_WMAIN */
+
+/*
+ * Wrap `XSUM_wmain()` using `main()` and `__wgetmainargs()` on MinGW without
+ * Unicode support.
+ *
+ * `__wgetmainargs()` is used in the CRT startup to retrieve the arguments for
+ * `wmain()`, so we use it on MinGW to emulate `wmain()`.
+ *
+ * It is an internal function and not declared in any public headers, so we
+ * have to declare it manually.
+ *
+ * An alternative that doesn't mess with internal APIs is `GetCommandLineW()`
+ * with `CommandLineToArgvW()`, but the former doesn't expand wildcards and the
+ * latter requires linking to Shell32.dll and its numerous dependencies.
+ *
+ * This method keeps our dependencies to kernel32.dll and the CRT.
+ *
+ * https://docs.microsoft.com/en-us/cpp/c-runtime-library/getmainargs-wgetmainargs?view=vs-2019
+ */
+typedef struct {
+    int newmode;
+} _startupinfo;
+
+#ifdef __cplusplus
+extern "C"
+#endif
+int __cdecl __wgetmainargs(
+    int*          Argc,
+    wchar_t***    Argv,
+    wchar_t***    Env,
+    int           DoWildCard,
+    _startupinfo* StartInfo
+);
+
+int main(int ansi_argc, char* ansi_argv[])
+{
+    int       utf16_argc;
+    wchar_t** utf16_argv;
+    wchar_t** utf16_envp;         /* Unused but required */
+    _startupinfo startinfo = {0}; /* 0 == don't change new mode */
+
+    /* Get wmain's UTF-16 arguments. Make sure we expand wildcards. */
+    if (__wgetmainargs(&utf16_argc, &utf16_argv, &utf16_envp, 1, &startinfo) < 0)
+        /* In the very unlikely case of an error, use the ANSI arguments. */
+        return XSUM_main(ansi_argc, ansi_argv);
+
+    /* Call XSUM_wmain with our UTF-16 arguments */
+    return XSUM_wmain(utf16_argc, utf16_argv);
+}
+
+#endif /* !XSUM_WIN32_USE_WMAIN */
+#endif /* !XSUM_NO_MAIN */
+#endif /* XSUM_WIN32_USE_WCHAR */
+
+
+/*
+ * Determines whether the file at filename is a directory.
+ */
+XSUM_API int XSUM_isDirectory(const char* filename)
+{
+    XSUM_stat_t statbuf;
+    int r = XSUM_stat(filename, &statbuf);
+#ifdef _MSC_VER
+    if (!r && (statbuf.st_mode & _S_IFDIR)) return 1;
+#else
+    if (!r && S_ISDIR(statbuf.st_mode)) return 1;
+#endif
+    return 0;
+}
+
+/*
+ * Returns the filesize of the file at filename.
+ */
+XSUM_API XSUM_U64 XSUM_getFileSize(const char* filename)
+{
+    XSUM_stat_t statbuf;
+    int r = XSUM_stat(filename, &statbuf);
+    if (r || !S_ISREG(statbuf.st_mode)) return 0;   /* No good... */
+    return (XSUM_U64)statbuf.st_size;
+}
diff --git a/grpc/third_party/xxhash/cli/xsum_os_specific.h b/grpc/third_party/xxhash/cli/xsum_os_specific.h
new file mode 100644
index 0000000..b3562b2
--- /dev/null
+++ b/grpc/third_party/xxhash/cli/xsum_os_specific.h
@@ -0,0 +1,89 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#ifndef XSUM_OS_SPECIFIC_H
+#define XSUM_OS_SPECIFIC_H
+
+#include "xsum_config.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Declared here to be implemented in user code.
+ *
+ * Functions like main(), but is passed UTF-8 arguments even on Windows.
+ */
+XSUM_API int XSUM_main(int argc, char* argv[]);
+
+/*
+ * Returns whether stream is a console.
+ *
+ * Functionally equivalent to isatty(fileno(stream)).
+ */
+XSUM_API int XSUM_isConsole(FILE* stream);
+
+/*
+ * Sets stream to pure binary mode (a.k.a. no CRLF conversions).
+ */
+XSUM_API void XSUM_setBinaryMode(FILE* stream);
+
+/*
+ * Returns whether the file at filename is a directory.
+ */
+XSUM_API int XSUM_isDirectory(const char* filename);
+
+/*
+ * Returns the file size of the file at filename.
+ */
+XSUM_API XSUM_U64 XSUM_getFileSize(const char* filename);
+
+/*
+ * UTF-8 stdio wrappers primarily for Windows
+ */
+
+/*
+ * fopen() wrapper. Accepts UTF-8 filenames on Windows.
+ *
+ * Specifically, on Windows, the arguments will be converted to UTF-16
+ * and passed to _wfopen().
+ */
+XSUM_API FILE* XSUM_fopen(const char* filename, const char* mode);
+
+/*
+ * vfprintf() wrapper which prints UTF-8 strings to Windows consoles
+ * if applicable.
+ */
+XSUM_ATTRIBUTE((__format__(__printf__, 2, 0)))
+XSUM_API int XSUM_vfprintf(FILE* stream, const char* format, va_list ap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XSUM_OS_SPECIFIC_H */
diff --git a/grpc/third_party/xxhash/cli/xsum_output.c b/grpc/third_party/xxhash/cli/xsum_output.c
new file mode 100644
index 0000000..a4d7411
--- /dev/null
+++ b/grpc/third_party/xxhash/cli/xsum_output.c
@@ -0,0 +1,67 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#include "xsum_output.h"
+#include "xsum_os_specific.h"
+#include <stdio.h>
+
+int XSUM_logLevel = 2;
+
+XSUM_ATTRIBUTE((__format__(__printf__, 1, 2)))
+XSUM_API int XSUM_log(const char* format, ...)
+{
+    int ret;
+    va_list ap;
+    va_start(ap, format);
+    ret = XSUM_vfprintf(stderr, format, ap);
+    va_end(ap);
+    return ret;
+}
+
+
+XSUM_ATTRIBUTE((__format__(__printf__, 1, 2)))
+XSUM_API int XSUM_output(const char* format, ...)
+{
+    int ret;
+    va_list ap;
+    va_start(ap, format);
+    ret = XSUM_vfprintf(stdout, format, ap);
+    va_end(ap);
+    return ret;
+}
+
+XSUM_ATTRIBUTE((__format__(__printf__, 2, 3)))
+XSUM_API int XSUM_logVerbose(int minLevel, const char* format, ...)
+{
+    if (XSUM_logLevel >= minLevel) {
+        int ret;
+        va_list ap;
+        va_start(ap, format);
+        ret = XSUM_vfprintf(stderr, format, ap);
+        va_end(ap);
+        return ret;
+    }
+    return 0;
+}
diff --git a/grpc/third_party/xxhash/cli/xsum_output.h b/grpc/third_party/xxhash/cli/xsum_output.h
new file mode 100644
index 0000000..8a02c1b
--- /dev/null
+++ b/grpc/third_party/xxhash/cli/xsum_output.h
@@ -0,0 +1,62 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#ifndef XSUM_OUTPUT_H
+#define XSUM_OUTPUT_H
+
+#include "xsum_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * How verbose the output is.
+ */
+extern int XSUM_logLevel;
+
+/*
+ * Same as fprintf(stderr, format, ...)
+ */
+XSUM_ATTRIBUTE((__format__(__printf__, 1, 2)))
+XSUM_API int XSUM_log(const char *format, ...);
+
+/*
+ * Like XSUM_log, but only outputs if XSUM_logLevel >= minLevel.
+ */
+XSUM_ATTRIBUTE((__format__(__printf__, 2, 3)))
+XSUM_API int XSUM_logVerbose(int minLevel, const char *format, ...);
+
+/*
+ * Same as printf(format, ...)
+ */
+XSUM_ATTRIBUTE((__format__(__printf__, 1, 2)))
+XSUM_API int XSUM_output(const char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XSUM_OUTPUT_H */
diff --git a/grpc/third_party/xxhash/cli/xsum_sanity_check.c b/grpc/third_party/xxhash/cli/xsum_sanity_check.c
new file mode 100644
index 0000000..347d1db
--- /dev/null
+++ b/grpc/third_party/xxhash/cli/xsum_sanity_check.c
@@ -0,0 +1,602 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#include "xsum_config.h"
+#include "xsum_sanity_check.h"
+#include "xsum_output.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#ifndef XXH_STATIC_LINKING_ONLY
+#  define XXH_STATIC_LINKING_ONLY
+#endif
+#include "../xxhash.h"
+
+/* use #define to make them constant, required for initialization */
+#define PRIME32 2654435761U
+#define PRIME64 11400714785074694797ULL
+
+/*
+ * Fills a test buffer with pseudorandom data.
+ *
+ * This is used in the sanity check - its values must not be changed.
+ */
+XSUM_API void XSUM_fillTestBuffer(XSUM_U8* buffer, size_t len)
+{
+    XSUM_U64 byteGen = PRIME32;
+    size_t i;
+
+    assert(buffer != NULL);
+
+    for (i=0; i<len; i++) {
+        buffer[i] = (XSUM_U8)(byteGen>>56);
+        byteGen *= PRIME64;
+    }
+}
+
+
+
+/* ************************************************
+ * Self-test:
+ * ensure results consistency accross platforms
+ *********************************************** */
+#if XSUM_NO_TESTS
+XSUM_API void XSUM_sanityCheck(void)
+{
+    XSUM_log("This version of xxhsum is not verified.\n");
+}
+#else
+
+/*
+ * Test data vectors
+ */
+typedef struct {
+    XSUM_U32 len;
+    XSUM_U32 seed;
+    XSUM_U32 Nresult;
+} XSUM_testdata32_t;
+
+typedef struct {
+    XSUM_U32 len;
+    XSUM_U64 seed;
+    XSUM_U64 Nresult;
+} XSUM_testdata64_t;
+
+typedef struct {
+    XSUM_U32 len;
+    XSUM_U64 seed;
+    XXH128_hash_t Nresult;
+} XSUM_testdata128_t;
+
+#define SECRET_SAMPLE_NBBYTES 4
+typedef struct {
+    XSUM_U32 len;
+    XSUM_U8 byte[SECRET_SAMPLE_NBBYTES];
+} XSUM_testdata_sample_t;
+
+/* XXH32 */
+static const XSUM_testdata32_t XSUM_XXH32_testdata[] = {
+    {   0,       0, 0x02CC5D05U },
+    {   0, PRIME32, 0x36B78AE7U },
+    {   1,       0, 0xCF65B03EU },
+    {   1, PRIME32, 0xB4545AA4U },
+    {  14,       0, 0x1208E7E2U },
+    {  14, PRIME32, 0x6AF1D1FEU },
+    { 222,       0, 0x5BD11DBDU },
+    { 222, PRIME32, 0x58803C5FU }
+};
+
+/* XXH64 */
+static const XSUM_testdata64_t XSUM_XXH64_testdata[] = {
+    {   0,       0, 0xEF46DB3751D8E999ULL },
+    {   0, PRIME32, 0xAC75FDA2929B17EFULL },
+    {   1,       0, 0xE934A84ADB052768ULL },
+    {   1, PRIME32, 0x5014607643A9B4C3ULL },
+    {   4,       0, 0x9136A0DCA57457EEULL },
+    {  14,       0, 0x8282DCC4994E35C8ULL },
+    {  14, PRIME32, 0xC3BD6BF63DEB6DF0ULL },
+    { 222,       0, 0xB641AE8CB691C174ULL },
+    { 222, PRIME32, 0x20CB8AB7AE10C14AULL }
+};
+/*
+ * XXH3:
+ * Due to being a more complex hash function with specializations for certain
+ * lengths, a more extensive test is used for XXH3.
+ */
+
+/* XXH3_64bits, seeded */
+static const XSUM_testdata64_t XSUM_XXH3_testdata[] = {
+    {    0,       0, 0x2D06800538D394C2ULL },  /* empty string */
+    {    0, PRIME64, 0xA8A6B918B2F0364AULL },  /* empty string */
+    {    1,       0, 0xC44BDFF4074EECDBULL },  /*  1 -  3 */
+    {    1, PRIME64, 0x032BE332DD766EF8ULL },  /*  1 -  3 */
+    {    6,       0, 0x27B56A84CD2D7325ULL },  /*  4 -  8 */
+    {    6, PRIME64, 0x84589C116AB59AB9ULL },  /*  4 -  8 */
+    {   12,       0, 0xA713DAF0DFBB77E7ULL },  /*  9 - 16 */
+    {   12, PRIME64, 0xE7303E1B2336DE0EULL },  /*  9 - 16 */
+    {   24,       0, 0xA3FE70BF9D3510EBULL },  /* 17 - 32 */
+    {   24, PRIME64, 0x850E80FC35BDD690ULL },  /* 17 - 32 */
+    {   48,       0, 0x397DA259ECBA1F11ULL },  /* 33 - 64 */
+    {   48, PRIME64, 0xADC2CBAA44ACC616ULL },  /* 33 - 64 */
+    {   80,       0, 0xBCDEFBBB2C47C90AULL },  /* 65 - 96 */
+    {   80, PRIME64, 0xC6DD0CB699532E73ULL },  /* 65 - 96 */
+    {  195,       0, 0xCD94217EE362EC3AULL },  /* 129-240 */
+    {  195, PRIME64, 0xBA68003D370CB3D9ULL },  /* 129-240 */
+
+    {  403,       0, 0xCDEB804D65C6DEA4ULL },  /* one block, last stripe is overlapping */
+    {  403, PRIME64, 0x6259F6ECFD6443FDULL },  /* one block, last stripe is overlapping */
+    {  512,       0, 0x617E49599013CB6BULL },  /* one block, finishing at stripe boundary */
+    {  512, PRIME64, 0x3CE457DE14C27708ULL },  /* one block, finishing at stripe boundary */
+    { 2048,       0, 0xDD59E2C3A5F038E0ULL },  /* 2 blocks, finishing at block boundary */
+    { 2048, PRIME64, 0x66F81670669ABABCULL },  /* 2 blocks, finishing at block boundary */
+    { 2240,       0, 0x6E73A90539CF2948ULL },  /* 3 blocks, finishing at stripe boundary */
+    { 2240, PRIME64, 0x757BA8487D1B5247ULL },  /* 3 blocks, finishing at stripe boundary */
+    { 2367,       0, 0xCB37AEB9E5D361EDULL },  /* 3 blocks, last stripe is overlapping */
+    { 2367, PRIME64, 0xD2DB3415B942B42AULL }   /* 3 blocks, last stripe is overlapping */
+};
+/* XXH3_64bits, custom secret */
+static const XSUM_testdata64_t XSUM_XXH3_withSecret_testdata[] = {
+    {       0, 0, 0x3559D64878C5C66CULL },  /* empty string */
+    {       1, 0, 0x8A52451418B2DA4DULL },  /*  1 -  3 */
+    {       6, 0, 0x82C90AB0519369ADULL },  /*  4 -  8 */
+    {      12, 0, 0x14631E773B78EC57ULL },  /*  9 - 16 */
+    {      24, 0, 0xCDD5542E4A9D9FE8ULL },  /* 17 - 32 */
+    {      48, 0, 0x33ABD54D094B2534ULL },  /* 33 - 64 */
+    {      80, 0, 0xE687BA1684965297ULL },  /* 65 - 96 */
+    {     195, 0, 0xA057273F5EECFB20ULL },  /* 129-240 */
+
+    {     403, 0, 0x14546019124D43B8ULL },  /* one block, last stripe is overlapping */
+    {     512, 0, 0x7564693DD526E28DULL },  /* one block, finishing at stripe boundary */
+    {    2048, 0, 0xD32E975821D6519FULL },  /* >= 2 blodcks, at least one scrambling */
+    {    2367, 0, 0x293FA8E5173BB5E7ULL },  /* >= 2 blocks, at least one scrambling, last stripe unaligned */
+
+    { 64*10*3, 0, 0x751D2EC54BC6038BULL }   /* exactly 3 full blocks, not a multiple of 256 */
+};
+/* XXH3_128bits, seeded */
+static const XSUM_testdata128_t XSUM_XXH128_testdata[] = {
+    {    0,       0, { 0x6001C324468D497FULL, 0x99AA06D3014798D8ULL } },  /* empty string */
+    {    0, PRIME32, { 0x5444F7869C671AB0ULL, 0x92220AE55E14AB50ULL } },  /* empty string */
+    {    1,       0, { 0xC44BDFF4074EECDBULL, 0xA6CD5E9392000F6AULL } },  /*  1 -  3 */
+    {    1, PRIME32, { 0xB53D5557E7F76F8DULL, 0x89B99554BA22467CULL } },  /*  1 -  3 */
+    {    6,       0, { 0x3E7039BDDA43CFC6ULL, 0x082AFE0B8162D12AULL } },  /*  4 -  8 */
+    {    6, PRIME32, { 0x269D8F70BE98856EULL, 0x5A865B5389ABD2B1ULL } },  /*  4 -  8 */
+    {   12,       0, { 0x061A192713F69AD9ULL, 0x6E3EFD8FC7802B18ULL } },  /*  9 - 16 */
+    {   12, PRIME32, { 0x9BE9F9A67F3C7DFBULL, 0xD7E09D518A3405D3ULL } },  /*  9 - 16 */
+    {   24,       0, { 0x1E7044D28B1B901DULL, 0x0CE966E4678D3761ULL } },  /* 17 - 32 */
+    {   24, PRIME32, { 0xD7304C54EBAD40A9ULL, 0x3162026714A6A243ULL } },  /* 17 - 32 */
+    {   48,       0, { 0xF942219AED80F67BULL, 0xA002AC4E5478227EULL } },  /* 33 - 64 */
+    {   48, PRIME32, { 0x7BA3C3E453A1934EULL, 0x163ADDE36C072295ULL } },  /* 33 - 64 */
+    {   81,       0, { 0x5E8BAFB9F95FB803ULL, 0x4952F58181AB0042ULL } },  /* 65 - 96 */
+    {   81, PRIME32, { 0x703FBB3D7A5F755CULL, 0x2724EC7ADC750FB6ULL } },  /* 65 - 96 */
+    {  222,       0, { 0xF1AEBD597CEC6B3AULL, 0x337E09641B948717ULL } },  /* 129-240 */
+    {  222, PRIME32, { 0xAE995BB8AF917A8DULL, 0x91820016621E97F1ULL } },  /* 129-240 */
+
+    {  403,       0, { 0xCDEB804D65C6DEA4ULL, 0x1B6DE21E332DD73DULL } },  /* one block, last stripe is overlapping */
+    {  403, PRIME64, { 0x6259F6ECFD6443FDULL, 0xBED311971E0BE8F2ULL } },  /* one block, last stripe is overlapping */
+    {  512,       0, { 0x617E49599013CB6BULL, 0x18D2D110DCC9BCA1ULL } },  /* one block, finishing at stripe boundary */
+    {  512, PRIME64, { 0x3CE457DE14C27708ULL, 0x925D06B8EC5B8040ULL } },  /* one block, finishing at stripe boundary */
+    { 2048,       0, { 0xDD59E2C3A5F038E0ULL, 0xF736557FD47073A5ULL } },  /* 2 blocks, finishing at block boundary */
+    { 2048, PRIME32, { 0x230D43F30206260BULL, 0x7FB03F7E7186C3EAULL } },  /* 2 blocks, finishing at block boundary */
+    { 2240,       0, { 0x6E73A90539CF2948ULL, 0xCCB134FBFA7CE49DULL } },  /* 3 blocks, finishing at stripe boundary */
+    { 2240, PRIME32, { 0xED385111126FBA6FULL, 0x50A1FE17B338995FULL } },  /* 3 blocks, finishing at stripe boundary */
+    { 2367,       0, { 0xCB37AEB9E5D361EDULL, 0xE89C0F6FF369B427ULL } },  /* 3 blocks, last stripe is overlapping */
+    { 2367, PRIME32, { 0x6F5360AE69C2F406ULL, 0xD23AAE4B76C31ECBULL } }   /* 3 blocks, last stripe is overlapping */
+};
+
+/* XXH128, custom secret */
+static const XSUM_testdata128_t XSUM_XXH128_withSecret_testdata[] = {
+    {  0, 0, { 0x005923CCEECBE8AEULL, 0x5F70F4EA232F1D38ULL } },  /* empty string */
+    {  1, 0, { 0x8A52451418B2DA4DULL, 0x3A66AF5A9819198EULL } },  /*  1 -  3 */
+    {  6, 0, { 0x0B61C8ACA7D4778FULL, 0x376BD91B6432F36DULL } },  /*  4 -  8 */
+    { 12, 0, { 0xAF82F6EBA263D7D8ULL, 0x90A3C2D839F57D0FULL } }   /*  9 - 16 */
+};
+
+static const XSUM_testdata_sample_t XSUM_XXH3_generateSecret_testdata[] = {
+    {                              0, { 0xB8, 0x26, 0x83, 0x7E } },
+    {                              1, { 0xA6, 0x16, 0x06, 0x7B } },
+    {     XXH3_SECRET_SIZE_MIN -   1, { 0xDA, 0x2A, 0x12, 0x11 } },
+    { XXH3_SECRET_DEFAULT_SIZE + 500, { 0x7E, 0x48, 0x0C, 0xA7 } }
+};
+
+static void XSUM_checkResult32(XXH32_hash_t r1, XXH32_hash_t r2)
+{
+    static int nbTests = 1;
+    if (r1!=r2) {
+        XSUM_log("\rError: 32-bit hash test %i: Internal sanity check failed!\n", nbTests);
+        XSUM_log("\rGot 0x%08X, expected 0x%08X.\n", (unsigned)r1, (unsigned)r2);
+        XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n"
+                  "or temporarily recompile with XSUM_NO_TESTS=1.\n");
+        exit(1);
+    }
+    nbTests++;
+}
+
+static void XSUM_checkResult64(XXH64_hash_t r1, XXH64_hash_t r2)
+{
+    static int nbTests = 1;
+    if (r1!=r2) {
+        XSUM_log("\rError: 64-bit hash test %i: Internal sanity check failed!\n", nbTests);
+        XSUM_log("\rGot 0x%08X%08XULL, expected 0x%08X%08XULL.\n",
+                (unsigned)(r1>>32), (unsigned)r1, (unsigned)(r2>>32), (unsigned)r2);
+        XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n"
+                  "or temporarily recompile with XSUM_NO_TESTS=1.\n");
+        exit(1);
+    }
+    nbTests++;
+}
+
+static void XSUM_checkResult128(XXH128_hash_t r1, XXH128_hash_t r2)
+{
+    static int nbTests = 1;
+    if ((r1.low64 != r2.low64) || (r1.high64 != r2.high64)) {
+        XSUM_log("\rError: 128-bit hash test %i: Internal sanity check failed.\n", nbTests);
+        XSUM_log("\rGot { 0x%08X%08XULL, 0x%08X%08XULL }, expected { 0x%08X%08XULL, 0x%08X%08XULL } \n",
+                (unsigned)(r1.low64>>32), (unsigned)r1.low64, (unsigned)(r1.high64>>32), (unsigned)r1.high64,
+                (unsigned)(r2.low64>>32), (unsigned)r2.low64, (unsigned)(r2.high64>>32), (unsigned)r2.high64 );
+        XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n"
+                  "or temporarily recompile with XSUM_NO_TESTS=1.\n");
+        exit(1);
+    }
+    nbTests++;
+}
+
+
+static void XSUM_testXXH32(const void* data, const XSUM_testdata32_t* testData)
+{
+    XXH32_state_t *state = XXH32_createState();
+    size_t pos;
+
+    size_t len = testData->len;
+    XSUM_U32 seed = testData->seed;
+    XSUM_U32 Nresult = testData->Nresult;
+
+    if (len == 0) {
+        data = NULL;
+    } else {
+        assert(data != NULL);
+    }
+
+    assert(state != NULL);
+
+    XSUM_checkResult32(XXH32(data, len, seed), Nresult);
+
+    (void)XXH32_reset(state, seed);
+    (void)XXH32_update(state, data, len);
+    XSUM_checkResult32(XXH32_digest(state), Nresult);
+
+    (void)XXH32_reset(state, seed);
+    for (pos=0; pos<len; pos++)
+        (void)XXH32_update(state, ((const char*)data)+pos, 1);
+    XSUM_checkResult32(XXH32_digest(state), Nresult);
+    XXH32_freeState(state);
+}
+
+static void XSUM_testXXH64(const void* data, const XSUM_testdata64_t* testData)
+{
+    XXH64_state_t *state = XXH64_createState();
+    size_t pos;
+
+    size_t len = (size_t)testData->len;
+    XSUM_U64 seed = testData->seed;
+    XSUM_U64 Nresult = testData->Nresult;
+
+    if (len == 0) {
+        data = NULL;
+    } else {
+        assert(data != NULL);
+    }
+
+    assert(state != NULL);
+
+    XSUM_checkResult64(XXH64(data, len, seed), Nresult);
+
+    (void)XXH64_reset(state, seed);
+    (void)XXH64_update(state, data, len);
+    XSUM_checkResult64(XXH64_digest(state), Nresult);
+
+    (void)XXH64_reset(state, seed);
+    for (pos=0; pos<len; pos++)
+        (void)XXH64_update(state, ((const char*)data)+pos, 1);
+    XSUM_checkResult64(XXH64_digest(state), Nresult);
+    XXH64_freeState(state);
+}
+
+/*
+ * Used to get "random" (but actually 100% reproducible) lengths for
+ * XSUM_XXH3_randomUpdate.
+ */
+static XSUM_U32 XSUM_rand(void)
+{
+    static XSUM_U64 seed = PRIME32;
+    seed *= PRIME64;
+    return (XSUM_U32)(seed >> 40);
+}
+
+/*
+ * Technically, XXH3_64bits_update is identical to XXH3_128bits_update as of
+ * v0.8.0, but we treat them as separate.
+ */
+typedef XXH_errorcode (*XSUM_XXH3_update_t)(XXH3_state_t* state, const void* input, size_t length);
+
+/*
+ * Runs the passed XXH3_update variant on random lengths. This is to test the
+ * more complex logic of the update function, catching bugs like this one:
+ *    https://github.com/Cyan4973/xxHash/issues/378
+ */
+static void XSUM_XXH3_randomUpdate(XXH3_state_t* state, const void* data,
+                                   size_t len, XSUM_XXH3_update_t update_fn)
+{
+    size_t p = 0;
+    while (p < len) {
+        size_t const modulo = len > 2 ? len : 2;
+        size_t l = (size_t)(XSUM_rand()) % modulo;
+        if (p + l > len) l = len - p;
+        (void)update_fn(state, (const char*)data+p, l);
+        p += l;
+    }
+}
+
+static void XSUM_testXXH3(const void* data, const XSUM_testdata64_t* testData)
+{
+    size_t len = testData->len;
+    XSUM_U64 seed = testData->seed;
+    XSUM_U64 Nresult = testData->Nresult;
+    if (len == 0) {
+        data = NULL;
+    } else {
+        assert(data != NULL);
+    }
+    {   XSUM_U64 const Dresult = XXH3_64bits_withSeed(data, len, seed);
+        XSUM_checkResult64(Dresult, Nresult);
+    }
+
+    /* check that the no-seed variant produces same result as seed==0 */
+    if (seed == 0) {
+        XSUM_U64 const Dresult = XXH3_64bits(data, len);
+        XSUM_checkResult64(Dresult, Nresult);
+    }
+
+    /* streaming API test */
+    {   XXH3_state_t* const state = XXH3_createState();
+        assert(state != NULL);
+        /* single ingestion */
+        (void)XXH3_64bits_reset_withSeed(state, seed);
+        (void)XXH3_64bits_update(state, data, len);
+        XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
+
+        /* random ingestion */
+        (void)XXH3_64bits_reset_withSeed(state, seed);
+        XSUM_XXH3_randomUpdate(state, data, len, &XXH3_64bits_update);
+        XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
+
+        /* byte by byte ingestion */
+        {   size_t pos;
+            (void)XXH3_64bits_reset_withSeed(state, seed);
+            for (pos=0; pos<len; pos++)
+                (void)XXH3_64bits_update(state, ((const char*)data)+pos, 1);
+            XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
+        }
+        XXH3_freeState(state);
+    }
+}
+
+static void XSUM_testXXH3_withSecret(const void* data, const void* secret,
+                                     size_t secretSize, const XSUM_testdata64_t* testData)
+{
+    size_t len = (size_t)testData->len;
+    XSUM_U64 Nresult = testData->Nresult;
+
+    if (len == 0) {
+        data = NULL;
+    } else {
+        assert(data != NULL);
+    }
+    {   XSUM_U64 const Dresult = XXH3_64bits_withSecret(data, len, secret, secretSize);
+        XSUM_checkResult64(Dresult, Nresult);
+    }
+
+    /* streaming API test */
+    {   XXH3_state_t *state = XXH3_createState();
+        assert(state != NULL);
+        (void)XXH3_64bits_reset_withSecret(state, secret, secretSize);
+        (void)XXH3_64bits_update(state, data, len);
+        XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
+
+        /* random ingestion */
+        (void)XXH3_64bits_reset_withSecret(state, secret, secretSize);
+        XSUM_XXH3_randomUpdate(state, data, len, &XXH3_64bits_update);
+        XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
+
+        /* byte by byte ingestion */
+        {   size_t pos;
+            (void)XXH3_64bits_reset_withSecret(state, secret, secretSize);
+            for (pos=0; pos<len; pos++)
+                (void)XXH3_64bits_update(state, ((const char*)data)+pos, 1);
+            XSUM_checkResult64(XXH3_64bits_digest(state), Nresult);
+        }
+        XXH3_freeState(state);
+    }
+}
+
+static void XSUM_testXXH128(const void* data, const XSUM_testdata128_t* testData)
+{
+    size_t len = (size_t)testData->len;
+    XSUM_U64 seed = testData->seed;
+    XXH128_hash_t const Nresult = testData->Nresult;
+    if (len == 0) {
+        data = NULL;
+    } else {
+        assert(data != NULL);
+    }
+
+    {   XXH128_hash_t const Dresult = XXH3_128bits_withSeed(data, len, seed);
+        XSUM_checkResult128(Dresult, Nresult);
+    }
+
+    /* check that XXH128() is identical to XXH3_128bits_withSeed() */
+    {   XXH128_hash_t const Dresult2 = XXH128(data, len, seed);
+        XSUM_checkResult128(Dresult2, Nresult);
+    }
+
+    /* check that the no-seed variant produces same result as seed==0 */
+    if (seed == 0) {
+        XXH128_hash_t const Dresult = XXH3_128bits(data, len);
+        XSUM_checkResult128(Dresult, Nresult);
+    }
+
+    /* streaming API test */
+    {   XXH3_state_t *state = XXH3_createState();
+        assert(state != NULL);
+
+        /* single ingestion */
+        (void)XXH3_128bits_reset_withSeed(state, seed);
+        (void)XXH3_128bits_update(state, data, len);
+        XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
+
+        /* random ingestion */
+        (void)XXH3_128bits_reset_withSeed(state, seed);
+        XSUM_XXH3_randomUpdate(state, data, len, &XXH3_128bits_update);
+        XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
+
+        /* byte by byte ingestion */
+        {   size_t pos;
+            (void)XXH3_128bits_reset_withSeed(state, seed);
+            for (pos=0; pos<len; pos++)
+                (void)XXH3_128bits_update(state, ((const char*)data)+pos, 1);
+            XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
+        }
+        XXH3_freeState(state);
+    }
+}
+
+static void XSUM_testXXH128_withSecret(const void* data, const void* secret, size_t secretSize, const XSUM_testdata128_t* testData)
+{
+    size_t len = testData->len;
+    XXH128_hash_t Nresult = testData->Nresult;
+    if (len == 0) {
+        data = NULL;
+    } else if (len>0) {
+        assert(data != NULL);
+    }
+    {   XXH128_hash_t const Dresult = XXH3_128bits_withSecret(data, len, secret, secretSize);
+        XSUM_checkResult128(Dresult, Nresult);
+    }
+
+    /* streaming API test */
+    {   XXH3_state_t* const state = XXH3_createState();
+        assert(state != NULL);
+        (void)XXH3_128bits_reset_withSecret(state, secret, secretSize);
+        (void)XXH3_128bits_update(state, data, len);
+        XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
+
+        /* random ingestion */
+        (void)XXH3_128bits_reset_withSecret(state, secret, secretSize);
+        XSUM_XXH3_randomUpdate(state, data, len, &XXH3_128bits_update);
+        XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
+
+        /* byte by byte ingestion */
+        {   size_t pos;
+            (void)XXH3_128bits_reset_withSecret(state, secret, secretSize);
+            for (pos=0; pos<len; pos++)
+                (void)XXH3_128bits_update(state, ((const char*)data)+pos, 1);
+            XSUM_checkResult128(XXH3_128bits_digest(state), Nresult);
+        }
+        XXH3_freeState(state);
+    }
+}
+
+static void XSUM_testSecretGenerator(const void* customSeed, const XSUM_testdata_sample_t* testData)
+{
+    static int nbTests = 1;
+    const int sampleIndex[SECRET_SAMPLE_NBBYTES] = { 0, 62, 131, 191};
+    XSUM_U8 secretBuffer[XXH3_SECRET_DEFAULT_SIZE] = {0};
+    XSUM_U8 samples[SECRET_SAMPLE_NBBYTES];
+    int i;
+
+    XXH3_generateSecret(secretBuffer, customSeed, testData->len);
+    for (i=0; i<SECRET_SAMPLE_NBBYTES; i++) {
+        samples[i] = secretBuffer[sampleIndex[i]];
+    }
+    if (memcmp(samples, testData->byte, sizeof(testData->byte))) {
+        XSUM_log("\rError: Secret generation test %i: Internal sanity check failed. \n", nbTests);
+        XSUM_log("\rGot { 0x%02X, 0x%02X, 0x%02X, 0x%02X }, expected { 0x%02X, 0x%02X, 0x%02X, 0x%02X } \n",
+                samples[0], samples[1], samples[2], samples[3],
+                testData->byte[0], testData->byte[1], testData->byte[2], testData->byte[3] );
+        exit(1);
+    }
+    nbTests++;
+}
+
+/*!
+ * XSUM_sanityCheck():
+ * Runs a sanity check before the benchmark.
+ *
+ * Exits on an incorrect output.
+ */
+XSUM_API void XSUM_sanityCheck(void)
+{
+    size_t i;
+#define SANITY_BUFFER_SIZE 2367
+    XSUM_U8 sanityBuffer[SANITY_BUFFER_SIZE];
+    const void* const secret = sanityBuffer + 7;
+    const size_t secretSize = XXH3_SECRET_SIZE_MIN + 11;
+    assert(sizeof(sanityBuffer) >= 7 + secretSize);
+
+    XSUM_fillTestBuffer(sanityBuffer, sizeof(sanityBuffer));
+
+    /* XXH32 */
+    for (i = 0; i < (sizeof(XSUM_XXH32_testdata)/sizeof(XSUM_XXH32_testdata[0])); i++) {
+        XSUM_testXXH32(sanityBuffer, &XSUM_XXH32_testdata[i]);
+    }
+    /* XXH64 */
+    for (i = 0; i < (sizeof(XSUM_XXH64_testdata)/sizeof(XSUM_XXH64_testdata[0])); i++) {
+        XSUM_testXXH64(sanityBuffer, &XSUM_XXH64_testdata[i]);
+    }
+    /* XXH3_64bits, seeded */
+    for (i = 0; i < (sizeof(XSUM_XXH3_testdata)/sizeof(XSUM_XXH3_testdata[0])); i++) {
+        XSUM_testXXH3(sanityBuffer, &XSUM_XXH3_testdata[i]);
+    }
+    /* XXH3_64bits, custom secret */
+    for (i = 0; i < (sizeof(XSUM_XXH3_withSecret_testdata)/sizeof(XSUM_XXH3_withSecret_testdata[0])); i++) {
+        XSUM_testXXH3_withSecret(sanityBuffer, secret, secretSize, &XSUM_XXH3_withSecret_testdata[i]);
+    }
+    /* XXH128 */
+    for (i = 0; i < (sizeof(XSUM_XXH128_testdata)/sizeof(XSUM_XXH128_testdata[0])); i++) {
+        XSUM_testXXH128(sanityBuffer, &XSUM_XXH128_testdata[i]);
+    }
+    /* XXH128 with custom Secret */
+    for (i = 0; i < (sizeof(XSUM_XXH128_withSecret_testdata)/sizeof(XSUM_XXH128_withSecret_testdata[0])); i++) {
+        XSUM_testXXH128_withSecret(sanityBuffer, secret, secretSize, &XSUM_XXH128_withSecret_testdata[i]);
+    }
+    /* secret generator */
+    for (i = 0; i < (sizeof(XSUM_XXH3_generateSecret_testdata)/sizeof(XSUM_XXH3_generateSecret_testdata[0])); i++) {
+        XSUM_testSecretGenerator(sanityBuffer, &XSUM_XXH3_generateSecret_testdata[i]);
+    }
+
+    XSUM_logVerbose(3, "\r%70s\r", "");       /* Clean display line */
+    XSUM_logVerbose(3, "Sanity check -- all tests ok\n");
+}
+
+#endif /* !XSUM_NO_TESTS */
diff --git a/grpc/third_party/xxhash/cli/xsum_sanity_check.h b/grpc/third_party/xxhash/cli/xsum_sanity_check.h
new file mode 100644
index 0000000..9f3f2b8
--- /dev/null
+++ b/grpc/third_party/xxhash/cli/xsum_sanity_check.h
@@ -0,0 +1,60 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#ifndef XSUM_SANITY_CHECK_H
+#define XSUM_SANITY_CHECK_H
+
+#include "xsum_config.h"  /* XSUM_API, XSUM_U8 */
+
+#include <stddef.h>   /* size_t */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Runs a series of self-tests.
+ *
+ * Exits if any of these tests fail, printing a message to stderr.
+ *
+ * If XSUM_NO_TESTS is defined to non-zero, this will instead print a warning
+ * if this is called (e.g. via xxhsum -b).
+ */
+XSUM_API void XSUM_sanityCheck(void);
+
+/*
+ * Fills a test buffer with pseudorandom data.
+ *
+ * This is used in the sanity check and the benchmarks - its values must not be
+ * changed.
+ */
+XSUM_API void XSUM_fillTestBuffer(XSUM_U8* buffer, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XSUM_SANITY_CHECK_H */
diff --git a/grpc/third_party/xxhash/cmake_unofficial/.gitignore b/grpc/third_party/xxhash/cmake_unofficial/.gitignore
new file mode 100644
index 0000000..93d9fe4
--- /dev/null
+++ b/grpc/third_party/xxhash/cmake_unofficial/.gitignore
@@ -0,0 +1,12 @@
+# cmake artifacts
+
+CMakeCache.txt
+CMakeFiles
+Makefile
+cmake_install.cmake
+
+
+# make compilation results
+
+*.dylib
+*.a
diff --git a/grpc/third_party/xxhash/cmake_unofficial/CMakeLists.txt b/grpc/third_party/xxhash/cmake_unofficial/CMakeLists.txt
new file mode 100644
index 0000000..41c7112
--- /dev/null
+++ b/grpc/third_party/xxhash/cmake_unofficial/CMakeLists.txt
@@ -0,0 +1,173 @@
+# To the extent possible under law, the author(s) have dedicated all
+# copyright and related and neighboring rights to this software to
+# the public domain worldwide. This software is distributed without
+# any warranty.
+#
+# For details, see <https://creativecommons.org/publicdomain/zero/1.0/>.
+
+cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR)
+
+set(XXHASH_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
+
+file(STRINGS "${XXHASH_DIR}/xxhash.h" XXHASH_VERSION_MAJOR REGEX "^#define XXH_VERSION_MAJOR +([0-9]+) *$")
+string(REGEX REPLACE "^#define XXH_VERSION_MAJOR +([0-9]+) *$" "\\1" XXHASH_VERSION_MAJOR "${XXHASH_VERSION_MAJOR}")
+file(STRINGS "${XXHASH_DIR}/xxhash.h" XXHASH_VERSION_MINOR REGEX "^#define XXH_VERSION_MINOR +([0-9]+) *$")
+string(REGEX REPLACE "^#define XXH_VERSION_MINOR +([0-9]+) *$" "\\1" XXHASH_VERSION_MINOR "${XXHASH_VERSION_MINOR}")
+file(STRINGS "${XXHASH_DIR}/xxhash.h" XXHASH_VERSION_RELEASE REGEX "^#define XXH_VERSION_RELEASE +([0-9]+) *$")
+string(REGEX REPLACE "^#define XXH_VERSION_RELEASE +([0-9]+) *$" "\\1" XXHASH_VERSION_RELEASE "${XXHASH_VERSION_RELEASE}")
+set(XXHASH_VERSION_STRING "${XXHASH_VERSION_MAJOR}.${XXHASH_VERSION_MINOR}.${XXHASH_VERSION_RELEASE}")
+set(XXHASH_LIB_VERSION ${XXHASH_VERSION_STRING})
+set(XXHASH_LIB_SOVERSION "${XXHASH_VERSION_MAJOR}")
+mark_as_advanced(XXHASH_VERSION_MAJOR XXHASH_VERSION_MINOR XXHASH_VERSION_RELEASE XXHASH_VERSION_STRING XXHASH_LIB_VERSION XXHASH_LIB_SOVERSION)
+
+if("${CMAKE_VERSION}" VERSION_LESS "3.13")
+    #message(WARNING "CMake ${CMAKE_VERSION} has no CMP0077 policy: options will erase uncached/untyped normal vars!")
+else()
+    cmake_policy (SET CMP0077 NEW)
+endif()
+if("${CMAKE_VERSION}" VERSION_LESS "3.0")
+    project(xxHash C)
+else()
+    cmake_policy (SET CMP0048 NEW)
+    project(xxHash
+        VERSION ${XXHASH_VERSION_STRING}
+        LANGUAGES C)
+endif()
+
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+  set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Project build type" FORCE)
+  set_property(CACHE CMAKE_BUILD_TYPE
+    PROPERTY STRINGS "Debug" "Release" "RelWithDebInfo" "MinSizeRel")
+endif()
+if(NOT CMAKE_CONFIGURATION_TYPES)
+  message(STATUS "xxHash build type: ${CMAKE_BUILD_TYPE}")
+endif()
+
+option(BUILD_SHARED_LIBS "Build shared library" ON)
+option(XXHASH_BUILD_XXHSUM "Build the xxhsum binary" ON)
+
+# If XXHASH is being bundled in another project, we don't want to
+# install anything.  However, we want to let people override this, so
+# we'll use the XXHASH_BUNDLED_MODE variable to let them do that; just
+# set it to OFF in your project before you add_subdirectory(xxhash/cmake_unofficial).
+if(NOT DEFINED XXHASH_BUNDLED_MODE)
+  if("${PROJECT_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
+    set(XXHASH_BUNDLED_MODE OFF)
+  else()
+    set(XXHASH_BUNDLED_MODE ON)
+  endif()
+endif()
+set(XXHASH_BUNDLED_MODE ${XXHASH_BUNDLED_MODE} CACHE BOOL "" FORCE)
+mark_as_advanced(XXHASH_BUNDLED_MODE)
+
+# Allow people to choose whether to build shared or static libraries
+# via the BUILD_SHARED_LIBS option unless we are in bundled mode, in
+# which case we always use static libraries.
+include(CMakeDependentOption)
+CMAKE_DEPENDENT_OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON "NOT XXHASH_BUNDLED_MODE" OFF)
+
+# libxxhash
+add_library(xxhash "${XXHASH_DIR}/xxhash.c")
+add_library(${PROJECT_NAME}::xxhash ALIAS xxhash)
+
+target_include_directories(xxhash
+  PUBLIC
+    $<BUILD_INTERFACE:${XXHASH_DIR}>
+    $<INSTALL_INTERFACE:include/>)
+if (BUILD_SHARED_LIBS)
+  target_compile_definitions(xxhash PUBLIC XXH_EXPORT)
+endif ()
+set_target_properties(xxhash PROPERTIES
+  SOVERSION "${XXHASH_VERSION_STRING}"
+  VERSION "${XXHASH_VERSION_STRING}")
+
+if(XXHASH_BUILD_XXHSUM)
+  set(XXHSUM_DIR "${XXHASH_DIR}/cli")
+  # xxhsum
+  add_executable(xxhsum "${XXHASH_DIR}/xxhsum.c"
+                        "${XXHSUM_DIR}/xsum_os_specific.c"
+                        "${XXHSUM_DIR}/xsum_output.c"
+                        "${XXHSUM_DIR}/xsum_sanity_check.c"
+                )
+  add_executable(${PROJECT_NAME}::xxhsum ALIAS xxhsum)
+
+  target_link_libraries(xxhsum PRIVATE xxhash)
+  target_include_directories(xxhsum PRIVATE "${XXHASH_DIR}")
+endif(XXHASH_BUILD_XXHSUM)
+
+# Extra warning flags
+include (CheckCCompilerFlag)
+if (XXHASH_C_FLAGS)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${XXHASH_C_FLAGS}")
+endif()
+foreach (flag
+    -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow
+    -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement
+    -Wstrict-prototypes -Wundef)
+  # Because https://gcc.gnu.org/wiki/FAQ#wnowarning
+  string(REGEX REPLACE "\\-Wno\\-(.+)" "-W\\1" flag_to_test "${flag}")
+  string(REGEX REPLACE "[^a-zA-Z0-9]+" "_" test_name "CFLAG_${flag_to_test}")
+
+  check_c_compiler_flag("${ADD_COMPILER_FLAGS_PREPEND} ${flag_to_test}" ${test_name})
+
+  if(${test_name})
+    set(CMAKE_C_FLAGS "${flag} ${CMAKE_C_FLAGS}")
+  endif()
+
+  unset(test_name)
+  unset(flag_to_test)
+endforeach (flag)
+
+if(NOT XXHASH_BUNDLED_MODE)
+  include(GNUInstallDirs)
+
+  install(TARGETS xxhash
+    EXPORT xxHashTargets
+    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+    LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
+  install(FILES "${XXHASH_DIR}/xxhash.h"
+    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
+  install(FILES "${XXHASH_DIR}/xxh3.h"
+    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
+  if(XXHASH_BUILD_XXHSUM)
+    install(TARGETS xxhsum
+      EXPORT xxHashTargets
+      RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+    install(FILES "${XXHASH_DIR}/xxhsum.1"
+      DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
+  endif(XXHASH_BUILD_XXHSUM)
+
+  include(CMakePackageConfigHelpers)
+
+  set(xxHash_VERSION_CONFIG "${PROJECT_BINARY_DIR}/xxHashConfigVersion.cmake")
+  set(xxHash_PROJECT_CONFIG "${PROJECT_BINARY_DIR}/xxHashConfig.cmake")
+  set(xxHash_TARGETS_CONFIG "${PROJECT_BINARY_DIR}/xxHashTargets.cmake")
+  set(xxHash_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/xxHash/")
+  write_basic_package_version_file(${xxHash_VERSION_CONFIG}
+    VERSION ${XXHASH_VERSION_STRING}
+    COMPATIBILITY AnyNewerVersion)
+  configure_package_config_file(
+    ${PROJECT_SOURCE_DIR}/xxHashConfig.cmake.in
+    ${xxHash_PROJECT_CONFIG}
+    INSTALL_DESTINATION ${xxHash_CONFIG_INSTALL_DIR})
+  if("${CMAKE_VERSION}" VERSION_LESS "3.0")
+      set(XXHASH_EXPORT_SET xxhash)
+      if(XXHASH_BUILD_XXHSUM)
+        set(XXHASH_EXPORT_SET ${XXHASH_EXPORT_SET} xxhsum)
+      endif()
+      export(TARGETS ${XXHASH_EXPORT_SET}
+      FILE ${xxHash_TARGETS_CONFIG}
+      NAMESPACE ${PROJECT_NAME}::)
+  else()
+    export(EXPORT xxHashTargets
+      FILE ${xxHash_TARGETS_CONFIG}
+      NAMESPACE ${PROJECT_NAME}::)
+  endif()
+
+  install(FILES ${xxHash_PROJECT_CONFIG} ${xxHash_VERSION_CONFIG}
+    DESTINATION ${xxHash_CONFIG_INSTALL_DIR})
+  install(EXPORT xxHashTargets
+    DESTINATION ${xxHash_CONFIG_INSTALL_DIR}
+    NAMESPACE ${PROJECT_NAME}::)
+endif(NOT XXHASH_BUNDLED_MODE)
diff --git a/grpc/third_party/xxhash/cmake_unofficial/README.md b/grpc/third_party/xxhash/cmake_unofficial/README.md
new file mode 100644
index 0000000..66df790
--- /dev/null
+++ b/grpc/third_party/xxhash/cmake_unofficial/README.md
@@ -0,0 +1,36 @@
+
+## Usage
+
+### Way 1: import targets
+Build xxHash targets:
+
+    cd </path/to/xxHash/>
+    mkdir build
+    cd build
+    cmake ../cmake_unofficial [options]
+    cmake --build .
+    cmake --build . --target install #optional
+
+Where possible options are:
+- `-DXXHASH_BUILD_ENABLE_INLINE_API=<ON|OFF>`: adds xxhash.c for the `-DXXH_INLINE_ALL` api. ON by default.
+- `-DXXHASH_BUILD_XXHSUM=<ON|OFF>`: build the command line binary. ON by default
+- `-DBUILD_SHARED_LIBS=<ON|OFF>`: build dynamic library. ON by default.
+- `-DCMAKE_INSTALL_PREFIX=<path>`: use custom install prefix path.
+
+Add lines into downstream CMakeLists.txt:
+
+    find_package(xxHash 0.7 CONFIG REQUIRED)
+    ...
+    target_link_libraries(MyTarget PRIVATE xxHash::xxhash)
+
+### Way 2: Add subdirectory
+Add lines into downstream CMakeLists.txt:
+
+    option(BUILD_SHARED_LIBS "Build shared libs" OFF) #optional
+    ...
+    set(XXHASH_BUILD_ENABLE_INLINE_API OFF) #optional
+    set(XXHASH_BUILD_XXHSUM OFF) #optional
+    add_subdirectory(</path/to/xxHash/cmake_unofficial/> </path/to/xxHash/build/> EXCLUDE_FROM_ALL)
+    ...
+    target_link_libraries(MyTarget PRIVATE xxHash::xxhash)
+
diff --git a/grpc/third_party/xxhash/cmake_unofficial/xxHashConfig.cmake.in b/grpc/third_party/xxhash/cmake_unofficial/xxHashConfig.cmake.in
new file mode 100644
index 0000000..fd282be
--- /dev/null
+++ b/grpc/third_party/xxhash/cmake_unofficial/xxHashConfig.cmake.in
@@ -0,0 +1,4 @@
+@PACKAGE_INIT@
+
+include(${CMAKE_CURRENT_LIST_DIR}/xxHashTargets.cmake)
+
diff --git a/grpc/third_party/xxhash/doc/README.md b/grpc/third_party/xxhash/doc/README.md
new file mode 100644
index 0000000..a73ad72
--- /dev/null
+++ b/grpc/third_party/xxhash/doc/README.md
@@ -0,0 +1,9 @@
+xxHash Specification
+=======================
+
+This directory contains material defining the xxHash algorithm.
+It's described in [this specification document](xxhash_spec.md).
+
+The algorithm is also be illustrated by a [simple educational library](https://github.com/easyaspi314/xxhash-clean),
+written by @easyaspi314 and designed for readability
+(as opposed to the reference library which is designed for speed).
diff --git a/grpc/third_party/xxhash/doc/xxhash.cry b/grpc/third_party/xxhash/doc/xxhash.cry
new file mode 100644
index 0000000..984e1c8
--- /dev/null
+++ b/grpc/third_party/xxhash/doc/xxhash.cry
@@ -0,0 +1,206 @@
+module xxhash where
+
+/**
+ * The 32-bit variant of xxHash. The first argument is the sequence
+ * of L bytes to hash. The second argument is a seed value.
+ */
+XXH32 : {L} (fin L) => [L][8] -> [32] -> [32]
+XXH32 input seed = XXH32_avalanche acc1
+  where (stripes16 # stripes4 # stripes1) = input
+        accR = foldl XXH32_rounds (XXH32_init seed) (split stripes16 : [L/16][16][8])
+        accL = `(L % 2^^32) + if (`L:Integer) < 16
+                              then seed + PRIME32_5
+                              else XXH32_converge accR
+        acc4 = foldl XXH32_digest4 accL (split stripes4 : [(L%16)/4][4][8])
+        acc1 = foldl XXH32_digest1 acc4 (stripes1 : [L%4][8])
+
+/**
+ * The 64-bit variant of xxHash. The first argument is the sequence
+ * of L bytes to hash. The second argument is a seed value.
+ */
+XXH64 : {L} (fin L) => [L][8] -> [64] -> [64]
+XXH64 input seed = XXH64_avalanche acc1
+  where (stripes32 # stripes8 # stripes4 # stripes1) = input
+        accR = foldl XXH64_rounds (XXH64_init seed) (split stripes32 : [L/32][32][8])
+        accL = `(L % 2^^64) + if (`L:Integer) < 32
+                              then seed + PRIME64_5
+                              else XXH64_converge accR
+        acc8 = foldl XXH64_digest8 accL (split stripes8 : [(L%32)/8][8][8])
+        acc4 = foldl XXH64_digest4 acc8 (split stripes4 : [(L%8)/4][4][8])
+        acc1 = foldl XXH64_digest1 acc4 (stripes1 : [L%4][8])
+
+private
+
+  //Utility functions
+
+  /**
+   * Combines a sequence of bytes into a word using the little-endian
+   * convention.
+   */
+  toLE bytes = join (reverse bytes)
+
+  //32-bit xxHash helper functions
+
+  //32-bit prime number constants
+  PRIME32_1 = 0x9E3779B1 : [32]
+  PRIME32_2 = 0x85EBCA77 : [32]
+  PRIME32_3 = 0xC2B2AE3D : [32]
+  PRIME32_4 = 0x27D4EB2F : [32]
+  PRIME32_5 = 0x165667B1 : [32]
+
+  /**
+   * The property shows that the hexadecimal representation of the
+   * PRIME32 constants is the same as the binary representation.
+   */
+  property PRIME32s_as_bits_correct =
+    (PRIME32_1 == 0b10011110001101110111100110110001) /\
+    (PRIME32_2 == 0b10000101111010111100101001110111) /\
+    (PRIME32_3 == 0b11000010101100101010111000111101) /\
+    (PRIME32_4 == 0b00100111110101001110101100101111) /\
+    (PRIME32_5 == 0b00010110010101100110011110110001)
+
+  /**
+   * This function initializes the four internal accumulators of XXH32.
+   */
+  XXH32_init : [32] -> [4][32]
+  XXH32_init seed = [acc1, acc2, acc3, acc4]
+    where acc1 = seed + PRIME32_1 + PRIME32_2
+          acc2 = seed + PRIME32_2
+          acc3 = seed + 0
+          acc4 = seed - PRIME32_1
+
+  /**
+   * This processes a single lane of the main round function of XXH32.
+   */
+  XXH32_round : [32] -> [32] -> [32]
+  XXH32_round accN laneN = ((accN + laneN * PRIME32_2) <<< 13) * PRIME32_1
+
+  /**
+   * This is the main round function of XXH32 and processes a stripe,
+   * i.e. 4 lanes with 4 bytes each.
+   */
+  XXH32_rounds : [4][32] -> [16][8] -> [4][32]
+  XXH32_rounds accs stripe =
+    [ XXH32_round accN (toLE laneN) | accN <- accs | laneN <- split stripe ]
+
+  /**
+   * This function combines the four lane accumulators into a single
+   * 32-bit value.
+   */
+  XXH32_converge : [4][32] -> [32]
+  XXH32_converge [acc1, acc2, acc3, acc4] =
+    (acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18)
+
+  /**
+   * This function digests a four byte lane
+   */
+  XXH32_digest4 : [32] -> [4][8] -> [32]
+  XXH32_digest4 acc lane = ((acc + toLE lane * PRIME32_3) <<< 17) * PRIME32_4
+
+  /**
+   * This function digests a single byte lane
+   */
+  XXH32_digest1 : [32] -> [8] -> [32]
+  XXH32_digest1 acc lane = ((acc + (0 # lane) * PRIME32_5) <<< 11) * PRIME32_1
+
+  /**
+   * This function ensures that all input bits have a chance to impact
+   * any bit in the output digest, resulting in an unbiased
+   * distribution.
+   */
+  XXH32_avalanche : [32] -> [32]
+  XXH32_avalanche acc0 = acc5
+    where acc1 = acc0 ^ (acc0 >> 15)
+          acc2 = acc1 * PRIME32_2
+          acc3 = acc2 ^ (acc2 >> 13)
+          acc4 = acc3 * PRIME32_3
+          acc5 = acc4 ^ (acc4 >> 16)
+
+  //64-bit xxHash helper functions
+
+  //64-bit prime number constants
+  PRIME64_1 = 0x9E3779B185EBCA87 : [64]
+  PRIME64_2 = 0xC2B2AE3D27D4EB4F : [64]
+  PRIME64_3 = 0x165667B19E3779F9 : [64]
+  PRIME64_4 = 0x85EBCA77C2B2AE63 : [64]
+  PRIME64_5 = 0x27D4EB2F165667C5 : [64]
+
+  /**
+   * The property shows that the hexadecimal representation of the
+   * PRIME64 constants is the same as the binary representation.
+   */
+  property PRIME64s_as_bits_correct =
+    (PRIME64_1 == 0b1001111000110111011110011011000110000101111010111100101010000111) /\
+    (PRIME64_2 == 0b1100001010110010101011100011110100100111110101001110101101001111) /\
+    (PRIME64_3 == 0b0001011001010110011001111011000110011110001101110111100111111001) /\
+    (PRIME64_4 == 0b1000010111101011110010100111011111000010101100101010111001100011) /\
+    (PRIME64_5 == 0b0010011111010100111010110010111100010110010101100110011111000101)
+
+  /**
+   * This function initializes the four internal accumulators of XXH64.
+   */
+  XXH64_init : [64] -> [4][64]
+  XXH64_init seed = [acc1, acc2, acc3, acc4]
+    where acc1 = seed + PRIME64_1 + PRIME64_2
+          acc2 = seed + PRIME64_2
+          acc3 = seed + 0
+          acc4 = seed - PRIME64_1
+
+  /**
+   * This processes a single lane of the main round function of XXH64.
+   */
+  XXH64_round : [64] -> [64] -> [64]
+  XXH64_round accN laneN = ((accN + laneN * PRIME64_2) <<< 31) * PRIME64_1
+
+  /**
+   * This is the main round function of XXH64 and processes a stripe,
+   * i.e. 4 lanes with 8 bytes each.
+   */
+  XXH64_rounds : [4][64] -> [32][8] -> [4][64]
+  XXH64_rounds accs stripe =
+    [ XXH64_round accN (toLE laneN) | accN <- accs | laneN <- split stripe ]
+
+  /**
+   * This is a helper function, used to merge the four lane accumulators.
+   */
+  mergeAccumulator : [64] -> [64] -> [64]
+  mergeAccumulator acc accN = (acc ^ XXH64_round 0 accN) * PRIME64_1 + PRIME64_4
+
+  /**
+   * This function combines the four lane accumulators into a single
+   * 64-bit value.
+   */
+  XXH64_converge : [4][64] -> [64]
+  XXH64_converge [acc1, acc2, acc3, acc4] =
+    foldl mergeAccumulator ((acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18)) [acc1, acc2, acc3, acc4]
+
+  /**
+   * This function digests an eight byte lane
+   */
+  XXH64_digest8 : [64] -> [8][8] -> [64]
+  XXH64_digest8 acc lane = ((acc ^ XXH64_round 0 (toLE lane)) <<< 27) * PRIME64_1 + PRIME64_4
+
+  /**
+   * This function digests a four byte lane
+   */
+  XXH64_digest4 : [64] -> [4][8] -> [64]
+  XXH64_digest4 acc lane = ((acc ^ (0 # toLE lane) * PRIME64_1) <<< 23) * PRIME64_2 + PRIME64_3
+
+  /**
+   * This function digests a single byte lane
+   */
+  XXH64_digest1 : [64] -> [8] -> [64]
+  XXH64_digest1 acc lane = ((acc ^ (0 # lane) * PRIME64_5) <<< 11) * PRIME64_1
+
+  /**
+   * This function ensures that all input bits have a chance to impact
+   * any bit in the output digest, resulting in an unbiased
+   * distribution.
+   */
+  XXH64_avalanche : [64] -> [64]
+  XXH64_avalanche acc0 = acc5
+    where acc1 = acc0 ^ (acc0 >> 33)
+          acc2 = acc1 * PRIME64_2
+          acc3 = acc2 ^ (acc2 >> 29)
+          acc4 = acc3 * PRIME64_3
+          acc5 = acc4 ^ (acc4 >> 32)
diff --git a/grpc/third_party/xxhash/doc/xxhash_spec.md b/grpc/third_party/xxhash/doc/xxhash_spec.md
new file mode 100644
index 0000000..af7ba90
--- /dev/null
+++ b/grpc/third_party/xxhash/doc/xxhash_spec.md
@@ -0,0 +1,317 @@
+xxHash fast digest algorithm
+======================
+
+### Notices
+
+Copyright (c) Yann Collet
+
+Permission is granted to copy and distribute this document
+for any purpose and without charge,
+including translations into other languages
+and incorporation into compilations,
+provided that the copyright notice and this notice are preserved,
+and that any substantive changes or deletions from the original
+are clearly marked.
+Distribution of this document is unlimited.
+
+### Version
+
+0.1.1 (10/10/18)
+
+
+Table of Contents
+---------------------
+- [Introduction](#introduction)
+- [XXH32 algorithm description](#xxh32-algorithm-description)
+- [XXH64 algorithm description](#xxh64-algorithm-description)
+- [Performance considerations](#performance-considerations)
+- [Reference Implementation](#reference-implementation)
+
+
+Introduction
+----------------
+
+This document describes the xxHash digest algorithm for both 32-bit and 64-bit variants, named `XXH32` and `XXH64`. The algorithm takes an input a message of arbitrary length and an optional seed value, then produces an output of 32 or 64-bit as "fingerprint" or "digest".
+
+xxHash is primarily designed for speed. It is labeled non-cryptographic, and is not meant to avoid intentional collisions (same digest for 2 different messages), or to prevent producing a message with a predefined digest.
+
+XXH32 is designed to be fast on 32-bit machines.
+XXH64 is designed to be fast on 64-bit machines.
+Both variants produce different output.
+However, a given variant shall produce exactly the same output, irrespective of the cpu / os used. In particular, the result remains identical whatever the endianness and width of the cpu is.
+
+### Operation notations
+
+All operations are performed modulo {32,64} bits. Arithmetic overflows are expected.
+`XXH32` uses 32-bit modular operations. `XXH64` uses 64-bit modular operations.
+
+- `+`: denotes modular addition
+- `*`: denotes modular multiplication
+- `X <<< s`: denotes the value obtained by circularly shifting (rotating) `X` left by `s` bit positions.
+- `X >> s`: denotes the value obtained by shifting `X` right by s bit positions. Upper `s` bits become `0`.
+- `X xor Y`: denotes the bit-wise XOR of `X` and `Y` (same width).
+
+
+XXH32 Algorithm Description
+-------------------------------------
+
+### Overview
+
+We begin by supposing that we have a message of any length `L` as input, and that we wish to find its digest. Here `L` is an arbitrary nonnegative integer; `L` may be zero. The following steps are performed to compute the digest of the message.
+
+The algorithm collect and transform input in _stripes_ of 16 bytes. The transforms are stored inside 4 "accumulators", each one storing an unsigned 32-bit value. Each accumulator can be processed independently in parallel, speeding up processing for cpu with multiple execution units.
+
+The algorithm uses 32-bits addition, multiplication, rotate, shift and xor operations. Many operations require some 32-bits prime number constants, all defined below:
+
+    static const u32 PRIME32_1 = 0x9E3779B1U;  // 0b10011110001101110111100110110001
+    static const u32 PRIME32_2 = 0x85EBCA77U;  // 0b10000101111010111100101001110111
+    static const u32 PRIME32_3 = 0xC2B2AE3DU;  // 0b11000010101100101010111000111101
+    static const u32 PRIME32_4 = 0x27D4EB2FU;  // 0b00100111110101001110101100101111
+    static const u32 PRIME32_5 = 0x165667B1U;  // 0b00010110010101100110011110110001
+
+These constants are prime numbers, and feature a good mix of bits 1 and 0, neither too regular, nor too dissymmetric. These properties help dispersion capabilities.
+
+### Step 1. Initialize internal accumulators
+
+Each accumulator gets an initial value based on optional `seed` input. Since the `seed` is optional, it can be `0`.
+
+        u32 acc1 = seed + PRIME32_1 + PRIME32_2;
+        u32 acc2 = seed + PRIME32_2;
+        u32 acc3 = seed + 0;
+        u32 acc4 = seed - PRIME32_1;
+
+#### Special case: input is less than 16 bytes
+
+When the input is too small (< 16 bytes), the algorithm will not process any stripes. Consequently, it will not make use of parallel accumulators.
+
+In this case, a simplified initialization is performed, using a single accumulator:
+
+      u32 acc  = seed + PRIME32_5;
+
+The algorithm then proceeds directly to step 4.
+
+### Step 2. Process stripes
+
+A stripe is a contiguous segment of 16 bytes.
+It is evenly divided into 4 _lanes_, of 4 bytes each.
+The first lane is used to update accumulator 1, the second lane is used to update accumulator 2, and so on.
+
+Each lane read its associated 32-bit value using __little-endian__ convention.
+
+For each {lane, accumulator}, the update process is called a _round_, and applies the following formula:
+
+    accN = accN + (laneN * PRIME32_2);
+    accN = accN <<< 13;
+    accN = accN * PRIME32_1;
+
+This shuffles the bits so that any bit from input _lane_ impacts several bits in output _accumulator_. All operations are performed modulo 2^32.
+
+Input is consumed one full stripe at a time. Step 2 is looped as many times as necessary to consume the whole input, except for the last remaining bytes which cannot form a stripe (< 16 bytes).
+When that happens, move to step 3.
+
+### Step 3. Accumulator convergence
+
+All 4 lane accumulators from the previous steps are merged to produce a single remaining accumulator of the same width (32-bit). The associated formula is as follows:
+
+    acc = (acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18);
+
+### Step 4. Add input length
+
+The input total length is presumed known at this stage. This step is just about adding the length to accumulator, so that it participates to final mixing.
+
+    acc = acc + (u32)inputLength;
+
+Note that, if input length is so large that it requires more than 32-bits, only the lower 32-bits are added to the accumulator.
+
+### Step 5. Consume remaining input
+
+There may be up to 15 bytes remaining to consume from the input.
+The final stage will digest them according to following pseudo-code:
+
+    while (remainingLength >= 4) {
+        lane = read_32bit_little_endian(input_ptr);
+        acc = acc + lane * PRIME32_3;
+        acc = (acc <<< 17) * PRIME32_4;
+        input_ptr += 4; remainingLength -= 4;
+    }
+
+    while (remainingLength >= 1) {
+        lane = read_byte(input_ptr);
+        acc = acc + lane * PRIME32_5;
+        acc = (acc <<< 11) * PRIME32_1;
+        input_ptr += 1; remainingLength -= 1;
+    }
+
+This process ensures that all input bytes are present in the final mix.
+
+### Step 6. Final mix (avalanche)
+
+The final mix ensures that all input bits have a chance to impact any bit in the output digest, resulting in an unbiased distribution. This is also called avalanche effect.
+
+    acc = acc xor (acc >> 15);
+    acc = acc * PRIME32_2;
+    acc = acc xor (acc >> 13);
+    acc = acc * PRIME32_3;
+    acc = acc xor (acc >> 16);
+
+### Step 7. Output
+
+The `XXH32()` function produces an unsigned 32-bit value as output.
+
+For systems which require to store and/or display the result in binary or hexadecimal format, the canonical format is defined to reproduce the same value as the natural decimal format, hence follows __big-endian__ convention (most significant byte first).
+
+
+XXH64 Algorithm Description
+-------------------------------------
+
+### Overview
+
+`XXH64`'s algorithm structure is very similar to `XXH32` one. The major difference is that `XXH64` uses 64-bit arithmetic, speeding up memory transfer for 64-bit compliant systems, but also relying on cpu capability to efficiently perform 64-bit operations.
+
+The algorithm collects and transforms input in _stripes_ of 32 bytes. The transforms are stored inside 4 "accumulators", each one storing an unsigned 64-bit value. Each accumulator can be processed independently in parallel, speeding up processing for cpu with multiple execution units.
+
+The algorithm uses 64-bit addition, multiplication, rotate, shift and xor operations. Many operations require some 64-bit prime number constants, all defined below:
+
+    static const u64 PRIME64_1 = 0x9E3779B185EBCA87ULL;  // 0b1001111000110111011110011011000110000101111010111100101010000111
+    static const u64 PRIME64_2 = 0xC2B2AE3D27D4EB4FULL;  // 0b1100001010110010101011100011110100100111110101001110101101001111
+    static const u64 PRIME64_3 = 0x165667B19E3779F9ULL;  // 0b0001011001010110011001111011000110011110001101110111100111111001
+    static const u64 PRIME64_4 = 0x85EBCA77C2B2AE63ULL;  // 0b1000010111101011110010100111011111000010101100101010111001100011
+    static const u64 PRIME64_5 = 0x27D4EB2F165667C5ULL;  // 0b0010011111010100111010110010111100010110010101100110011111000101
+
+These constants are prime numbers, and feature a good mix of bits 1 and 0, neither too regular, nor too dissymmetric. These properties help dispersion capabilities.
+
+### Step 1. Initialise internal accumulators
+
+Each accumulator gets an initial value based on optional `seed` input. Since the `seed` is optional, it can be `0`.
+
+        u64 acc1 = seed + PRIME64_1 + PRIME64_2;
+        u64 acc2 = seed + PRIME64_2;
+        u64 acc3 = seed + 0;
+        u64 acc4 = seed - PRIME64_1;
+
+#### Special case: input is less than 32 bytes
+
+When the input is too small (< 32 bytes), the algorithm will not process any stripes. Consequently, it will not make use of parallel accumulators.
+
+In this case, a simplified initialization is performed, using a single accumulator:
+
+      u64 acc  = seed + PRIME64_5;
+
+The algorithm then proceeds directly to step 4.
+
+### Step 2. Process stripes
+
+A stripe is a contiguous segment of 32 bytes.
+It is evenly divided into 4 _lanes_, of 8 bytes each.
+The first lane is used to update accumulator 1, the second lane is used to update accumulator 2, and so on.
+
+Each lane read its associated 64-bit value using __little-endian__ convention.
+
+For each {lane, accumulator}, the update process is called a _round_, and applies the following formula:
+
+    round(accN,laneN):
+    accN = accN + (laneN * PRIME64_2);
+    accN = accN <<< 31;
+    return accN * PRIME64_1;
+
+This shuffles the bits so that any bit from input _lane_ impacts several bits in output _accumulator_. All operations are performed modulo 2^64.
+
+Input is consumed one full stripe at a time. Step 2 is looped as many times as necessary to consume the whole input, except for the last remaining bytes which cannot form a stripe (< 32 bytes).
+When that happens, move to step 3.
+
+### Step 3. Accumulator convergence
+
+All 4 lane accumulators from previous steps are merged to produce a single remaining accumulator of same width (64-bit). The associated formula is as follows.
+
+Note that accumulator convergence is more complex than 32-bit variant, and requires to define another function called _mergeAccumulator()_:
+
+    mergeAccumulator(acc,accN):
+    acc  = acc xor round(0, accN);
+    acc  = acc * PRIME64_1;
+    return acc + PRIME64_4;
+
+which is then used in the convergence formula:
+
+    acc = (acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18);
+    acc = mergeAccumulator(acc, acc1);
+    acc = mergeAccumulator(acc, acc2);
+    acc = mergeAccumulator(acc, acc3);
+    acc = mergeAccumulator(acc, acc4);
+
+### Step 4. Add input length
+
+The input total length is presumed known at this stage. This step is just about adding the length to accumulator, so that it participates to final mixing.
+
+    acc = acc + inputLength;
+
+### Step 5. Consume remaining input
+
+There may be up to 31 bytes remaining to consume from the input.
+The final stage will digest them according to following pseudo-code:
+
+    while (remainingLength >= 8) {
+        lane = read_64bit_little_endian(input_ptr);
+        acc = acc xor round(0, lane);
+        acc = (acc <<< 27) * PRIME64_1;
+        acc = acc + PRIME64_4;
+        input_ptr += 8; remainingLength -= 8;
+    }
+
+    if (remainingLength >= 4) {
+        lane = read_32bit_little_endian(input_ptr);
+        acc = acc xor (lane * PRIME64_1);
+        acc = (acc <<< 23) * PRIME64_2;
+        acc = acc + PRIME64_3;
+        input_ptr += 4; remainingLength -= 4;
+    }
+
+    while (remainingLength >= 1) {
+        lane = read_byte(input_ptr);
+        acc = acc xor (lane * PRIME64_5);
+        acc = (acc <<< 11) * PRIME64_1;
+        input_ptr += 1; remainingLength -= 1;
+    }
+
+This process ensures that all input bytes are present in the final mix.
+
+### Step 6. Final mix (avalanche)
+
+The final mix ensures that all input bits have a chance to impact any bit in the output digest, resulting in an unbiased distribution. This is also called avalanche effect.
+
+    acc = acc xor (acc >> 33);
+    acc = acc * PRIME64_2;
+    acc = acc xor (acc >> 29);
+    acc = acc * PRIME64_3;
+    acc = acc xor (acc >> 32);
+
+### Step 7. Output
+
+The `XXH64()` function produces an unsigned 64-bit value as output.
+
+For systems which require to store and/or display the result in binary or hexadecimal format, the canonical format is defined to reproduce the same value as the natural decimal format, hence follows __big-endian__ convention (most significant byte first).
+
+Performance considerations
+----------------------------------
+
+The xxHash algorithms are simple and compact to implement. They provide a system independent "fingerprint" or digest of a message of arbitrary length.
+
+The algorithm allows input to be streamed and processed in multiple steps. In such case, an internal buffer is needed to ensure data is presented to the algorithm in full stripes.
+
+On 64-bit systems, the 64-bit variant `XXH64` is generally faster to compute, so it is a recommended variant, even when only 32-bit are needed.
+
+On 32-bit systems though, positions are reversed: `XXH64` performance is reduced, due to its usage of 64-bit arithmetic. `XXH32` becomes a faster variant.
+
+
+Reference Implementation
+----------------------------------------
+
+A reference library written in C is available at https://www.xxhash.com.
+The web page also links to multiple other implementations written in many different languages.
+It links to the [github project page](https://github.com/Cyan4973/xxHash) where an [issue board](https://github.com/Cyan4973/xxHash/issues) can be used for further public discussions on the topic.
+
+
+Version changes
+--------------------
+v0.7.3: Minor fixes
+v0.1.1: added a note on rationale for selection of constants
+v0.1.0: initial release
diff --git a/grpc/third_party/xxhash/libxxhash.pc.in b/grpc/third_party/xxhash/libxxhash.pc.in
new file mode 100644
index 0000000..28c1644
--- /dev/null
+++ b/grpc/third_party/xxhash/libxxhash.pc.in
@@ -0,0 +1,15 @@
+#   xxHash - Extremely fast hash algorithm
+#   Copyright (C) 2012-2020, Yann Collet, Facebook
+#   BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+
+prefix=@PREFIX@
+exec_prefix=@EXECPREFIX@
+includedir=${prefix}/@INCLUDEDIR@
+libdir=${exec_prefix}/@LIBDIR@
+
+Name: xxhash
+Description: extremely fast hash algorithm
+URL: http://www.xxhash.com/
+Version: @VERSION@
+Libs: -L${libdir} -lxxhash
+Cflags: -I${includedir}
diff --git a/grpc/third_party/xxhash/tests/Makefile b/grpc/third_party/xxhash/tests/Makefile
new file mode 100644
index 0000000..092711a
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/Makefile
@@ -0,0 +1,83 @@
+CFLAGS += -Wall -Wextra -Wundef -g
+
+NM = nm
+GREP = grep
+
+# Define *.exe as extension for Windows systems
+ifneq (,$(filter Windows%,$(OS)))
+EXT =.exe
+else
+EXT =
+endif
+
+ifneq (,$(filter %UTF-8,$(LANG)))
+ENABLE_UNICODE ?= 1
+else
+ENABLE_UNICODE ?= 0
+endif
+
+.PHONY: default
+default: all
+
+.PHONY: all
+all: test
+
+.PHONY: test
+test: test_multiInclude test_unicode
+
+.PHONY: test_multiInclude
+test_multiInclude:
+	@$(MAKE) clean
+	# compile without xxhash.o, ensure symbols exist within target
+	# Note: built using only default rules
+	$(MAKE) multiInclude
+	@$(MAKE) clean
+	# compile with xxhash.o, to detect duplicated symbols
+	$(MAKE) multiInclude_withxxhash
+	@$(MAKE) clean
+	# Note: XXH_INLINE_ALL with XXH_NAMESPACE is currently disabled
+	# compile with XXH_NAMESPACE
+	# CPPFLAGS=-DXXH_NAMESPACE=TESTN_ $(MAKE) multiInclude_withxxhash
+	# no symbol prefixed TESTN_ should exist
+	# ! $(NM) multiInclude_withxxhash | $(GREP) TESTN_
+	#$(MAKE) clean
+	# compile with XXH_NAMESPACE and without xxhash.o
+	# CPPFLAGS=-DXXH_NAMESPACE=TESTN_ $(MAKE) multiInclude
+	# no symbol prefixed TESTN_ should exist
+	# ! $(NM) multiInclude | $(GREP) TESTN_
+	#@$(MAKE) clean
+
+.PHONY: test_ppc_redefine
+test_ppc_redefine: ppc_define.c
+	@$(MAKE) clean
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $^
+
+xxhsum$(EXT): ../xxhash.c ../xxhash.h ../xxhsum.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -DXXH_INLINE_ALL ../xxhsum.c -o $@
+
+# Make sure that Unicode filenames work.
+# https://github.com/Cyan4973/xxHash/issues/293
+.PHONY: test_unicode
+ifeq (0,$(ENABLE_UNICODE))
+test_unicode:
+	@echo "Skipping Unicode test, your terminal doesn't appear to support UTF-8."
+	@echo "Try with ENABLE_UNICODE=1"
+else
+test_unicode: xxhsum$(EXT) generate_unicode_test.c
+	# Generate a Unicode filename test dynamically
+	# to keep UTF-8 out of the source tree.
+	$(CC) $(CFLAGS) $(LDFLAGS) generate_unicode_test.c -o generate_unicode_test$(EXT)
+	./generate_unicode_test$(EXT)
+	$(SHELL) ./unicode_test.sh
+endif
+
+xxhash.o: ../xxhash.c ../xxhash.h
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -c -o $@ $<
+
+multiInclude_withxxhash: multiInclude.o xxhash.o
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^
+
+clean:
+	@$(RM) *.o
+	@$(RM) multiInclude multiInclude_withxxhash
+	@$(RM) *.unicode generate_unicode_test$(EXT) unicode_test.* xxhsum$(EXT)
diff --git a/grpc/third_party/xxhash/tests/bench/.gitignore b/grpc/third_party/xxhash/tests/bench/.gitignore
new file mode 100644
index 0000000..ede2d58
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/.gitignore
@@ -0,0 +1,11 @@
+# build artifacts
+
+*.o
+benchHash
+benchHash32
+benchHash_avx2
+benchHash_hw
+
+# test files
+
+test*
diff --git a/grpc/third_party/xxhash/tests/bench/LICENSE b/grpc/third_party/xxhash/tests/bench/LICENSE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/LICENSE
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/grpc/third_party/xxhash/tests/bench/Makefile b/grpc/third_party/xxhash/tests/bench/Makefile
new file mode 100644
index 0000000..cdccfff
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/Makefile
@@ -0,0 +1,67 @@
+# ################################################################
+# xxHash benchHash Makefile
+# Copyright (C) 2019-2020 Yann Collet
+#
+# GPL v2 License
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# You can contact the author at:
+#   - xxHash homepage: https://www.xxhash.com
+#   - xxHash source repository: https://github.com/Cyan4973/xxHash
+# ################################################################
+# benchHash: A generic benchmark for hash algorithms
+#            measuring throughput, latency and bandwidth
+# ################################################################
+
+
+CPPFLAGS += -I../..   # directory of xxHash source files
+CFLAGS   ?= -O3
+CFLAGS   += -std=c99 -Wall -Wextra -Wstrict-aliasing=1
+CFLAGS   += $(MOREFLAGS)   # custom way to add flags
+CXXFLAGS ?= -O3
+LDFLAGS  += $(MOREFLAGS)
+
+
+OBJ_LIST  = main.o bhDisplay.o benchHash.o benchfn.o timefn.o
+
+
+default: benchHash
+
+all: benchHash
+
+benchHash32: CFLAGS   += -m32
+benchHash32: CXXFLAGS += -m32
+
+benchHash_avx2: CFLAGS   += -mavx2
+benchHash_avx2: CXXFLAGS += -mavx2
+
+benchHash_hw: CPPFLAGS += -DHARDWARE_SUPPORT
+benchHash_hw: CFLAGS   += -mavx2 -maes
+benchHash_hw: CXXFLAGS += -mavx2 -mpclmul -std=c++14
+
+benchHash benchHash32 benchHash_avx2 benchHash_nosimd benchHash_hw: $(OBJ_LIST)
+	$(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
+
+
+main.o: bhDisplay.h hashes.h
+
+bhDisplay.o: bhDisplay.h benchHash.h
+
+benchHash.o: benchHash.h
+
+
+clean:
+	$(RM) *.o benchHash benchHash32 benchHash_avx2 benchHash_hw
diff --git a/grpc/third_party/xxhash/tests/bench/benchHash.c b/grpc/third_party/xxhash/tests/bench/benchHash.c
new file mode 100644
index 0000000..05739c7
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/benchHash.c
@@ -0,0 +1,164 @@
+/*
+*  Hash benchmark module
+*  Part of the xxHash project
+*  Copyright (C) 2019-2020 Yann Collet
+*
+*  GPL v2 License
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License along
+*  with this program; if not, write to the Free Software Foundation, Inc.,
+*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+*  You can contact the author at:
+*  - xxHash homepage: https://www.xxhash.com
+*  - xxHash source repository: https://github.com/Cyan4973/xxHash
+*/
+
+/* benchmark hash functions */
+
+#include <stdlib.h>   // malloc
+#include <assert.h>
+
+#include "benchHash.h"
+
+
+static void initBuffer(void* buffer, size_t size)
+{
+    const unsigned long long k1 = 11400714785074694791ULL;   /* 0b1001111000110111011110011011000110000101111010111100101010000111 */
+    const unsigned long long k2 = 14029467366897019727ULL;   /* 0b1100001010110010101011100011110100100111110101001110101101001111 */
+    unsigned long long acc = k2;
+    unsigned char* const p = (unsigned char*)buffer;
+    for (size_t s = 0; s < size; s++) {
+        acc *= k1;
+        p[s] = (unsigned char)(acc >> 56);
+    }
+}
+
+
+#define MARGIN_FOR_LATENCY 1024
+#define START_MASK (MARGIN_FOR_LATENCY-1)
+
+typedef size_t (*sizeFunction_f)(size_t targetSize);
+
+/*
+ * bench_hash_internal():
+ * Benchmarks hashfn repeateadly over single input of size `size`
+ * return: nb of hashes per second
+ */
+static double
+bench_hash_internal(BMK_benchFn_t hashfn, void* payload,
+                    size_t nbBlocks, sizeFunction_f selectSize, size_t size,
+                    unsigned total_time_ms, unsigned iter_time_ms)
+{
+    BMK_timedFnState_shell shell;
+    BMK_timedFnState_t* const txf = BMK_initStatic_timedFnState(&shell, sizeof(shell), total_time_ms, iter_time_ms);
+    assert(txf != NULL);
+
+    size_t const srcSize = (size_t)size;
+    size_t const srcBufferSize = srcSize + MARGIN_FOR_LATENCY;
+    void* const srcBuffer = malloc(srcBufferSize);
+    assert(srcBuffer != NULL);
+    initBuffer(srcBuffer, srcBufferSize);
+    #define FAKE_DSTSIZE 32
+    size_t const dstSize = FAKE_DSTSIZE;
+    char dstBuffer_static[FAKE_DSTSIZE] = {0};
+
+    #define NB_BLOCKS_MAX 1024
+    const void* srcBuffers[NB_BLOCKS_MAX];
+    size_t srcSizes[NB_BLOCKS_MAX];
+    void* dstBuffers[NB_BLOCKS_MAX];
+    size_t dstCapacities[NB_BLOCKS_MAX];
+    assert(nbBlocks < NB_BLOCKS_MAX);
+
+    assert(size > 0);
+    for (size_t n=0; n < nbBlocks; n++) {
+        srcBuffers[n] = srcBuffer;
+        srcSizes[n] = selectSize(size);
+        dstBuffers[n] = dstBuffer_static;
+        dstCapacities[n] = dstSize;
+    }
+
+
+    BMK_benchParams_t params = {
+        .benchFn = hashfn,
+        .benchPayload = payload,
+        .initFn = NULL,
+        .initPayload = NULL,
+        .errorFn = NULL,
+        .blockCount = nbBlocks,
+        .srcBuffers = srcBuffers,
+        .srcSizes = srcSizes,
+        .dstBuffers = dstBuffers,
+        .dstCapacities = dstCapacities,
+        .blockResults = NULL
+    };
+    BMK_runOutcome_t result;
+
+    while (!BMK_isCompleted_TimedFn(txf)) {
+        result = BMK_benchTimedFn(txf, params);
+        assert(BMK_isSuccessful_runOutcome(result));
+    }
+
+    BMK_runTime_t const runTime = BMK_extract_runTime(result);
+
+    free(srcBuffer);
+    assert(runTime.nanoSecPerRun != 0);
+    return (1000000000U / runTime.nanoSecPerRun) * nbBlocks;
+
+}
+
+
+static size_t rand_1_N(size_t N) { return ((size_t)rand() % N)  + 1; }
+
+static size_t identity(size_t s) { return s; }
+
+static size_t
+benchLatency(const void* src, size_t srcSize,
+                   void* dst, size_t dstCapacity,
+                   void* customPayload)
+{
+    (void)dst; (void)dstCapacity;
+    BMK_benchFn_t benchfn = (BMK_benchFn_t)customPayload;
+    static size_t hash = 0;
+
+    const void* const start = (const char*)src + (hash & START_MASK);
+
+    return hash = benchfn(start, srcSize, dst, dstCapacity, NULL);
+}
+
+
+
+#ifndef SIZE_TO_HASH_PER_ROUND
+#  define SIZE_TO_HASH_PER_ROUND 200000
+#endif
+
+#ifndef NB_HASH_ROUNDS_MAX
+#  define NB_HASH_ROUNDS_MAX 1000
+#endif
+
+double bench_hash(BMK_benchFn_t hashfn,
+                  BMK_benchMode benchMode,
+                  size_t size, BMK_sizeMode sizeMode,
+                  unsigned total_time_ms, unsigned iter_time_ms)
+{
+    sizeFunction_f const sizef = (sizeMode == BMK_fixedSize) ? identity : rand_1_N;
+    BMK_benchFn_t const benchfn = (benchMode == BMK_throughput) ? hashfn : benchLatency;
+    BMK_benchFn_t const payload = (benchMode == BMK_throughput) ? NULL : hashfn;
+
+    size_t nbBlocks = (SIZE_TO_HASH_PER_ROUND / size) + 1;
+    if (nbBlocks > NB_HASH_ROUNDS_MAX) nbBlocks = NB_HASH_ROUNDS_MAX;
+
+    return bench_hash_internal(benchfn, payload,
+                               nbBlocks, sizef, size,
+                               total_time_ms, iter_time_ms);
+}
diff --git a/grpc/third_party/xxhash/tests/bench/benchHash.h b/grpc/third_party/xxhash/tests/bench/benchHash.h
new file mode 100644
index 0000000..6c9ba91
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/benchHash.h
@@ -0,0 +1,67 @@
+/*
+*  Hash benchmark module
+*  Part of the xxHash project
+*  Copyright (C) 2019-2020 Yann Collet
+*
+*  GPL v2 License
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License along
+*  with this program; if not, write to the Free Software Foundation, Inc.,
+*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+*  You can contact the author at:
+*  - xxHash homepage: https://www.xxhash.com
+*  - xxHash source repository: https://github.com/Cyan4973/xxHash
+*/
+
+
+#ifndef BENCH_HASH_H_983426678
+#define BENCH_HASH_H_983426678
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* ===  Dependencies  === */
+
+#include "benchfn.h"   /* BMK_benchFn_t */
+
+
+/* ===  Declarations  === */
+
+typedef enum { BMK_throughput, BMK_latency } BMK_benchMode;
+
+typedef enum { BMK_fixedSize,   /* hash always `size` bytes */
+               BMK_randomSize,  /* hash a random nb of bytes, between 1 and `size` (inclusive) */
+} BMK_sizeMode;
+
+/*
+ * bench_hash():
+ * Returns speed expressed as nb hashes per second.
+ * total_time_ms: time spent benchmarking the hash function with given parameters
+ * iter_time_ms: time spent for one round. If multiple rounds are run,
+ *               bench_hash() will report the speed of best round.
+ */
+double bench_hash(BMK_benchFn_t hashfn,
+                  BMK_benchMode benchMode,
+                  size_t size, BMK_sizeMode sizeMode,
+                  unsigned total_time_ms, unsigned iter_time_ms);
+
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* BENCH_HASH_H_983426678 */
diff --git a/grpc/third_party/xxhash/tests/bench/benchfn.c b/grpc/third_party/xxhash/tests/bench/benchfn.c
new file mode 100644
index 0000000..ec7e9a2
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/benchfn.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2016-2020 Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+
+/* *************************************
+*  Includes
+***************************************/
+#include <stdlib.h>      /* malloc, free */
+#include <string.h>      /* memset */
+#undef NDEBUG            /* assert must not be disabled */
+#include <assert.h>      /* assert */
+
+#include "timefn.h"        /* UTIL_time_t, UTIL_getTime */
+#include "benchfn.h"
+
+
+/* *************************************
+*  Constants
+***************************************/
+#define TIMELOOP_MICROSEC     SEC_TO_MICRO      /* 1 second */
+#define TIMELOOP_NANOSEC      (1*1000000000ULL) /* 1 second */
+
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+
+/* *************************************
+*  Debug errors
+***************************************/
+#if defined(DEBUG) && (DEBUG >= 1)
+#  include <stdio.h>       /* fprintf */
+#  define DISPLAY(...)       fprintf(stderr, __VA_ARGS__)
+#  define DEBUGOUTPUT(...) { if (DEBUG) DISPLAY(__VA_ARGS__); }
+#else
+#  define DEBUGOUTPUT(...)
+#endif
+
+
+/* error without displaying */
+#define RETURN_QUIET_ERROR(retValue, ...) {           \
+    DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__);    \
+    DEBUGOUTPUT("Error : ");                          \
+    DEBUGOUTPUT(__VA_ARGS__);                         \
+    DEBUGOUTPUT(" \n");                               \
+    return retValue;                                  \
+}
+
+
+/* *************************************
+*  Benchmarking an arbitrary function
+***************************************/
+
+int BMK_isSuccessful_runOutcome(BMK_runOutcome_t outcome)
+{
+    return outcome.error_tag_never_ever_use_directly == 0;
+}
+
+/* warning : this function will stop program execution if outcome is invalid !
+ *           check outcome validity first, using BMK_isValid_runResult() */
+BMK_runTime_t BMK_extract_runTime(BMK_runOutcome_t outcome)
+{
+    assert(outcome.error_tag_never_ever_use_directly == 0);
+    return outcome.internal_never_ever_use_directly;
+}
+
+size_t BMK_extract_errorResult(BMK_runOutcome_t outcome)
+{
+    assert(outcome.error_tag_never_ever_use_directly != 0);
+    return outcome.error_result_never_ever_use_directly;
+}
+
+static BMK_runOutcome_t BMK_runOutcome_error(size_t errorResult)
+{
+    BMK_runOutcome_t b;
+    memset(&b, 0, sizeof(b));
+    b.error_tag_never_ever_use_directly = 1;
+    b.error_result_never_ever_use_directly = errorResult;
+    return b;
+}
+
+static BMK_runOutcome_t BMK_setValid_runTime(BMK_runTime_t runTime)
+{
+    BMK_runOutcome_t outcome;
+    outcome.error_tag_never_ever_use_directly = 0;
+    outcome.internal_never_ever_use_directly = runTime;
+    return outcome;
+}
+
+
+/* initFn will be measured once, benchFn will be measured `nbLoops` times */
+/* initFn is optional, provide NULL if none */
+/* benchFn must return a size_t value that errorFn can interpret */
+/* takes # of blocks and list of size & stuff for each. */
+/* can report result of benchFn for each block into blockResult. */
+/* blockResult is optional, provide NULL if this information is not required */
+/* note : time per loop can be reported as zero if run time < timer resolution */
+BMK_runOutcome_t BMK_benchFunction(BMK_benchParams_t p,
+                                   unsigned nbLoops)
+{
+    /* init */
+    {   size_t i;
+        for (i = 0; i < p.blockCount; i++) {
+            memset(p.dstBuffers[i], 0xE5, p.dstCapacities[i]);  /* warm up and erase result buffer */
+    }   }
+
+    /* benchmark */
+    {   UTIL_time_t const clockStart = UTIL_getTime();
+        size_t dstSize = 0;
+        unsigned loopNb, blockNb;
+        nbLoops += !nbLoops;   /* minimum nbLoops is 1 */
+        if (p.initFn != NULL) p.initFn(p.initPayload);
+        for (loopNb = 0; loopNb < nbLoops; loopNb++) {
+            for (blockNb = 0; blockNb < p.blockCount; blockNb++) {
+                size_t const res = p.benchFn(p.srcBuffers[blockNb], p.srcSizes[blockNb],
+                                   p.dstBuffers[blockNb], p.dstCapacities[blockNb],
+                                   p.benchPayload);
+                if (loopNb == 0) {
+                    if (p.blockResults != NULL) p.blockResults[blockNb] = res;
+                    if ((p.errorFn != NULL) && (p.errorFn(res))) {
+                        RETURN_QUIET_ERROR(BMK_runOutcome_error(res),
+                            "Function benchmark failed on block %u (of size %u) with error %i",
+                            blockNb, (unsigned)p.srcSizes[blockNb], (int)res);
+                    }
+                    dstSize += res;
+            }   }
+        }  /* for (loopNb = 0; loopNb < nbLoops; loopNb++) */
+
+        {   PTime const totalTime = UTIL_clockSpanNano(clockStart);
+            BMK_runTime_t rt;
+            rt.nanoSecPerRun = (double)totalTime / nbLoops;
+            rt.sumOfReturn = dstSize;
+            return BMK_setValid_runTime(rt);
+    }   }
+}
+
+
+/* ====  Benchmarking any function, providing intermediate results  ==== */
+
+struct BMK_timedFnState_s {
+    PTime timeSpent_ns;
+    PTime timeBudget_ns;
+    PTime runBudget_ns;
+    BMK_runTime_t fastestRun;
+    unsigned nbLoops;
+    UTIL_time_t coolTime;
+};  /* typedef'd to BMK_timedFnState_t within bench.h */
+
+BMK_timedFnState_t* BMK_createTimedFnState(unsigned total_ms, unsigned run_ms)
+{
+    BMK_timedFnState_t* const r = (BMK_timedFnState_t*)malloc(sizeof(*r));
+    if (r == NULL) return NULL;   /* malloc() error */
+    BMK_resetTimedFnState(r, total_ms, run_ms);
+    return r;
+}
+
+void BMK_freeTimedFnState(BMK_timedFnState_t* state) { free(state); }
+
+BMK_timedFnState_t*
+BMK_initStatic_timedFnState(void* buffer, size_t size, unsigned total_ms, unsigned run_ms)
+{
+    typedef char check_size[ 2 * (sizeof(BMK_timedFnState_shell) >= sizeof(struct BMK_timedFnState_s)) - 1];  /* static assert : a compilation failure indicates that BMK_timedFnState_shell is not large enough */
+    typedef struct { check_size c; BMK_timedFnState_t tfs; } tfs_align;  /* force tfs to be aligned at its next best position */
+    size_t const tfs_alignment = offsetof(tfs_align, tfs); /* provides the minimal alignment restriction for BMK_timedFnState_t */
+    BMK_timedFnState_t* const r = (BMK_timedFnState_t*)buffer;
+    if (buffer == NULL) return NULL;
+    if (size < sizeof(struct BMK_timedFnState_s)) return NULL;
+    if ((size_t)buffer % tfs_alignment) return NULL;  /* buffer must be properly aligned */
+    BMK_resetTimedFnState(r, total_ms, run_ms);
+    return r;
+}
+
+void BMK_resetTimedFnState(BMK_timedFnState_t* timedFnState, unsigned total_ms, unsigned run_ms)
+{
+    if (!total_ms) total_ms = 1 ;
+    if (!run_ms) run_ms = 1;
+    if (run_ms > total_ms) run_ms = total_ms;
+    timedFnState->timeSpent_ns = 0;
+    timedFnState->timeBudget_ns = (PTime)total_ms * TIMELOOP_NANOSEC / 1000;
+    timedFnState->runBudget_ns = (PTime)run_ms * TIMELOOP_NANOSEC / 1000;
+    timedFnState->fastestRun.nanoSecPerRun = (double)TIMELOOP_NANOSEC * 2000000000;  /* hopefully large enough : must be larger than any potential measurement */
+    timedFnState->fastestRun.sumOfReturn = (size_t)(-1LL);
+    timedFnState->nbLoops = 1;
+    timedFnState->coolTime = UTIL_getTime();
+}
+
+/* Tells if nb of seconds set in timedFnState for all runs is spent.
+ * note : this function will return 1 if BMK_benchFunctionTimed() has actually errored. */
+int BMK_isCompleted_TimedFn(const BMK_timedFnState_t* timedFnState)
+{
+    return (timedFnState->timeSpent_ns >= timedFnState->timeBudget_ns);
+}
+
+
+#undef MIN
+#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )
+
+#define MINUSABLETIME  (TIMELOOP_NANOSEC / 2)  /* 0.5 seconds */
+
+BMK_runOutcome_t BMK_benchTimedFn(BMK_timedFnState_t* cont,
+                                  BMK_benchParams_t p)
+{
+    PTime const runBudget_ns = cont->runBudget_ns;
+    PTime const runTimeMin_ns = runBudget_ns / 2;
+    BMK_runTime_t bestRunTime = cont->fastestRun;
+
+    for (;;) {
+        BMK_runOutcome_t const runResult = BMK_benchFunction(p, cont->nbLoops);
+
+        if (!BMK_isSuccessful_runOutcome(runResult)) { /* error : move out */
+            return runResult;
+        }
+
+        {   BMK_runTime_t const newRunTime = BMK_extract_runTime(runResult);
+            double const loopDuration_ns = newRunTime.nanoSecPerRun * cont->nbLoops;
+
+            cont->timeSpent_ns += (unsigned long long)loopDuration_ns;
+
+            /* estimate nbLoops for next run to last approximately 1 second */
+            if (loopDuration_ns > (runBudget_ns / 50)) {
+                double const fastestRun_ns = MIN(bestRunTime.nanoSecPerRun, newRunTime.nanoSecPerRun);
+                cont->nbLoops = (unsigned)(runBudget_ns / fastestRun_ns) + 1;
+            } else {
+                /* previous run was too short : blindly increase workload by x multiplier */
+                const unsigned multiplier = 10;
+                assert(cont->nbLoops < ((unsigned)-1) / multiplier);  /* avoid overflow */
+                cont->nbLoops *= multiplier;
+            }
+
+            if (loopDuration_ns < runTimeMin_ns) {
+                /* When benchmark run time is too small : don't report results.
+                 * increased risks of rounding errors */
+                continue;
+            }
+
+            if (newRunTime.nanoSecPerRun < bestRunTime.nanoSecPerRun) {
+                bestRunTime = newRunTime;
+            }
+        }
+        break;
+    }   /* while (!completed) */
+
+    return BMK_setValid_runTime(bestRunTime);
+}
diff --git a/grpc/third_party/xxhash/tests/bench/benchfn.h b/grpc/third_party/xxhash/tests/bench/benchfn.h
new file mode 100644
index 0000000..42d1033
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/benchfn.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2016-2020 Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* benchfn :
+ * benchmark any function on a set of input
+ * providing result in nanoSecPerRun
+ * or detecting and returning an error
+ */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef BENCH_FN_H_23876
+#define BENCH_FN_H_23876
+
+/* ===  Dependencies  === */
+#include <stddef.h>   /* size_t */
+
+
+/* ====  Benchmark any function, iterated on a set of blocks  ==== */
+
+/* BMK_runTime_t: valid result return type */
+
+typedef struct {
+    double nanoSecPerRun;  /* time per iteration (over all blocks) */
+    size_t sumOfReturn;         /* sum of return values */
+} BMK_runTime_t;
+
+
+/* BMK_runOutcome_t:
+ * type expressing the outcome of a benchmark run by BMK_benchFunction(),
+ * which can be either valid or invalid.
+ * benchmark outcome can be invalid if errorFn is provided.
+ * BMK_runOutcome_t must be considered "opaque" : never access its members directly.
+ * Instead, use its assigned methods :
+ * BMK_isSuccessful_runOutcome, BMK_extract_runTime, BMK_extract_errorResult.
+ * The structure is only described here to allow its allocation on stack. */
+
+typedef struct {
+    BMK_runTime_t internal_never_ever_use_directly;
+    size_t error_result_never_ever_use_directly;
+    int error_tag_never_ever_use_directly;
+} BMK_runOutcome_t;
+
+
+/* prototypes for benchmarked functions */
+typedef size_t (*BMK_benchFn_t)(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload);
+typedef size_t (*BMK_initFn_t)(void* initPayload);
+typedef unsigned (*BMK_errorFn_t)(size_t);
+
+
+/* BMK_benchFunction() parameters are provided via the following structure.
+ * A structure is preferable for readability,
+ * as the number of parameters required is fairly large.
+ * No initializer is provided, because it doesn't make sense to provide some "default" :
+ * all parameters must be specified by the caller.
+ * optional parameters are labelled explicitly, and accept value NULL when not used */
+typedef struct {
+    BMK_benchFn_t benchFn;    /* the function to benchmark, over the set of blocks */
+    void* benchPayload;       /* pass custom parameters to benchFn  :
+                               * (*benchFn)(srcBuffers[i], srcSizes[i], dstBuffers[i], dstCapacities[i], benchPayload) */
+    BMK_initFn_t initFn;      /* (*initFn)(initPayload) is run once per run, at the beginning. */
+    void* initPayload;        /* Both arguments can be NULL, in which case nothing is run. */
+    BMK_errorFn_t errorFn;    /* errorFn will check each return value of benchFn over each block, to determine if it failed or not.
+                               * errorFn can be NULL, in which case no check is performed.
+                               * errorFn must return 0 when benchFn was successful, and >= 1 if it detects an error.
+                               * Execution is stopped as soon as an error is detected.
+                               * the triggering return value can be retrieved using BMK_extract_errorResult(). */
+    size_t blockCount;        /* number of blocks to operate benchFn on.
+                               * It's also the size of all array parameters :
+                               * srcBuffers, srcSizes, dstBuffers, dstCapacities, blockResults */
+    const void *const * srcBuffers; /* read-only array of buffers to be operated on by benchFn */
+    const size_t* srcSizes;   /* read-only array containing sizes of srcBuffers */
+    void *const * dstBuffers; /* array of buffers to be written into by benchFn. This array is not optional, it must be provided even if unused by benchfn. */
+    const size_t* dstCapacities; /* read-only array containing capacities of dstBuffers. This array must be present. */
+    size_t* blockResults;     /* Optional: store the return value of benchFn for each block. Use NULL if this result is not requested. */
+} BMK_benchParams_t;
+
+
+/* BMK_benchFunction() :
+ * This function benchmarks benchFn and initFn, providing a result.
+ *
+ * params : see description of BMK_benchParams_t above.
+ * nbLoops: defines number of times benchFn is run over the full set of blocks.
+ *          Minimum value is 1. A 0 is interpreted as a 1.
+ *
+ * @return: can express either an error or a successful result.
+ *          Use BMK_isSuccessful_runOutcome() to check if benchmark was successful.
+ *          If yes, extract the result with BMK_extract_runTime(),
+ *          it will contain :
+ *              .sumOfReturn : the sum of all return values of benchFn through all of blocks
+ *              .nanoSecPerRun : time per run of benchFn + (time for initFn / nbLoops)
+ *          .sumOfReturn is generally intended for functions which return a # of bytes written into dstBuffer,
+ *              in which case, this value will be the total amount of bytes written into dstBuffer.
+ *
+ * blockResults : when provided (!= NULL), and when benchmark is successful,
+ *                params.blockResults contains all return values of `benchFn` over all blocks.
+ *                when provided (!= NULL), and when benchmark failed,
+ *                params.blockResults contains return values of `benchFn` over all blocks preceding and including the failed block.
+ */
+BMK_runOutcome_t BMK_benchFunction(BMK_benchParams_t params, unsigned nbLoops);
+
+
+
+/* check first if the benchmark was successful or not */
+int BMK_isSuccessful_runOutcome(BMK_runOutcome_t outcome);
+
+/* If the benchmark was successful, extract the result.
+ * note : this function will abort() program execution if benchmark failed !
+ *        always check if benchmark was successful first !
+ */
+BMK_runTime_t BMK_extract_runTime(BMK_runOutcome_t outcome);
+
+/* when benchmark failed, it means one invocation of `benchFn` failed.
+ * The failure was detected by `errorFn`, operating on return values of `benchFn`.
+ * Returns the faulty return value.
+ * note : this function will abort() program execution if benchmark did not failed.
+ *        always check if benchmark failed first !
+ */
+size_t BMK_extract_errorResult(BMK_runOutcome_t outcome);
+
+
+
+/* ====  Benchmark any function, returning intermediate results  ==== */
+
+/* state information tracking benchmark session */
+typedef struct BMK_timedFnState_s BMK_timedFnState_t;
+
+/* BMK_benchTimedFn() :
+ * Similar to BMK_benchFunction(), most arguments being identical.
+ * Automatically determines `nbLoops` so that each result is regularly produced at interval of about run_ms.
+ * Note : minimum `nbLoops` is 1, therefore a run may last more than run_ms, and possibly even more than total_ms.
+ * Usage - initialize timedFnState, select benchmark duration (total_ms) and each measurement duration (run_ms)
+ *         call BMK_benchTimedFn() repetitively, each measurement is supposed to last about run_ms
+ *         Check if total time budget is spent or exceeded, using BMK_isCompleted_TimedFn()
+ */
+BMK_runOutcome_t BMK_benchTimedFn(BMK_timedFnState_t* timedFnState,
+                                  BMK_benchParams_t params);
+
+/* Tells if duration of all benchmark runs has exceeded total_ms
+ */
+int BMK_isCompleted_TimedFn(const BMK_timedFnState_t* timedFnState);
+
+/* BMK_createTimedFnState() and BMK_resetTimedFnState() :
+ * Create/Set BMK_timedFnState_t for next benchmark session,
+ * which shall last a minimum of total_ms milliseconds,
+ * producing intermediate results, paced at interval of (approximately) run_ms.
+ */
+BMK_timedFnState_t* BMK_createTimedFnState(unsigned total_ms, unsigned run_ms);
+void BMK_resetTimedFnState(BMK_timedFnState_t* timedFnState, unsigned total_ms, unsigned run_ms);
+void BMK_freeTimedFnState(BMK_timedFnState_t* state);
+
+
+/* BMK_timedFnState_shell and BMK_initStatic_timedFnState() :
+ * Makes it possible to statically allocate a BMK_timedFnState_t on stack.
+ * BMK_timedFnState_shell is only there to allocate space,
+ * never ever access its members.
+ * BMK_timedFnState_t() actually accepts any buffer.
+ * It will check if provided buffer is large enough and is correctly aligned,
+ * and will return NULL if conditions are not respected.
+ */
+#define BMK_TIMEDFNSTATE_SIZE 64
+typedef union {
+    char never_access_space[BMK_TIMEDFNSTATE_SIZE];
+    long long alignment_enforcer;  /* must be aligned on 8-bytes boundaries */
+} BMK_timedFnState_shell;
+BMK_timedFnState_t* BMK_initStatic_timedFnState(void* buffer, size_t size, unsigned total_ms, unsigned run_ms);
+
+
+#endif   /* BENCH_FN_H_23876 */
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/grpc/third_party/xxhash/tests/bench/bhDisplay.c b/grpc/third_party/xxhash/tests/bench/bhDisplay.c
new file mode 100644
index 0000000..601ca1f
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/bhDisplay.c
@@ -0,0 +1,160 @@
+/*
+*  CSV Display module for the hash benchmark program
+*  Part of the xxHash project
+*  Copyright (C) 2019-2020 Yann Collet
+*
+*  GPL v2 License
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License along
+*  with this program; if not, write to the Free Software Foundation, Inc.,
+*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+*  You can contact the author at :
+*  - xxHash homepage : https://www.xxhash.com
+*  - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+
+/* ===  Dependencies  === */
+
+#include <stdlib.h>   /* rand */
+#include <stdio.h>    /* printf */
+#include <assert.h>
+
+#include "benchHash.h"
+#include "bhDisplay.h"
+
+
+/* ===  benchmark large input  === */
+
+#define MB_UNIT           1000000
+#define BENCH_LARGE_ITER_MS   490
+#define BENCH_LARGE_TOTAL_MS 1010
+static void bench_oneHash_largeInput(Bench_Entry hashDesc, int minlog, int maxlog)
+{
+    printf("%-7s", hashDesc.name);
+    for (int sizelog=minlog; sizelog<=maxlog; sizelog++) {
+        size_t const inputSize = (size_t)1 << sizelog;
+        double const nbhps = bench_hash(hashDesc.hash, BMK_throughput,
+                                        inputSize, BMK_fixedSize,
+                                        BENCH_LARGE_TOTAL_MS, BENCH_LARGE_ITER_MS);
+        printf(",%6.0f", nbhps * inputSize / MB_UNIT); fflush(NULL);
+    }
+    printf("\n");
+}
+
+void bench_largeInput(Bench_Entry const* hashDescTable, int nbHashes, int minlog, int maxlog)
+{
+    assert(maxlog <  31);
+    assert(minlog >=  0);
+    printf("benchmarking large inputs : from %u bytes (log%i) to %u MB (log%i) \n",
+        1U << minlog, minlog,
+        (1U << maxlog) >> 20, maxlog);
+    for (int i=0; i<nbHashes; i++)
+        bench_oneHash_largeInput(hashDescTable[i], minlog, maxlog);
+}
+
+
+
+/* ===  Benchmark small inputs  === */
+
+#define BENCH_SMALL_ITER_MS   170
+#define BENCH_SMALL_TOTAL_MS  490
+static void bench_throughput_oneHash_smallInputs(Bench_Entry hashDesc, size_t sizeMin, size_t sizeMax)
+{
+    printf("%-7s", hashDesc.name);
+    for (size_t s=sizeMin; s<sizeMax+1; s++) {
+        double const nbhps = bench_hash(hashDesc.hash, BMK_throughput,
+                                        s, BMK_fixedSize,
+                                        BENCH_SMALL_TOTAL_MS, BENCH_SMALL_ITER_MS);
+        printf(",%10.0f", nbhps); fflush(NULL);
+    }
+    printf("\n");
+}
+
+void bench_throughput_smallInputs(Bench_Entry const* hashDescTable, int nbHashes, size_t sizeMin, size_t sizeMax)
+{
+    printf("Throughput small inputs of fixed size (from %zu to %zu bytes): \n",
+            sizeMin, sizeMax);
+    for (int i=0; i<nbHashes; i++)
+        bench_throughput_oneHash_smallInputs(hashDescTable[i], sizeMin, sizeMax);
+}
+
+
+
+/* ===   Latency measurements (small keys)   === */
+
+static void bench_latency_oneHash_smallInputs(Bench_Entry hashDesc, size_t size_min, size_t size_max)
+{
+    printf("%-7s", hashDesc.name);
+    for (size_t s=size_min; s<size_max+1; s++) {
+        double const nbhps = bench_hash(hashDesc.hash, BMK_latency,
+                                        s, BMK_fixedSize,
+                                        BENCH_SMALL_TOTAL_MS, BENCH_SMALL_ITER_MS);
+        printf(",%10.0f", nbhps); fflush(NULL);
+    }
+    printf("\n");
+}
+
+void bench_latency_smallInputs(Bench_Entry const* hashDescTable, int nbHashes, size_t size_min, size_t size_max)
+{
+    printf("Latency for small inputs of fixed size : \n");
+    for (int i=0; i<nbHashes; i++)
+        bench_latency_oneHash_smallInputs(hashDescTable[i], size_min, size_max);
+}
+
+
+/* ===   Random input Length   === */
+
+static void bench_randomInputLength_withOneHash(Bench_Entry hashDesc, size_t size_min, size_t size_max)
+{
+    printf("%-7s", hashDesc.name);
+    for (size_t s=size_min; s<size_max+1; s++) {
+        srand((unsigned)s);   /* ensure random sequence of length will be the same for a given s */
+        double const nbhps = bench_hash(hashDesc.hash, BMK_throughput,
+                                        s, BMK_randomSize,
+                                        BENCH_SMALL_TOTAL_MS, BENCH_SMALL_ITER_MS);
+        printf(",%10.0f", nbhps); fflush(NULL);
+    }
+    printf("\n");
+}
+
+void bench_throughput_randomInputLength(Bench_Entry const* hashDescTable, int nbHashes, size_t size_min, size_t size_max)
+{
+    printf("benchmarking random size inputs [1-N] : \n");
+    for (int i=0; i<nbHashes; i++)
+        bench_randomInputLength_withOneHash(hashDescTable[i], size_min, size_max);
+}
+
+
+/* ===   Latency with Random input Length   === */
+
+static void bench_latency_oneHash_randomInputLength(Bench_Entry hashDesc, size_t size_min, size_t size_max)
+{
+    printf("%-7s", hashDesc.name);
+    for (size_t s=size_min; s<size_max+1; s++) {
+        srand((unsigned)s);   /* ensure random sequence of length will be the same for a given s */
+        double const nbhps = bench_hash(hashDesc.hash, BMK_latency,
+                                        s, BMK_randomSize,
+                                        BENCH_SMALL_TOTAL_MS, BENCH_SMALL_ITER_MS);
+        printf(",%10.0f", nbhps); fflush(NULL);
+    }
+    printf("\n");
+}
+
+void bench_latency_randomInputLength(Bench_Entry const* hashDescTable, int nbHashes, size_t size_min, size_t size_max)
+{
+    printf("Latency for small inputs of random size [1-N] : \n");
+    for (int i=0; i<nbHashes; i++)
+        bench_latency_oneHash_randomInputLength(hashDescTable[i], size_min, size_max);
+}
diff --git a/grpc/third_party/xxhash/tests/bench/bhDisplay.h b/grpc/third_party/xxhash/tests/bench/bhDisplay.h
new file mode 100644
index 0000000..42c4bb2
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/bhDisplay.h
@@ -0,0 +1,61 @@
+/*
+*  CSV Display module for the hash benchmark program
+*  Part of the xxHash project
+*  Copyright (C) 2019-2020 Yann Collet
+*
+*  GPL v2 License
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License along
+*  with this program; if not, write to the Free Software Foundation, Inc.,
+*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+*  You can contact the author at:
+*  - xxHash homepage: https://www.xxhash.com
+*  - xxHash source repository: https://github.com/Cyan4973/xxHash
+*/
+
+#ifndef BH_DISPLAY_H_192088098
+#define BH_DISPLAY_H_192088098
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* ===  Dependencies  === */
+
+#include "benchfn.h"   /* BMK_benchFn_t */
+
+
+/* ===  Declarations  === */
+
+typedef struct {
+    const char* name;
+    BMK_benchFn_t hash;
+} Bench_Entry;
+
+void bench_largeInput(Bench_Entry const* hashDescTable, int nbHashes, int sizeLogMin, int sizeLogMax);
+
+void bench_throughput_smallInputs(Bench_Entry const* hashDescTable, int nbHashes, size_t sizeMin, size_t sizeMax);
+void bench_throughput_randomInputLength(Bench_Entry const* hashDescTable, int nbHashes, size_t sizeMin, size_t sizeMax);
+
+void bench_latency_smallInputs(Bench_Entry const* hashDescTable, int nbHashes, size_t sizeMin, size_t sizeMax);
+void bench_latency_randomInputLength(Bench_Entry const* hashDescTable, int nbHashes, size_t sizeMin, size_t sizeMax);
+
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif   /* BH_DISPLAY_H_192088098 */
diff --git a/grpc/third_party/xxhash/tests/bench/hashes.h b/grpc/third_party/xxhash/tests/bench/hashes.h
new file mode 100644
index 0000000..2042dc5
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/hashes.h
@@ -0,0 +1,118 @@
+/*
+*  List hash algorithms to benchmark
+*  Part of xxHash project
+*  Copyright (C) 2019-2020 Yann Collet
+*
+*  GPL v2 License
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  This program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License along
+*  with this program; if not, write to the Free Software Foundation, Inc.,
+*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+*  You can contact the author at:
+*  - xxHash homepage: https://www.xxhash.com
+*  - xxHash source repository: https://github.com/Cyan4973/xxHash
+*/
+
+
+/* ===   Dependencies   === */
+
+#include <stddef.h>   /* size_t */
+
+
+/* ==================================================
+ *   Non-portable hash algorithms
+ * =============================================== */
+
+
+#ifdef HARDWARE_SUPPORT
+
+/*
+ * List any hash algorithms that depend on specific hardware support,
+ * including for example:
+ * - Hardware crc32c
+ * - Hardware AES support
+ * - Carryless Multipliers (clmul)
+ * - AVX2
+ */
+
+#endif
+
+
+
+/* ==================================================
+ * List of hashes
+ * ==================================================
+ * Each hash must be wrapped in a thin redirector conformant with the BMK_benchfn_t.
+ * BMK_benchfn_t is generic, not specifically designed for hashes.
+ * For hashes, the following parameters are expected to be useless:
+ * dst, dstCapacity, customPayload.
+ *
+ * The result of each hash is assumed to be provided as function return value.
+ * This condition is important for latency measurements.
+ */
+
+ /* ===  xxHash  === */
+#define XXH_INLINE_ALL
+#include "xxhash.h"
+
+size_t XXH32_wrapper(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload)
+{
+    (void)dst; (void)dstCapacity; (void)customPayload;
+    return (size_t) XXH32(src, srcSize, 0);
+}
+
+
+size_t XXH64_wrapper(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload)
+{
+    (void)dst; (void)dstCapacity; (void)customPayload;
+    return (size_t) XXH64(src, srcSize, 0);
+}
+
+
+size_t xxh3_wrapper(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload)
+{
+    (void)dst; (void)dstCapacity; (void)customPayload;
+    return (size_t) XXH3_64bits(src, srcSize);
+}
+
+
+size_t XXH128_wrapper(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload)
+{
+    (void)dst; (void)dstCapacity; (void)customPayload;
+    return (size_t) XXH3_128bits(src, srcSize).low64;
+}
+
+
+
+/* ==================================================
+ * Table of hashes
+ * =============================================== */
+
+#include "bhDisplay.h"   /* Bench_Entry */
+
+#ifndef HARDWARE_SUPPORT
+#  define NB_HASHES 4
+#else
+#  define NB_HASHES 4
+#endif
+
+Bench_Entry const hashCandidates[NB_HASHES] = {
+    { "xxh3"  , xxh3_wrapper },
+    { "XXH32" , XXH32_wrapper },
+    { "XXH64" , XXH64_wrapper },
+    { "XXH128", XXH128_wrapper },
+#ifdef HARDWARE_SUPPORT
+    /* list here codecs which require specific hardware support, such SSE4.1, PCLMUL, AVX2, etc. */
+#endif
+};
diff --git a/grpc/third_party/xxhash/tests/bench/main.c b/grpc/third_party/xxhash/tests/bench/main.c
new file mode 100644
index 0000000..1cf6e80
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/main.c
@@ -0,0 +1,220 @@
+/*
+ * Main program to benchmark hash functions
+ * Part of the xxHash project
+ * Copyright (C) 2019-2020 Yann Collet
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ * - xxHash homepage: https://www.xxhash.com
+ * - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+
+/* ===  dependencies  === */
+
+#include <stdio.h>       /* printf */
+#include <limits.h>      /* INT_MAX */
+#include "bhDisplay.h"   /* bench_x */
+
+
+/* ===  defines list of hashes `hashCandidates` and NB_HASHES  *** */
+
+#include "hashes.h"
+
+
+/* ===  parse command line  === */
+
+#undef NDEBUG
+#include <assert.h>
+
+
+/*!
+ * readIntFromChar():
+ * Allows and interprets K, KB, KiB, M, MB and MiB suffix.
+ * Will also modify `*stringPtr`, advancing it to position where it stopped reading.
+ */
+static int readIntFromChar(const char** stringPtr)
+{
+    static int const max = (INT_MAX / 10) - 1;
+    int result = 0;
+    while ((**stringPtr >='0') && (**stringPtr <='9')) {
+        assert(result < max);
+        result *= 10;
+        result += (unsigned)(**stringPtr - '0');
+        (*stringPtr)++ ;
+    }
+    if ((**stringPtr=='K') || (**stringPtr=='M')) {
+        int const maxK = INT_MAX >> 10;
+        assert(result < maxK);
+        result <<= 10;
+        if (**stringPtr=='M') {
+            assert(result < maxK);
+            result <<= 10;
+        }
+        (*stringPtr)++;  /* skip `K` or `M` */
+        if (**stringPtr=='i') (*stringPtr)++;
+        if (**stringPtr=='B') (*stringPtr)++;
+    }
+    return result;
+}
+
+
+/**
+ * isCommand():
+ * Checks if string is the same as longCommand.
+ * If yes, @return 1, otherwise @return 0
+ */
+static int isCommand(const char* string, const char* longCommand)
+{
+    assert(string);
+    assert(longCommand);
+    size_t const comSize = strlen(longCommand);
+    return !strncmp(string, longCommand, comSize);
+}
+
+/*
+ * longCommandWArg():
+ * Checks if *stringPtr is the same as longCommand.
+ * If yes, @return 1 and advances *stringPtr to the position which immediately
+ * follows longCommand.
+ * @return 0 and doesn't modify *stringPtr otherwise.
+ */
+static int longCommandWArg(const char** stringPtr, const char* longCommand)
+{
+    assert(stringPtr);
+    assert(longCommand);
+    size_t const comSize = strlen(longCommand);
+    int const result = isCommand(*stringPtr, longCommand);
+    if (result) *stringPtr += comSize;
+    return result;
+}
+
+
+/* ===   default values - can be redefined at compilation time   === */
+
+#ifndef SMALL_SIZE_MIN_DEFAULT
+#  define SMALL_SIZE_MIN_DEFAULT   1
+#endif
+#ifndef SMALL_SIZE_MAX_DEFAULT
+#  define SMALL_SIZE_MAX_DEFAULT 127
+#endif
+#ifndef LARGE_SIZELOG_MIN_DEFAULT
+#  define LARGE_SIZELOG_MIN_DEFAULT   9
+#endif
+#ifndef LARGE_SIZELOG_MAX_DEFAULT
+#  define LARGE_SIZELOG_MAX_DEFAULT  27
+#endif
+
+
+static int display_hash_names(void)
+{
+    int i;
+    printf("available hashes : \n");
+    for (i=0; i<NB_HASHES; i++) {
+        printf("%s, ", hashCandidates[i].name);
+    }
+    printf("\b\b  \n");
+    return 0;
+}
+
+/*
+ * @return: hashID (necessarily between 0 and NB_HASHES) if present
+ *          -1 on error (hname not present)
+ */
+static int hashID(const char* hname)
+{
+    int id;
+    assert(hname);
+    for (id=0; id < NB_HASHES; id++) {
+        assert(hashCandidates[id].name);
+        if (strlen(hname) != strlen(hashCandidates[id].name)) continue;
+        if (isCommand(hname, hashCandidates[id].name)) return id;
+    }
+    return -1;
+}
+
+static int help(const char* exename)
+{
+    printf("Usage: %s [options]... [hash]\n", exename);
+    printf("Runs various benchmarks at various lengths for the listed hash functions\n");
+    printf("and outputs them in a CSV format.\n\n");
+    printf("Options: \n");
+    printf("  --list       Name available hash algorithms and exit \n");
+    printf("  --mins=LEN   Starting length for small size bench (default: %i) \n", SMALL_SIZE_MIN_DEFAULT);
+    printf("  --maxs=LEN   End length for small size bench (default: %i) \n", SMALL_SIZE_MAX_DEFAULT);
+    printf("  --minl=LEN   Starting log2(length) for large size bench (default: %i) \n", LARGE_SIZELOG_MIN_DEFAULT);
+    printf("  --maxl=LEN   End log2(length) for large size bench (default: %i) \n", LARGE_SIZELOG_MAX_DEFAULT);
+    printf("  [hash]       Optional, bench all available hashes if not provided \n");
+    return 0;
+}
+
+static int badusage(const char* exename)
+{
+    printf("Bad command ... \n");
+    help(exename);
+    return 1;
+}
+
+int main(int argc, const char* argv[])
+{
+    const char* const exename = argv[0];
+    int hashNb = 0;
+    int nb_h_test = NB_HASHES;
+    int largeTest_log_min = LARGE_SIZELOG_MIN_DEFAULT;
+    int largeTest_log_max = LARGE_SIZELOG_MAX_DEFAULT;
+    size_t smallTest_size_min = SMALL_SIZE_MIN_DEFAULT;
+    size_t smallTest_size_max = SMALL_SIZE_MAX_DEFAULT;
+
+    int arg_nb;
+    for (arg_nb = 1; arg_nb < argc; arg_nb++) {
+        const char** arg = argv + arg_nb;
+        if (isCommand(*arg, "-h")) { assert(argc >= 1); return help(exename); }
+        if (isCommand(*arg, "--list")) { return display_hash_names(); }
+        if (longCommandWArg(arg, "--n=")) { nb_h_test = readIntFromChar(arg); continue; }  /* hidden command */
+        if (longCommandWArg(arg, "--minl=")) { largeTest_log_min = readIntFromChar(arg); continue; }
+        if (longCommandWArg(arg, "--maxl=")) { largeTest_log_max = readIntFromChar(arg); continue; }
+        if (longCommandWArg(arg, "--mins=")) { smallTest_size_min = (size_t)readIntFromChar(arg); continue; }
+        if (longCommandWArg(arg, "--maxs=")) { smallTest_size_max = (size_t)readIntFromChar(arg); continue; }
+        /* not a command: must be a hash name */
+        hashNb = hashID(*arg);
+        if (hashNb >= 0) {
+            nb_h_test = 1;
+        } else {
+            /* not a hash name: error */
+            return badusage(exename);
+        }
+    }
+
+    /* border case (requires (mis)using hidden command `--n=#`) */
+    if (hashNb + nb_h_test > NB_HASHES) {
+        printf("wrong hash selection \n");
+        return 1;
+    }
+
+    printf(" ===  benchmarking %i hash functions  === \n", nb_h_test);
+    if (largeTest_log_max >= largeTest_log_min) {
+        bench_largeInput(hashCandidates+hashNb, nb_h_test, largeTest_log_min, largeTest_log_max);
+    }
+    if (smallTest_size_max >= smallTest_size_min) {
+        bench_throughput_smallInputs(hashCandidates+hashNb, nb_h_test, smallTest_size_min, smallTest_size_max);
+        bench_throughput_randomInputLength(hashCandidates+hashNb, nb_h_test, smallTest_size_min, smallTest_size_max);
+        bench_latency_smallInputs(hashCandidates+hashNb, nb_h_test, smallTest_size_min, smallTest_size_max);
+        bench_latency_randomInputLength(hashCandidates+hashNb, nb_h_test, smallTest_size_min, smallTest_size_max);
+    }
+
+    return 0;
+}
diff --git a/grpc/third_party/xxhash/tests/bench/timefn.c b/grpc/third_party/xxhash/tests/bench/timefn.c
new file mode 100644
index 0000000..8568128
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/timefn.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019-2020 Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ===  Dependencies  === */
+
+#include "timefn.h"
+
+
+/*-****************************************
+*  Time functions
+******************************************/
+
+#if defined(_WIN32)   /* Windows */
+
+#include <stdlib.h>   /* abort */
+#include <stdio.h>    /* perror */
+
+UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; }
+
+PTime UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd)
+{
+    static LARGE_INTEGER ticksPerSecond;
+    static int init = 0;
+    if (!init) {
+        if (!QueryPerformanceFrequency(&ticksPerSecond)) {
+            perror("timefn::QueryPerformanceFrequency");
+            abort();
+        }
+        init = 1;
+    }
+    return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart;
+}
+
+PTime UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd)
+{
+    static LARGE_INTEGER ticksPerSecond;
+    static int init = 0;
+    if (!init) {
+        if (!QueryPerformanceFrequency(&ticksPerSecond)) {
+            perror("timefn::QueryPerformanceFrequency");
+            abort();
+        }
+        init = 1;
+    }
+    return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart;
+}
+
+
+
+#elif defined(__APPLE__) && defined(__MACH__)
+
+UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); }
+
+PTime UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd)
+{
+    static mach_timebase_info_data_t rate;
+    static int init = 0;
+    if (!init) {
+        mach_timebase_info(&rate);
+        init = 1;
+    }
+    return (((clockEnd - clockStart) * (PTime)rate.numer) / ((PTime)rate.denom))/1000ULL;
+}
+
+PTime UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd)
+{
+    static mach_timebase_info_data_t rate;
+    static int init = 0;
+    if (!init) {
+        mach_timebase_info(&rate);
+        init = 1;
+    }
+    return ((clockEnd - clockStart) * (PTime)rate.numer) / ((PTime)rate.denom);
+}
+
+
+
+#elif (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */) \
+    && defined(TIME_UTC) /* C11 requires timespec_get, but FreeBSD 11 lacks it, while still claiming C11 compliance */
+
+#include <stdlib.h>   /* abort */
+#include <stdio.h>    /* perror */
+
+UTIL_time_t UTIL_getTime(void)
+{
+    /* time must be initialized, othersize it may fail msan test.
+     * No good reason, likely a limitation of timespec_get() for some target */
+    UTIL_time_t time = UTIL_TIME_INITIALIZER;
+    if (timespec_get(&time, TIME_UTC) != TIME_UTC) {
+        perror("timefn::timespec_get");
+        abort();
+    }
+    return time;
+}
+
+static UTIL_time_t UTIL_getSpanTime(UTIL_time_t begin, UTIL_time_t end)
+{
+    UTIL_time_t diff;
+    if (end.tv_nsec < begin.tv_nsec) {
+        diff.tv_sec = (end.tv_sec - 1) - begin.tv_sec;
+        diff.tv_nsec = (end.tv_nsec + 1000000000ULL) - begin.tv_nsec;
+    } else {
+        diff.tv_sec = end.tv_sec - begin.tv_sec;
+        diff.tv_nsec = end.tv_nsec - begin.tv_nsec;
+    }
+    return diff;
+}
+
+PTime UTIL_getSpanTimeMicro(UTIL_time_t begin, UTIL_time_t end)
+{
+    UTIL_time_t const diff = UTIL_getSpanTime(begin, end);
+    PTime micro = 0;
+    micro += 1000000ULL * diff.tv_sec;
+    micro += diff.tv_nsec / 1000ULL;
+    return micro;
+}
+
+PTime UTIL_getSpanTimeNano(UTIL_time_t begin, UTIL_time_t end)
+{
+    UTIL_time_t const diff = UTIL_getSpanTime(begin, end);
+    PTime nano = 0;
+    nano += 1000000000ULL * diff.tv_sec;
+    nano += diff.tv_nsec;
+    return nano;
+}
+
+
+
+#else   /* relies on standard C90 (note : clock_t measurements can be wrong when using multi-threading) */
+
+UTIL_time_t UTIL_getTime(void) { return clock(); }
+PTime UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
+PTime UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
+
+#endif
+
+
+
+/* returns time span in microseconds */
+PTime UTIL_clockSpanMicro(UTIL_time_t clockStart )
+{
+    UTIL_time_t const clockEnd = UTIL_getTime();
+    return UTIL_getSpanTimeMicro(clockStart, clockEnd);
+}
+
+/* returns time span in microseconds */
+PTime UTIL_clockSpanNano(UTIL_time_t clockStart )
+{
+    UTIL_time_t const clockEnd = UTIL_getTime();
+    return UTIL_getSpanTimeNano(clockStart, clockEnd);
+}
+
+void UTIL_waitForNextTick(void)
+{
+    UTIL_time_t const clockStart = UTIL_getTime();
+    UTIL_time_t clockEnd;
+    do {
+        clockEnd = UTIL_getTime();
+    } while (UTIL_getSpanTimeNano(clockStart, clockEnd) == 0);
+}
diff --git a/grpc/third_party/xxhash/tests/bench/timefn.h b/grpc/third_party/xxhash/tests/bench/timefn.h
new file mode 100644
index 0000000..41007f3
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/bench/timefn.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016-2020 Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef TIME_FN_H_MODULE_287987
+#define TIME_FN_H_MODULE_287987
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/*-****************************************
+*  Dependencies
+******************************************/
+#include <sys/types.h>    /* utime */
+#if defined(_MSC_VER)
+#  include <sys/utime.h>  /* utime */
+#else
+#  include <utime.h>      /* utime */
+#endif
+#include <time.h>         /* clock_t, clock, CLOCKS_PER_SEC */
+
+
+
+/*-****************************************
+*  Local Types
+******************************************/
+
+#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include <stdint.h>
+  typedef uint64_t           PTime;  /* Precise Time */
+#else
+  typedef unsigned long long PTime;  /* does not support compilers without long long support */
+#endif
+
+
+
+/*-****************************************
+*  Time functions
+******************************************/
+#if defined(_WIN32)   /* Windows */
+
+    #include <Windows.h>   /* LARGE_INTEGER */
+    typedef LARGE_INTEGER UTIL_time_t;
+    #define UTIL_TIME_INITIALIZER { { 0, 0 } }
+
+#elif defined(__APPLE__) && defined(__MACH__)
+
+    #include <mach/mach_time.h>
+    typedef PTime UTIL_time_t;
+    #define UTIL_TIME_INITIALIZER 0
+
+#elif (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */) \
+    && defined(TIME_UTC) /* C11 requires timespec_get, but FreeBSD 11 lacks it, while still claiming C11 compliance */
+
+    typedef struct timespec UTIL_time_t;
+    #define UTIL_TIME_INITIALIZER { 0, 0 }
+
+#else   /* relies on standard C90 (note : clock_t measurements can be wrong when using multi-threading) */
+
+    typedef clock_t UTIL_time_t;
+    #define UTIL_TIME_INITIALIZER 0
+
+#endif
+
+
+UTIL_time_t UTIL_getTime(void);
+PTime UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd);
+PTime UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd);
+
+#define SEC_TO_MICRO ((PTime)1000000)
+PTime UTIL_clockSpanMicro(UTIL_time_t clockStart);
+PTime UTIL_clockSpanNano(UTIL_time_t clockStart);
+
+void UTIL_waitForNextTick(void);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* TIME_FN_H_MODULE_287987 */
diff --git a/grpc/third_party/xxhash/tests/collisions/.gitignore b/grpc/third_party/xxhash/tests/collisions/.gitignore
new file mode 100644
index 0000000..f855926
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/.gitignore
@@ -0,0 +1,2 @@
+#build artefacts
+collisionsTest
diff --git a/grpc/third_party/xxhash/tests/collisions/LICENSE b/grpc/third_party/xxhash/tests/collisions/LICENSE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/LICENSE
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/grpc/third_party/xxhash/tests/collisions/Makefile b/grpc/third_party/xxhash/tests/collisions/Makefile
new file mode 100644
index 0000000..bad9835
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/Makefile
@@ -0,0 +1,74 @@
+#  Brute force collision tester for 64-bit hashes
+#  Part of xxHash project
+#  Copyright (C) 2019-2020 Yann Collet
+#
+# GPL v2 License
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+#  You can contact the author at:
+#  - xxHash homepage: https://www.xxhash.com
+#  - xxHash source repository: https://github.com/Cyan4973/xxHash
+#
+
+SRC_DIRS = ./ ../../ allcodecs/
+VPATH = $(SRC_DIRS)
+CPPFLAGS += $(addprefix -I ,$(SRC_DIRS))
+CFLAGS   ?= -std=c99 \
+            -Wall -Wextra -Wconversion
+CXXFLAGS ?= -Wall -Wextra -Wconversion -std=c++11
+LDFLAGS  += -pthread
+TESTHASHES = 110000000
+
+HASH_SRC := $(sort $(wildcard allcodecs/*.c allcodecs/*.cc))
+HASH_OBJ := $(patsubst %.c,%.o,$(HASH_SRC))
+
+
+.PHONY: default
+default: release
+
+.PHONY: all
+all: release
+
+collisionsTest: main.o pool.o threading.o sort.o $(HASH_OBJ)
+	$(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
+
+main.o: hashes.h xxhash.h
+
+release: CXXFLAGS += -O3
+release: CFLAGS += -O3
+release: collisionsTest
+
+debug: CXXFLAGS += -g3 -O0 -DDEBUG
+debug: CFLAGS += -g3 -O0 -DDEBUG
+debug: collisionsTest
+
+.PHONY: check
+check: test
+
+.PHONY: test
+test: debug
+	@echo ""
+	@echo "## $(TESTHASHES) hashes with original and 0 threads"
+	@time ./collisionsTest --nbh=$(TESTHASHES)
+	@echo ""
+	@echo "## $(TESTHASHES) hashes with original and 4 threads"
+	@time ./collisionsTest --nbh=$(TESTHASHES) --threadlog=2
+	@echo ""
+
+.PHONY: clean
+clean:
+	$(RM) *.o allcodecs/*.o
+	$(RM) collisionsTest
diff --git a/grpc/third_party/xxhash/tests/collisions/README.md b/grpc/third_party/xxhash/tests/collisions/README.md
new file mode 100644
index 0000000..683b115
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/README.md
@@ -0,0 +1,122 @@
+
+__collisionsTest__ is a brute force hash analyzer
+which will measure a 64-bit hash algorithm's collision rate
+by generating billions of hashes,
+and comparing the result to an "ideal" target.
+
+The test requires a very large amount of memory.
+By default, it will generate 24 billion of 64-bit hashes,
+requiring __192 GB of RAM__ for their storage.
+The number of hashes can be modified using command `--nbh=`.
+Be aware that testing the collision ratio of 64-bit hashes
+requires a very large amount of hashes (several billion) for meaningful measurements.
+
+To reduce RAM usage, an optional filter can be requested, with `--filter`.
+It reduces the nb of candidates to analyze, hence associated RAM budget.
+Note that the filter itself requires a lot of RAM
+(32 GB by default, can be modified using `--filterlog=`,
+a too small filter will not be efficient, aim at ~2 bytes per hash),
+and reading and writing into filter cost a significant CPU budget,
+so this method is slower.
+It also doesn't allow advanced analysis of partial bitfields,
+since most hashes will be discarded and not stored.
+
+When using the filter, the RAM budget consists of the filter and a list of candidates,
+which will be a fraction of the original hash list.
+Using default settings (24 billion hashes, 32 GB filter),
+the number of potential candidates should be reduced to less than 2 billion,
+requiring ~14 GB for their storage.
+Such a result also depends on hash algorithm's efficiency.
+The number of effective candidates is likely to be lower, at ~ 1 billion,
+but storage must allocate an upper bound.
+
+For the default test, the expected "optimal" collision rate for a 64-bit hash function is ~18 collisions.
+
+#### How to build
+```
+make
+```
+
+Note: the code is a mix of C99 and C++14,
+it's not compatible with a C90-only compiler.
+
+#### Build modifier
+
+- `SLAB5`: use alternative pattern generator, friendlier for weak hash algorithms
+- `POOL_MT`: if `=0`, disable multi-threading code (enabled by default)
+
+#### How to integrate any hash in the tester
+
+The build script will compile files found in `./allcodecs`.
+Put the source code here.
+This also works if the hash is a single `*.h` file.
+
+The glue happens in `hashes.h`.
+In this file, there are 2 sections:
+- Adds the required `#include "header.h"`, and creates a wrapper
+to respect the format expected by the function pointer.
+- Adds the wrapper, along with the name and an indication of the output width,
+to the table, at the end of `hashes.h`
+
+Build with `make`. Locate your new hash with `./collisionsTest -h`,
+it should be listed.
+
+
+#### Usage
+
+```
+usage: ./collisionsTest [hashName] [opt]
+
+list of hashNames: (...)
+
+Optional parameters:
+  --nbh=NB       Select nb of hashes to generate (25769803776 by default)
+  --filter       Enable the filter. Slower, but reduces memory usage for same nb of hashes.
+  --threadlog=NB Use 2^NB threads
+  --len=NB       Select length of input (255 bytes by default)
+```
+
+#### Some advises on how to setup a collisions test
+
+Most tests are primarily driven by the amount of RAM available.
+Here's a method to decide the size of the test.
+
+Presuming that RAM budget is not plentiful, for this example 32 GB,
+the `--filter` mode is actually compulsory to measure anything meaningful.
+Let's plan 50% of memory for the filter, that's 16 GB.
+This will be good enough to filter about 10% less hashes than this size.
+Let's round down to 14 G.
+
+By requesting 14G, the expectation is that the program will automatically
+size the filter to 16 GB, and expect to store ~1G candidates,
+leaving enough room to breeze for the system.
+
+The command line becomes:
+```
+./collisionsTest --nbh=14G --filter NameOfHash
+```
+
+#### Examples:
+
+Here are a few results produced with this tester:
+
+| Algorithm | Input Len | Nb Hashes | Expected | Nb Collisions | Notes |
+| ---        | --- | ---    | ---   | --- | --- |
+| __XXH3__   | 255 | 100 Gi | 312.5 | 326 |  |
+| __XXH64__  | 255 | 100 Gi | 312.5 | 294 |  |
+| __XXH128__ low64 | 512 | 100 Gi | 312.5 | 321 |  |
+| __XXH128__ high64| 512 | 100 Gi | 312.5 | 325 |  |
+| __XXH128__ | 255 | 100 Gi |   0.0 |   0 | a 128-bit hash is expected to generate 0 collisions |
+
+Test on small inputs:
+
+| Algorithm  | Input Len | Nb Hashes | Expected | Nb Collisions | Notes |
+| ---        | --- | ---    | --- | --- | --- |
+| __XXH64__  |   8 | 100 Gi | 312.5 | __0__ | `XXH64` is bijective for `len==8` |
+| __XXH3__   |   8 | 100 Gi | 312.5 | __0__ | `XXH3` is also bijective for `len==8` |
+| __XXH3__   |  16 | 100 Gi | 312.5 | 332 |  |
+| __XXH3__   |  32 |  14 Gi |   6.1 |   3 |  |
+| __XXH128__ |  16 |  25 Gi |   0.0 |   0 | test range 9-16 |
+| __XXH128__ |  32 |  25 Gi |   0.0 |   0 | test range 17-128 |
+| __XXH128__ | 100 |  13 Gi |   0.0 |   0 | test range 17-128 |
+| __XXH128__ | 200 |  13 Gi |   0.0 |   0 | test range 129-240 |
diff --git a/grpc/third_party/xxhash/tests/collisions/allcodecs/README.md b/grpc/third_party/xxhash/tests/collisions/allcodecs/README.md
new file mode 100644
index 0000000..d41fc2d
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/allcodecs/README.md
@@ -0,0 +1 @@
+Put in this directory all hash algorithms to test
diff --git a/grpc/third_party/xxhash/tests/collisions/allcodecs/dummy.c b/grpc/third_party/xxhash/tests/collisions/allcodecs/dummy.c
new file mode 100644
index 0000000..547d5c7
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/allcodecs/dummy.c
@@ -0,0 +1,38 @@
+/*
+ * dummy.c, a fake hash algorithm, just to test integration capabilities.
+ * Part of the xxHash project
+ * Copyright (C) 2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ * - xxHash homepage: https://www.xxhash.com
+ * - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+
+#include <dummy.h>
+
+unsigned badsum32(const void* input, size_t len, unsigned seed)
+{
+    unsigned sum = seed;
+    const unsigned char* in8 = input;
+    size_t c;
+    for (c=0; c<len; c++)
+        sum += in8[c];
+    return sum;
+}
diff --git a/grpc/third_party/xxhash/tests/collisions/allcodecs/dummy.h b/grpc/third_party/xxhash/tests/collisions/allcodecs/dummy.h
new file mode 100644
index 0000000..85856ef
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/allcodecs/dummy.h
@@ -0,0 +1,45 @@
+/*
+ * dummy.c,
+ * A fake hash algorithm, just to test integration capabilities.
+ * Part of the xxHash project
+ * Copyright (C) 2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ * - xxHash homepage: https://www.xxhash.com
+ * - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#ifndef DUMMY_H_987987
+#define DUMMY_H_987987
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+#include <stddef.h> /* size_t */
+
+unsigned badsum32(const void* input, size_t len, unsigned seed);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif  /* DUMMY_H_987987 */
diff --git a/grpc/third_party/xxhash/tests/collisions/hashes.h b/grpc/third_party/xxhash/tests/collisions/hashes.h
new file mode 100644
index 0000000..0b7223d
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/hashes.h
@@ -0,0 +1,127 @@
+/*
+ * List of hashes for the brute force collision tester
+ * Part of xxHash project
+ * Copyright (C) 2019-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ * - xxHash homepage: https://www.xxhash.com
+ * - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#ifndef HASHES_H_1235465
+#define HASHES_H_1235465
+
+#include <stddef.h>      /* size_t */
+#include <stdint.h>      /* uint64_t */
+#define XXH_INLINE_ALL   /* XXH128_hash_t */
+#include "xxhash.h"
+
+
+/* return type */
+
+typedef union {
+    uint64_t       h64;
+    XXH128_hash_t h128;
+} UniHash;
+
+UniHash uniHash32(uint64_t v32)
+{   UniHash unih;
+    unih.h64 = v32;
+    return unih;
+}
+
+UniHash uniHash64(uint64_t v64)
+{   UniHash unih;
+    unih.h64 = v64;
+    return unih;
+}
+
+UniHash uniHash128(XXH128_hash_t v128)
+{   UniHash unih;
+    unih.h128 = v128;
+    return unih;
+}
+
+
+/* ===  xxHash  === */
+
+UniHash XXH3_wrapper (const void* data, size_t size)
+{
+    return uniHash64( XXH3_64bits(data, size) );
+}
+
+UniHash XXH128_wrapper (const void* data, size_t size)
+{
+    return uniHash128( XXH3_128bits(data, size) );
+}
+
+UniHash XXH128l_wrapper (const void* data, size_t size)
+{
+    return uniHash64( XXH3_128bits(data, size).low64 );
+}
+
+UniHash XXH128h_wrapper (const void* data, size_t size)
+{
+    return uniHash64( XXH3_128bits(data, size).high64 );
+}
+
+UniHash XXH64_wrapper (const void* data, size_t size)
+{
+    return uniHash64 ( XXH64(data, size, 0) );
+}
+
+UniHash XXH32_wrapper (const void* data, size_t size)
+{
+    return uniHash32( XXH32(data, size, 0) );
+}
+
+/* ===  Dummy integration example  === */
+
+#include "dummy.h"
+
+UniHash badsum32_wrapper (const void* data, size_t size)
+{
+    return uniHash32( badsum32(data, size, 0) );
+}
+
+
+
+/* ===  Table  === */
+
+typedef UniHash (*hashfn) (const void* data, size_t size);
+
+typedef struct {
+    const char* name;
+    hashfn fn;
+    int bits;
+} hashDescription;
+
+#define HASH_FN_TOTAL 7
+
+hashDescription hashfnTable[HASH_FN_TOTAL] = {
+    { "xxh3"  ,  XXH3_wrapper,     64 },
+    { "xxh64" ,  XXH64_wrapper,    64 },
+    { "xxh128",  XXH128_wrapper,  128 },
+    { "xxh128l", XXH128l_wrapper,  64 },
+    { "xxh128h", XXH128h_wrapper,  64 },
+    { "xxh32" ,  XXH32_wrapper,    32 },
+    { "badsum32",badsum32_wrapper, 32 },
+};
+
+#endif   /* HASHES_H_1235465 */
diff --git a/grpc/third_party/xxhash/tests/collisions/main.c b/grpc/third_party/xxhash/tests/collisions/main.c
new file mode 100644
index 0000000..a857341
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/main.c
@@ -0,0 +1,1120 @@
+/*
+ * Brute force collision tester for 64-bit hashes
+ * Part of the xxHash project
+ * Copyright (C) 2019-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+/*
+ * The collision tester will generate 24 billion hashes (by default),
+ * and count how many collisions were produced by the 64-bit hash algorithm.
+ * The optimal amount of collisions for 64-bit is ~18 collisions.
+ * A good hash should be close to this figure.
+ *
+ * This program requires a lot of memory:
+ * - Either store hash values directly => 192 GB
+ * - Or use a filter:
+ *   -  32 GB (by default) for the filter itself
+ *   -  + ~14 GB for the list of hashes (depending on the filter's outcome)
+ * Due to these memory constraints, it requires a 64-bit system.
+ */
+
+
+ /* ===  Dependencies  === */
+
+#include <stdint.h>   /* uint64_t */
+#include <stdlib.h>   /* malloc, free, qsort, exit */
+#include <string.h>   /* memset */
+#include <stdio.h>    /* printf, fflush */
+
+#undef NDEBUG   /* ensure assert is _not_ disabled */
+#include <assert.h>
+
+#include "hashes.h"   /* UniHash, hashfn, hashfnTable */
+
+#include "sort.hh"    /* sort64 */
+
+
+
+typedef enum { ht32, ht64, ht128 } Htype_e;
+
+/* ===  Debug  === */
+
+#define EXIT(...) { printf(__VA_ARGS__); printf("\n"); exit(1); }
+
+static void hexRaw(const void* buffer, size_t size)
+{
+    const unsigned char* p = (const unsigned char*)buffer;
+    for (size_t i=0; i<size; i++) {
+        printf("%02X", p[i]);
+    }
+}
+
+void printHash(const void* table, size_t n, Htype_e htype)
+{
+    if ((htype == ht64) || (htype == ht32)){
+        uint64_t const h64 = ((const uint64_t*)table)[n];
+        hexRaw(&h64, sizeof(h64));
+    } else {
+        assert(htype == ht128);
+        XXH128_hash_t const h128 = ((const XXH128_hash_t*)table)[n];
+        hexRaw(&h128, sizeof(h128));
+    }
+}
+
+/* ===  Generate Random unique Samples to hash  === */
+
+/*
+ * These functions will generate and update a sample to hash.
+ * initSample() will fill a buffer with random bytes,
+ * updateSample() will modify one slab in the input buffer.
+ * updateSample() guarantees it will produce unique samples,
+ * but it needs to know the total number of samples.
+ */
+
+
+static const uint64_t prime64_1 = 11400714785074694791ULL;   /* 0b1001111000110111011110011011000110000101111010111100101010000111 */
+static const uint64_t prime64_2 = 14029467366897019727ULL;   /* 0b1100001010110010101011100011110100100111110101001110101101001111 */
+static const uint64_t prime64_3 =  1609587929392839161ULL;   /* 0b0001011001010110011001111011000110011110001101110111100111111001 */
+
+static uint64_t avalanche64(uint64_t h64)
+{
+    h64 ^= h64 >> 33;
+    h64 *= prime64_2;
+    h64 ^= h64 >> 29;
+    h64 *= prime64_3;
+    h64 ^= h64 >> 32;
+    return h64;
+}
+
+static unsigned char randomByte(size_t n)
+{
+    uint64_t n64 = avalanche64(n+1);
+    n64 *= prime64_1;
+    return (unsigned char)(n64 >> 56);
+}
+
+typedef enum { sf_slab5, sf_sparse } sf_genMode;
+
+
+#ifdef SLAB5
+
+/*
+ * Slab5 sample generation.
+ * This algorithm generates unique inputs flipping on average 16 bits per candidate.
+ * It is generally much more friendly for most hash algorithms, especially
+ * weaker ones, as it shuffles more the input.
+ * The algorithm also avoids overfitting the per4 or per8 ingestion patterns.
+ */
+
+#define SLAB_SIZE 5
+
+typedef struct {
+    void* buffer;
+    size_t size;
+    sf_genMode mode;
+    size_t prngSeed;
+    uint64_t hnb;
+} sampleFactory;
+
+static void init_sampleFactory(sampleFactory* sf, uint64_t htotal)
+{
+    uint64_t const minNbSlabs = ((htotal-1) >> 32) + 1;
+    uint64_t const minSize = minNbSlabs * SLAB_SIZE;
+    if (sf->size < minSize)
+        EXIT("sample size must be >= %i bytes for this amount of hashes",
+            (int)minSize);
+
+    unsigned char* const p = (unsigned char*)sf->buffer;
+    for (size_t n=0; n < sf->size; n++)
+        p[n] = randomByte(n);
+    sf->hnb = 0;
+}
+
+static sampleFactory*
+create_sampleFactory(size_t size, uint64_t htotal, uint64_t seed)
+{
+    sampleFactory* const sf = malloc(sizeof(sampleFactory));
+    if (!sf) EXIT("not enough memory");
+    void* const buffer = malloc(size);
+    if (!buffer) EXIT("not enough memory");
+    sf->buffer = buffer;
+    sf->size = size;
+    sf->mode = sf_slab5;
+    sf->prngSeed = seed;
+    init_sampleFactory(sf, htotal);
+    return sf;
+}
+
+static void free_sampleFactory(sampleFactory* sf)
+{
+    if (!sf) return;
+    free(sf->buffer);
+    free(sf);
+}
+
+static inline void update_sampleFactory(sampleFactory* sf)
+{
+    size_t const nbSlabs = sf->size / SLAB_SIZE;
+    size_t const SlabNb = sf->hnb % nbSlabs;
+    sf->hnb++;
+
+    char* const ptr = (char*)sf->buffer;
+    size_t const start = (SlabNb * SLAB_SIZE) + 1;
+    uint32_t val32;
+    memcpy(&val32, ptr+start, sizeof(val32));
+    static const uint32_t prime32_5 = 374761393U;
+    val32 += prime32_5;
+    memcpy(ptr+start, &val32, sizeof(val32));
+}
+
+#else
+
+/*
+ * Sparse sample generation.
+ * This is the default pattern generator.
+ * It only flips one bit at a time (mostly).
+ * Low hamming distance scenario is more difficult for weak hash algorithms.
+ * Note that CRC is immune to this scenario, since they are specifically
+ * designed to detect low hamming distances.
+ * Prefer the Slab5 pattern generator for collisions on CRC algorithms.
+ */
+
+#define SPARSE_LEVEL_MAX 15
+
+/* Nb of combinations of m bits in a register of n bits */
+static double Cnm(int n, int m)
+{
+    assert(n > 0);
+    assert(m > 0);
+    assert(m <= m);
+    double acc = 1;
+    for (int i=0; i<m; i++) {
+        acc *= n - i;
+        acc /= 1 + i;
+    }
+    return acc;
+}
+
+static int enoughCombos(size_t size, uint64_t htotal)
+{
+    if (size < 2) return 0;   /* ensure no multiplication by negative */
+    uint64_t acc = 0;
+    uint64_t const srcBits = size * 8; assert(srcBits < INT_MAX);
+    int nbBitsSet = 0;
+    while (acc < htotal) {
+        nbBitsSet++;
+        if (nbBitsSet >= SPARSE_LEVEL_MAX) return 0;
+        acc += (uint64_t)Cnm((int)srcBits, nbBitsSet);
+    }
+    return 1;
+}
+
+typedef struct {
+    void* buffer;
+    size_t size;
+    sf_genMode mode;
+    /* sparse */
+    size_t bitIdx[SPARSE_LEVEL_MAX];
+    int level;
+    size_t maxBitIdx;
+    /* slab5 */
+    size_t nbSlabs;
+    size_t current;
+    size_t prngSeed;
+} sampleFactory;
+
+static void init_sampleFactory(sampleFactory* sf, uint64_t htotal)
+{
+    if (!enoughCombos(sf->size, htotal)) {
+        EXIT("sample size must be larger for this amount of hashes");
+    }
+
+    memset(sf->bitIdx, 0, sizeof(sf->bitIdx));
+    sf->level = 0;
+
+    unsigned char* const p = (unsigned char*)sf->buffer;
+    for (size_t n=0; n<sf->size; n++)
+        p[n] = randomByte(sf->prngSeed + n);
+}
+
+static sampleFactory*
+create_sampleFactory(size_t size, uint64_t htotal, uint64_t seed)
+{
+    sampleFactory* const sf = malloc(sizeof(sampleFactory));
+    if (!sf) EXIT("not enough memory");
+    void* const buffer = malloc(size);
+    if (!buffer) EXIT("not enough memory");
+    sf->buffer = buffer;
+    sf->size = size;
+    sf->mode = sf_sparse;
+    sf->maxBitIdx = size * 8;
+    sf->prngSeed = seed;
+    init_sampleFactory(sf, htotal);
+    return sf;
+}
+
+static void free_sampleFactory(sampleFactory* sf)
+{
+    if (!sf) return;
+    free(sf->buffer);
+    free(sf);
+}
+
+static void flipbit(void* buffer, uint64_t bitID)
+{
+    size_t const pos = bitID >> 3;
+    unsigned char const mask = (unsigned char)(1 << (bitID & 7));
+    unsigned char* const p = (unsigned char*)buffer;
+    p[pos] ^= mask;
+}
+
+static int updateBit(void* buffer, size_t* bitIdx, int level, size_t max)
+{
+    if (level==0) return 0;   /* can't progress further */
+
+    flipbit(buffer, bitIdx[level]); /* erase previous bits */
+
+    if (bitIdx[level] < max-1) { /* simple case: go to next bit */
+        bitIdx[level]++;
+        flipbit(buffer, bitIdx[level]); /* set new bit */
+        return 1;
+    }
+
+    /* reached last bit: need to update a bit from lower level */
+    if (!updateBit(buffer, bitIdx, level-1, max-1)) return 0;
+    bitIdx[level] = bitIdx[level-1] + 1;
+    flipbit(buffer, bitIdx[level]); /* set new bit */
+    return 1;
+}
+
+static inline void update_sampleFactory(sampleFactory* sf)
+{
+    if (!updateBit(sf->buffer, sf->bitIdx, sf->level, sf->maxBitIdx)) {
+        /* no more room => move to next level */
+        sf->level++;
+        assert(sf->level < SPARSE_LEVEL_MAX);
+
+        /* set new bits */
+        for (int i=1; i <= sf->level; i++) {
+            sf->bitIdx[i] = (size_t)(i-1);
+            flipbit(sf->buffer, sf->bitIdx[i]);
+        }
+    }
+}
+
+#endif /* pattern generator selection */
+
+
+/* ===  Candidate Filter  === */
+
+typedef unsigned char Filter;
+
+Filter* create_Filter(int bflog)
+{
+    assert(bflog < 64 && bflog > 1);
+    size_t bfsize = (size_t)1 << bflog;
+    Filter* bf = malloc(bfsize);
+    assert(((void)"Filter creation failed", bf));
+    memset(bf, 0, bfsize);
+    return bf;
+}
+
+void free_Filter(Filter* bf)
+{
+    free(bf);
+}
+
+#ifdef FILTER_1_PROBE
+
+/*
+ * Attach hash to a slot
+ * return: Nb of potential collision candidates detected
+ *          0: position not yet occupied
+ *          2: position previously occupied by a single candidate
+ *          1: position already occupied by multiple candidates
+ */
+inline int Filter_insert(Filter* bf, int bflog, uint64_t hash)
+{
+    int const slotNb = hash & 3;
+    int const shift = slotNb * 2 ;
+
+    size_t const bfmask = ((size_t)1 << bflog) - 1;
+    size_t const pos = (hash >> 2) & bfmask;
+
+    int const existingCandidates = ((((unsigned char*)bf)[pos]) >> shift) & 3;
+
+    static const int addCandidates[4] = { 0, 2, 1, 1 };
+    static const int nextValue[4] = { 1, 2, 3, 3 };
+
+    ((unsigned char*)bf)[pos] |= (unsigned char)(nextValue[existingCandidates] << shift);
+    return addCandidates[existingCandidates];
+}
+
+/*
+ * Check if provided 64-bit hash is a collision candidate
+ * Requires the slot to be occupied by at least 2 candidates.
+ * return >0 if hash is a collision candidate
+ *         0 otherwise (slot unoccupied, or only one candidate)
+ * note: unoccupied slots should not happen in this algorithm,
+ *       since all hashes are supposed to have been inserted at least once.
+ */
+inline int Filter_check(const Filter* bf, int bflog, uint64_t hash)
+{
+    int const slotNb = hash & 3;
+    int const shift = slotNb * 2;
+
+    size_t const bfmask = ((size_t)1 << bflog) - 1;
+    size_t const pos = (hash >> 2) & bfmask;
+
+    return (((const unsigned char*)bf)[pos]) >> (shift+1) & 1;
+}
+
+#else
+
+/*
+ * 2-probes strategy,
+ * more efficient at filtering candidates,
+ * requires filter size to be > nb of hashes
+ */
+
+#define MIN(a,b)   ((a) < (b) ? (a) : (b))
+#define MAX(a,b)   ((a) > (b) ? (a) : (b))
+
+/*
+ * Attach hash to 2 slots
+ * return: Nb of potential candidates detected
+ *          0: position not yet occupied
+ *          2: position previously occupied by a single candidate (at most)
+ *          1: position already occupied by multiple candidates
+ */
+static inline int Filter_insert(Filter* bf, int bflog, uint64_t hash)
+ {
+     hash = avalanche64(hash);
+     unsigned const slot1 = hash & 255;
+     hash >>= 8;
+     unsigned const slot2 = hash & 255;
+     hash >>= 8;
+
+     size_t const fclmask = ((size_t)1 << (bflog-6)) - 1;
+     size_t const cacheLineNb = hash & fclmask;
+
+     size_t const pos1 = (cacheLineNb << 6) + (slot1 >> 2);
+     unsigned const shift1 = (slot1 & 3) * 2;
+     unsigned const ex1 = (bf[pos1] >> shift1) & 3;
+
+     size_t const pos2 = (cacheLineNb << 6) + (slot2 >> 2);
+     unsigned const shift2 = (slot2 & 3) * 2;
+     unsigned const ex2 = (bf[pos2] >> shift2) & 3;
+
+     unsigned const existing = MIN(ex1, ex2);
+
+     static const int addCandidates[4] = { 0, 2, 1, 1 };
+     static const unsigned nextValue[4] = { 1, 2, 3, 3 };
+
+     bf[pos1] &= (Filter)(~(3 << shift1)); /* erase previous value */
+     bf[pos1] |= (Filter)(MAX(ex1, nextValue[existing]) << shift1);
+     bf[pos2] |= (Filter)(MAX(ex2, nextValue[existing]) << shift2);
+
+     return addCandidates[existing];
+ }
+
+
+/*
+ * Check if provided 64-bit hash is a collision candidate
+ * Requires the slot to be occupied by at least 2 candidates.
+ * return >0 if hash is a collision candidate
+ *         0 otherwise (slot unoccupied, or only one candidate)
+ * note: unoccupied slots should not happen in this algorithm,
+ *       since all hashes are supposed to have been inserted at least once.
+ */
+static inline int Filter_check(const Filter* bf, int bflog, uint64_t hash)
+ {
+     hash = avalanche64(hash);
+     unsigned const slot1 = hash & 255;
+     hash >>= 8;
+     unsigned const slot2 = hash & 255;
+     hash >>= 8;
+
+     size_t const fclmask = ((size_t)1 << (bflog-6)) - 1;
+     size_t const cacheLineNb = hash & fclmask;
+
+     size_t const pos1 = (cacheLineNb << 6) + (slot1 >> 2);
+     unsigned const shift1 = (slot1 & 3) * 2;
+     unsigned const ex1 = (bf[pos1] >> shift1) & 3;
+
+     size_t const pos2 = (cacheLineNb << 6) + (slot2 >> 2);
+     unsigned const shift2 = (slot2 & 3) * 2;
+     unsigned const ex2 = (bf[pos2] >> shift2) & 3;
+
+     return (ex1 >= 2) && (ex2 >= 2);
+ }
+
+#endif // FILTER_1_PROBE
+
+
+/* ===  Display  === */
+
+#include <time.h>   /* clock_t, clock, time_t, time, difftime */
+
+void update_indicator(uint64_t v, uint64_t total)
+{
+    static clock_t start = 0;
+    if (start==0) start = clock();
+    clock_t const updateRate = CLOCKS_PER_SEC / 2;
+
+    clock_t const clockSpan = (clock_t)(clock() - start);
+    if (clockSpan > updateRate) {
+        start = clock();
+        assert(v <= total);
+        assert(total > 0);
+        double share = ((double)v / (double)total) * 100;
+        printf("%6.2f%% (%llu)  \r", share, (unsigned long long)v);
+        fflush(NULL);
+    }
+}
+
+/* note: not thread safe */
+const char* displayDelay(double delay_s)
+{
+    static char delayString[50];
+    memset(delayString, 0, sizeof(delayString));
+
+    int const mn = ((int)delay_s / 60) % 60;
+    int const h = (int)delay_s / 3600;
+    int const sec = (int)delay_s % 60;
+
+    char* p = delayString;
+    if (h) sprintf(p, "%i h ", h);
+    if (mn || h) {
+        p = delayString + strlen(delayString);
+        sprintf(p, "%i mn ", mn);
+    }
+    p = delayString + strlen(delayString);
+    sprintf(p, "%is ", sec);
+
+    return delayString;
+}
+
+
+/* ===  Math  === */
+
+static double power(uint64_t base, int p)
+{
+    double value = 1;
+    assert(p>=0);
+    for (int i=0; i<p; i++) {
+        value *= (double)base;
+    }
+    return value;
+}
+
+static double estimateNbCollisions(uint64_t nbH, int nbBits)
+{
+    return ((double)nbH * (double)(nbH-1)) / power(2, nbBits+1);
+}
+
+static int highestBitSet(uint64_t v)
+{
+    assert(v!=0);
+    int bitId = 0;
+    while (v >>= 1) bitId++;
+    return bitId;
+}
+
+
+/* ===  Filter and search collisions  === */
+
+#undef NDEBUG   /* ensure assert is not disabled */
+#include <assert.h>
+
+/* will recommend 24 billion samples for 64-bit hashes,
+ * expecting 18 collisions for a good 64-bit hash */
+#define NB_BITS_MAX 64   /* can't store nor analyze hash wider than 64-bits for the time being */
+uint64_t select_nbh(int nbBits)
+{
+    assert(nbBits > 0);
+    if (nbBits > NB_BITS_MAX) nbBits = NB_BITS_MAX;
+    double targetColls = (double)((128 + 17) - (nbBits * 2));
+    uint64_t nbH = 24;
+    while (estimateNbCollisions(nbH, nbBits) < targetColls) nbH *= 2;
+    return nbH;
+}
+
+
+typedef struct {
+    uint64_t nbCollisions;
+} searchCollisions_results;
+
+typedef struct {
+    uint64_t nbH;
+    uint64_t mask;
+    uint64_t maskSelector;
+    size_t sampleSize;
+    uint64_t prngSeed;
+    int filterLog;      /* <0 = disable filter;  0 = auto-size; */
+    int hashID;
+    int display;
+    int nbThreads;
+    searchCollisions_results* resultPtr;
+} searchCollisions_parameters;
+
+#define DISPLAY(...) { if (display) printf(__VA_ARGS__); }
+
+static int isEqual(void* hTablePtr, size_t index1, size_t index2, Htype_e htype)
+{
+    if ((htype == ht64) || (htype == ht32)) {
+        uint64_t const h1 = ((const uint64_t*)hTablePtr)[index1];
+        uint64_t const h2 = ((const uint64_t*)hTablePtr)[index2];
+        return (h1 == h2);
+    } else {
+        assert(htype == ht128);
+        XXH128_hash_t const h1 = ((const XXH128_hash_t*)hTablePtr)[index1];
+        XXH128_hash_t const h2 = ((const XXH128_hash_t*)hTablePtr)[index2];
+        return XXH128_isEqual(h1, h2);
+    }
+}
+
+static int isHighEqual(void* hTablePtr, size_t index1, size_t index2, Htype_e htype, int rShift)
+{
+    uint64_t h1, h2;
+    if ((htype == ht64) || (htype == ht32)) {
+        h1 = ((const uint64_t*)hTablePtr)[index1];
+        h2 = ((const uint64_t*)hTablePtr)[index2];
+    } else {
+        assert(htype == ht128);
+        h1 = ((const XXH128_hash_t*)hTablePtr)[index1].high64;
+        h2 = ((const XXH128_hash_t*)hTablePtr)[index2].high64;
+        assert(rShift >= 64);
+        rShift -= 64;
+    }
+    assert(0 <= rShift && rShift < 64);
+    return (h1 >> rShift) == (h2 >> rShift);
+}
+
+/* assumption: (htype*)hTablePtr[index] is valid */
+static void addHashCandidate(void* hTablePtr, UniHash h, Htype_e htype, size_t index)
+{
+    if ((htype == ht64) || (htype == ht32)) {
+        ((uint64_t*)hTablePtr)[index] = h.h64;
+    } else {
+        assert(htype == ht128);
+        ((XXH128_hash_t*)hTablePtr)[index] = h.h128;
+    }
+}
+
+static int getNbBits_fromHtype(Htype_e htype) {
+    switch(htype) {
+        case ht32: return 32;
+        case ht64: return 64;
+        case ht128:return 128;
+        default: EXIT("hash size not supported");
+    }
+}
+
+static Htype_e getHtype_fromHbits(int nbBits) {
+    switch(nbBits) {
+        case 32 : return ht32;
+        case 64 : return ht64;
+        case 128: return ht128;
+        default: EXIT("hash size not supported");
+    }
+}
+
+static size_t search_collisions(
+    searchCollisions_parameters param)
+{
+    uint64_t totalH = param.nbH;
+    const uint64_t hMask = param.mask;
+    const uint64_t hSelector = param.maskSelector;
+    int bflog = param.filterLog;
+    const int filter = (param.filterLog >= 0);
+    const size_t sampleSize = param.sampleSize;
+    const int hashID = param.hashID;
+    const Htype_e htype = getHtype_fromHbits(hashfnTable[hashID].bits);
+    const int display = param.display;
+    /* init */
+    sampleFactory* const sf = create_sampleFactory(sampleSize, totalH, param.prngSeed);
+    if (!sf) EXIT("not enough memory");
+
+    //const char* const hname = hashfnTable[hashID].name;
+    hashfn const hfunction = hashfnTable[hashID].fn;
+    int const hwidth = hashfnTable[hashID].bits;
+    if (totalH == 0) totalH = select_nbh(hwidth);
+    if (bflog == 0) bflog = highestBitSet(totalH) + 1;   /* auto-size filter */
+    uint64_t const bfsize = (1ULL << bflog);
+
+
+    /* ===  filter hashes (optional)  === */
+
+    Filter* bf = NULL;
+    uint64_t nbPresents = totalH;
+
+    if (filter) {
+        time_t const filterTBegin = time(NULL);
+        DISPLAY(" Creating filter (%i GB) \n", (int)(bfsize >> 30));
+        bf = create_Filter(bflog);
+        if (!bf) EXIT("not enough memory for filter");
+
+
+        DISPLAY(" Generate %llu hashes from samples of %u bytes \n",
+                (unsigned long long)totalH, (unsigned)sampleSize);
+        nbPresents = 0;
+
+        for (uint64_t n=0; n < totalH; n++) {
+            if (display && ((n&0xFFFFF) == 1) )
+                update_indicator(n, totalH);
+            update_sampleFactory(sf);
+
+            UniHash const h = hfunction(sf->buffer, sampleSize);
+            if ((h.h64 & hMask) != hSelector) continue;
+
+            nbPresents += (uint64_t)Filter_insert(bf, bflog, h.h64);
+        }
+
+        if (nbPresents==0) {
+            DISPLAY(" Analysis completed: No collision detected \n");
+            if (param.resultPtr) param.resultPtr->nbCollisions = 0;
+            free_Filter(bf);
+            free_sampleFactory(sf);
+            return 0;
+        }
+
+        {   double const filterDelay = difftime(time(NULL), filterTBegin);
+            DISPLAY(" Generation and filter completed in %s, detected up to %llu candidates \n",
+                    displayDelay(filterDelay), (unsigned long long) nbPresents);
+    }   }
+
+
+    /* === store hash candidates: duplicates will be present here === */
+
+    time_t const storeTBegin = time(NULL);
+    size_t const hashByteSize = (htype == ht128) ? 16 : 8;
+    size_t const tableSize = (nbPresents+1) * hashByteSize;
+    assert(tableSize > nbPresents);  /* check tableSize calculation overflow */
+    DISPLAY(" Storing hash candidates (%i MB) \n", (int)(tableSize >> 20));
+
+    /* Generate and store hashes */
+    void* const hashCandidates = malloc(tableSize);
+    if (!hashCandidates) EXIT("not enough memory to store candidates");
+    init_sampleFactory(sf, totalH);
+    size_t nbCandidates = 0;
+    for (uint64_t n=0; n < totalH; n++) {
+        if (display && ((n&0xFFFFF) == 1) ) update_indicator(n, totalH);
+        update_sampleFactory(sf);
+
+        UniHash const h = hfunction(sf->buffer, sampleSize);
+        if ((h.h64 & hMask) != hSelector) continue;
+
+        if (filter) {
+            if (Filter_check(bf, bflog, h.h64)) {
+                assert(nbCandidates < nbPresents);
+                addHashCandidate(hashCandidates, h, htype, nbCandidates++);
+            }
+        } else {
+            assert(nbCandidates < nbPresents);
+            addHashCandidate(hashCandidates, h, htype, nbCandidates++);
+        }
+    }
+    if (nbCandidates < nbPresents) {
+        /* Try to mitigate gnuc_quicksort behavior, by reducing allocated memory,
+         * since gnuc_quicksort uses a lot of additional memory for mergesort */
+        void* const checkPtr = realloc(hashCandidates, nbCandidates * hashByteSize);
+        assert(checkPtr != NULL);
+        assert(checkPtr == hashCandidates);  /* simplification: since we are reducing the size,
+                                              * we hope to keep the same ptr position.
+                                              * Otherwise, hashCandidates must be mutable. */
+        DISPLAY(" List of hashes reduced to %u MB from %u MB (saved %u MB) \n",
+                (unsigned)((nbCandidates * hashByteSize) >> 20),
+                (unsigned)(tableSize >> 20),
+                (unsigned)((tableSize - (nbCandidates * hashByteSize)) >> 20) );
+    }
+    double const storeTDelay = difftime(time(NULL), storeTBegin);
+    DISPLAY(" Stored %llu hash candidates in %s \n",
+            (unsigned long long) nbCandidates, displayDelay(storeTDelay));
+    free_Filter(bf);
+    free_sampleFactory(sf);
+
+
+    /* === step 3: look for duplicates === */
+    time_t const sortTBegin = time(NULL);
+    DISPLAY(" Sorting candidates... ");
+    fflush(NULL);
+    if ((htype == ht64) || (htype == ht32)) {
+        /*
+         * Use C++'s std::sort, as it's faster than C stdlib's qsort, and
+         * doesn't suffer from gnuc_libsort's memory expansion
+         */
+        sort64(hashCandidates, nbCandidates);
+    } else {
+        assert(htype == ht128);
+        sort128(hashCandidates, nbCandidates); /* sort with custom comparator */
+    }
+    double const sortTDelay = difftime(time(NULL), sortTBegin);
+    DISPLAY(" Completed in %s \n", displayDelay(sortTDelay));
+
+    /* scan and count duplicates */
+    time_t const countBegin = time(NULL);
+    DISPLAY(" Looking for duplicates: ");
+    fflush(NULL);
+    size_t collisions = 0;
+    for (size_t n=1; n<nbCandidates; n++) {
+        if (isEqual(hashCandidates, n, n-1, htype)) {
+#if defined(COL_DISPLAY_DUPLICATES)
+            printf("collision: ");
+            printHash(hashCandidates, n, htype);
+            printf(" / ");
+            printHash(hashCandidates, n-1, htype);
+            printf(" \n");
+#endif
+            collisions++;
+    }   }
+
+    if (!filter /* all candidates */ && display /*single thead*/ ) {
+        /* check partial bitfields (high bits) */
+        DISPLAY(" \n");
+        int const hashBits = getNbBits_fromHtype(htype);
+        double worstRatio = 0.;
+        int worstNbHBits = 0;
+        for (int nbHBits = 1; nbHBits < hashBits; nbHBits++) {
+            uint64_t const nbSlots = (uint64_t)1 << nbHBits;
+            double const expectedCollisions = estimateNbCollisions(nbCandidates, nbHBits);
+            if ( (nbSlots > nbCandidates * 100)  /* within range for meaningfull collision analysis results */
+              && (expectedCollisions > 18.0) ) {
+                int const rShift = hashBits - nbHBits;
+                size_t HBits_collisions = 0;
+                for (size_t n=1; n<nbCandidates; n++) {
+                    if (isHighEqual(hashCandidates, n, n-1, htype, rShift)) {
+                        HBits_collisions++;
+                }   }
+                double const collisionRatio = (double)HBits_collisions / expectedCollisions;
+                if (collisionRatio > 2.0) DISPLAY("WARNING !!!  ===> ");
+                DISPLAY(" high %i bits: %zu collision (%.1f expected): x%.2f \n",
+                        nbHBits, HBits_collisions, expectedCollisions, collisionRatio);
+                if (collisionRatio > worstRatio) {
+                    worstNbHBits = nbHBits;
+                    worstRatio = collisionRatio;
+        }   }   }
+        DISPLAY("Worst collision ratio at %i high bits: x%.2f \n",
+                worstNbHBits, worstRatio);
+    }
+    double const countDelay = difftime(time(NULL), countBegin);
+    DISPLAY(" Completed in %s \n", displayDelay(countDelay));
+
+    /* clean and exit */
+    free (hashCandidates);
+
+#if 0  /* debug */
+    for (size_t n=0; n<nbCandidates; n++)
+        printf("0x%016llx \n", (unsigned long long)hashCandidates[n]);
+#endif
+
+    if (param.resultPtr) param.resultPtr->nbCollisions = collisions;
+    return collisions;
+}
+
+
+
+#if defined(__MACH__) || defined(__linux__)
+#include <sys/resource.h>
+static size_t getProcessMemUsage(int children)
+{
+    struct rusage stats;
+    if (getrusage(children ? RUSAGE_CHILDREN : RUSAGE_SELF, &stats) == 0)
+      return (size_t)stats.ru_maxrss;
+    return 0;
+}
+#else
+static size_t getProcessMemUsage(int ignore) { return 0; }
+#endif
+
+void time_collisions(searchCollisions_parameters param)
+{
+    uint64_t totalH = param.nbH;
+    int hashID = param.hashID;
+    int display = param.display;
+
+    /* init */
+    assert(0 <= hashID && hashID < HASH_FN_TOTAL);
+    //const char* const hname = hashfnTable[hashID].name;
+    int const hwidth = hashfnTable[hashID].bits;
+    if (totalH == 0) totalH = select_nbh(hwidth);
+    double const targetColls = estimateNbCollisions(totalH, hwidth);
+
+    /* Start the timer to measure start/end of hashing + collision detection. */
+    time_t const programTBegin = time(NULL);
+
+    /* Generate hashes, and count collisions */
+    size_t const collisions = search_collisions(param);
+
+    /* display results */
+    double const programTDelay = difftime(time(NULL), programTBegin);
+    size_t const programBytesSelf = getProcessMemUsage(0);
+    size_t const programBytesChildren = getProcessMemUsage(1);
+    DISPLAY("\n\n");
+    DISPLAY("===>   Found %llu collisions (x%.2f, %.1f expected) in %s\n",
+            (unsigned long long)collisions,
+            (double)collisions / targetColls,
+            targetColls,
+            displayDelay(programTDelay));
+    if (programBytesSelf)
+      DISPLAY("===>   MaxRSS(self) %zuMB, MaxRSS(children) %zuMB\n",
+              programBytesSelf>>20,
+              programBytesChildren>>20);
+    DISPLAY("------------------------------------------ \n");
+}
+
+// wrapper for pthread interface
+void MT_searchCollisions(void* payload)
+{
+    search_collisions(*(searchCollisions_parameters*)payload);
+}
+
+/* ===  Command Line  === */
+
+/*!
+ * readU64FromChar():
+ * Allows and interprets K, KB, KiB, M, MB and MiB suffix.
+ * Will also modify `*stringPtr`, advancing it to the position where it stopped reading.
+ */
+static uint64_t readU64FromChar(const char** stringPtr)
+{
+    static uint64_t const max = (((uint64_t)(-1)) / 10) - 1;
+    uint64_t result = 0;
+    while ((**stringPtr >='0') && (**stringPtr <='9')) {
+        assert(result < max);
+        result *= 10;
+        result += (unsigned)(**stringPtr - '0');
+        (*stringPtr)++ ;
+    }
+    if ((**stringPtr=='K') || (**stringPtr=='M') || (**stringPtr=='G')) {
+        uint64_t const maxK = ((uint64_t)(-1)) >> 10;
+        assert(result < maxK);
+        result <<= 10;
+        if ((**stringPtr=='M') || (**stringPtr=='G')) {
+            assert(result < maxK);
+            result <<= 10;
+            if (**stringPtr=='G') {
+                assert(result < maxK);
+                result <<= 10;
+            }
+        }
+        (*stringPtr)++;  /* skip `K` or `M` */
+        if (**stringPtr=='i') (*stringPtr)++;
+        if (**stringPtr=='B') (*stringPtr)++;
+    }
+    return result;
+}
+
+
+/**
+ * longCommandWArg():
+ * Checks if *stringPtr is the same as longCommand.
+ * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand.
+ * @return 0 and doesn't modify *stringPtr otherwise.
+ */
+static int longCommandWArg(const char** stringPtr, const char* longCommand)
+{
+    assert(longCommand); assert(stringPtr); assert(*stringPtr);
+    size_t const comSize = strlen(longCommand);
+    int const result = !strncmp(*stringPtr, longCommand, comSize);
+    if (result) *stringPtr += comSize;
+    return result;
+}
+
+
+#include "pool.h"
+
+/*
+ * As some hashes use different algorithms depending on input size,
+ * it can be necessary to test multiple input sizes
+ * to paint an accurate picture of collision performance
+ */
+#define SAMPLE_SIZE_DEFAULT 256
+#define HASHFN_ID_DEFAULT 0
+
+void help(const char* exeName)
+{
+    printf("usage: %s [hashName] [opt] \n\n", exeName);
+    printf("list of hashNames:");
+    printf("%s ", hashfnTable[0].name);
+    for (int i=1; i < HASH_FN_TOTAL; i++) {
+        printf(", %s ", hashfnTable[i].name);
+    }
+    printf(" \n");
+    printf("Default hashName is %s\n", hashfnTable[HASHFN_ID_DEFAULT].name);
+
+    printf(" \n");
+    printf("Optional parameters: \n");
+    printf("  --nbh=NB       Select nb of hashes to generate (%llu by default) \n", (unsigned long long)select_nbh(64));
+    printf("  --filter       Activates the filter. Slower, but reduces memory usage for the same nb of hashes.\n");
+    printf("  --threadlog=NB Use 2^NB threads.\n");
+    printf("  --len=MB       Set length of the input (%i bytes by default) \n", SAMPLE_SIZE_DEFAULT);
+}
+
+int bad_argument(const char* exeName)
+{
+    printf("incorrect command: \n");
+    help(exeName);
+    return 1;
+}
+
+
+int main(int argc, const char** argv)
+{
+    if (sizeof(size_t) < 8) return 1;  // cannot work on systems without ability to allocate objects >= 4 GB
+
+    assert(argc > 0);
+    const char* const exeName = argv[0];
+    uint64_t totalH = 0;  /* auto, based on nbBits */
+    int bflog = 0;    /* auto */
+    int filter = 0;   /* disabled */
+    size_t sampleSize = SAMPLE_SIZE_DEFAULT;
+    int hashID = HASHFN_ID_DEFAULT;
+    int threadlog = 0;
+    uint64_t prngSeed = 0;
+
+    int arg_nb;
+    for (arg_nb = 1; arg_nb < argc; arg_nb++) {
+        const char** arg = argv + arg_nb;
+
+        if (!strcmp(*arg, "-h")) { help(exeName); return 0; }
+        if (longCommandWArg(arg, "-T")) { threadlog = (int)readU64FromChar(arg); continue; }
+
+        if (!strcmp(*arg, "--filter"))    { filter=1; continue; }
+        if (!strcmp(*arg, "--no-filter")) { filter=0; continue; }
+
+        if (longCommandWArg(arg, "--seed")) { prngSeed = readU64FromChar(arg); continue; }
+        if (longCommandWArg(arg, "--nbh=")) { totalH = readU64FromChar(arg); continue; }
+        if (longCommandWArg(arg, "--filter=")) { filter=1; bflog = (int)readU64FromChar(arg); assert(bflog < 64); continue; }
+        if (longCommandWArg(arg, "--filterlog=")) { filter=1; bflog = (int)readU64FromChar(arg); assert(bflog < 64); continue; }
+        if (longCommandWArg(arg, "--size=")) { sampleSize = (size_t)readU64FromChar(arg); continue; }
+        if (longCommandWArg(arg, "--len=")) { sampleSize = (size_t)readU64FromChar(arg); continue; }
+        if (longCommandWArg(arg, "--threadlog=")) { threadlog = (int)readU64FromChar(arg); continue; }
+
+        /* argument understood as hash name (must be correct) */
+        int hnb;
+        for (hnb=0; hnb < HASH_FN_TOTAL; hnb++) {
+            if (!strcmp(*arg, hashfnTable[hnb].name)) { hashID = hnb; break; }
+        }
+        if (hnb == HASH_FN_TOTAL) return bad_argument(exeName);
+    }
+
+    /* init */
+    const char* const hname = hashfnTable[hashID].name;
+    int const hwidth = hashfnTable[hashID].bits;
+    if (totalH == 0) totalH = select_nbh(hwidth);
+    double const targetColls = estimateNbCollisions(totalH, hwidth);
+    if (bflog == 0) bflog = highestBitSet(totalH) + 1;   /* auto-size filter */
+    if (!filter) bflog = -1; // disable filter
+
+    if (sizeof(size_t) < 8)
+      EXIT("This program has not been validated on architectures other than "
+           "64bit \n");
+
+    printf(" *** Collision tester for 64+ bit hashes ***  \n\n");
+    printf("Testing %s algorithm (%i-bit) \n", hname, hwidth);
+    printf("This program will allocate a lot of memory,\n");
+    printf("generate %llu %i-bit hashes from samples of %u bytes, \n",
+            (unsigned long long)totalH, hwidth, (unsigned)sampleSize);
+    printf("and attempt to produce %.0f collisions. \n\n", targetColls);
+
+    int const nbThreads = 1 << threadlog;
+    if (nbThreads <= 0) EXIT("Invalid --threadlog value.");
+
+    if (nbThreads == 1) {
+
+        searchCollisions_parameters params;
+        params.nbH = totalH;
+        params.mask = 0;
+        params.maskSelector = 0;
+        params.sampleSize = sampleSize;
+        params.filterLog = bflog;
+        params.hashID = hashID;
+        params.display = 1;
+        params.resultPtr = NULL;
+        params.prngSeed = prngSeed;
+        params.nbThreads = 1;
+        time_collisions(params);
+
+    } else { /*  nbThreads > 1 */
+
+        /* use multithreading */
+        if (threadlog >= 30) EXIT("too many threads requested");
+        if ((uint64_t)nbThreads > (totalH >> 16))
+            EXIT("too many threads requested");
+        if (bflog > 0 && threadlog > (bflog-10))
+            EXIT("too many threads requested");
+        printf("using %i threads ... \n", nbThreads);
+
+        /* allocation */
+        time_t const programTBegin = time(NULL);
+        POOL_ctx* const pt = POOL_create((size_t)nbThreads, 1);
+        if (!pt) EXIT("not enough memory for threads");
+        searchCollisions_results* const MTresults = calloc (sizeof(searchCollisions_results), (size_t)nbThreads);
+        if (!MTresults) EXIT("not enough memory");
+        searchCollisions_parameters* const MTparams = calloc (sizeof(searchCollisions_parameters), (size_t)nbThreads);
+        if (!MTparams) EXIT("not enough memory");
+
+        /* distribute jobs */
+        for (int tnb=0; tnb<nbThreads; tnb++) {
+            MTparams[tnb].nbH = totalH;
+            MTparams[tnb].mask = (uint64_t)nbThreads - 1;
+            MTparams[tnb].sampleSize = sampleSize;
+            MTparams[tnb].filterLog = bflog ? bflog - threadlog : 0;
+            MTparams[tnb].hashID = hashID;
+            MTparams[tnb].display = 0;
+            MTparams[tnb].resultPtr = MTresults+tnb;
+            MTparams[tnb].prngSeed = prngSeed;
+            MTparams[tnb].maskSelector = (uint64_t)tnb;
+            POOL_add(pt, MT_searchCollisions, MTparams + tnb);
+        }
+        POOL_free(pt);  /* actually joins and free */
+
+        /* Gather results */
+        uint64_t nbCollisions=0;
+        for (int tnb=0; tnb<nbThreads; tnb++) {
+            nbCollisions += MTresults[tnb].nbCollisions;
+        }
+
+        double const programTDelay = difftime(time(NULL), programTBegin);
+        size_t const programBytesSelf = getProcessMemUsage(0);
+        size_t const programBytesChildren = getProcessMemUsage(1);
+        printf("\n\n");
+        printf("===>   Found %llu collisions (x%.2f, %.1f expected) in %s\n",
+                (unsigned long long)nbCollisions,
+                (double)nbCollisions / targetColls,
+                targetColls,
+                displayDelay(programTDelay));
+        if (programBytesSelf)
+          printf("===>   MaxRSS(self) %zuMB, MaxRSS(children) %zuMB\n",
+                 programBytesSelf>>20,
+                 programBytesChildren>>20);
+        printf("------------------------------------------ \n");
+
+        /* Clean up */
+        free(MTparams);
+        free(MTresults);
+    }
+
+    return 0;
+}
diff --git a/grpc/third_party/xxhash/tests/collisions/pool.c b/grpc/third_party/xxhash/tests/collisions/pool.c
new file mode 100644
index 0000000..c0eaefd
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/pool.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2016-2020 Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+
+/* ======   Dependencies   ======= */
+#include <stddef.h>    /* size_t */
+#include <stdlib.h>    /* malloc, calloc, free */
+#include <string.h>    /* memcpy */
+#include <assert.h>
+
+#include "pool.h"
+
+
+/* ======   Compiler specifics   ====== */
+#if defined(_MSC_VER)
+#  pragma warning(disable : 4204)        /* disable: C4204: non-constant aggregate initializer */
+#endif
+
+
+/* ===  Build Macro  === */
+
+#ifndef POOL_MT   // can be defined on command line
+#  define POOL_MT 1
+#endif
+
+
+/* ===  Implementation  === */
+
+#if POOL_MT
+
+#include "threading.h"   /* pthread adaptation */
+
+/* A job is a function and an opaque argument */
+typedef struct POOL_job_s {
+    POOL_function function;
+    void *opaque;
+} POOL_job;
+
+struct POOL_ctx_s {
+    /* Keep track of the threads */
+    ZSTD_pthread_t* threads;
+    size_t threadCapacity;
+    size_t threadLimit;
+
+    /* The queue is a circular buffer */
+    POOL_job *queue;
+    size_t queueHead;
+    size_t queueTail;
+    size_t queueSize;
+
+    /* The number of threads working on jobs */
+    size_t numThreadsBusy;
+    /* Indicates if the queue is empty */
+    int queueEmpty;
+
+    /* The mutex protects the queue */
+    ZSTD_pthread_mutex_t queueMutex;
+    /* Condition variable for pushers to wait on when the queue is full */
+    ZSTD_pthread_cond_t queuePushCond;
+    /* Condition variables for poppers to wait on when the queue is empty */
+    ZSTD_pthread_cond_t queuePopCond;
+    /* Indicates if the queue is shutting down */
+    int shutdown;
+};
+
+/* POOL_thread() :
+ * Work thread for the thread pool.
+ * Waits for jobs and executes them.
+ * @returns : NULL on failure else non-null.
+ */
+static void* POOL_thread(void* opaque)
+{
+    POOL_ctx* const ctx = (POOL_ctx*)opaque;
+    if (!ctx) { return NULL; }
+    for (;;) {
+        /* Lock the mutex and wait for a non-empty queue or until shutdown */
+        ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+
+        while ( ctx->queueEmpty
+            || (ctx->numThreadsBusy >= ctx->threadLimit) ) {
+            if (ctx->shutdown) {
+                /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit),
+                 * a few threads will be shutdown while !queueEmpty,
+                 * but enough threads will remain active to finish the queue */
+                ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+                return opaque;
+            }
+            ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
+        }
+        /* Pop a job off the queue */
+        {   POOL_job const job = ctx->queue[ctx->queueHead];
+            ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize;
+            ctx->numThreadsBusy++;
+            ctx->queueEmpty = ctx->queueHead == ctx->queueTail;
+            /* Unlock the mutex, signal a pusher, and run the job */
+            ZSTD_pthread_cond_signal(&ctx->queuePushCond);
+            ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+
+            job.function(job.opaque);
+
+            /* If the intended queue size was 0, signal after finishing job */
+            ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+            ctx->numThreadsBusy--;
+            if (ctx->queueSize == 1) {
+                ZSTD_pthread_cond_signal(&ctx->queuePushCond);
+            }
+            ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+        }
+    }  /* for (;;) */
+    assert(0);  /* Unreachable */
+}
+
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize)
+{
+    POOL_ctx* ctx;
+    /* Check parameters */
+    if (!numThreads) { return NULL; }
+    /* Allocate the context and zero initialize */
+    ctx = (POOL_ctx*)calloc(1, sizeof(POOL_ctx));
+    if (!ctx) { return NULL; }
+    /* Initialize the job queue.
+     * It needs one extra space since one space is wasted to differentiate
+     * empty and full queues.
+     */
+    ctx->queueSize = queueSize + 1;
+    ctx->queue = (POOL_job*)malloc(ctx->queueSize * sizeof(POOL_job));
+    ctx->queueHead = 0;
+    ctx->queueTail = 0;
+    ctx->numThreadsBusy = 0;
+    ctx->queueEmpty = 1;
+    (void)ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
+    (void)ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
+    (void)ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
+    ctx->shutdown = 0;
+    /* Allocate space for the thread handles */
+    ctx->threads = (ZSTD_pthread_t*)malloc(numThreads * sizeof(ZSTD_pthread_t));
+    ctx->threadCapacity = 0;
+    /* Check for errors */
+    if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
+    /* Initialize the threads */
+    {   size_t i;
+        for (i = 0; i < numThreads; ++i) {
+            if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
+                ctx->threadCapacity = i;
+                POOL_free(ctx);
+                return NULL;
+        }   }
+        ctx->threadCapacity = numThreads;
+        ctx->threadLimit = numThreads;
+    }
+    return ctx;
+}
+
+/*! POOL_join() :
+    Shutdown the queue, wake any sleeping threads, and join all of the threads.
+*/
+static void POOL_join(POOL_ctx* ctx) {
+    /* Shut down the queue */
+    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+    ctx->shutdown = 1;
+    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+
+    /* Wake up sleeping threads */
+    ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
+    ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
+
+    /* Join all of the threads */
+    {   size_t i;
+        for (i = 0; i < ctx->threadCapacity; ++i) {
+            ZSTD_pthread_join(ctx->threads[i], NULL);  /* note : could fail */
+    }   }
+}
+
+void POOL_free(POOL_ctx *ctx) {
+    if (!ctx) { return; }
+    POOL_join(ctx);
+    ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
+    ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
+    ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
+    free(ctx->queue);
+    free(ctx->threads);
+    free(ctx);
+}
+
+
+
+size_t POOL_sizeof(POOL_ctx *ctx) {
+    if (ctx==NULL) return 0;  /* supports sizeof NULL */
+    return sizeof(*ctx)
+        + ctx->queueSize * sizeof(POOL_job)
+        + ctx->threadCapacity * sizeof(ZSTD_pthread_t);
+}
+
+
+/* @return : 0 on success, 1 on error */
+static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
+{
+    if (numThreads <= ctx->threadCapacity) {
+        if (!numThreads) return 1;
+        ctx->threadLimit = numThreads;
+        return 0;
+    }
+    /* numThreads > threadCapacity */
+    {   ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)malloc(numThreads * sizeof(ZSTD_pthread_t));
+        if (!threadPool) return 1;
+        /* replace existing thread pool */
+        memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
+        free(ctx->threads);
+        ctx->threads = threadPool;
+        /* Initialize additional threads */
+        {   size_t threadId;
+            for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) {
+                if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) {
+                    ctx->threadCapacity = threadId;
+                    return 1;
+            }   }
+    }   }
+    /* successfully expanded */
+    ctx->threadCapacity = numThreads;
+    ctx->threadLimit = numThreads;
+    return 0;
+}
+
+/* @return : 0 on success, 1 on error */
+int POOL_resize(POOL_ctx* ctx, size_t numThreads)
+{
+    int result;
+    if (ctx==NULL) return 1;
+    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+    result = POOL_resize_internal(ctx, numThreads);
+    ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
+    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+    return result;
+}
+
+/**
+ * Returns 1 if the queue is full and 0 otherwise.
+ *
+ * When queueSize is 1 (pool was created with an intended queueSize of 0),
+ * then a queue is empty if there is a thread free _and_ no job is waiting.
+ */
+static int isQueueFull(POOL_ctx const* ctx) {
+    if (ctx->queueSize > 1) {
+        return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize);
+    } else {
+        return (ctx->numThreadsBusy == ctx->threadLimit) ||
+               !ctx->queueEmpty;
+    }
+}
+
+
+static void POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque)
+{
+    POOL_job const job = {function, opaque};
+    assert(ctx != NULL);
+    if (ctx->shutdown) return;
+
+    ctx->queueEmpty = 0;
+    ctx->queue[ctx->queueTail] = job;
+    ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
+    ZSTD_pthread_cond_signal(&ctx->queuePopCond);
+}
+
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque)
+{
+    assert(ctx != NULL);
+    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+    /* Wait until there is space in the queue for the new job */
+    while (isQueueFull(ctx) && (!ctx->shutdown)) {
+        ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
+    }
+    POOL_add_internal(ctx, function, opaque);
+    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+}
+
+
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
+{
+    assert(ctx != NULL);
+    ZSTD_pthread_mutex_lock(&ctx->queueMutex);
+    if (isQueueFull(ctx)) {
+        ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+        return 0;
+    }
+    POOL_add_internal(ctx, function, opaque);
+    ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
+    return 1;
+}
+
+
+#else  /* POOL_MT  not defined */
+
+/* ========================== */
+/* No multi-threading support */
+/* ========================== */
+
+
+/* We don't need any data, but if it is empty, malloc() might return NULL. */
+struct POOL_ctx_s {
+    int dummy;
+};
+static POOL_ctx g_ctx;
+
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
+    (void)numThreads;
+    (void)queueSize;
+    return &g_ctx;
+}
+
+void POOL_free(POOL_ctx* ctx) {
+    assert(!ctx || ctx == &g_ctx);
+    (void)ctx;
+}
+
+int POOL_resize(POOL_ctx* ctx, size_t numThreads) {
+    (void)ctx; (void)numThreads;
+    return 0;
+}
+
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
+    (void)ctx;
+    function(opaque);
+}
+
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
+    (void)ctx;
+    function(opaque);
+    return 1;
+}
+
+size_t POOL_sizeof(POOL_ctx* ctx) {
+    if (ctx==NULL) return 0;  /* supports sizeof NULL */
+    assert(ctx == &g_ctx);
+    return sizeof(*ctx);
+}
+
+#endif  /* ZSTD_MULTITHREAD */
diff --git a/grpc/third_party/xxhash/tests/collisions/pool.h b/grpc/third_party/xxhash/tests/collisions/pool.h
new file mode 100644
index 0000000..7c5e867
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/pool.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016-2020 Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#ifndef POOL_H
+#define POOL_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+#include <stddef.h>   /* size_t */
+
+typedef struct POOL_ctx_s POOL_ctx;
+
+/*! POOL_create() :
+ *  Create a thread pool with at most `numThreads` threads.
+ * `numThreads` must be at least 1.
+ *  The maximum number of queued jobs before blocking is `queueSize`.
+ * @return : POOL_ctx pointer on success, else NULL.
+*/
+POOL_ctx* POOL_create(size_t numThreads, size_t queueSize);
+
+/*! POOL_free() :
+ *  Free a thread pool returned by POOL_create().
+ */
+void POOL_free(POOL_ctx* ctx);
+
+/*! POOL_resize() :
+ *  Expands or shrinks pool's number of threads.
+ *  This is more efficient than releasing + creating a new context,
+ *  since it tries to preserve and re-use existing threads.
+ * `numThreads` must be at least 1.
+ * @return : 0 when resize was successful,
+ *           !0 (typically 1) if there is an error.
+ *    note : only numThreads can be resized, queueSize remains unchanged.
+ */
+int POOL_resize(POOL_ctx* ctx, size_t numThreads);
+
+/*! POOL_sizeof() :
+ * @return threadpool memory usage
+ *  note : compatible with NULL (returns 0 in this case)
+ */
+size_t POOL_sizeof(POOL_ctx* ctx);
+
+/*! POOL_function :
+ *  The function type that can be added to a thread pool.
+ */
+typedef void (*POOL_function)(void*);
+
+/*! POOL_add() :
+ *  Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
+ *  Possibly blocks until there is room in the queue.
+ *  Note : The function may be executed asynchronously,
+ *         therefore, `opaque` must live until function has been completed.
+ */
+void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque);
+
+
+/*! POOL_tryAdd() :
+ *  Add the job `function(opaque)` to thread pool _if_ a worker is available.
+ *  Returns immediately even if not (does not block).
+ * @return : 1 if successful, 0 if not.
+ */
+int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque);
+
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
diff --git a/grpc/third_party/xxhash/tests/collisions/sort.cc b/grpc/third_party/xxhash/tests/collisions/sort.cc
new file mode 100644
index 0000000..237a114
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/sort.cc
@@ -0,0 +1,59 @@
+/*
+ * sort.cc - C++ sort functions
+ * Copyright (C) 2019-2020 Yann Collet
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+/*
+ * C++ sort functions tend to run faster than C ones due to templates allowing
+ * inline optimizations.
+ * Also, glibc's qsort() seems to inflate memory usage, resulting in OOM
+ * crashes on the test server.
+ */
+
+#include <algorithm>  // std::sort
+#define XXH_INLINE_ALL  // XXH128_cmp
+#include <xxhash.h>
+
+#include "sort.hh"
+
+void sort64(uint64_t* table, size_t size)
+{
+    std::sort(table, table + size);
+}
+
+#include <stdlib.h>  // qsort
+
+void sort128(XXH128_hash_t* table, size_t size)
+{
+#if 0
+    // C++ sort using a custom function object
+    struct {
+        bool operator()(XXH128_hash_t a, XXH128_hash_t b) const
+        {
+            return XXH128_cmp(&a, &b);
+        }
+    } customLess;
+    std::sort(table, table + size, customLess);
+#else
+    qsort(table, size, sizeof(*table), XXH128_cmp);
+#endif
+}
diff --git a/grpc/third_party/xxhash/tests/collisions/sort.hh b/grpc/third_party/xxhash/tests/collisions/sort.hh
new file mode 100644
index 0000000..278ce05
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/sort.hh
@@ -0,0 +1,40 @@
+/*
+ * sort.hh - headers for C++ sort functions
+ * Copyright (C) 2019-2020 Yann Collet
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at :
+ *   - xxHash homepage : https://www.xxhash.com
+ *   - xxHash source repository : https://github.com/Cyan4973/xxHash
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>   // size
+#include <stdint.h>   // uint64_t
+#define XXH_STATIC_LINKING_ONLY  // XXH128_hash_t
+#include "xxhash.h"
+
+void sort64(uint64_t* table, size_t size);
+
+void sort128(XXH128_hash_t* table, size_t size);
+
+#ifdef __cplusplus
+}  // extern C
+#endif
diff --git a/grpc/third_party/xxhash/tests/collisions/threading.c b/grpc/third_party/xxhash/tests/collisions/threading.c
new file mode 100644
index 0000000..5164667
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/threading.c
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2016 Tino Reichardt
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ *
+ * You can contact the author at:
+ * - zstdmt source repository: https://github.com/mcmilk/zstdmt
+ */
+
+/**
+ * This file will hold wrapper for systems, which do not support pthreads
+ */
+
+
+ /* ===  Build Macro  === */
+
+ #ifndef POOL_MT   // can be defined on command line
+ #  define POOL_MT 1
+ #endif
+
+
+/* create fake symbol to avoid empty translation unit warning */
+int g_ZSTD_threading_useles_symbol;
+
+#if POOL_MT && defined(_WIN32)
+
+/**
+ * Windows minimalist Pthread Wrapper
+ */
+
+
+/* ===  Dependencies  === */
+#include <process.h>
+#include <errno.h>
+#include "threading.h"
+
+
+/* ===  Implementation  === */
+
+static unsigned __stdcall worker(void *arg)
+{
+    ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg;
+    thread->arg = thread->start_routine(thread->arg);
+    return 0;
+}
+
+int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
+            void* (*start_routine) (void*), void* arg)
+{
+    (void)unused;
+    thread->arg = arg;
+    thread->start_routine = start_routine;
+    thread->handle = (HANDLE) _beginthreadex(NULL, 0, worker, thread, 0, NULL);
+
+    if (!thread->handle)
+        return errno;
+    else
+        return 0;
+}
+
+int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr)
+{
+    DWORD result;
+
+    if (!thread.handle) return 0;
+
+    result = WaitForSingleObject(thread.handle, INFINITE);
+    switch (result) {
+    case WAIT_OBJECT_0:
+        if (value_ptr) *value_ptr = thread.arg;
+        return 0;
+    case WAIT_ABANDONED:
+        return EINVAL;
+    default:
+        return (int)GetLastError();
+    }
+}
+
+#endif   /* POOL_MT */
diff --git a/grpc/third_party/xxhash/tests/collisions/threading.h b/grpc/third_party/xxhash/tests/collisions/threading.h
new file mode 100644
index 0000000..700bf44
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/collisions/threading.h
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2016 Tino Reichardt
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ *
+ * You can contact the author at:
+ * - zstdmt source repository: https://github.com/mcmilk/zstdmt
+ */
+
+#ifndef THREADING_H_938743
+#define THREADING_H_938743
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/* ===  Build Macro  === */
+
+#ifndef POOL_MT   // can be defined on command line
+#  define POOL_MT 1
+#endif
+
+
+/* ===  Implementation  === */
+
+#if POOL_MT && defined(_WIN32)
+
+/**
+ * Define windows version before include
+ */
+#undef  WINVER
+#define WINVER       0x0600
+
+#undef  _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+
+#ifndef WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+#include <stdio.h>
+
+/* mutex */
+#define ZSTD_pthread_mutex_t           CRITICAL_SECTION
+#define ZSTD_pthread_mutex_init(a, b)  ((void)(b), InitializeCriticalSection((a)), 0)
+#define ZSTD_pthread_mutex_destroy(a)  DeleteCriticalSection((a))
+#define ZSTD_pthread_mutex_lock(a)     EnterCriticalSection((a))
+#define ZSTD_pthread_mutex_unlock(a)   LeaveCriticalSection((a))
+
+/* condition variable */
+#define ZSTD_pthread_cond_t             CONDITION_VARIABLE
+#define ZSTD_pthread_cond_init(a, b)    ((void)(b), InitializeConditionVariable((a)), 0)
+#define ZSTD_pthread_cond_destroy(a)    ((void)(a))
+#define ZSTD_pthread_cond_wait(a, b)    SleepConditionVariableCS((a), (b), INFINITE)
+#define ZSTD_pthread_cond_signal(a)     WakeConditionVariable((a))
+#define ZSTD_pthread_cond_broadcast(a)  WakeAllConditionVariable((a))
+
+/* ZSTD_pthread_create() and ZSTD_pthread_join() */
+typedef struct {
+    HANDLE handle;
+    void* (*start_routine)(void*);
+    void* arg;
+} ZSTD_pthread_t;
+
+int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
+                   void* (*start_routine) (void*), void* arg);
+
+int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr);
+
+/**
+ * add here more wrappers as required
+ */
+
+
+#elif POOL_MT   /* posix assumed ; need a better detection method */
+/* ===   POSIX Systems   === */
+#  include <pthread.h>
+
+#define ZSTD_pthread_mutex_t            pthread_mutex_t
+#define ZSTD_pthread_mutex_init(a, b)   pthread_mutex_init((a), (b))
+#define ZSTD_pthread_mutex_destroy(a)   pthread_mutex_destroy((a))
+#define ZSTD_pthread_mutex_lock(a)      pthread_mutex_lock((a))
+#define ZSTD_pthread_mutex_unlock(a)    pthread_mutex_unlock((a))
+
+#define ZSTD_pthread_cond_t             pthread_cond_t
+#define ZSTD_pthread_cond_init(a, b)    pthread_cond_init((a), (b))
+#define ZSTD_pthread_cond_destroy(a)    pthread_cond_destroy((a))
+#define ZSTD_pthread_cond_wait(a, b)    pthread_cond_wait((a), (b))
+#define ZSTD_pthread_cond_signal(a)     pthread_cond_signal((a))
+#define ZSTD_pthread_cond_broadcast(a)  pthread_cond_broadcast((a))
+
+#define ZSTD_pthread_t                  pthread_t
+#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
+#define ZSTD_pthread_join(a, b)         pthread_join((a),(b))
+
+#else  /* POOL_MT == 0 */
+/* No multithreading support */
+
+typedef int ZSTD_pthread_mutex_t;
+#define ZSTD_pthread_mutex_init(a, b)   ((void)(a), (void)(b), 0)
+#define ZSTD_pthread_mutex_destroy(a)   ((void)(a))
+#define ZSTD_pthread_mutex_lock(a)      ((void)(a))
+#define ZSTD_pthread_mutex_unlock(a)    ((void)(a))
+
+typedef int ZSTD_pthread_cond_t;
+#define ZSTD_pthread_cond_init(a, b)    ((void)(a), (void)(b), 0)
+#define ZSTD_pthread_cond_destroy(a)    ((void)(a))
+#define ZSTD_pthread_cond_wait(a, b)    ((void)(a), (void)(b))
+#define ZSTD_pthread_cond_signal(a)     ((void)(a))
+#define ZSTD_pthread_cond_broadcast(a)  ((void)(a))
+
+/* do not use ZSTD_pthread_t */
+
+#endif /* POOL_MT */
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* THREADING_H_938743 */
diff --git a/grpc/third_party/xxhash/tests/generate_unicode_test.c b/grpc/third_party/xxhash/tests/generate_unicode_test.c
new file mode 100644
index 0000000..eed6ac0
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/generate_unicode_test.c
@@ -0,0 +1,154 @@
+/*
+ * Generates a Unicode test for xxhsum without using Unicode in the source files.
+ *
+ * Copyright (C) 2020 Devin Hussey (easyaspi314)
+ *
+ * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Certain terminals don't properly handle UTF-8 (i.e. rxvt and command prompt
+ * in the default codepage), and that can cause issues when editing text.
+ *
+ * We use this C file to generate a file with a Unicode filename, a file with
+ * a checksum of said file, and both a Windows batch script and a Unix shell
+ * script to test the file.
+ */
+
+#define _CRT_SECURE_NO_WARNINGS /* Silence warnings on MSVC */
+#include <stdio.h>
+
+/* Use a Japanese filename, something that can't be cheated with ANSI.
+ * yuniko-do.unicode (literally unicode.unicode) */
+
+/* Use raw hex values to ensure that the output is well-formed UTF-8. It is also more C90 compliant. */
+static const char FILENAME[] = {
+    (char)0xe3, (char)0x83, (char)0xa6,  /* U+30e6: Katakana letter yu */
+    (char)0xe3, (char)0x83, (char)0x8b,  /* U+30cb: Katakana letter ni */
+    (char)0xe3, (char)0x82, (char)0xb3,  /* U+30b3: Katakana letter ko */
+    (char)0xe3, (char)0x83, (char)0xbc,  /* U+30fc: Katakana-Hiragana prolonged sound mark (dash) */
+    (char)0xe3, (char)0x83, (char)0x89,  /* U+30c9: Katakana letter do */
+    '.','u','n','i','c','o','d','e','\0' /* ".unicode" (so we can glob in make clean and .gitignore) */
+};
+
+#ifdef _WIN32
+/* The same text as above, but encoded in Windows UTF-16. */
+static const wchar_t WFILENAME[] = { 0x30e6, 0x30cb, 0x30b3, 0x30fc, 0x30c9, L'.', L'u', L'n', L'i', L'c', L'o', L'd', L'e', L'\0' };
+#endif
+
+int main(void)
+{
+    FILE *f, *script, *checksum;
+
+    /* Create our Unicode file. Use _wfopen on Windows as fopen doesn't support Unicode filenames. */
+#ifdef _WIN32
+    if (!(f = _wfopen(WFILENAME, L"wb"))) return 1;
+#else
+    if (!(f = fopen(FILENAME, "wb"))) return 1;
+#endif
+    fprintf(f, "test\n");
+    fclose(f);
+
+    /* XXH64 checksum file with the precalculated checksum for said file. */
+    if (!(checksum = fopen("unicode_test.xxh64", "wb")))
+        return 1;
+    fprintf(checksum, "2d7f1808da1fa63c  %s\n", FILENAME);
+    fclose(checksum);
+
+
+    /* Create two scripts for both Windows and Unix. */
+
+    /* Generate a Windows batch script. Always insert CRLF manually. */
+    if (!(script = fopen("unicode_test.bat", "wb")))
+        return 1;
+
+    /* Disable echoing the commands. We do that ourselves the naive way. */
+    fprintf(script, "@echo off\r\n");
+
+    /* Change to codepage 65001 to enable UTF-8 support. */
+    fprintf(script, "chcp 65001 >NUL 2>&1\r\n");
+
+    /* First test a Unicode filename */
+    fprintf(script, "echo Testing filename provided on command line...\r\n");
+    fprintf(script, "echo xxhsum.exe \"%s\"\r\n", FILENAME);
+    fprintf(script, "xxhsum.exe \"%s\"\r\n", FILENAME);
+
+    /* Bail on error */
+    fprintf(script, "if %%ERRORLEVEL%% neq 0 (\r\n");
+    fprintf(script, "    exit /B %%ERRORLEVEL%%\r\n");
+    fprintf(script, ")\r\n");
+
+    /* Then test a checksum file. */
+    fprintf(script, "echo Testing a checksum file...\r\n");
+    fprintf(script, "echo xxhsum.exe -c unicode_test.xxh64\r\n");
+    fprintf(script, "xxhsum.exe -c unicode_test.xxh64\r\n");
+
+    fprintf(script, "exit /B %%ERRORLEVEL%%\r\n");
+
+    fclose(script);
+
+    /* Generate a Unix shell script */
+    if (!(script = fopen("unicode_test.sh", "wb")))
+        return 1;
+
+    fprintf(script, "#!/bin/sh\n");
+    /*
+     * Some versions of MSYS, MinGW and Cygwin do not support UTF-8, and the ones that
+     * don't may error with something like this:
+     *
+     *    Error: Could not open '<mojibake>.unicode': No such file or directory.
+     *
+     * which is an internal error that happens when it tries to convert MinGW/Cygwin
+     * paths to Windows paths.
+     *
+     * In that case, we bail to cmd.exe and the batch script, which supports UTF-8
+     * on Windows 7 and later.
+     */
+    fprintf(script, "case $(uname) in\n");
+    /* MinGW/MSYS converts /c to C:\ unless you have a double slash,
+     * Cygwin does not. */
+    fprintf(script, "    *CYGWIN*)\n");
+    fprintf(script, "        exec cmd.exe /c unicode_test.bat\n");
+    fprintf(script, "        ;;\n");
+    fprintf(script, "    *MINGW*|*MSYS*)\n");
+    fprintf(script, "        exec cmd.exe //c unicode_test.bat\n");
+    fprintf(script, "        ;;\n");
+    fprintf(script, "esac\n");
+
+    /* First test a Unicode filename */
+    fprintf(script, "echo Testing filename provided on command line...\n");
+    fprintf(script, "echo './xxhsum \"%s\" || exit $?'\n", FILENAME);
+    fprintf(script, "./xxhsum \"%s\" || exit $?\n", FILENAME);
+
+    /* Then test a checksum file. */
+    fprintf(script, "echo Testing a checksum file...\n");
+    fprintf(script, "echo './xxhsum -c unicode_test.xxh64 || exit $?'\n");
+    fprintf(script, "./xxhsum -c unicode_test.xxh64 || exit $?\n");
+
+    fclose(script);
+
+    return 0;
+}
diff --git a/grpc/third_party/xxhash/tests/multiInclude.c b/grpc/third_party/xxhash/tests/multiInclude.c
new file mode 100644
index 0000000..7d2bc8a
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/multiInclude.c
@@ -0,0 +1,66 @@
+/*
+ * Multi-include test program
+ * Validates that xxhash.h can be included multiple times and in any order
+ *
+ * Copyright (C) 2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#include <stdio.h>   /* printf */
+
+/* Normal include, gives access to public symbols */
+#include "../xxhash.h"
+
+/*
+ * Advanced include, gives access to experimental symbols
+ * This test ensure that xxhash.h can be included multiple times and in any
+ * order. This order is more difficult: Without care, the declaration of
+ * experimental symbols could be skipped.
+ */
+#define XXH_STATIC_LINKING_ONLY
+#include "../xxhash.h"
+
+/*
+ * Inlining: Re-define all identifiers, keep them private to the unit.
+ * Note: Without specific efforts, the identifier names would collide.
+ *
+ * To be linked with and without xxhash.o to test the symbol's presence and
+ * naming collisions.
+ */
+#define XXH_INLINE_ALL
+#include "../xxhash.h"
+
+
+int main(void)
+{
+    XXH3_state_t state;   /* part of experimental API */
+
+    XXH3_64bits_reset(&state);
+    const char input[] = "Hello World !";
+
+    XXH3_64bits_update(&state, input, sizeof(input));
+
+    XXH64_hash_t const h = XXH3_64bits_digest(&state);
+    printf("hash '%s': %08x%08x \n", input, (unsigned)(h >> 32), (unsigned)h);
+
+    return 0;
+}
diff --git a/grpc/third_party/xxhash/tests/ppc_define.c b/grpc/third_party/xxhash/tests/ppc_define.c
new file mode 100644
index 0000000..d94c2c7
--- /dev/null
+++ b/grpc/third_party/xxhash/tests/ppc_define.c
@@ -0,0 +1,62 @@
+/*
+ * Multi-include test program
+ * ensure that pixel, bool and vector are not redefined
+ *
+ * Copyright (C) 2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+/* gcc's altivec.h, included for the VSX code path,
+ * may, in some circumstances, redefine
+ * bool, vector and pixel keywords.
+ *
+ * This unit checks if it happens.
+ * It's a compile test.
+ * The test is mostly meaningful for PPC target using altivec.h
+ * hence XXH_VECTOR == XXH_VSX
+ */
+
+#define BOOL_VALUE 32123456
+#define bool BOOL_VALUE
+
+#define VECTOR_VALUE 374464784
+#define vector VECTOR_VALUE
+
+#define PIXEL_VALUE 5846841
+#define pixel PIXEL_VALUE
+
+#define XXH_INLINE_ALL
+#include "../xxhash.h"
+
+#if (bool != BOOL_VALUE)
+#  error "bool macro was redefined !"
+#endif
+
+#if (vector != VECTOR_VALUE)
+#  error "vector macro was redefined !"
+#endif
+
+#if (pixel != PIXEL_VALUE)
+#  error "pixel macro was redefined !"
+#endif
+
+int g_nonEmptyUnit = 0;
diff --git a/grpc/third_party/xxhash/xxh3.h b/grpc/third_party/xxhash/xxh3.h
new file mode 100644
index 0000000..7e83e64
--- /dev/null
+++ b/grpc/third_party/xxhash/xxh3.h
@@ -0,0 +1,55 @@
+/*
+ * xxHash - Extremely Fast Hash algorithm
+ * Development source file for `xxh3`
+ * Copyright (C) 2019-2020 Yann Collet
+ *
+ * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other materials provided with the
+ *      distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+/*
+ * Note: This file used to host the source code of XXH3_* variants.
+ * during the development period.
+ * The source code is now properly integrated within xxhash.h.
+ *
+ * xxh3.h is no longer useful,
+ * but it is still provided for compatibility with source code
+ * which used to include it directly.
+ *
+ * Programs are now highly discourage to include xxh3.h.
+ * Include `xxhash.h` instead, which is the officially supported interface.
+ *
+ * In the future, xxh3.h will start to generate warnings, then errors,
+ * then it will be removed from source package and from include directory.
+ */
+
+/* Simulate the same impact as including the old xxh3.h source file */
+
+#define XXH_INLINE_ALL
+#include "xxhash.h"
diff --git a/grpc/third_party/xxhash/xxh_x86dispatch.c b/grpc/third_party/xxhash/xxh_x86dispatch.c
new file mode 100644
index 0000000..ab33832
--- /dev/null
+++ b/grpc/third_party/xxhash/xxh_x86dispatch.c
@@ -0,0 +1,770 @@
+/*
+ * xxHash - Extremely Fast Hash algorithm
+ * Copyright (C) 2020 Yann Collet
+ *
+ * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other materials provided with the
+ *      distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+
+/*!
+ * @file xxh_x86dispatch.c
+ *
+ * Automatic dispatcher code for the @ref xxh3_family on x86-based targets.
+ *
+ * Optional add-on.
+ *
+ * **Compile this file with the default flags for your target.** Do not compile
+ * with flags like `-mavx*`, `-march=native`, or `/arch:AVX*`, there will be
+ * an error. See @ref XXH_X86DISPATCH_ALLOW_AVX for details.
+ *
+ * @defgroup dispatch x86 Dispatcher
+ * @{
+ */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#if !(defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64))
+#  error "Dispatching is currently only supported on x86 and x86_64."
+#endif
+
+/*!
+ * @def XXH_X86DISPATCH_ALLOW_AVX
+ * @brief Disables the AVX sanity check.
+ *
+ * Don't compile xxh_x86dispatch.c with options like `-mavx*`, `-march=native`,
+ * or `/arch:AVX*`. It is intended to be compiled for the minimum target, and
+ * it selectively enables SSE2, AVX2, and AVX512 when it is needed.
+ *
+ * Using this option _globally_ allows this feature, and therefore makes it
+ * undefined behavior to execute on any CPU without said feature.
+ *
+ * Even if the source code isn't directly using AVX intrinsics in a function,
+ * the compiler can still generate AVX code from autovectorization and by
+ * "upgrading" SSE2 intrinsics to use the VEX prefixes (a.k.a. AVX128).
+ *
+ * Use the same flags that you use to compile the rest of the program; this
+ * file will safely generate SSE2, AVX2, and AVX512 without these flags.
+ *
+ * Define XXH_X86DISPATCH_ALLOW_AVX to ignore this check, and feel free to open
+ * an issue if there is a target in the future where AVX is a default feature.
+ */
+#ifdef XXH_DOXYGEN
+#  define XXH_X86DISPATCH_ALLOW_AVX
+#endif
+
+#if defined(__AVX__) && !defined(XXH_X86DISPATCH_ALLOW_AVX)
+#  error "Do not compile xxh_x86dispatch.c with AVX enabled! See the comment above."
+#endif
+
+#ifdef __has_include
+#  define XXH_HAS_INCLUDE(header) __has_include(header)
+#else
+#  define XXH_HAS_INCLUDE(header) 0
+#endif
+
+/*!
+ * @def XXH_DISPATCH_SCALAR
+ * @brief Enables/dispatching the scalar code path.
+ *
+ * If this is defined to 0, SSE2 support is assumed. This reduces code size
+ * when the scalar path is not needed.
+ *
+ * This is automatically defined to 0 when...
+ *   - SSE2 support is enabled in the compiler
+ *   - Targeting x86_64
+ *   - Targeting Android x86
+ *   - Targeting macOS
+ */
+#ifndef XXH_DISPATCH_SCALAR
+#  if defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) /* SSE2 on by default */ \
+     || defined(__x86_64__) || defined(_M_X64) /* x86_64 */ \
+     || defined(__ANDROID__) || defined(__APPLEv__) /* Android or macOS */
+#     define XXH_DISPATCH_SCALAR 0 /* disable */
+#  else
+#     define XXH_DISPATCH_SCALAR 1
+#  endif
+#endif
+/*!
+ * @def XXH_DISPATCH_AVX2
+ * @brief Enables/disables dispatching for AVX2.
+ *
+ * This is automatically detected if it is not defined.
+ *  - GCC 4.7 and later are known to support AVX2, but >4.9 is required for
+ *    to get the AVX2 intrinsics and typedefs without -mavx -mavx2.
+ *  - Visual Studio 2013 Update 2 and later are known to support AVX2.
+ *  - The GCC/Clang internal header `<avx2intrin.h>` is detected. While this is
+ *    not allowed to be included directly, it still appears in the builtin
+ *    include path and is detectable with `__has_include`.
+ *
+ * @see XXH_AVX2
+ */
+#ifndef XXH_DISPATCH_AVX2
+#  if (defined(__GNUC__) && (__GNUC__ > 4)) /* GCC 5.0+ */ \
+   || (defined(_MSC_VER) && _MSC_VER >= 1900) /* VS 2015+ */ \
+   || (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 180030501) /* VS 2013 Update 2 */ \
+   || XXH_HAS_INCLUDE(<avx2intrin.h>) /* GCC/Clang internal header */
+#    define XXH_DISPATCH_AVX2 1   /* enable dispatch towards AVX2 */
+#  else
+#    define XXH_DISPATCH_AVX2 0
+#  endif
+#endif /* XXH_DISPATCH_AVX2 */
+
+/*!
+ * @def XXH_DISPATCH_AVX512
+ * @brief Enables/disables dispatching for AVX512.
+ *
+ * Automatically detected if one of the following conditions is met:
+ *  - GCC 4.9 and later are known to support AVX512.
+ *  - Visual Studio 2017  and later are known to support AVX2.
+ *  - The GCC/Clang internal header `<avx512fintrin.h>` is detected. While this
+ *    is not allowed to be included directly, it still appears in the builtin
+ *    include path and is detectable with `__has_include`.
+ *
+ * @see XXH_AVX512
+ */
+#ifndef XXH_DISPATCH_AVX512
+#  if (defined(__GNUC__) \
+       && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))) /* GCC 4.9+ */ \
+   || (defined(_MSC_VER) && _MSC_VER >= 1910) /* VS 2017+ */ \
+   || XXH_HAS_INCLUDE(<avx512fintrin.h>) /* GCC/Clang internal header */
+#    define XXH_DISPATCH_AVX512 1   /* enable dispatch towards AVX512 */
+#  else
+#    define XXH_DISPATCH_AVX512 0
+#  endif
+#endif /* XXH_DISPATCH_AVX512 */
+
+/*!
+ * @def XXH_TARGET_SSE2
+ * @brief Allows a function to be compiled with SSE2 intrinsics.
+ *
+ * Uses `__attribute__((__target__("sse2")))` on GCC to allow SSE2 to be used
+ * even with `-mno-sse2`.
+ *
+ * @def XXH_TARGET_AVX2
+ * @brief Like @ref XXH_TARGET_SSE2, but for AVX2.
+ *
+ * @def XXH_TARGET_AVX512
+ * @brief Like @ref XXH_TARGET_SSE2, but for AVX512.
+ */
+#if defined(__GNUC__)
+#  include <emmintrin.h> /* SSE2 */
+#  if XXH_DISPATCH_AVX2 || XXH_DISPATCH_AVX512
+#    include <immintrin.h> /* AVX2, AVX512F */
+#  endif
+#  define XXH_TARGET_SSE2 __attribute__((__target__("sse2")))
+#  define XXH_TARGET_AVX2 __attribute__((__target__("avx2")))
+#  define XXH_TARGET_AVX512 __attribute__((__target__("avx512f")))
+#elif defined(_MSC_VER)
+#  include <intrin.h>
+#  define XXH_TARGET_SSE2
+#  define XXH_TARGET_AVX2
+#  define XXH_TARGET_AVX512
+#else
+#  error "Dispatching is currently not supported for your compiler."
+#endif
+
+#ifdef XXH_DISPATCH_DEBUG
+/* debug logging */
+#  include <stdio.h>
+#  define XXH_debugPrint(str) { fprintf(stderr, "DEBUG: xxHash dispatch: %s \n", str); fflush(NULL); }
+#else
+#  define XXH_debugPrint(str) ((void)0)
+#  undef NDEBUG /* avoid redefinition */
+#  define NDEBUG
+#endif
+#include <assert.h>
+
+#define XXH_INLINE_ALL
+#define XXH_X86DISPATCH
+#include "xxhash.h"
+
+/*
+ * Support both AT&T and Intel dialects
+ *
+ * GCC doesn't convert AT&T syntax to Intel syntax, and will error out if
+ * compiled with -masm=intel. Instead, it supports dialect switching with
+ * curly braces: { AT&T syntax | Intel syntax }
+ *
+ * Clang's integrated assembler automatically converts AT&T syntax to Intel if
+ * needed, making the dialect switching useless (it isn't even supported).
+ *
+ * Note: Comments are written in the inline assembly itself.
+ */
+#ifdef __clang__
+#  define XXH_I_ATT(intel, att) att "\n\t"
+#else
+#  define XXH_I_ATT(intel, att) "{" att "|" intel "}\n\t"
+#endif
+
+/*!
+ * @internal
+ * @brief Runs CPUID.
+ *
+ * @param eax, ecx The parameters to pass to CPUID, %eax and %ecx respectively.
+ * @param abcd The array to store the result in, `{ eax, ebx, ecx, edx }`
+ */
+static void XXH_cpuid(xxh_u32 eax, xxh_u32 ecx, xxh_u32* abcd)
+{
+#if defined(_MSC_VER)
+    __cpuidex(abcd, eax, ecx);
+#else
+    xxh_u32 ebx, edx;
+# if defined(__i386__) && defined(__PIC__)
+    __asm__(
+        "# Call CPUID\n\t"
+        "#\n\t"
+        "# On 32-bit x86 with PIC enabled, we are not allowed to overwrite\n\t"
+        "# EBX, so we use EDI instead.\n\t"
+        XXH_I_ATT("mov     edi, ebx",   "movl    %%ebx, %%edi")
+        XXH_I_ATT("cpuid",              "cpuid"               )
+        XXH_I_ATT("xchg    edi, ebx",   "xchgl   %%ebx, %%edi")
+        : "=D" (ebx),
+# else
+    __asm__(
+        "# Call CPUID\n\t"
+        XXH_I_ATT("cpuid",              "cpuid")
+        : "=b" (ebx),
+# endif
+              "+a" (eax), "+c" (ecx), "=d" (edx));
+    abcd[0] = eax;
+    abcd[1] = ebx;
+    abcd[2] = ecx;
+    abcd[3] = edx;
+#endif
+}
+
+/*
+ * Modified version of Intel's guide
+ * https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
+ */
+
+#if XXH_DISPATCH_AVX2 || XXH_DISPATCH_AVX512
+/*!
+ * @internal
+ * @brief Runs `XGETBV`.
+ *
+ * While the CPU may support AVX2, the operating system might not properly save
+ * the full YMM/ZMM registers.
+ *
+ * xgetbv is used for detecting this: Any compliant operating system will define
+ * a set of flags in the xcr0 register indicating how it saves the AVX registers.
+ *
+ * You can manually disable this flag on Windows by running, as admin:
+ *
+ *   bcdedit.exe /set xsavedisable 1
+ *
+ * and rebooting. Run the same command with 0 to re-enable it.
+ */
+static xxh_u64 XXH_xgetbv(void)
+{
+#if defined(_MSC_VER)
+    return _xgetbv(0);  /* min VS2010 SP1 compiler is required */
+#else
+    xxh_u32 xcr0_lo, xcr0_hi;
+    __asm__(
+        "# Call XGETBV\n\t"
+        "#\n\t"
+        "# Older assemblers (e.g. macOS's ancient GAS version) don't support\n\t"
+        "# the XGETBV opcode, so we encode it by hand instead.\n\t"
+        "# See <https://github.com/asmjit/asmjit/issues/78> for details.\n\t"
+        ".byte   0x0f, 0x01, 0xd0\n\t"
+       : "=a" (xcr0_lo), "=d" (xcr0_hi) : "c" (0));
+    return xcr0_lo | ((xxh_u64)xcr0_hi << 32);
+#endif
+}
+#endif
+
+#define XXH_SSE2_CPUID_MASK (1 << 26)
+#define XXH_OSXSAVE_CPUID_MASK ((1 << 26) | (1 << 27))
+#define XXH_AVX2_CPUID_MASK (1 << 5)
+#define XXH_AVX2_XGETBV_MASK ((1 << 2) | (1 << 1))
+#define XXH_AVX512F_CPUID_MASK (1 << 16)
+#define XXH_AVX512F_XGETBV_MASK ((7 << 5) | (1 << 2) | (1 << 1))
+
+/*!
+ * @internal
+ * @brief Returns the best XXH3 implementation.
+ *
+ * Runs various CPUID/XGETBV tests to try and determine the best implementation.
+ *
+ * @ret The best @ref XXH_VECTOR implementation.
+ * @see XXH_VECTOR_TYPES
+ */
+static int XXH_featureTest(void)
+{
+    xxh_u32 abcd[4];
+    xxh_u32 max_leaves;
+    int best = XXH_SCALAR;
+#if XXH_DISPATCH_AVX2 || XXH_DISPATCH_AVX512
+    xxh_u64 xgetbv_val;
+#endif
+#if defined(__GNUC__) && defined(__i386__)
+    xxh_u32 cpuid_supported;
+    __asm__(
+        "# For the sake of ruthless backwards compatibility, check if CPUID\n\t"
+        "# is supported in the EFLAGS on i386.\n\t"
+        "# This is not necessary on x86_64 - CPUID is mandatory.\n\t"
+        "#   The ID flag (bit 21) in the EFLAGS register indicates support\n\t"
+        "#   for the CPUID instruction. If a software procedure can set and\n\t"
+        "#   clear this flag, the processor executing the procedure supports\n\t"
+        "#   the CPUID instruction.\n\t"
+        "#   <https://c9x.me/x86/html/file_module_x86_id_45.html>\n\t"
+        "#\n\t"
+        "# Routine is from <https://wiki.osdev.org/CPUID>.\n\t"
+
+        "# Save EFLAGS\n\t"
+        XXH_I_ATT("pushfd",                           "pushfl"                    )
+        "# Store EFLAGS\n\t"
+        XXH_I_ATT("pushfd",                           "pushfl"                    )
+        "# Invert the ID bit in stored EFLAGS\n\t"
+        XXH_I_ATT("xor     dword ptr[esp], 0x200000", "xorl    $0x200000, (%%esp)")
+        "# Load stored EFLAGS (with ID bit inverted)\n\t"
+        XXH_I_ATT("popfd",                            "popfl"                     )
+        "# Store EFLAGS again (ID bit may or not be inverted)\n\t"
+        XXH_I_ATT("pushfd",                           "pushfl"                    )
+        "# eax = modified EFLAGS (ID bit may or may not be inverted)\n\t"
+        XXH_I_ATT("pop     eax",                      "popl    %%eax"             )
+        "# eax = whichever bits were changed\n\t"
+        XXH_I_ATT("xor     eax, dword ptr[esp]",      "xorl    (%%esp), %%eax"    )
+        "# Restore original EFLAGS\n\t"
+        XXH_I_ATT("popfd",                            "popfl"                     )
+        "# eax = zero if ID bit can't be changed, else non-zero\n\t"
+        XXH_I_ATT("and     eax, 0x200000",            "andl    $0x200000, %%eax"  )
+        : "=a" (cpuid_supported) :: "cc");
+
+    if (XXH_unlikely(!cpuid_supported)) {
+        XXH_debugPrint("CPUID support is not detected!");
+        return best;
+    }
+
+#endif
+    /* Check how many CPUID pages we have */
+    XXH_cpuid(0, 0, abcd);
+    max_leaves = abcd[0];
+
+    /* Shouldn't happen on hardware, but happens on some QEMU configs. */
+    if (XXH_unlikely(max_leaves == 0)) {
+        XXH_debugPrint("Max CPUID leaves == 0!");
+        return best;
+    }
+
+    /* Check for SSE2, OSXSAVE and xgetbv */
+    XXH_cpuid(1, 0, abcd);
+
+    /*
+     * Test for SSE2. The check is redundant on x86_64, but it doesn't hurt.
+     */
+    if (XXH_unlikely((abcd[3] & XXH_SSE2_CPUID_MASK) != XXH_SSE2_CPUID_MASK))
+        return best;
+
+    XXH_debugPrint("SSE2 support detected.");
+
+    best = XXH_SSE2;
+#if XXH_DISPATCH_AVX2 || XXH_DISPATCH_AVX512
+    /* Make sure we have enough leaves */
+    if (XXH_unlikely(max_leaves < 7))
+        return best;
+
+    /* Test for OSXSAVE and XGETBV */
+    if ((abcd[2] & XXH_OSXSAVE_CPUID_MASK) != XXH_OSXSAVE_CPUID_MASK)
+        return best;
+
+    /* CPUID check for AVX features */
+    XXH_cpuid(7, 0, abcd);
+
+    xgetbv_val = XXH_xgetbv();
+#if XXH_DISPATCH_AVX2
+    /* Validate that AVX2 is supported by the CPU */
+    if ((abcd[1] & XXH_AVX2_CPUID_MASK) != XXH_AVX2_CPUID_MASK)
+        return best;
+
+    /* Validate that the OS supports YMM registers */
+    if ((xgetbv_val & XXH_AVX2_XGETBV_MASK) != XXH_AVX2_XGETBV_MASK) {
+        XXH_debugPrint("AVX2 supported by the CPU, but not the OS.");
+        return best;
+    }
+
+    /* AVX2 supported */
+    XXH_debugPrint("AVX2 support detected.");
+    best = XXH_AVX2;
+#endif
+#if XXH_DISPATCH_AVX512
+    /* Check if AVX512F is supported by the CPU */
+    if ((abcd[1] & XXH_AVX512F_CPUID_MASK) != XXH_AVX512F_CPUID_MASK) {
+        XXH_debugPrint("AVX512F not supported by CPU");
+        return best;
+    }
+
+    /* Validate that the OS supports ZMM registers */
+    if ((xgetbv_val & XXH_AVX512F_XGETBV_MASK) != XXH_AVX512F_XGETBV_MASK) {
+        XXH_debugPrint("AVX512F supported by the CPU, but not the OS.");
+        return best;
+    }
+
+    /* AVX512F supported */
+    XXH_debugPrint("AVX512F support detected.");
+    best = XXH_AVX512;
+#endif
+#endif
+    return best;
+}
+
+
+/* ===   Vector implementations   === */
+
+/*!
+ * @internal
+ * @brief Defines the various dispatch functions.
+ *
+ * TODO: Consolidate?
+ *
+ * @param suffix The suffix for the functions, e.g. sse2 or scalar
+ * @param target XXH_TARGET_* or empty.
+ */
+#define XXH_DEFINE_DISPATCH_FUNCS(suffix, target)                             \
+                                                                              \
+/* ===   XXH3, default variants   === */                                      \
+                                                                              \
+XXH_NO_INLINE target XXH64_hash_t                                             \
+XXHL64_default_##suffix(const void* XXH_RESTRICT input, size_t len)           \
+{                                                                             \
+    return XXH3_hashLong_64b_internal(                                        \
+               input, len, XXH3_kSecret, sizeof(XXH3_kSecret),                \
+               XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix        \
+    );                                                                        \
+}                                                                             \
+                                                                              \
+/* ===   XXH3, Seeded variants   === */                                       \
+                                                                              \
+XXH_NO_INLINE target XXH64_hash_t                                             \
+XXHL64_seed_##suffix(const void* XXH_RESTRICT input, size_t len,              \
+                     XXH64_hash_t seed)                                       \
+{                                                                             \
+    return XXH3_hashLong_64b_withSeed_internal(                               \
+                    input, len, seed, XXH3_accumulate_512_##suffix,           \
+                    XXH3_scrambleAcc_##suffix, XXH3_initCustomSecret_##suffix \
+    );                                                                        \
+}                                                                             \
+                                                                              \
+/* ===   XXH3, Secret variants   === */                                       \
+                                                                              \
+XXH_NO_INLINE target XXH64_hash_t                                             \
+XXHL64_secret_##suffix(const void* XXH_RESTRICT input, size_t len,            \
+                       const void* secret, size_t secretLen)                  \
+{                                                                             \
+    return XXH3_hashLong_64b_internal(                                        \
+                    input, len, secret, secretLen,                            \
+                    XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix   \
+    );                                                                        \
+}                                                                             \
+                                                                              \
+/* ===   XXH3 update variants   === */                                        \
+                                                                              \
+XXH_NO_INLINE target XXH_errorcode                                            \
+XXH3_update_##suffix(XXH3_state_t* state, const void* input, size_t len)      \
+{                                                                             \
+    return XXH3_update(state, (const xxh_u8*)input, len,                      \
+                    XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix); \
+}                                                                             \
+                                                                              \
+/* ===   XXH128 default variants   === */                                     \
+                                                                              \
+XXH_NO_INLINE target XXH128_hash_t                                            \
+XXHL128_default_##suffix(const void* XXH_RESTRICT input, size_t len)          \
+{                                                                             \
+    return XXH3_hashLong_128b_internal(                                       \
+                    input, len, XXH3_kSecret, sizeof(XXH3_kSecret),           \
+                    XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix   \
+    );                                                                        \
+}                                                                             \
+                                                                              \
+/* ===   XXH128 Secret variants   === */                                      \
+                                                                              \
+XXH_NO_INLINE target XXH128_hash_t                                            \
+XXHL128_secret_##suffix(const void* XXH_RESTRICT input, size_t len,           \
+                        const void* XXH_RESTRICT secret, size_t secretLen)    \
+{                                                                             \
+    return XXH3_hashLong_128b_internal(                                       \
+                    input, len, (const xxh_u8*)secret, secretLen,             \
+                    XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix); \
+}                                                                             \
+                                                                              \
+/* ===   XXH128 Seeded variants   === */                                      \
+                                                                              \
+XXH_NO_INLINE target XXH128_hash_t                                            \
+XXHL128_seed_##suffix(const void* XXH_RESTRICT input, size_t len,             \
+                      XXH64_hash_t seed)                                      \
+{                                                                             \
+    return XXH3_hashLong_128b_withSeed_internal(input, len, seed,             \
+                    XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix,  \
+                    XXH3_initCustomSecret_##suffix);                          \
+}
+
+/* End XXH_DEFINE_DISPATCH_FUNCS */
+
+#if XXH_DISPATCH_SCALAR
+XXH_DEFINE_DISPATCH_FUNCS(scalar, /* nothing */)
+#endif
+XXH_DEFINE_DISPATCH_FUNCS(sse2, XXH_TARGET_SSE2)
+#if XXH_DISPATCH_AVX2
+XXH_DEFINE_DISPATCH_FUNCS(avx2, XXH_TARGET_AVX2)
+#endif
+#if XXH_DISPATCH_AVX512
+XXH_DEFINE_DISPATCH_FUNCS(avx512, XXH_TARGET_AVX512)
+#endif
+#undef XXH_DEFINE_DISPATCH_FUNCS
+
+/* ====    Dispatchers    ==== */
+
+typedef XXH64_hash_t (*XXH3_dispatchx86_hashLong64_default)(const void* XXH_RESTRICT, size_t);
+
+typedef XXH64_hash_t (*XXH3_dispatchx86_hashLong64_withSeed)(const void* XXH_RESTRICT, size_t, XXH64_hash_t);
+
+typedef XXH64_hash_t (*XXH3_dispatchx86_hashLong64_withSecret)(const void* XXH_RESTRICT, size_t, const void* XXH_RESTRICT, size_t);
+
+typedef XXH_errorcode (*XXH3_dispatchx86_update)(XXH3_state_t*, const void*, size_t);
+
+typedef struct {
+    XXH3_dispatchx86_hashLong64_default    hashLong64_default;
+    XXH3_dispatchx86_hashLong64_withSeed   hashLong64_seed;
+    XXH3_dispatchx86_hashLong64_withSecret hashLong64_secret;
+    XXH3_dispatchx86_update                update;
+} XXH_dispatchFunctions_s;
+
+#define XXH_NB_DISPATCHES 4
+
+/*!
+ * @internal
+ * @brief Table of dispatchers for @ref XXH3_64bits().
+ *
+ * @pre The indices must match @ref XXH_VECTOR_TYPE.
+ */
+static const XXH_dispatchFunctions_s XXH_kDispatch[XXH_NB_DISPATCHES] = {
+#if XXH_DISPATCH_SCALAR
+    /* Scalar */ { XXHL64_default_scalar, XXHL64_seed_scalar, XXHL64_secret_scalar, XXH3_update_scalar },
+#else
+    /* Scalar */ { NULL, NULL, NULL, NULL },
+#endif
+    /* SSE2   */ { XXHL64_default_sse2,   XXHL64_seed_sse2,   XXHL64_secret_sse2,   XXH3_update_sse2 },
+#if XXH_DISPATCH_AVX2
+    /* AVX2   */ { XXHL64_default_avx2,   XXHL64_seed_avx2,   XXHL64_secret_avx2,   XXH3_update_avx2 },
+#else
+    /* AVX2   */ { NULL, NULL, NULL, NULL },
+#endif
+#if XXH_DISPATCH_AVX512
+    /* AVX512 */ { XXHL64_default_avx512, XXHL64_seed_avx512, XXHL64_secret_avx512, XXH3_update_avx512 }
+#else
+    /* AVX512 */ { NULL, NULL, NULL, NULL }
+#endif
+};
+/*!
+ * @internal
+ * @brief The selected dispatch table for @ref XXH3_64bits().
+ */
+static XXH_dispatchFunctions_s XXH_g_dispatch = { NULL, NULL, NULL, NULL };
+
+
+typedef XXH128_hash_t (*XXH3_dispatchx86_hashLong128_default)(const void* XXH_RESTRICT, size_t);
+
+typedef XXH128_hash_t (*XXH3_dispatchx86_hashLong128_withSeed)(const void* XXH_RESTRICT, size_t, XXH64_hash_t);
+
+typedef XXH128_hash_t (*XXH3_dispatchx86_hashLong128_withSecret)(const void* XXH_RESTRICT, size_t, const void* XXH_RESTRICT, size_t);
+
+typedef struct {
+    XXH3_dispatchx86_hashLong128_default    hashLong128_default;
+    XXH3_dispatchx86_hashLong128_withSeed   hashLong128_seed;
+    XXH3_dispatchx86_hashLong128_withSecret hashLong128_secret;
+    XXH3_dispatchx86_update                 update;
+} XXH_dispatch128Functions_s;
+
+
+/*!
+ * @internal
+ * @brief Table of dispatchers for @ref XXH3_128bits().
+ *
+ * @pre The indices must match @ref XXH_VECTOR_TYPE.
+ */
+static const XXH_dispatch128Functions_s XXH_kDispatch128[XXH_NB_DISPATCHES] = {
+#if XXH_DISPATCH_SCALAR
+    /* Scalar */ { XXHL128_default_scalar, XXHL128_seed_scalar, XXHL128_secret_scalar, XXH3_update_scalar },
+#else
+    /* Scalar */ { NULL, NULL, NULL, NULL },
+#endif
+    /* SSE2   */ { XXHL128_default_sse2,   XXHL128_seed_sse2,   XXHL128_secret_sse2,   XXH3_update_sse2 },
+#if XXH_DISPATCH_AVX2
+    /* AVX2   */ { XXHL128_default_avx2,   XXHL128_seed_avx2,   XXHL128_secret_avx2,   XXH3_update_avx2 },
+#else
+    /* AVX2   */ { NULL, NULL, NULL, NULL },
+#endif
+#if XXH_DISPATCH_AVX512
+    /* AVX512 */ { XXHL128_default_avx512, XXHL128_seed_avx512, XXHL128_secret_avx512, XXH3_update_avx512 }
+#else
+    /* AVX512 */ { NULL, NULL, NULL, NULL }
+#endif
+};
+
+/*!
+ * @internal
+ * @brief The selected dispatch table for @ref XXH3_64bits().
+ */
+static XXH_dispatch128Functions_s XXH_g_dispatch128 = { NULL, NULL, NULL, NULL };
+
+/*!
+ * @internal
+ * @brief Runs a CPUID check and sets the correct dispatch tables.
+ */
+static void XXH_setDispatch(void)
+{
+    int vecID = XXH_featureTest();
+    XXH_STATIC_ASSERT(XXH_AVX512 == XXH_NB_DISPATCHES-1);
+    assert(XXH_SCALAR <= vecID && vecID <= XXH_AVX512);
+#if !XXH_DISPATCH_SCALAR
+    assert(vecID != XXH_SCALAR);
+#endif
+#if !XXH_DISPATCH_AVX512
+    assert(vecID != XXH_AVX512);
+#endif
+#if !XXH_DISPATCH_AVX2
+    assert(vecID != XXH_AVX2);
+#endif
+    XXH_g_dispatch = XXH_kDispatch[vecID];
+    XXH_g_dispatch128 = XXH_kDispatch128[vecID];
+}
+
+
+/* ====    XXH3 public functions    ==== */
+
+static XXH64_hash_t
+XXH3_hashLong_64b_defaultSecret_selection(const void* input, size_t len,
+                                          XXH64_hash_t seed64, const xxh_u8* secret, size_t secretLen)
+{
+    (void)seed64; (void)secret; (void)secretLen;
+    if (XXH_g_dispatch.hashLong64_default == NULL) XXH_setDispatch();
+    return XXH_g_dispatch.hashLong64_default(input, len);
+}
+
+XXH64_hash_t XXH3_64bits_dispatch(const void* input, size_t len)
+{
+    return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_defaultSecret_selection);
+}
+
+static XXH64_hash_t
+XXH3_hashLong_64b_withSeed_selection(const void* input, size_t len,
+                                     XXH64_hash_t seed64, const xxh_u8* secret, size_t secretLen)
+{
+    (void)secret; (void)secretLen;
+    if (XXH_g_dispatch.hashLong64_seed == NULL) XXH_setDispatch();
+    return XXH_g_dispatch.hashLong64_seed(input, len, seed64);
+}
+
+XXH64_hash_t XXH3_64bits_withSeed_dispatch(const void* input, size_t len, XXH64_hash_t seed)
+{
+    return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed_selection);
+}
+
+static XXH64_hash_t
+XXH3_hashLong_64b_withSecret_selection(const void* input, size_t len,
+                                       XXH64_hash_t seed64, const xxh_u8* secret, size_t secretLen)
+{
+    (void)seed64;
+    if (XXH_g_dispatch.hashLong64_secret == NULL) XXH_setDispatch();
+    return XXH_g_dispatch.hashLong64_secret(input, len, secret, secretLen);
+}
+
+XXH64_hash_t XXH3_64bits_withSecret_dispatch(const void* input, size_t len, const void* secret, size_t secretLen)
+{
+    return XXH3_64bits_internal(input, len, 0, secret, secretLen, XXH3_hashLong_64b_withSecret_selection);
+}
+
+XXH_errorcode
+XXH3_64bits_update_dispatch(XXH3_state_t* state, const void* input, size_t len)
+{
+    if (XXH_g_dispatch.update == NULL) XXH_setDispatch();
+    return XXH_g_dispatch.update(state, (const xxh_u8*)input, len);
+}
+
+
+/* ====    XXH128 public functions    ==== */
+
+static XXH128_hash_t
+XXH3_hashLong_128b_defaultSecret_selection(const void* input, size_t len,
+                                           XXH64_hash_t seed64, const void* secret, size_t secretLen)
+{
+    (void)seed64; (void)secret; (void)secretLen;
+    if (XXH_g_dispatch128.hashLong128_default == NULL) XXH_setDispatch();
+    return XXH_g_dispatch128.hashLong128_default(input, len);
+}
+
+XXH128_hash_t XXH3_128bits_dispatch(const void* input, size_t len)
+{
+    return XXH3_128bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_defaultSecret_selection);
+}
+
+static XXH128_hash_t
+XXH3_hashLong_128b_withSeed_selection(const void* input, size_t len,
+                                     XXH64_hash_t seed64, const void* secret, size_t secretLen)
+{
+    (void)secret; (void)secretLen;
+    if (XXH_g_dispatch128.hashLong128_seed == NULL) XXH_setDispatch();
+    return XXH_g_dispatch128.hashLong128_seed(input, len, seed64);
+}
+
+XXH128_hash_t XXH3_128bits_withSeed_dispatch(const void* input, size_t len, XXH64_hash_t seed)
+{
+    return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_withSeed_selection);
+}
+
+static XXH128_hash_t
+XXH3_hashLong_128b_withSecret_selection(const void* input, size_t len,
+                                        XXH64_hash_t seed64, const void* secret, size_t secretLen)
+{
+    (void)seed64;
+    if (XXH_g_dispatch128.hashLong128_secret == NULL) XXH_setDispatch();
+    return XXH_g_dispatch128.hashLong128_secret(input, len, secret, secretLen);
+}
+
+XXH128_hash_t XXH3_128bits_withSecret_dispatch(const void* input, size_t len, const void* secret, size_t secretLen)
+{
+    return XXH3_128bits_internal(input, len, 0, secret, secretLen, XXH3_hashLong_128b_withSecret_selection);
+}
+
+XXH_errorcode
+XXH3_128bits_update_dispatch(XXH3_state_t* state, const void* input, size_t len)
+{
+    if (XXH_g_dispatch128.update == NULL) XXH_setDispatch();
+    return XXH_g_dispatch128.update(state, (const xxh_u8*)input, len);
+}
+
+#if defined (__cplusplus)
+}
+#endif
+/*! @} */
diff --git a/grpc/third_party/xxhash/xxh_x86dispatch.h b/grpc/third_party/xxhash/xxh_x86dispatch.h
new file mode 100644
index 0000000..6bc17bc
--- /dev/null
+++ b/grpc/third_party/xxhash/xxh_x86dispatch.h
@@ -0,0 +1,86 @@
+/*
+ * xxHash - XXH3 Dispatcher for x86-based targets
+ * Copyright (C) 2020 Yann Collet
+ *
+ * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other materials provided with the
+ *      distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+#ifndef XXH_X86DISPATCH_H_13563687684
+#define XXH_X86DISPATCH_H_13563687684
+
+#include "xxhash.h"  /* XXH64_hash_t, XXH3_state_t */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+XXH_PUBLIC_API XXH64_hash_t  XXH3_64bits_dispatch(const void* input, size_t len);
+XXH_PUBLIC_API XXH64_hash_t  XXH3_64bits_withSeed_dispatch(const void* input, size_t len, XXH64_hash_t seed);
+XXH_PUBLIC_API XXH64_hash_t  XXH3_64bits_withSecret_dispatch(const void* input, size_t len, const void* secret, size_t secretLen);
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update_dispatch(XXH3_state_t* state, const void* input, size_t len);
+
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_dispatch(const void* input, size_t len);
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed_dispatch(const void* input, size_t len, XXH64_hash_t seed);
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret_dispatch(const void* input, size_t len, const void* secret, size_t secretLen);
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update_dispatch(XXH3_state_t* state, const void* input, size_t len);
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* automatic replacement of XXH3 functions.
+ * can be disabled by setting XXH_DISPATCH_DISABLE_REPLACE */
+#ifndef XXH_DISPATCH_DISABLE_REPLACE
+
+# undef  XXH3_64bits
+# define XXH3_64bits XXH3_64bits_dispatch
+# undef  XXH3_64bits_withSeed
+# define XXH3_64bits_withSeed XXH3_64bits_withSeed_dispatch
+# undef  XXH3_64bits_withSecret
+# define XXH3_64bits_withSecret XXH3_64bits_withSecret_dispatch
+# undef  XXH3_64bits_update
+# define XXH3_64bits_update XXH3_64bits_update_dispatch
+
+# undef  XXH128
+# define XXH128 XXH3_128bits_withSeed_dispatch
+# define XXH3_128bits XXH3_128bits_dispatch
+# undef  XXH3_128bits
+# define XXH3_128bits XXH3_128bits_dispatch
+# undef  XXH3_128bits_withSeed
+# define XXH3_128bits_withSeed XXH3_128bits_withSeed_dispatch
+# undef  XXH3_128bits_withSecret
+# define XXH3_128bits_withSecret XXH3_128bits_withSecret_dispatch
+# undef  XXH3_128bits_update
+# define XXH3_128bits_update XXH3_128bits_update_dispatch
+
+#endif /* XXH_DISPATCH_DISABLE_REPLACE */
+
+#endif /* XXH_X86DISPATCH_H_13563687684 */
diff --git a/grpc/third_party/xxhash/xxhash.c b/grpc/third_party/xxhash/xxhash.c
new file mode 100644
index 0000000..0fae88c
--- /dev/null
+++ b/grpc/third_party/xxhash/xxhash.c
@@ -0,0 +1,43 @@
+/*
+ * xxHash - Extremely Fast Hash algorithm
+ * Copyright (C) 2012-2020 Yann Collet
+ *
+ * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other materials provided with the
+ *      distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+
+/*
+ * xxhash.c instantiates functions defined in xxhash.h
+ */
+
+#define XXH_STATIC_LINKING_ONLY   /* access advanced declarations */
+#define XXH_IMPLEMENTATION   /* access definitions */
+
+#include "xxhash.h"
diff --git a/grpc/third_party/xxhash/xxhash.h b/grpc/third_party/xxhash/xxhash.h
new file mode 100644
index 0000000..29c44e4
--- /dev/null
+++ b/grpc/third_party/xxhash/xxhash.h
@@ -0,0 +1,5443 @@
+/*
+ * xxHash - Extremely Fast Hash algorithm
+ * Header File
+ * Copyright (C) 2012-2020 Yann Collet
+ *
+ * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following disclaimer
+ *      in the documentation and/or other materials provided with the
+ *      distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+/*!
+ * @mainpage xxHash
+ *
+ * @file xxhash.h
+ * xxHash prototypes and implementation
+ */
+/* TODO: update */
+/* Notice extracted from xxHash homepage:
+
+xxHash is an extremely fast hash algorithm, running at RAM speed limits.
+It also successfully passes all tests from the SMHasher suite.
+
+Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
+
+Name            Speed       Q.Score   Author
+xxHash          5.4 GB/s     10
+CrapWow         3.2 GB/s      2       Andrew
+MurmurHash 3a   2.7 GB/s     10       Austin Appleby
+SpookyHash      2.0 GB/s     10       Bob Jenkins
+SBox            1.4 GB/s      9       Bret Mulvey
+Lookup3         1.2 GB/s      9       Bob Jenkins
+SuperFastHash   1.2 GB/s      1       Paul Hsieh
+CityHash64      1.05 GB/s    10       Pike & Alakuijala
+FNV             0.55 GB/s     5       Fowler, Noll, Vo
+CRC32           0.43 GB/s     9
+MD5-32          0.33 GB/s    10       Ronald L. Rivest
+SHA1-32         0.28 GB/s    10
+
+Q.Score is a measure of quality of the hash function.
+It depends on successfully passing SMHasher test set.
+10 is a perfect score.
+
+Note: SMHasher's CRC32 implementation is not the fastest one.
+Other speed-oriented implementations can be faster,
+especially in combination with PCLMUL instruction:
+https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735
+
+A 64-bit version, named XXH64, is available since r35.
+It offers much better speed, but for 64-bit applications only.
+Name     Speed on 64 bits    Speed on 32 bits
+XXH64       13.8 GB/s            1.9 GB/s
+XXH32        6.8 GB/s            6.0 GB/s
+*/
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/* ****************************
+ *  INLINE mode
+ ******************************/
+/*!
+ * XXH_INLINE_ALL (and XXH_PRIVATE_API)
+ * Use these build macros to inline xxhash into the target unit.
+ * Inlining improves performance on small inputs, especially when the length is
+ * expressed as a compile-time constant:
+ *
+ *      https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html
+ *
+ * It also keeps xxHash symbols private to the unit, so they are not exported.
+ *
+ * Usage:
+ *     #define XXH_INLINE_ALL
+ *     #include "xxhash.h"
+ *
+ * Do not compile and link xxhash.o as a separate object, as it is not useful.
+ */
+#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \
+    && !defined(XXH_INLINE_ALL_31684351384)
+   /* this section should be traversed only once */
+#  define XXH_INLINE_ALL_31684351384
+   /* give access to the advanced API, required to compile implementations */
+#  undef XXH_STATIC_LINKING_ONLY   /* avoid macro redef */
+#  define XXH_STATIC_LINKING_ONLY
+   /* make all functions private */
+#  undef XXH_PUBLIC_API
+#  if defined(__GNUC__)
+#    define XXH_PUBLIC_API static __inline __attribute__((unused))
+#  elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+#    define XXH_PUBLIC_API static inline
+#  elif defined(_MSC_VER)
+#    define XXH_PUBLIC_API static __inline
+#  else
+     /* note: this version may generate warnings for unused static functions */
+#    define XXH_PUBLIC_API static
+#  endif
+
+   /*
+    * This part deals with the special case where a unit wants to inline xxHash,
+    * but "xxhash.h" has previously been included without XXH_INLINE_ALL, such
+    * as part of some previously included *.h header file.
+    * Without further action, the new include would just be ignored,
+    * and functions would effectively _not_ be inlined (silent failure).
+    * The following macros solve this situation by prefixing all inlined names,
+    * avoiding naming collision with previous inclusions.
+    */
+#  ifdef XXH_NAMESPACE
+#    error "XXH_INLINE_ALL with XXH_NAMESPACE is not supported"
+     /*
+      * Note: Alternative: #undef all symbols (it's a pretty large list).
+      * Without #error: it compiles, but functions are actually not inlined.
+      */
+#  endif
+#  define XXH_NAMESPACE XXH_INLINE_
+   /*
+    * Some identifiers (enums, type names) are not symbols, but they must
+    * still be renamed to avoid redeclaration.
+    * Alternative solution: do not redeclare them.
+    * However, this requires some #ifdefs, and is a more dispersed action.
+    * Meanwhile, renaming can be achieved in a single block
+    */
+#  define XXH_IPREF(Id)   XXH_INLINE_ ## Id
+#  define XXH_OK XXH_IPREF(XXH_OK)
+#  define XXH_ERROR XXH_IPREF(XXH_ERROR)
+#  define XXH_errorcode XXH_IPREF(XXH_errorcode)
+#  define XXH32_canonical_t  XXH_IPREF(XXH32_canonical_t)
+#  define XXH64_canonical_t  XXH_IPREF(XXH64_canonical_t)
+#  define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t)
+#  define XXH32_state_s XXH_IPREF(XXH32_state_s)
+#  define XXH32_state_t XXH_IPREF(XXH32_state_t)
+#  define XXH64_state_s XXH_IPREF(XXH64_state_s)
+#  define XXH64_state_t XXH_IPREF(XXH64_state_t)
+#  define XXH3_state_s  XXH_IPREF(XXH3_state_s)
+#  define XXH3_state_t  XXH_IPREF(XXH3_state_t)
+#  define XXH128_hash_t XXH_IPREF(XXH128_hash_t)
+   /* Ensure the header is parsed again, even if it was previously included */
+#  undef XXHASH_H_5627135585666179
+#  undef XXHASH_H_STATIC_13879238742
+#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */
+
+
+
+/* ****************************************************************
+ *  Stable API
+ *****************************************************************/
+#ifndef XXHASH_H_5627135585666179
+#define XXHASH_H_5627135585666179 1
+
+
+/*!
+ * @defgroup public Public API
+ * Contains details on the public xxHash functions.
+ * @{
+ */
+/* specific declaration modes for Windows */
+#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)
+#  if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT))
+#    ifdef XXH_EXPORT
+#      define XXH_PUBLIC_API __declspec(dllexport)
+#    elif XXH_IMPORT
+#      define XXH_PUBLIC_API __declspec(dllimport)
+#    endif
+#  else
+#    define XXH_PUBLIC_API   /* do nothing */
+#  endif
+#endif
+
+#ifdef XXH_DOXYGEN
+/*!
+ * @brief Emulate a namespace by transparently prefixing all symbols.
+ *
+ * If you want to include _and expose_ xxHash functions from within your own
+ * library, but also want to avoid symbol collisions with other libraries which
+ * may also include xxHash, you can use XXH_NAMESPACE to automatically prefix
+ * any public symbol from xxhash library with the value of XXH_NAMESPACE
+ * (therefore, avoid empty or numeric values).
+ *
+ * Note that no change is required within the calling program as long as it
+ * includes `xxhash.h`: Regular symbol names will be automatically translated
+ * by this header.
+ */
+#  define XXH_NAMESPACE /* YOUR NAME HERE */
+#  undef XXH_NAMESPACE
+#endif
+
+#ifdef XXH_NAMESPACE
+#  define XXH_CAT(A,B) A##B
+#  define XXH_NAME2(A,B) XXH_CAT(A,B)
+#  define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
+/* XXH32 */
+#  define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
+#  define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
+#  define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
+#  define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
+#  define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
+#  define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
+#  define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
+#  define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
+#  define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
+/* XXH64 */
+#  define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
+#  define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
+#  define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
+#  define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
+#  define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
+#  define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
+#  define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
+#  define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
+#  define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
+/* XXH3_64bits */
+#  define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits)
+#  define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret)
+#  define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed)
+#  define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState)
+#  define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState)
+#  define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState)
+#  define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset)
+#  define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed)
+#  define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret)
+#  define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update)
+#  define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest)
+#  define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret)
+/* XXH3_128bits */
+#  define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128)
+#  define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits)
+#  define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed)
+#  define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret)
+#  define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset)
+#  define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed)
+#  define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret)
+#  define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update)
+#  define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest)
+#  define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual)
+#  define XXH128_cmp     XXH_NAME2(XXH_NAMESPACE, XXH128_cmp)
+#  define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash)
+#  define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical)
+#endif
+
+
+/* *************************************
+*  Version
+***************************************/
+#define XXH_VERSION_MAJOR    0
+#define XXH_VERSION_MINOR    8
+#define XXH_VERSION_RELEASE  0
+#define XXH_VERSION_NUMBER  (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
+
+/*!
+ * @brief Obtains the xxHash version.
+ *
+ * This is only useful when xxHash is compiled as a shared library, as it is
+ * independent of the version defined in the header.
+ *
+ * @return `XXH_VERSION_NUMBER` as of when the function was compiled.
+ */
+XXH_PUBLIC_API unsigned XXH_versionNumber (void);
+
+
+/* ****************************
+*  Definitions
+******************************/
+#include <stddef.h>   /* size_t */
+typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
+
+
+/*-**********************************************************************
+*  32-bit hash
+************************************************************************/
+#if defined(XXH_DOXYGEN) /* Don't show <stdint.h> include */
+/*!
+ * @brief An unsigned 32-bit integer.
+ *
+ * Not necessarily defined to `uint32_t` but functionally equivalent.
+ */
+typedef uint32_t XXH32_hash_t;
+#elif !defined (__VMS) \
+  && (defined (__cplusplus) \
+  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+#   include <stdint.h>
+    typedef uint32_t XXH32_hash_t;
+#else
+#   include <limits.h>
+#   if UINT_MAX == 0xFFFFFFFFUL
+      typedef unsigned int XXH32_hash_t;
+#   else
+#     if ULONG_MAX == 0xFFFFFFFFUL
+        typedef unsigned long XXH32_hash_t;
+#     else
+#       error "unsupported platform: need a 32-bit type"
+#     endif
+#   endif
+#endif
+
+/*!
+ * @}
+ *
+ * @defgroup xxh32_family XXH32 family
+ * @ingroup public
+ * Contains functions used in the classic 32-bit xxHash algorithm.
+ *
+ * @note
+ *   XXH32 is considered rather weak by today's standards.
+ *   The @ref xxh3_family provides competitive speed for both 32-bit and 64-bit
+ *   systems, and offers true 64/128 bit hash results. It provides a superior
+ *   level of dispersion, and greatly reduces the risks of collisions.
+ *
+ * @see @ref xxh64_family, @ref xxh3_family : Other xxHash families
+ * @see @ref xxh32_impl for implementation details
+ * @{
+ */
+
+/*!
+ * @brief Calculates the 32-bit hash of @p input using xxHash32.
+ *
+ * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s
+ *
+ * @param input The block of data to be hashed, at least @p length bytes in size.
+ * @param length The length of @p input, in bytes.
+ * @param seed The 32-bit seed to alter the hash's output predictably.
+ *
+ * @pre
+ *   The memory between @p input and @p input + @p length must be valid,
+ *   readable, contiguous memory. However, if @p length is `0`, @p input may be
+ *   `NULL`. In C++, this also must be *TriviallyCopyable*.
+ *
+ * @return The calculated 32-bit hash value.
+ *
+ * @see
+ *    XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128():
+ *    Direct equivalents for the other variants of xxHash.
+ * @see
+ *    XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version.
+ */
+XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed);
+
+/*!
+ * Streaming functions generate the xxHash value from an incremental input.
+ * This method is slower than single-call functions, due to state management.
+ * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.
+ *
+ * An XXH state must first be allocated using `XXH*_createState()`.
+ *
+ * Start a new hash by initializing the state with a seed using `XXH*_reset()`.
+ *
+ * Then, feed the hash state by calling `XXH*_update()` as many times as necessary.
+ *
+ * The function returns an error code, with 0 meaning OK, and any other value
+ * meaning there is an error.
+ *
+ * Finally, a hash value can be produced anytime, by using `XXH*_digest()`.
+ * This function returns the nn-bits hash as an int or long long.
+ *
+ * It's still possible to continue inserting input into the hash state after a
+ * digest, and generate new hash values later on by invoking `XXH*_digest()`.
+ *
+ * When done, release the state using `XXH*_freeState()`.
+ *
+ * Example code for incrementally hashing a file:
+ * @code{.c}
+ *    #include <stdio.h>
+ *    #include <xxhash.h>
+ *    #define BUFFER_SIZE 256
+ *
+ *    // Note: XXH64 and XXH3 use the same interface.
+ *    XXH32_hash_t
+ *    hashFile(FILE* stream)
+ *    {
+ *        XXH32_state_t* state;
+ *        unsigned char buf[BUFFER_SIZE];
+ *        size_t amt;
+ *        XXH32_hash_t hash;
+ *
+ *        state = XXH32_createState();       // Create a state
+ *        assert(state != NULL);             // Error check here
+ *        XXH32_reset(state, 0xbaad5eed);    // Reset state with our seed
+ *        while ((amt = fread(buf, 1, sizeof(buf), stream)) != 0) {
+ *            XXH32_update(state, buf, amt); // Hash the file in chunks
+ *        }
+ *        hash = XXH32_digest(state);        // Finalize the hash
+ *        XXH32_freeState(state);            // Clean up
+ *        return hash;
+ *    }
+ * @endcode
+ */
+
+/*!
+ * @typedef struct XXH32_state_s XXH32_state_t
+ * @brief The opaque state struct for the XXH32 streaming API.
+ *
+ * @see XXH32_state_s for details.
+ */
+typedef struct XXH32_state_s XXH32_state_t;
+
+/*!
+ * @brief Allocates an @ref XXH32_state_t.
+ *
+ * Must be freed with XXH32_freeState().
+ * @return An allocated XXH32_state_t on success, `NULL` on failure.
+ */
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
+/*!
+ * @brief Frees an @ref XXH32_state_t.
+ *
+ * Must be allocated with XXH32_createState().
+ * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState().
+ * @return XXH_OK.
+ */
+XXH_PUBLIC_API XXH_errorcode  XXH32_freeState(XXH32_state_t* statePtr);
+/*!
+ * @brief Copies one @ref XXH32_state_t to another.
+ *
+ * @param dst_state The state to copy to.
+ * @param src_state The state to copy from.
+ * @pre
+ *   @p dst_state and @p src_state must not be `NULL` and must not overlap.
+ */
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
+
+/*!
+ * @brief Resets an @ref XXH32_state_t to begin a new hash.
+ *
+ * This function resets and seeds a state. Call it before @ref XXH32_update().
+ *
+ * @param statePtr The state struct to reset.
+ * @param seed The 32-bit seed to alter the hash result predictably.
+ *
+ * @pre
+ *   @p statePtr must not be `NULL`.
+ *
+ * @return @ref XXH_OK on success, @ref XXH_ERROR on failure.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH32_reset  (XXH32_state_t* statePtr, XXH32_hash_t seed);
+
+/*!
+ * @brief Consumes a block of @p input to an @ref XXH32_state_t.
+ *
+ * Call this to incrementally consume blocks of data.
+ *
+ * @param statePtr The state struct to update.
+ * @param input The block of data to be hashed, at least @p length bytes in size.
+ * @param length The length of @p input, in bytes.
+ *
+ * @pre
+ *   @p statePtr must not be `NULL`.
+ * @pre
+ *   The memory between @p input and @p input + @p length must be valid,
+ *   readable, contiguous memory. However, if @p length is `0`, @p input may be
+ *   `NULL`. In C++, this also must be *TriviallyCopyable*.
+ *
+ * @return @ref XXH_OK on success, @ref XXH_ERROR on failure.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
+
+/*!
+ * @brief Returns the calculated hash value from an @ref XXH32_state_t.
+ *
+ * @note
+ *   Calling XXH32_digest() will not affect @p statePtr, so you can update,
+ *   digest, and update again.
+ *
+ * @param statePtr The state struct to calculate the hash from.
+ *
+ * @pre
+ *  @p statePtr must not be `NULL`.
+ *
+ * @return The calculated xxHash32 value from that state.
+ */
+XXH_PUBLIC_API XXH32_hash_t  XXH32_digest (const XXH32_state_t* statePtr);
+
+/*******   Canonical representation   *******/
+
+/*
+ * The default return values from XXH functions are unsigned 32 and 64 bit
+ * integers.
+ * This the simplest and fastest format for further post-processing.
+ *
+ * However, this leaves open the question of what is the order on the byte level,
+ * since little and big endian conventions will store the same number differently.
+ *
+ * The canonical representation settles this issue by mandating big-endian
+ * convention, the same convention as human-readable numbers (large digits first).
+ *
+ * When writing hash values to storage, sending them over a network, or printing
+ * them, it's highly recommended to use the canonical representation to ensure
+ * portability across a wider range of systems, present and future.
+ *
+ * The following functions allow transformation of hash values to and from
+ * canonical format.
+ */
+
+/*!
+ * @brief Canonical (big endian) representation of @ref XXH32_hash_t.
+ */
+typedef struct {
+    unsigned char digest[4]; /*!< Hash bytes, big endian */
+} XXH32_canonical_t;
+
+/*!
+ * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t.
+ *
+ * @param dst The @ref XXH32_canonical_t pointer to be stored to.
+ * @param hash The @ref XXH32_hash_t to be converted.
+ *
+ * @pre
+ *   @p dst must not be `NULL`.
+ */
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
+
+/*!
+ * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t.
+ *
+ * @param src The @ref XXH32_canonical_t to convert.
+ *
+ * @pre
+ *   @p src must not be `NULL`.
+ *
+ * @return The converted hash.
+ */
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
+
+
+/*!
+ * @}
+ * @ingroup public
+ * @{
+ */
+
+#ifndef XXH_NO_LONG_LONG
+/*-**********************************************************************
+*  64-bit hash
+************************************************************************/
+#if defined(XXH_DOXYGEN) /* don't include <stdint.h> */
+/*!
+ * @brief An unsigned 64-bit integer.
+ *
+ * Not necessarily defined to `uint64_t` but functionally equivalent.
+ */
+typedef uint64_t XXH64_hash_t;
+#elif !defined (__VMS) \
+  && (defined (__cplusplus) \
+  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+#  include <stdint.h>
+   typedef uint64_t XXH64_hash_t;
+#else
+#  include <limits.h>
+#  if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL
+     /* LP64 ABI says uint64_t is unsigned long */
+     typedef unsigned long XXH64_hash_t;
+#  else
+     /* the following type must have a width of 64-bit */
+     typedef unsigned long long XXH64_hash_t;
+#  endif
+#endif
+
+/*!
+ * @}
+ *
+ * @defgroup xxh64_family XXH64 family
+ * @ingroup public
+ * @{
+ * Contains functions used in the classic 64-bit xxHash algorithm.
+ *
+ * @note
+ *   XXH3 provides competitive speed for both 32-bit and 64-bit systems,
+ *   and offers true 64/128 bit hash results. It provides a superior level of
+ *   dispersion, and greatly reduces the risks of collisions.
+ */
+
+
+/*!
+ * @brief Calculates the 64-bit hash of @p input using xxHash64.
+ *
+ * This function usually runs faster on 64-bit systems, but slower on 32-bit
+ * systems (see benchmark).
+ *
+ * @param input The block of data to be hashed, at least @p length bytes in size.
+ * @param length The length of @p input, in bytes.
+ * @param seed The 64-bit seed to alter the hash's output predictably.
+ *
+ * @pre
+ *   The memory between @p input and @p input + @p length must be valid,
+ *   readable, contiguous memory. However, if @p length is `0`, @p input may be
+ *   `NULL`. In C++, this also must be *TriviallyCopyable*.
+ *
+ * @return The calculated 64-bit hash.
+ *
+ * @see
+ *    XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128():
+ *    Direct equivalents for the other variants of xxHash.
+ * @see
+ *    XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version.
+ */
+XXH_PUBLIC_API XXH64_hash_t XXH64(const void* input, size_t length, XXH64_hash_t seed);
+
+/*******   Streaming   *******/
+/*!
+ * @brief The opaque state struct for the XXH64 streaming API.
+ *
+ * @see XXH64_state_s for details.
+ */
+typedef struct XXH64_state_s XXH64_state_t;   /* incomplete type */
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
+XXH_PUBLIC_API XXH_errorcode  XXH64_freeState(XXH64_state_t* statePtr);
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset  (XXH64_state_t* statePtr, XXH64_hash_t seed);
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH64_hash_t  XXH64_digest (const XXH64_state_t* statePtr);
+
+/*******   Canonical representation   *******/
+typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t;
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
+
+/*!
+ * @}
+ * ************************************************************************
+ * @defgroup xxh3_family XXH3 family
+ * @ingroup public
+ * @{
+ *
+ * XXH3 is a more recent hash algorithm featuring:
+ *  - Improved speed for both small and large inputs
+ *  - True 64-bit and 128-bit outputs
+ *  - SIMD acceleration
+ *  - Improved 32-bit viability
+ *
+ * Speed analysis methodology is explained here:
+ *
+ *    https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html
+ *
+ * Compared to XXH64, expect XXH3 to run approximately
+ * ~2x faster on large inputs and >3x faster on small ones,
+ * exact differences vary depending on platform.
+ *
+ * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic,
+ * but does not require it.
+ * Any 32-bit and 64-bit targets that can run XXH32 smoothly
+ * can run XXH3 at competitive speeds, even without vector support.
+ * Further details are explained in the implementation.
+ *
+ * Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8,
+ * ZVector and scalar targets. This can be controlled via the XXH_VECTOR macro.
+ *
+ * XXH3 implementation is portable:
+ * it has a generic C90 formulation that can be compiled on any platform,
+ * all implementations generage exactly the same hash value on all platforms.
+ * Starting from v0.8.0, it's also labelled "stable", meaning that
+ * any future version will also generate the same hash value.
+ *
+ * XXH3 offers 2 variants, _64bits and _128bits.
+ *
+ * When only 64 bits are needed, prefer invoking the _64bits variant, as it
+ * reduces the amount of mixing, resulting in faster speed on small inputs.
+ * It's also generally simpler to manipulate a scalar return type than a struct.
+ *
+ * The API supports one-shot hashing, streaming mode, and custom secrets.
+ */
+
+/*-**********************************************************************
+*  XXH3 64-bit variant
+************************************************************************/
+
+/* XXH3_64bits():
+ * default 64-bit variant, using default secret and default seed of 0.
+ * It's the fastest variant. */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len);
+
+/*
+ * XXH3_64bits_withSeed():
+ * This variant generates a custom secret on the fly
+ * based on default secret altered using the `seed` value.
+ * While this operation is decently fast, note that it's not completely free.
+ * Note: seed==0 produces the same results as XXH3_64bits().
+ */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed);
+
+/*!
+ * The bare minimum size for a custom secret.
+ *
+ * @see
+ *  XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(),
+ *  XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret().
+ */
+#define XXH3_SECRET_SIZE_MIN 136
+
+/*
+ * XXH3_64bits_withSecret():
+ * It's possible to provide any blob of bytes as a "secret" to generate the hash.
+ * This makes it more difficult for an external actor to prepare an intentional collision.
+ * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN).
+ * However, the quality of produced hash values depends on secret's entropy.
+ * Technically, the secret must look like a bunch of random bytes.
+ * Avoid "trivial" or structured data such as repeated sequences or a text document.
+ * Whenever unsure about the "randomness" of the blob of bytes,
+ * consider relabelling it as a "custom seed" instead,
+ * and employ "XXH3_generateSecret()" (see below)
+ * to generate a high entropy secret derived from the custom seed.
+ */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize);
+
+
+/*******   Streaming   *******/
+/*
+ * Streaming requires state maintenance.
+ * This operation costs memory and CPU.
+ * As a consequence, streaming is slower than one-shot hashing.
+ * For better performance, prefer one-shot functions whenever applicable.
+ */
+
+/*!
+ * @brief The state struct for the XXH3 streaming API.
+ *
+ * @see XXH3_state_s for details.
+ */
+typedef struct XXH3_state_s XXH3_state_t;
+XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr);
+XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state);
+
+/*
+ * XXH3_64bits_reset():
+ * Initialize with default parameters.
+ * digest will be equivalent to `XXH3_64bits()`.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr);
+/*
+ * XXH3_64bits_reset_withSeed():
+ * Generate a custom secret from `seed`, and store it into `statePtr`.
+ * digest will be equivalent to `XXH3_64bits_withSeed()`.
+ */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed);
+/*
+ * XXH3_64bits_reset_withSecret():
+ * `secret` is referenced, it _must outlive_ the hash streaming session.
+ * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`,
+ * and the quality of produced hash values depends on secret's entropy
+ * (secret's content should look like a bunch of random bytes).
+ * When in doubt about the randomness of a candidate `secret`,
+ * consider employing `XXH3_generateSecret()` instead (see below).
+ */
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize);
+
+XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH3_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH64_hash_t  XXH3_64bits_digest (const XXH3_state_t* statePtr);
+
+/* note : canonical representation of XXH3 is the same as XXH64
+ * since they both produce XXH64_hash_t values */
+
+
+/*-**********************************************************************
+*  XXH3 128-bit variant
+************************************************************************/
+
+/*!
+ * @brief The return value from 128-bit hashes.
+ *
+ * Stored in little endian order, although the fields themselves are in native
+ * endianness.
+ */
+typedef struct {
+    XXH64_hash_t low64;   /*!< `value & 0xFFFFFFFFFFFFFFFF` */
+    XXH64_hash_t high64;  /*!< `value >> 64` */
+} XXH128_hash_t;
+
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len);
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed);
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize);
+
+/*******   Streaming   *******/
+/*
+ * Streaming requires state maintenance.
+ * This operation costs memory and CPU.
+ * As a consequence, streaming is slower than one-shot hashing.
+ * For better performance, prefer one-shot functions whenever applicable.
+ *
+ * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits().
+ * Use already declared XXH3_createState() and XXH3_freeState().
+ *
+ * All reset and streaming functions have same meaning as their 64-bit counterpart.
+ */
+
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr);
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed);
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize);
+
+XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr);
+
+/* Following helper functions make it possible to compare XXH128_hast_t values.
+ * Since XXH128_hash_t is a structure, this capability is not offered by the language.
+ * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */
+
+/*!
+ * XXH128_isEqual():
+ * Return: 1 if `h1` and `h2` are equal, 0 if they are not.
+ */
+XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2);
+
+/*!
+ * XXH128_cmp():
+ *
+ * This comparator is compatible with stdlib's `qsort()`/`bsearch()`.
+ *
+ * return: >0 if *h128_1  > *h128_2
+ *         =0 if *h128_1 == *h128_2
+ *         <0 if *h128_1  < *h128_2
+ */
+XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2);
+
+
+/*******   Canonical representation   *******/
+typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t;
+XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash);
+XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src);
+
+
+#endif  /* XXH_NO_LONG_LONG */
+
+/*!
+ * @}
+ */
+#endif /* XXHASH_H_5627135585666179 */
+
+
+
+#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742)
+#define XXHASH_H_STATIC_13879238742
+/* ****************************************************************************
+ * This section contains declarations which are not guaranteed to remain stable.
+ * They may change in future versions, becoming incompatible with a different
+ * version of the library.
+ * These declarations should only be used with static linking.
+ * Never use them in association with dynamic linking!
+ ***************************************************************************** */
+
+/*
+ * These definitions are only present to allow static allocation
+ * of XXH states, on stack or in a struct, for example.
+ * Never **ever** access their members directly.
+ */
+
+/*!
+ * @internal
+ * @brief Structure for XXH32 streaming API.
+ *
+ * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
+ * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is
+ * an opaque type. This allows fields to safely be changed.
+ *
+ * Typedef'd to @ref XXH32_state_t.
+ * Do not access the members of this struct directly.
+ * @see XXH64_state_s, XXH3_state_s
+ */
+struct XXH32_state_s {
+   XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */
+   XXH32_hash_t large_len;    /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */
+   XXH32_hash_t v1;           /*!< First accumulator lane */
+   XXH32_hash_t v2;           /*!< Second accumulator lane */
+   XXH32_hash_t v3;           /*!< Third accumulator lane */
+   XXH32_hash_t v4;           /*!< Fourth accumulator lane */
+   XXH32_hash_t mem32[4];     /*!< Internal buffer for partial reads. Treated as unsigned char[16]. */
+   XXH32_hash_t memsize;      /*!< Amount of data in @ref mem32 */
+   XXH32_hash_t reserved;     /*!< Reserved field. Do not read or write to it, it may be removed. */
+};   /* typedef'd to XXH32_state_t */
+
+
+#ifndef XXH_NO_LONG_LONG  /* defined when there is no 64-bit support */
+
+/*!
+ * @internal
+ * @brief Structure for XXH64 streaming API.
+ *
+ * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
+ * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is
+ * an opaque type. This allows fields to safely be changed.
+ *
+ * Typedef'd to @ref XXH64_state_t.
+ * Do not access the members of this struct directly.
+ * @see XXH32_state_s, XXH3_state_s
+ */
+struct XXH64_state_s {
+   XXH64_hash_t total_len;    /*!< Total length hashed. This is always 64-bit. */
+   XXH64_hash_t v1;           /*!< First accumulator lane */
+   XXH64_hash_t v2;           /*!< Second accumulator lane */
+   XXH64_hash_t v3;           /*!< Third accumulator lane */
+   XXH64_hash_t v4;           /*!< Fourth accumulator lane */
+   XXH64_hash_t mem64[4];     /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */
+   XXH32_hash_t memsize;      /*!< Amount of data in @ref mem64 */
+   XXH32_hash_t reserved32;   /*!< Reserved field, needed for padding anyways*/
+   XXH64_hash_t reserved64;   /*!< Reserved field. Do not read or write to it, it may be removed. */
+};   /* typedef'd to XXH64_state_t */
+
+#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)   /* C11+ */
+#  include <stdalign.h>
+#  define XXH_ALIGN(n)      alignas(n)
+#elif defined(__GNUC__)
+#  define XXH_ALIGN(n)      __attribute__ ((aligned(n)))
+#elif defined(_MSC_VER)
+#  define XXH_ALIGN(n)      __declspec(align(n))
+#else
+#  define XXH_ALIGN(n)   /* disabled */
+#endif
+
+/* Old GCC versions only accept the attribute after the type in structures. */
+#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))   /* C11+ */ \
+    && defined(__GNUC__)
+#   define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align)
+#else
+#   define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type
+#endif
+
+/*!
+ * @brief The size of the internal XXH3 buffer.
+ *
+ * This is the optimal update size for incremental hashing.
+ *
+ * @see XXH3_64b_update(), XXH3_128b_update().
+ */
+#define XXH3_INTERNALBUFFER_SIZE 256
+
+/*!
+ * @brief Default size of the secret buffer (and @ref XXH3_kSecret).
+ *
+ * This is the size used in @ref XXH3_kSecret and the seeded functions.
+ *
+ * Not to be confused with @ref XXH3_SECRET_SIZE_MIN.
+ */
+#define XXH3_SECRET_DEFAULT_SIZE 192
+
+/*!
+ * @internal
+ * @brief Structure for XXH3 streaming API.
+ *
+ * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
+ * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is
+ * an opaque type. This allows fields to safely be changed.
+ *
+ * @note **This structure has a strict alignment requirement of 64 bytes.** Do
+ * not allocate this with `malloc()` or `new`, it will not be sufficiently
+ * aligned. Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack
+ * allocation.
+ *
+ * Typedef'd to @ref XXH3_state_t.
+ * Do not access the members of this struct directly.
+ *
+ * @see XXH3_INITSTATE() for stack initialization.
+ * @see XXH3_createState(), XXH3_freeState().
+ * @see XXH32_state_s, XXH64_state_s
+ */
+struct XXH3_state_s {
+   XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]);
+       /*!< The 8 accumulators. Similar to `vN` in @ref XXH32_state_s::v1 and @ref XXH64_state_s */
+   XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]);
+       /*!< Used to store a custom secret generated from a seed. */
+   XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]);
+       /*!< The internal buffer. @see XXH32_state_s::mem32 */
+   XXH32_hash_t bufferedSize;
+       /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */
+   XXH32_hash_t reserved32;
+       /*!< Reserved field. Needed for padding on 64-bit. */
+   size_t nbStripesSoFar;
+       /*!< Number or stripes processed. */
+   XXH64_hash_t totalLen;
+       /*!< Total length hashed. 64-bit even on 32-bit targets. */
+   size_t nbStripesPerBlock;
+       /*!< Number of stripes per block. */
+   size_t secretLimit;
+       /*!< Size of @ref customSecret or @ref extSecret */
+   XXH64_hash_t seed;
+       /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */
+   XXH64_hash_t reserved64;
+       /*!< Reserved field. */
+   const unsigned char* extSecret;
+       /*!< Reference to an external secret for the _withSecret variants, NULL
+        *   for other variants. */
+   /* note: there may be some padding at the end due to alignment on 64 bytes */
+}; /* typedef'd to XXH3_state_t */
+
+#undef XXH_ALIGN_MEMBER
+
+/*!
+ * @brief Initializes a stack-allocated `XXH3_state_s`.
+ *
+ * When the @ref XXH3_state_t structure is merely emplaced on stack,
+ * it should be initialized with XXH3_INITSTATE() or a memset()
+ * in case its first reset uses XXH3_NNbits_reset_withSeed().
+ * This init can be omitted if the first reset uses default or _withSecret mode.
+ * This operation isn't necessary when the state is created with XXH3_createState().
+ * Note that this doesn't prepare the state for a streaming operation,
+ * it's still necessary to use XXH3_NNbits_reset*() afterwards.
+ */
+#define XXH3_INITSTATE(XXH3_state_ptr)   { (XXH3_state_ptr)->seed = 0; }
+
+
+/* ===   Experimental API   === */
+/* Symbols defined below must be considered tied to a specific library version. */
+
+/*
+ * XXH3_generateSecret():
+ *
+ * Derive a high-entropy secret from any user-defined content, named customSeed.
+ * The generated secret can be used in combination with `*_withSecret()` functions.
+ * The `_withSecret()` variants are useful to provide a higher level of protection than 64-bit seed,
+ * as it becomes much more difficult for an external actor to guess how to impact the calculation logic.
+ *
+ * The function accepts as input a custom seed of any length and any content,
+ * and derives from it a high-entropy secret of length XXH3_SECRET_DEFAULT_SIZE
+ * into an already allocated buffer secretBuffer.
+ * The generated secret is _always_ XXH_SECRET_DEFAULT_SIZE bytes long.
+ *
+ * The generated secret can then be used with any `*_withSecret()` variant.
+ * Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`,
+ * `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()`
+ * are part of this list. They all accept a `secret` parameter
+ * which must be very long for implementation reasons (>= XXH3_SECRET_SIZE_MIN)
+ * _and_ feature very high entropy (consist of random-looking bytes).
+ * These conditions can be a high bar to meet, so
+ * this function can be used to generate a secret of proper quality.
+ *
+ * customSeed can be anything. It can have any size, even small ones,
+ * and its content can be anything, even stupidly "low entropy" source such as a bunch of zeroes.
+ * The resulting `secret` will nonetheless provide all expected qualities.
+ *
+ * Supplying NULL as the customSeed copies the default secret into `secretBuffer`.
+ * When customSeedSize > 0, supplying NULL as customSeed is undefined behavior.
+ */
+XXH_PUBLIC_API void XXH3_generateSecret(void* secretBuffer, const void* customSeed, size_t customSeedSize);
+
+
+/* simple short-cut to pre-selected XXH3_128bits variant */
+XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed);
+
+
+#endif  /* XXH_NO_LONG_LONG */
+#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
+#  define XXH_IMPLEMENTATION
+#endif
+
+#endif  /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */
+
+
+/* ======================================================================== */
+/* ======================================================================== */
+/* ======================================================================== */
+
+
+/*-**********************************************************************
+ * xxHash implementation
+ *-**********************************************************************
+ * xxHash's implementation used to be hosted inside xxhash.c.
+ *
+ * However, inlining requires implementation to be visible to the compiler,
+ * hence be included alongside the header.
+ * Previously, implementation was hosted inside xxhash.c,
+ * which was then #included when inlining was activated.
+ * This construction created issues with a few build and install systems,
+ * as it required xxhash.c to be stored in /include directory.
+ *
+ * xxHash implementation is now directly integrated within xxhash.h.
+ * As a consequence, xxhash.c is no longer needed in /include.
+ *
+ * xxhash.c is still available and is still useful.
+ * In a "normal" setup, when xxhash is not inlined,
+ * xxhash.h only exposes the prototypes and public symbols,
+ * while xxhash.c can be built into an object file xxhash.o
+ * which can then be linked into the final binary.
+ ************************************************************************/
+
+#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \
+   || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387)
+#  define XXH_IMPLEM_13a8737387
+
+/* *************************************
+*  Tuning parameters
+***************************************/
+
+/*!
+ * @defgroup tuning Tuning parameters
+ * @{
+ *
+ * Various macros to control xxHash's behavior.
+ */
+#ifdef XXH_DOXYGEN
+/*!
+ * @brief Define this to disable 64-bit code.
+ *
+ * Useful if only using the @ref xxh32_family and you have a strict C90 compiler.
+ */
+#  define XXH_NO_LONG_LONG
+#  undef XXH_NO_LONG_LONG /* don't actually */
+/*!
+ * @brief Controls how unaligned memory is accessed.
+ *
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is
+ * safe and portable.
+ *
+ * Unfortunately, on some target/compiler combinations, the generated assembly
+ * is sub-optimal.
+ *
+ * The below switch allow selection of a different access method
+ * in the search for improved performance.
+ *
+ * @par Possible options:
+ *
+ *  - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy`
+ *   @par
+ *     Use `memcpy()`. Safe and portable. Note that most modern compilers will
+ *     eliminate the function call and treat it as an unaligned access.
+ *
+ *  - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((packed))`
+ *   @par
+ *     Depends on compiler extensions and is therefore not portable.
+ *     This method is safe _if_ your compiler supports it,
+ *     and *generally* as fast or faster than `memcpy`.
+ *
+ *  - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast
+ *  @par
+ *     Casts directly and dereferences. This method doesn't depend on the
+ *     compiler, but it violates the C standard as it directly dereferences an
+ *     unaligned pointer. It can generate buggy code on targets which do not
+ *     support unaligned memory accesses, but in some circumstances, it's the
+ *     only known way to get the most performance.
+ *
+ *  - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift
+ *  @par
+ *     Also portable. This can generate the best code on old compilers which don't
+ *     inline small `memcpy()` calls, and it might also be faster on big-endian
+ *     systems which lack a native byteswap instruction. However, some compilers
+ *     will emit literal byteshifts even if the target supports unaligned access.
+ *  .
+ *
+ * @warning
+ *   Methods 1 and 2 rely on implementation-defined behavior. Use these with
+ *   care, as what works on one compiler/platform/optimization level may cause
+ *   another to read garbage data or even crash.
+ *
+ * See https://stackoverflow.com/a/32095106/646947 for details.
+ *
+ * Prefer these methods in priority order (0 > 3 > 1 > 2)
+ */
+#  define XXH_FORCE_MEMORY_ACCESS 0
+/*!
+ * @def XXH_ACCEPT_NULL_INPUT_POINTER
+ * @brief Whether to add explicit `NULL` checks.
+ *
+ * If the input pointer is `NULL` and the length is non-zero, xxHash's default
+ * behavior is to dereference it, triggering a segfault.
+ *
+ * When this macro is enabled, xxHash actively checks the input for a null pointer.
+ * If it is, the result for null input pointers is the same as a zero-length input.
+ */
+#  define XXH_ACCEPT_NULL_INPUT_POINTER 0
+/*!
+ * @def XXH_FORCE_ALIGN_CHECK
+ * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32()
+ * and XXH64() only).
+ *
+ * This is an important performance trick for architectures without decent
+ * unaligned memory access performance.
+ *
+ * It checks for input alignment, and when conditions are met, uses a "fast
+ * path" employing direct 32-bit/64-bit reads, resulting in _dramatically
+ * faster_ read speed.
+ *
+ * The check costs one initial branch per hash, which is generally negligible,
+ * but not zero.
+ *
+ * Moreover, it's not useful to generate an additional code path if memory
+ * access uses the same instruction for both aligned and unaligned
+ * addresses (e.g. x86 and aarch64).
+ *
+ * In these cases, the alignment check can be removed by setting this macro to 0.
+ * Then the code will always use unaligned memory access.
+ * Align check is automatically disabled on x86, x64 & arm64,
+ * which are platforms known to offer good unaligned memory accesses performance.
+ *
+ * This option does not affect XXH3 (only XXH32 and XXH64).
+ */
+#  define XXH_FORCE_ALIGN_CHECK 0
+
+/*!
+ * @def XXH_NO_INLINE_HINTS
+ * @brief When non-zero, sets all functions to `static`.
+ *
+ * By default, xxHash tries to force the compiler to inline almost all internal
+ * functions.
+ *
+ * This can usually improve performance due to reduced jumping and improved
+ * constant folding, but significantly increases the size of the binary which
+ * might not be favorable.
+ *
+ * Additionally, sometimes the forced inlining can be detrimental to performance,
+ * depending on the architecture.
+ *
+ * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the
+ * compiler full control on whether to inline or not.
+ *
+ * When not optimizing (-O0), optimizing for size (-Os, -Oz), or using
+ * -fno-inline with GCC or Clang, this will automatically be defined.
+ */
+#  define XXH_NO_INLINE_HINTS 0
+
+/*!
+ * @def XXH_REROLL
+ * @brief Whether to reroll `XXH32_finalize` and `XXH64_finalize`.
+ *
+ * For performance, `XXH32_finalize` and `XXH64_finalize` use an unrolled loop
+ * in the form of a switch statement.
+ *
+ * This is not always desirable, as it generates larger code, and depending on
+ * the architecture, may even be slower
+ *
+ * This is automatically defined with `-Os`/`-Oz` on GCC and Clang.
+ */
+#  define XXH_REROLL 0
+
+/*!
+ * @internal
+ * @brief Redefines old internal names.
+ *
+ * For compatibility with code that uses xxHash's internals before the names
+ * were changed to improve namespacing. There is no other reason to use this.
+ */
+#  define XXH_OLD_NAMES
+#  undef XXH_OLD_NAMES /* don't actually use, it is ugly. */
+#endif /* XXH_DOXYGEN */
+/*!
+ * @}
+ */
+
+#ifndef XXH_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */
+   /* prefer __packed__ structures (method 1) for gcc on armv7 and armv8 */
+#  if !defined(__clang__) && ( \
+    (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \
+    (defined(__GNUC__) && (defined(__ARM_ARCH) && __ARM_ARCH >= 7)) )
+#    define XXH_FORCE_MEMORY_ACCESS 1
+#  endif
+#endif
+
+#ifndef XXH_ACCEPT_NULL_INPUT_POINTER   /* can be defined externally */
+#  define XXH_ACCEPT_NULL_INPUT_POINTER 0
+#endif
+
+#ifndef XXH_FORCE_ALIGN_CHECK  /* can be defined externally */
+#  if defined(__i386)  || defined(__x86_64__) || defined(__aarch64__) \
+   || defined(_M_IX86) || defined(_M_X64)     || defined(_M_ARM64) /* visual */
+#    define XXH_FORCE_ALIGN_CHECK 0
+#  else
+#    define XXH_FORCE_ALIGN_CHECK 1
+#  endif
+#endif
+
+#ifndef XXH_NO_INLINE_HINTS
+#  if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \
+   || defined(__NO_INLINE__)     /* -O0, -fno-inline */
+#    define XXH_NO_INLINE_HINTS 1
+#  else
+#    define XXH_NO_INLINE_HINTS 0
+#  endif
+#endif
+
+#ifndef XXH_REROLL
+#  if defined(__OPTIMIZE_SIZE__)
+#    define XXH_REROLL 1
+#  else
+#    define XXH_REROLL 0
+#  endif
+#endif
+
+/*!
+ * @defgroup impl Implementation
+ * @{
+ */
+
+
+/* *************************************
+*  Includes & Memory related functions
+***************************************/
+/*
+ * Modify the local functions below should you wish to use
+ * different memory routines for malloc() and free()
+ */
+#include <stdlib.h>
+
+/*!
+ * @internal
+ * @brief Modify this function to use a different routine than malloc().
+ */
+static void* XXH_malloc(size_t s) { return malloc(s); }
+
+/*!
+ * @internal
+ * @brief Modify this function to use a different routine than free().
+ */
+static void XXH_free(void* p) { free(p); }
+
+#include <string.h>
+
+/*!
+ * @internal
+ * @brief Modify this function to use a different routine than memcpy().
+ */
+static void* XXH_memcpy(void* dest, const void* src, size_t size)
+{
+    return memcpy(dest,src,size);
+}
+
+#include <limits.h>   /* ULLONG_MAX */
+
+
+/* *************************************
+*  Compiler Specific Options
+***************************************/
+#ifdef _MSC_VER /* Visual Studio warning fix */
+#  pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+#endif
+
+#if XXH_NO_INLINE_HINTS  /* disable inlining hints */
+#  if defined(__GNUC__)
+#    define XXH_FORCE_INLINE static __attribute__((unused))
+#  else
+#    define XXH_FORCE_INLINE static
+#  endif
+#  define XXH_NO_INLINE static
+/* enable inlining hints */
+#elif defined(_MSC_VER)  /* Visual Studio */
+#  define XXH_FORCE_INLINE static __forceinline
+#  define XXH_NO_INLINE static __declspec(noinline)
+#elif defined(__GNUC__)
+#  define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused))
+#  define XXH_NO_INLINE static __attribute__((noinline))
+#elif defined (__cplusplus) \
+  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))   /* C99 */
+#  define XXH_FORCE_INLINE static inline
+#  define XXH_NO_INLINE static
+#else
+#  define XXH_FORCE_INLINE static
+#  define XXH_NO_INLINE static
+#endif
+
+
+
+/* *************************************
+*  Debug
+***************************************/
+/*!
+ * @ingroup tuning
+ * @def XXH_DEBUGLEVEL
+ * @brief Sets the debugging level.
+ *
+ * XXH_DEBUGLEVEL is expected to be defined externally, typically via the
+ * compiler's command line options. The value must be a number.
+ */
+#ifndef XXH_DEBUGLEVEL
+#  ifdef DEBUGLEVEL /* backwards compat */
+#    define XXH_DEBUGLEVEL DEBUGLEVEL
+#  else
+#    define XXH_DEBUGLEVEL 0
+#  endif
+#endif
+
+#if (XXH_DEBUGLEVEL>=1)
+#  include <assert.h>   /* note: can still be disabled with NDEBUG */
+#  define XXH_ASSERT(c)   assert(c)
+#else
+#  define XXH_ASSERT(c)   ((void)0)
+#endif
+
+/* note: use after variable declarations */
+#define XXH_STATIC_ASSERT(c)  do { enum { XXH_sa = 1/(int)(!!(c)) }; } while (0)
+
+
+/* *************************************
+*  Basic Types
+***************************************/
+#if !defined (__VMS) \
+ && (defined (__cplusplus) \
+ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include <stdint.h>
+  typedef uint8_t xxh_u8;
+#else
+  typedef unsigned char xxh_u8;
+#endif
+typedef XXH32_hash_t xxh_u32;
+
+#ifdef XXH_OLD_NAMES
+#  define BYTE xxh_u8
+#  define U8   xxh_u8
+#  define U32  xxh_u32
+#endif
+
+/* ***   Memory access   *** */
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_read32(const void* ptr)
+ * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness.
+ *
+ * Affected by @ref XXH_FORCE_MEMORY_ACCESS.
+ *
+ * @param ptr The pointer to read from.
+ * @return The 32-bit native endian integer from the bytes at @p ptr.
+ */
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_readLE32(const void* ptr)
+ * @brief Reads an unaligned 32-bit little endian integer from @p ptr.
+ *
+ * Affected by @ref XXH_FORCE_MEMORY_ACCESS.
+ *
+ * @param ptr The pointer to read from.
+ * @return The 32-bit little endian integer from the bytes at @p ptr.
+ */
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_readBE32(const void* ptr)
+ * @brief Reads an unaligned 32-bit big endian integer from @p ptr.
+ *
+ * Affected by @ref XXH_FORCE_MEMORY_ACCESS.
+ *
+ * @param ptr The pointer to read from.
+ * @return The 32-bit big endian integer from the bytes at @p ptr.
+ */
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align)
+ * @brief Like @ref XXH_readLE32(), but has an option for aligned reads.
+ *
+ * Affected by @ref XXH_FORCE_MEMORY_ACCESS.
+ * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is
+ * always @ref XXH_alignment::XXH_unaligned.
+ *
+ * @param ptr The pointer to read from.
+ * @param align Whether @p ptr is aligned.
+ * @pre
+ *   If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte
+ *   aligned.
+ * @return The 32-bit little endian integer from the bytes at @p ptr.
+ */
+
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))
+/*
+ * Manual byteshift. Best for old compilers which don't inline memcpy.
+ * We actually directly use XXH_readLE32 and XXH_readBE32.
+ */
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
+
+/*
+ * Force direct memory access. Only works on CPU which support unaligned memory
+ * access in hardware.
+ */
+static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; }
+
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
+
+/*
+ * __pack instructions are safer but compiler specific, hence potentially
+ * problematic for some compilers.
+ *
+ * Currently only defined for GCC and ICC.
+ */
+#ifdef XXH_OLD_NAMES
+typedef union { xxh_u32 u32; } __attribute__((packed)) unalign;
+#endif
+static xxh_u32 XXH_read32(const void* ptr)
+{
+    typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign;
+    return ((const xxh_unalign*)ptr)->u32;
+}
+
+#else
+
+/*
+ * Portable and safe solution. Generally efficient.
+ * see: https://stackoverflow.com/a/32095106/646947
+ */
+static xxh_u32 XXH_read32(const void* memPtr)
+{
+    xxh_u32 val;
+    memcpy(&val, memPtr, sizeof(val));
+    return val;
+}
+
+#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+
+/* ***   Endianness   *** */
+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
+
+/*!
+ * @ingroup tuning
+ * @def XXH_CPU_LITTLE_ENDIAN
+ * @brief Whether the target is little endian.
+ *
+ * Defined to 1 if the target is little endian, or 0 if it is big endian.
+ * It can be defined externally, for example on the compiler command line.
+ *
+ * If it is not defined, a runtime check (which is usually constant folded)
+ * is used instead.
+ *
+ * @note
+ *   This is not necessarily defined to an integer constant.
+ *
+ * @see XXH_isLittleEndian() for the runtime check.
+ */
+#ifndef XXH_CPU_LITTLE_ENDIAN
+/*
+ * Try to detect endianness automatically, to avoid the nonstandard behavior
+ * in `XXH_isLittleEndian()`
+ */
+#  if defined(_WIN32) /* Windows is always little endian */ \
+     || defined(__LITTLE_ENDIAN__) \
+     || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#    define XXH_CPU_LITTLE_ENDIAN 1
+#  elif defined(__BIG_ENDIAN__) \
+     || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#    define XXH_CPU_LITTLE_ENDIAN 0
+#  else
+/*!
+ * @internal
+ * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN.
+ *
+ * Most compilers will constant fold this.
+ */
+static int XXH_isLittleEndian(void)
+{
+    /*
+     * Portable and well-defined behavior.
+     * Don't use static: it is detrimental to performance.
+     */
+    const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 };
+    return one.c[0];
+}
+#   define XXH_CPU_LITTLE_ENDIAN   XXH_isLittleEndian()
+#  endif
+#endif
+
+
+
+
+/* ****************************************
+*  Compiler-specific Functions and Macros
+******************************************/
+#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+#ifdef __has_builtin
+#  define XXH_HAS_BUILTIN(x) __has_builtin(x)
+#else
+#  define XXH_HAS_BUILTIN(x) 0
+#endif
+
+/*!
+ * @internal
+ * @def XXH_rotl32(x,r)
+ * @brief 32-bit rotate left.
+ *
+ * @param x The 32-bit integer to be rotated.
+ * @param r The number of bits to rotate.
+ * @pre
+ *   @p r > 0 && @p r < 32
+ * @note
+ *   @p x and @p r may be evaluated multiple times.
+ * @return The rotated result.
+ */
+#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \
+                               && XXH_HAS_BUILTIN(__builtin_rotateleft64)
+#  define XXH_rotl32 __builtin_rotateleft32
+#  define XXH_rotl64 __builtin_rotateleft64
+/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */
+#elif defined(_MSC_VER)
+#  define XXH_rotl32(x,r) _rotl(x,r)
+#  define XXH_rotl64(x,r) _rotl64(x,r)
+#else
+#  define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#  define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r))))
+#endif
+
+/*!
+ * @internal
+ * @fn xxh_u32 XXH_swap32(xxh_u32 x)
+ * @brief A 32-bit byteswap.
+ *
+ * @param x The 32-bit integer to byteswap.
+ * @return @p x, byteswapped.
+ */
+#if defined(_MSC_VER)     /* Visual Studio */
+#  define XXH_swap32 _byteswap_ulong
+#elif XXH_GCC_VERSION >= 403
+#  define XXH_swap32 __builtin_bswap32
+#else
+static xxh_u32 XXH_swap32 (xxh_u32 x)
+{
+    return  ((x << 24) & 0xff000000 ) |
+            ((x <<  8) & 0x00ff0000 ) |
+            ((x >>  8) & 0x0000ff00 ) |
+            ((x >> 24) & 0x000000ff );
+}
+#endif
+
+
+/* ***************************
+*  Memory reads
+*****************************/
+
+/*!
+ * @internal
+ * @brief Enum to indicate whether a pointer is aligned.
+ */
+typedef enum {
+    XXH_aligned,  /*!< Aligned */
+    XXH_unaligned /*!< Possibly unaligned */
+} XXH_alignment;
+
+/*
+ * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load.
+ *
+ * This is ideal for older compilers which don't inline memcpy.
+ */
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))
+
+XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr)
+{
+    const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;
+    return bytePtr[0]
+         | ((xxh_u32)bytePtr[1] << 8)
+         | ((xxh_u32)bytePtr[2] << 16)
+         | ((xxh_u32)bytePtr[3] << 24);
+}
+
+XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr)
+{
+    const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;
+    return bytePtr[3]
+         | ((xxh_u32)bytePtr[2] << 8)
+         | ((xxh_u32)bytePtr[1] << 16)
+         | ((xxh_u32)bytePtr[0] << 24);
+}
+
+#else
+XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr)
+{
+    return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
+}
+
+static xxh_u32 XXH_readBE32(const void* ptr)
+{
+    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
+}
+#endif
+
+XXH_FORCE_INLINE xxh_u32
+XXH_readLE32_align(const void* ptr, XXH_alignment align)
+{
+    if (align==XXH_unaligned) {
+        return XXH_readLE32(ptr);
+    } else {
+        return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr);
+    }
+}
+
+
+/* *************************************
+*  Misc
+***************************************/
+/*! @ingroup public */
+XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
+
+
+/* *******************************************************************
+*  32-bit hash functions
+*********************************************************************/
+/*!
+ * @}
+ * @defgroup xxh32_impl XXH32 implementation
+ * @ingroup impl
+ * @{
+ */
+static const xxh_u32 XXH_PRIME32_1 = 0x9E3779B1U;   /*!< 0b10011110001101110111100110110001 */
+static const xxh_u32 XXH_PRIME32_2 = 0x85EBCA77U;   /*!< 0b10000101111010111100101001110111 */
+static const xxh_u32 XXH_PRIME32_3 = 0xC2B2AE3DU;   /*!< 0b11000010101100101010111000111101 */
+static const xxh_u32 XXH_PRIME32_4 = 0x27D4EB2FU;   /*!< 0b00100111110101001110101100101111 */
+static const xxh_u32 XXH_PRIME32_5 = 0x165667B1U;   /*!< 0b00010110010101100110011110110001 */
+
+#ifdef XXH_OLD_NAMES
+#  define PRIME32_1 XXH_PRIME32_1
+#  define PRIME32_2 XXH_PRIME32_2
+#  define PRIME32_3 XXH_PRIME32_3
+#  define PRIME32_4 XXH_PRIME32_4
+#  define PRIME32_5 XXH_PRIME32_5
+#endif
+
+/*!
+ * @internal
+ * @brief Normal stripe processing routine.
+ *
+ * This shuffles the bits so that any bit from @p input impacts several bits in
+ * @p acc.
+ *
+ * @param acc The accumulator lane.
+ * @param input The stripe of input to mix.
+ * @return The mixed accumulator lane.
+ */
+static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input)
+{
+    acc += input * XXH_PRIME32_2;
+    acc  = XXH_rotl32(acc, 13);
+    acc *= XXH_PRIME32_1;
+#if defined(__GNUC__) && defined(__SSE4_1__) && !defined(XXH_ENABLE_AUTOVECTORIZE)
+    /*
+     * UGLY HACK:
+     * This inline assembly hack forces acc into a normal register. This is the
+     * only thing that prevents GCC and Clang from autovectorizing the XXH32
+     * loop (pragmas and attributes don't work for some reason) without globally
+     * disabling SSE4.1.
+     *
+     * The reason we want to avoid vectorization is because despite working on
+     * 4 integers at a time, there are multiple factors slowing XXH32 down on
+     * SSE4:
+     * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on
+     *   newer chips!) making it slightly slower to multiply four integers at
+     *   once compared to four integers independently. Even when pmulld was
+     *   fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE
+     *   just to multiply unless doing a long operation.
+     *
+     * - Four instructions are required to rotate,
+     *      movqda tmp,  v // not required with VEX encoding
+     *      pslld  tmp, 13 // tmp <<= 13
+     *      psrld  v,   19 // x >>= 19
+     *      por    v,  tmp // x |= tmp
+     *   compared to one for scalar:
+     *      roll   v, 13    // reliably fast across the board
+     *      shldl  v, v, 13 // Sandy Bridge and later prefer this for some reason
+     *
+     * - Instruction level parallelism is actually more beneficial here because
+     *   the SIMD actually serializes this operation: While v1 is rotating, v2
+     *   can load data, while v3 can multiply. SSE forces them to operate
+     *   together.
+     *
+     * How this hack works:
+     * __asm__(""       // Declare an assembly block but don't declare any instructions
+     *          :       // However, as an Input/Output Operand,
+     *          "+r"    // constrain a read/write operand (+) as a general purpose register (r).
+     *          (acc)   // and set acc as the operand
+     * );
+     *
+     * Because of the 'r', the compiler has promised that seed will be in a
+     * general purpose register and the '+' says that it will be 'read/write',
+     * so it has to assume it has changed. It is like volatile without all the
+     * loads and stores.
+     *
+     * Since the argument has to be in a normal register (not an SSE register),
+     * each time XXH32_round is called, it is impossible to vectorize.
+     */
+    __asm__("" : "+r" (acc));
+#endif
+    return acc;
+}
+
+/*!
+ * @internal
+ * @brief Mixes all bits to finalize the hash.
+ *
+ * The final mix ensures that all input bits have a chance to impact any bit in
+ * the output digest, resulting in an unbiased distribution.
+ *
+ * @param h32 The hash to avalanche.
+ * @return The avalanched hash.
+ */
+static xxh_u32 XXH32_avalanche(xxh_u32 h32)
+{
+    h32 ^= h32 >> 15;
+    h32 *= XXH_PRIME32_2;
+    h32 ^= h32 >> 13;
+    h32 *= XXH_PRIME32_3;
+    h32 ^= h32 >> 16;
+    return(h32);
+}
+
+#define XXH_get32bits(p) XXH_readLE32_align(p, align)
+
+/*!
+ * @internal
+ * @brief Processes the last 0-15 bytes of @p ptr.
+ *
+ * There may be up to 15 bytes remaining to consume from the input.
+ * This final stage will digest them to ensure that all input bytes are present
+ * in the final mix.
+ *
+ * @param h32 The hash to finalize.
+ * @param ptr The pointer to the remaining input.
+ * @param len The remaining length, modulo 16.
+ * @param align Whether @p ptr is aligned.
+ * @return The finalized hash.
+ */
+static xxh_u32
+XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align)
+{
+#define XXH_PROCESS1 do {                           \
+    h32 += (*ptr++) * XXH_PRIME32_5;                \
+    h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1;      \
+} while (0)
+
+#define XXH_PROCESS4 do {                           \
+    h32 += XXH_get32bits(ptr) * XXH_PRIME32_3;      \
+    ptr += 4;                                   \
+    h32  = XXH_rotl32(h32, 17) * XXH_PRIME32_4;     \
+} while (0)
+
+    /* Compact rerolled version */
+    if (XXH_REROLL) {
+        len &= 15;
+        while (len >= 4) {
+            XXH_PROCESS4;
+            len -= 4;
+        }
+        while (len > 0) {
+            XXH_PROCESS1;
+            --len;
+        }
+        return XXH32_avalanche(h32);
+    } else {
+         switch(len&15) /* or switch(bEnd - p) */ {
+           case 12:      XXH_PROCESS4;
+                         /* fallthrough */
+           case 8:       XXH_PROCESS4;
+                         /* fallthrough */
+           case 4:       XXH_PROCESS4;
+                         return XXH32_avalanche(h32);
+
+           case 13:      XXH_PROCESS4;
+                         /* fallthrough */
+           case 9:       XXH_PROCESS4;
+                         /* fallthrough */
+           case 5:       XXH_PROCESS4;
+                         XXH_PROCESS1;
+                         return XXH32_avalanche(h32);
+
+           case 14:      XXH_PROCESS4;
+                         /* fallthrough */
+           case 10:      XXH_PROCESS4;
+                         /* fallthrough */
+           case 6:       XXH_PROCESS4;
+                         XXH_PROCESS1;
+                         XXH_PROCESS1;
+                         return XXH32_avalanche(h32);
+
+           case 15:      XXH_PROCESS4;
+                         /* fallthrough */
+           case 11:      XXH_PROCESS4;
+                         /* fallthrough */
+           case 7:       XXH_PROCESS4;
+                         /* fallthrough */
+           case 3:       XXH_PROCESS1;
+                         /* fallthrough */
+           case 2:       XXH_PROCESS1;
+                         /* fallthrough */
+           case 1:       XXH_PROCESS1;
+                         /* fallthrough */
+           case 0:       return XXH32_avalanche(h32);
+        }
+        XXH_ASSERT(0);
+        return h32;   /* reaching this point is deemed impossible */
+    }
+}
+
+#ifdef XXH_OLD_NAMES
+#  define PROCESS1 XXH_PROCESS1
+#  define PROCESS4 XXH_PROCESS4
+#else
+#  undef XXH_PROCESS1
+#  undef XXH_PROCESS4
+#endif
+
+/*!
+ * @internal
+ * @brief The implementation for @ref XXH32().
+ *
+ * @param input, len, seed Directly passed from @ref XXH32().
+ * @param align Whether @p input is aligned.
+ * @return The calculated hash.
+ */
+XXH_FORCE_INLINE xxh_u32
+XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align)
+{
+    const xxh_u8* bEnd = input + len;
+    xxh_u32 h32;
+
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+    if (input==NULL) {
+        len=0;
+        bEnd=input=(const xxh_u8*)(size_t)16;
+    }
+#endif
+
+    if (len>=16) {
+        const xxh_u8* const limit = bEnd - 15;
+        xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
+        xxh_u32 v2 = seed + XXH_PRIME32_2;
+        xxh_u32 v3 = seed + 0;
+        xxh_u32 v4 = seed - XXH_PRIME32_1;
+
+        do {
+            v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4;
+            v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4;
+            v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4;
+            v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4;
+        } while (input < limit);
+
+        h32 = XXH_rotl32(v1, 1)  + XXH_rotl32(v2, 7)
+            + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
+    } else {
+        h32  = seed + XXH_PRIME32_5;
+    }
+
+    h32 += (xxh_u32)len;
+
+    return XXH32_finalize(h32, input, len&15, align);
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed)
+{
+#if 0
+    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+    XXH32_state_t state;
+    XXH32_reset(&state, seed);
+    XXH32_update(&state, (const xxh_u8*)input, len);
+    return XXH32_digest(&state);
+#else
+    if (XXH_FORCE_ALIGN_CHECK) {
+        if ((((size_t)input) & 3) == 0) {   /* Input is 4-bytes aligned, leverage the speed benefit */
+            return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned);
+    }   }
+
+    return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned);
+#endif
+}
+
+
+
+/*******   Hash streaming   *******/
+/*!
+ * @ingroup xxh32_family
+ */
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
+{
+    return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
+}
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
+{
+    XXH_free(statePtr);
+    return XXH_OK;
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
+{
+    memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed)
+{
+    XXH32_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+    memset(&state, 0, sizeof(state));
+    state.v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
+    state.v2 = seed + XXH_PRIME32_2;
+    state.v3 = seed + 0;
+    state.v4 = seed - XXH_PRIME32_1;
+    /* do not write into reserved, planned to be removed in a future version */
+    memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
+    return XXH_OK;
+}
+
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH32_update(XXH32_state_t* state, const void* input, size_t len)
+{
+    if (input==NULL)
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+        return XXH_OK;
+#else
+        return XXH_ERROR;
+#endif
+
+    {   const xxh_u8* p = (const xxh_u8*)input;
+        const xxh_u8* const bEnd = p + len;
+
+        state->total_len_32 += (XXH32_hash_t)len;
+        state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16));
+
+        if (state->memsize + len < 16)  {   /* fill in tmp buffer */
+            XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len);
+            state->memsize += (XXH32_hash_t)len;
+            return XXH_OK;
+        }
+
+        if (state->memsize) {   /* some data left from previous update */
+            XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize);
+            {   const xxh_u32* p32 = state->mem32;
+                state->v1 = XXH32_round(state->v1, XXH_readLE32(p32)); p32++;
+                state->v2 = XXH32_round(state->v2, XXH_readLE32(p32)); p32++;
+                state->v3 = XXH32_round(state->v3, XXH_readLE32(p32)); p32++;
+                state->v4 = XXH32_round(state->v4, XXH_readLE32(p32));
+            }
+            p += 16-state->memsize;
+            state->memsize = 0;
+        }
+
+        if (p <= bEnd-16) {
+            const xxh_u8* const limit = bEnd - 16;
+            xxh_u32 v1 = state->v1;
+            xxh_u32 v2 = state->v2;
+            xxh_u32 v3 = state->v3;
+            xxh_u32 v4 = state->v4;
+
+            do {
+                v1 = XXH32_round(v1, XXH_readLE32(p)); p+=4;
+                v2 = XXH32_round(v2, XXH_readLE32(p)); p+=4;
+                v3 = XXH32_round(v3, XXH_readLE32(p)); p+=4;
+                v4 = XXH32_round(v4, XXH_readLE32(p)); p+=4;
+            } while (p<=limit);
+
+            state->v1 = v1;
+            state->v2 = v2;
+            state->v3 = v3;
+            state->v4 = v4;
+        }
+
+        if (p < bEnd) {
+            XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
+            state->memsize = (unsigned)(bEnd-p);
+        }
+    }
+
+    return XXH_OK;
+}
+
+
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state)
+{
+    xxh_u32 h32;
+
+    if (state->large_len) {
+        h32 = XXH_rotl32(state->v1, 1)
+            + XXH_rotl32(state->v2, 7)
+            + XXH_rotl32(state->v3, 12)
+            + XXH_rotl32(state->v4, 18);
+    } else {
+        h32 = state->v3 /* == seed */ + XXH_PRIME32_5;
+    }
+
+    h32 += state->total_len_32;
+
+    return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned);
+}
+
+
+/*******   Canonical representation   *******/
+
+/*!
+ * @ingroup xxh32_family
+ * The default return values from XXH functions are unsigned 32 and 64 bit
+ * integers.
+ *
+ * The canonical representation uses big endian convention, the same convention
+ * as human-readable numbers (large digits first).
+ *
+ * This way, hash values can be written into a file or buffer, remaining
+ * comparable across different systems.
+ *
+ * The following functions allow transformation of hash values to and from their
+ * canonical format.
+ */
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
+{
+    XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
+    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
+    memcpy(dst, &hash, sizeof(*dst));
+}
+/*! @ingroup xxh32_family */
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
+{
+    return XXH_readBE32(src);
+}
+
+
+#ifndef XXH_NO_LONG_LONG
+
+/* *******************************************************************
+*  64-bit hash functions
+*********************************************************************/
+/*!
+ * @}
+ * @ingroup impl
+ * @{
+ */
+/*******   Memory access   *******/
+
+typedef XXH64_hash_t xxh_u64;
+
+#ifdef XXH_OLD_NAMES
+#  define U64 xxh_u64
+#endif
+
+/*!
+ * XXH_REROLL_XXH64:
+ * Whether to reroll the XXH64_finalize() loop.
+ *
+ * Just like XXH32, we can unroll the XXH64_finalize() loop. This can be a
+ * performance gain on 64-bit hosts, as only one jump is required.
+ *
+ * However, on 32-bit hosts, because arithmetic needs to be done with two 32-bit
+ * registers, and 64-bit arithmetic needs to be simulated, it isn't beneficial
+ * to unroll. The code becomes ridiculously large (the largest function in the
+ * binary on i386!), and rerolling it saves anywhere from 3kB to 20kB. It is
+ * also slightly faster because it fits into cache better and is more likely
+ * to be inlined by the compiler.
+ *
+ * If XXH_REROLL is defined, this is ignored and the loop is always rerolled.
+ */
+#ifndef XXH_REROLL_XXH64
+#  if (defined(__ILP32__) || defined(_ILP32)) /* ILP32 is often defined on 32-bit GCC family */ \
+   || !(defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) /* x86-64 */ \
+     || defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__) /* aarch64 */ \
+     || defined(__PPC64__) || defined(__PPC64LE__) || defined(__ppc64__) || defined(__powerpc64__) /* ppc64 */ \
+     || defined(__mips64__) || defined(__mips64)) /* mips64 */ \
+   || (!defined(SIZE_MAX) || SIZE_MAX < ULLONG_MAX) /* check limits */
+#    define XXH_REROLL_XXH64 1
+#  else
+#    define XXH_REROLL_XXH64 0
+#  endif
+#endif /* !defined(XXH_REROLL_XXH64) */
+
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))
+/*
+ * Manual byteshift. Best for old compilers which don't inline memcpy.
+ * We actually directly use XXH_readLE64 and XXH_readBE64.
+ */
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
+
+/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
+static xxh_u64 XXH_read64(const void* memPtr)
+{
+    return *(const xxh_u64*) memPtr;
+}
+
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
+
+/*
+ * __pack instructions are safer, but compiler specific, hence potentially
+ * problematic for some compilers.
+ *
+ * Currently only defined for GCC and ICC.
+ */
+#ifdef XXH_OLD_NAMES
+typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64;
+#endif
+static xxh_u64 XXH_read64(const void* ptr)
+{
+    typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64;
+    return ((const xxh_unalign64*)ptr)->u64;
+}
+
+#else
+
+/*
+ * Portable and safe solution. Generally efficient.
+ * see: https://stackoverflow.com/a/32095106/646947
+ */
+static xxh_u64 XXH_read64(const void* memPtr)
+{
+    xxh_u64 val;
+    memcpy(&val, memPtr, sizeof(val));
+    return val;
+}
+
+#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+#if defined(_MSC_VER)     /* Visual Studio */
+#  define XXH_swap64 _byteswap_uint64
+#elif XXH_GCC_VERSION >= 403
+#  define XXH_swap64 __builtin_bswap64
+#else
+static xxh_u64 XXH_swap64(xxh_u64 x)
+{
+    return  ((x << 56) & 0xff00000000000000ULL) |
+            ((x << 40) & 0x00ff000000000000ULL) |
+            ((x << 24) & 0x0000ff0000000000ULL) |
+            ((x << 8)  & 0x000000ff00000000ULL) |
+            ((x >> 8)  & 0x00000000ff000000ULL) |
+            ((x >> 24) & 0x0000000000ff0000ULL) |
+            ((x >> 40) & 0x000000000000ff00ULL) |
+            ((x >> 56) & 0x00000000000000ffULL);
+}
+#endif
+
+
+/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))
+
+XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr)
+{
+    const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;
+    return bytePtr[0]
+         | ((xxh_u64)bytePtr[1] << 8)
+         | ((xxh_u64)bytePtr[2] << 16)
+         | ((xxh_u64)bytePtr[3] << 24)
+         | ((xxh_u64)bytePtr[4] << 32)
+         | ((xxh_u64)bytePtr[5] << 40)
+         | ((xxh_u64)bytePtr[6] << 48)
+         | ((xxh_u64)bytePtr[7] << 56);
+}
+
+XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr)
+{
+    const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;
+    return bytePtr[7]
+         | ((xxh_u64)bytePtr[6] << 8)
+         | ((xxh_u64)bytePtr[5] << 16)
+         | ((xxh_u64)bytePtr[4] << 24)
+         | ((xxh_u64)bytePtr[3] << 32)
+         | ((xxh_u64)bytePtr[2] << 40)
+         | ((xxh_u64)bytePtr[1] << 48)
+         | ((xxh_u64)bytePtr[0] << 56);
+}
+
+#else
+XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr)
+{
+    return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
+}
+
+static xxh_u64 XXH_readBE64(const void* ptr)
+{
+    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
+}
+#endif
+
+XXH_FORCE_INLINE xxh_u64
+XXH_readLE64_align(const void* ptr, XXH_alignment align)
+{
+    if (align==XXH_unaligned)
+        return XXH_readLE64(ptr);
+    else
+        return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr);
+}
+
+
+/*******   xxh64   *******/
+/*!
+ * @}
+ * @defgroup xxh64_impl XXH64 implementation
+ * @ingroup impl
+ * @{
+ */
+static const xxh_u64 XXH_PRIME64_1 = 0x9E3779B185EBCA87ULL;   /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */
+static const xxh_u64 XXH_PRIME64_2 = 0xC2B2AE3D27D4EB4FULL;   /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */
+static const xxh_u64 XXH_PRIME64_3 = 0x165667B19E3779F9ULL;   /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */
+static const xxh_u64 XXH_PRIME64_4 = 0x85EBCA77C2B2AE63ULL;   /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */
+static const xxh_u64 XXH_PRIME64_5 = 0x27D4EB2F165667C5ULL;   /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */
+
+#ifdef XXH_OLD_NAMES
+#  define PRIME64_1 XXH_PRIME64_1
+#  define PRIME64_2 XXH_PRIME64_2
+#  define PRIME64_3 XXH_PRIME64_3
+#  define PRIME64_4 XXH_PRIME64_4
+#  define PRIME64_5 XXH_PRIME64_5
+#endif
+
+static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input)
+{
+    acc += input * XXH_PRIME64_2;
+    acc  = XXH_rotl64(acc, 31);
+    acc *= XXH_PRIME64_1;
+    return acc;
+}
+
+static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val)
+{
+    val  = XXH64_round(0, val);
+    acc ^= val;
+    acc  = acc * XXH_PRIME64_1 + XXH_PRIME64_4;
+    return acc;
+}
+
+static xxh_u64 XXH64_avalanche(xxh_u64 h64)
+{
+    h64 ^= h64 >> 33;
+    h64 *= XXH_PRIME64_2;
+    h64 ^= h64 >> 29;
+    h64 *= XXH_PRIME64_3;
+    h64 ^= h64 >> 32;
+    return h64;
+}
+
+
+#define XXH_get64bits(p) XXH_readLE64_align(p, align)
+
+static xxh_u64
+XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align)
+{
+#define XXH_PROCESS1_64 do {                                   \
+    h64 ^= (*ptr++) * XXH_PRIME64_5;                           \
+    h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;                 \
+} while (0)
+
+#define XXH_PROCESS4_64 do {                                   \
+    h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1;      \
+    ptr += 4;                                              \
+    h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;     \
+} while (0)
+
+#define XXH_PROCESS8_64 do {                                   \
+    xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); \
+    ptr += 8;                                              \
+    h64 ^= k1;                                             \
+    h64  = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;     \
+} while (0)
+
+    /* Rerolled version for 32-bit targets is faster and much smaller. */
+    if (XXH_REROLL || XXH_REROLL_XXH64) {
+        len &= 31;
+        while (len >= 8) {
+            XXH_PROCESS8_64;
+            len -= 8;
+        }
+        if (len >= 4) {
+            XXH_PROCESS4_64;
+            len -= 4;
+        }
+        while (len > 0) {
+            XXH_PROCESS1_64;
+            --len;
+        }
+         return  XXH64_avalanche(h64);
+    } else {
+        switch(len & 31) {
+           case 24: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 16: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case  8: XXH_PROCESS8_64;
+                    return XXH64_avalanche(h64);
+
+           case 28: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 20: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 12: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case  4: XXH_PROCESS4_64;
+                    return XXH64_avalanche(h64);
+
+           case 25: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 17: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case  9: XXH_PROCESS8_64;
+                    XXH_PROCESS1_64;
+                    return XXH64_avalanche(h64);
+
+           case 29: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 21: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 13: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case  5: XXH_PROCESS4_64;
+                    XXH_PROCESS1_64;
+                    return XXH64_avalanche(h64);
+
+           case 26: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 18: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 10: XXH_PROCESS8_64;
+                    XXH_PROCESS1_64;
+                    XXH_PROCESS1_64;
+                    return XXH64_avalanche(h64);
+
+           case 30: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 22: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 14: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case  6: XXH_PROCESS4_64;
+                    XXH_PROCESS1_64;
+                    XXH_PROCESS1_64;
+                    return XXH64_avalanche(h64);
+
+           case 27: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 19: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 11: XXH_PROCESS8_64;
+                    XXH_PROCESS1_64;
+                    XXH_PROCESS1_64;
+                    XXH_PROCESS1_64;
+                    return XXH64_avalanche(h64);
+
+           case 31: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 23: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case 15: XXH_PROCESS8_64;
+                         /* fallthrough */
+           case  7: XXH_PROCESS4_64;
+                         /* fallthrough */
+           case  3: XXH_PROCESS1_64;
+                         /* fallthrough */
+           case  2: XXH_PROCESS1_64;
+                         /* fallthrough */
+           case  1: XXH_PROCESS1_64;
+                         /* fallthrough */
+           case  0: return XXH64_avalanche(h64);
+        }
+    }
+    /* impossible to reach */
+    XXH_ASSERT(0);
+    return 0;  /* unreachable, but some compilers complain without it */
+}
+
+#ifdef XXH_OLD_NAMES
+#  define PROCESS1_64 XXH_PROCESS1_64
+#  define PROCESS4_64 XXH_PROCESS4_64
+#  define PROCESS8_64 XXH_PROCESS8_64
+#else
+#  undef XXH_PROCESS1_64
+#  undef XXH_PROCESS4_64
+#  undef XXH_PROCESS8_64
+#endif
+
+XXH_FORCE_INLINE xxh_u64
+XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align)
+{
+    const xxh_u8* bEnd = input + len;
+    xxh_u64 h64;
+
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+    if (input==NULL) {
+        len=0;
+        bEnd=input=(const xxh_u8*)(size_t)32;
+    }
+#endif
+
+    if (len>=32) {
+        const xxh_u8* const limit = bEnd - 32;
+        xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
+        xxh_u64 v2 = seed + XXH_PRIME64_2;
+        xxh_u64 v3 = seed + 0;
+        xxh_u64 v4 = seed - XXH_PRIME64_1;
+
+        do {
+            v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8;
+            v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8;
+            v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8;
+            v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8;
+        } while (input<=limit);
+
+        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+        h64 = XXH64_mergeRound(h64, v1);
+        h64 = XXH64_mergeRound(h64, v2);
+        h64 = XXH64_mergeRound(h64, v3);
+        h64 = XXH64_mergeRound(h64, v4);
+
+    } else {
+        h64  = seed + XXH_PRIME64_5;
+    }
+
+    h64 += (xxh_u64) len;
+
+    return XXH64_finalize(h64, input, len, align);
+}
+
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t len, XXH64_hash_t seed)
+{
+#if 0
+    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+    XXH64_state_t state;
+    XXH64_reset(&state, seed);
+    XXH64_update(&state, (const xxh_u8*)input, len);
+    return XXH64_digest(&state);
+#else
+    if (XXH_FORCE_ALIGN_CHECK) {
+        if ((((size_t)input) & 7)==0) {  /* Input is aligned, let's leverage the speed advantage */
+            return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned);
+    }   }
+
+    return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned);
+
+#endif
+}
+
+/*******   Hash Streaming   *******/
+
+/*! @ingroup xxh64_family*/
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
+{
+    return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
+}
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
+{
+    XXH_free(statePtr);
+    return XXH_OK;
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
+{
+    memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, XXH64_hash_t seed)
+{
+    XXH64_state_t state;   /* use a local state to memcpy() in order to avoid strict-aliasing warnings */
+    memset(&state, 0, sizeof(state));
+    state.v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
+    state.v2 = seed + XXH_PRIME64_2;
+    state.v3 = seed + 0;
+    state.v4 = seed - XXH_PRIME64_1;
+     /* do not write into reserved64, might be removed in a future version */
+    memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved64));
+    return XXH_OK;
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH64_update (XXH64_state_t* state, const void* input, size_t len)
+{
+    if (input==NULL)
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+        return XXH_OK;
+#else
+        return XXH_ERROR;
+#endif
+
+    {   const xxh_u8* p = (const xxh_u8*)input;
+        const xxh_u8* const bEnd = p + len;
+
+        state->total_len += len;
+
+        if (state->memsize + len < 32) {  /* fill in tmp buffer */
+            XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len);
+            state->memsize += (xxh_u32)len;
+            return XXH_OK;
+        }
+
+        if (state->memsize) {   /* tmp buffer is full */
+            XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize);
+            state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0));
+            state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1));
+            state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2));
+            state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3));
+            p += 32 - state->memsize;
+            state->memsize = 0;
+        }
+
+        if (p+32 <= bEnd) {
+            const xxh_u8* const limit = bEnd - 32;
+            xxh_u64 v1 = state->v1;
+            xxh_u64 v2 = state->v2;
+            xxh_u64 v3 = state->v3;
+            xxh_u64 v4 = state->v4;
+
+            do {
+                v1 = XXH64_round(v1, XXH_readLE64(p)); p+=8;
+                v2 = XXH64_round(v2, XXH_readLE64(p)); p+=8;
+                v3 = XXH64_round(v3, XXH_readLE64(p)); p+=8;
+                v4 = XXH64_round(v4, XXH_readLE64(p)); p+=8;
+            } while (p<=limit);
+
+            state->v1 = v1;
+            state->v2 = v2;
+            state->v3 = v3;
+            state->v4 = v4;
+        }
+
+        if (p < bEnd) {
+            XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
+            state->memsize = (unsigned)(bEnd-p);
+        }
+    }
+
+    return XXH_OK;
+}
+
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state)
+{
+    xxh_u64 h64;
+
+    if (state->total_len >= 32) {
+        xxh_u64 const v1 = state->v1;
+        xxh_u64 const v2 = state->v2;
+        xxh_u64 const v3 = state->v3;
+        xxh_u64 const v4 = state->v4;
+
+        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+        h64 = XXH64_mergeRound(h64, v1);
+        h64 = XXH64_mergeRound(h64, v2);
+        h64 = XXH64_mergeRound(h64, v3);
+        h64 = XXH64_mergeRound(h64, v4);
+    } else {
+        h64  = state->v3 /*seed*/ + XXH_PRIME64_5;
+    }
+
+    h64 += (xxh_u64) state->total_len;
+
+    return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned);
+}
+
+
+/******* Canonical representation   *******/
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
+{
+    XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
+    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
+    memcpy(dst, &hash, sizeof(*dst));
+}
+
+/*! @ingroup xxh64_family */
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
+{
+    return XXH_readBE64(src);
+}
+
+
+
+/* *********************************************************************
+*  XXH3
+*  New generation hash designed for speed on small keys and vectorization
+************************************************************************ */
+/*!
+ * @}
+ * @defgroup xxh3_impl XXH3 implementation
+ * @ingroup impl
+ * @{
+ */
+
+/* ===   Compiler specifics   === */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* >= C99 */
+#  define XXH_RESTRICT   restrict
+#else
+/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */
+#  define XXH_RESTRICT   /* disable */
+#endif
+
+#if (defined(__GNUC__) && (__GNUC__ >= 3))  \
+  || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \
+  || defined(__clang__)
+#    define XXH_likely(x) __builtin_expect(x, 1)
+#    define XXH_unlikely(x) __builtin_expect(x, 0)
+#else
+#    define XXH_likely(x) (x)
+#    define XXH_unlikely(x) (x)
+#endif
+
+#if defined(__GNUC__)
+#  if defined(__AVX2__)
+#    include <immintrin.h>
+#  elif defined(__SSE2__)
+#    include <emmintrin.h>
+#  elif defined(__ARM_NEON__) || defined(__ARM_NEON)
+#    define inline __inline__  /* circumvent a clang bug */
+#    include <arm_neon.h>
+#    undef inline
+#  endif
+#elif defined(_MSC_VER)
+#  include <intrin.h>
+#endif
+
+/*
+ * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while
+ * remaining a true 64-bit/128-bit hash function.
+ *
+ * This is done by prioritizing a subset of 64-bit operations that can be
+ * emulated without too many steps on the average 32-bit machine.
+ *
+ * For example, these two lines seem similar, and run equally fast on 64-bit:
+ *
+ *   xxh_u64 x;
+ *   x ^= (x >> 47); // good
+ *   x ^= (x >> 13); // bad
+ *
+ * However, to a 32-bit machine, there is a major difference.
+ *
+ * x ^= (x >> 47) looks like this:
+ *
+ *   x.lo ^= (x.hi >> (47 - 32));
+ *
+ * while x ^= (x >> 13) looks like this:
+ *
+ *   // note: funnel shifts are not usually cheap.
+ *   x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13));
+ *   x.hi ^= (x.hi >> 13);
+ *
+ * The first one is significantly faster than the second, simply because the
+ * shift is larger than 32. This means:
+ *  - All the bits we need are in the upper 32 bits, so we can ignore the lower
+ *    32 bits in the shift.
+ *  - The shift result will always fit in the lower 32 bits, and therefore,
+ *    we can ignore the upper 32 bits in the xor.
+ *
+ * Thanks to this optimization, XXH3 only requires these features to be efficient:
+ *
+ *  - Usable unaligned access
+ *  - A 32-bit or 64-bit ALU
+ *      - If 32-bit, a decent ADC instruction
+ *  - A 32 or 64-bit multiply with a 64-bit result
+ *  - For the 128-bit variant, a decent byteswap helps short inputs.
+ *
+ * The first two are already required by XXH32, and almost all 32-bit and 64-bit
+ * platforms which can run XXH32 can run XXH3 efficiently.
+ *
+ * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one
+ * notable exception.
+ *
+ * First of all, Thumb-1 lacks support for the UMULL instruction which
+ * performs the important long multiply. This means numerous __aeabi_lmul
+ * calls.
+ *
+ * Second of all, the 8 functional registers are just not enough.
+ * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need
+ * Lo registers, and this shuffling results in thousands more MOVs than A32.
+ *
+ * A32 and T32 don't have this limitation. They can access all 14 registers,
+ * do a 32->64 multiply with UMULL, and the flexible operand allowing free
+ * shifts is helpful, too.
+ *
+ * Therefore, we do a quick sanity check.
+ *
+ * If compiling Thumb-1 for a target which supports ARM instructions, we will
+ * emit a warning, as it is not a "sane" platform to compile for.
+ *
+ * Usually, if this happens, it is because of an accident and you probably need
+ * to specify -march, as you likely meant to compile for a newer architecture.
+ *
+ * Credit: large sections of the vectorial and asm source code paths
+ *         have been contributed by @easyaspi314
+ */
+#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM)
+#   warning "XXH3 is highly inefficient without ARM or Thumb-2."
+#endif
+
+/* ==========================================
+ * Vectorization detection
+ * ========================================== */
+
+#ifdef XXH_DOXYGEN
+/*!
+ * @ingroup tuning
+ * @brief Overrides the vectorization implementation chosen for XXH3.
+ *
+ * Can be defined to 0 to disable SIMD or any of the values mentioned in
+ * @ref XXH_VECTOR_TYPE.
+ *
+ * If this is not defined, it uses predefined macros to determine the best
+ * implementation.
+ */
+#  define XXH_VECTOR XXH_SCALAR
+/*!
+ * @ingroup tuning
+ * @brief Possible values for @ref XXH_VECTOR.
+ *
+ * Note that these are actually implemented as macros.
+ *
+ * If this is not defined, it is detected automatically.
+ * @ref XXH_X86DISPATCH overrides this.
+ */
+enum XXH_VECTOR_TYPE /* fake enum */ {
+    XXH_SCALAR = 0,  /*!< Portable scalar version */
+    XXH_SSE2   = 1,  /*!<
+                      * SSE2 for Pentium 4, Opteron, all x86_64.
+                      *
+                      * @note SSE2 is also guaranteed on Windows 10, macOS, and
+                      * Android x86.
+                      */
+    XXH_AVX2   = 2,  /*!< AVX2 for Haswell and Bulldozer */
+    XXH_AVX512 = 3,  /*!< AVX512 for Skylake and Icelake */
+    XXH_NEON   = 4,  /*!< NEON for most ARMv7-A and all AArch64 */
+    XXH_VSX    = 5,  /*!< VSX and ZVector for POWER8/z13 (64-bit) */
+};
+/*!
+ * @ingroup tuning
+ * @brief Selects the minimum alignment for XXH3's accumulators.
+ *
+ * When using SIMD, this should match the alignment reqired for said vector
+ * type, so, for example, 32 for AVX2.
+ *
+ * Default: Auto detected.
+ */
+#  define XXH_ACC_ALIGN 8
+#endif
+
+/* Actual definition */
+#ifndef XXH_DOXYGEN
+#  define XXH_SCALAR 0
+#  define XXH_SSE2   1
+#  define XXH_AVX2   2
+#  define XXH_AVX512 3
+#  define XXH_NEON   4
+#  define XXH_VSX    5
+#endif
+
+#ifndef XXH_VECTOR    /* can be defined on command line */
+#  if defined(__AVX512F__)
+#    define XXH_VECTOR XXH_AVX512
+#  elif defined(__AVX2__)
+#    define XXH_VECTOR XXH_AVX2
+#  elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2))
+#    define XXH_VECTOR XXH_SSE2
+#  elif defined(__GNUC__) /* msvc support maybe later */ \
+  && (defined(__ARM_NEON__) || defined(__ARM_NEON)) \
+  && (defined(__LITTLE_ENDIAN__) /* We only support little endian NEON */ \
+    || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+#    define XXH_VECTOR XXH_NEON
+#  elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \
+     || (defined(__s390x__) && defined(__VEC__)) \
+     && defined(__GNUC__) /* TODO: IBM XL */
+#    define XXH_VECTOR XXH_VSX
+#  else
+#    define XXH_VECTOR XXH_SCALAR
+#  endif
+#endif
+
+/*
+ * Controls the alignment of the accumulator,
+ * for compatibility with aligned vector loads, which are usually faster.
+ */
+#ifndef XXH_ACC_ALIGN
+#  if defined(XXH_X86DISPATCH)
+#     define XXH_ACC_ALIGN 64  /* for compatibility with avx512 */
+#  elif XXH_VECTOR == XXH_SCALAR  /* scalar */
+#     define XXH_ACC_ALIGN 8
+#  elif XXH_VECTOR == XXH_SSE2  /* sse2 */
+#     define XXH_ACC_ALIGN 16
+#  elif XXH_VECTOR == XXH_AVX2  /* avx2 */
+#     define XXH_ACC_ALIGN 32
+#  elif XXH_VECTOR == XXH_NEON  /* neon */
+#     define XXH_ACC_ALIGN 16
+#  elif XXH_VECTOR == XXH_VSX   /* vsx */
+#     define XXH_ACC_ALIGN 16
+#  elif XXH_VECTOR == XXH_AVX512  /* avx512 */
+#     define XXH_ACC_ALIGN 64
+#  endif
+#endif
+
+#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \
+    || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512
+#  define XXH_SEC_ALIGN XXH_ACC_ALIGN
+#else
+#  define XXH_SEC_ALIGN 8
+#endif
+
+/*
+ * UGLY HACK:
+ * GCC usually generates the best code with -O3 for xxHash.
+ *
+ * However, when targeting AVX2, it is overzealous in its unrolling resulting
+ * in code roughly 3/4 the speed of Clang.
+ *
+ * There are other issues, such as GCC splitting _mm256_loadu_si256 into
+ * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which
+ * only applies to Sandy and Ivy Bridge... which don't even support AVX2.
+ *
+ * That is why when compiling the AVX2 version, it is recommended to use either
+ *   -O2 -mavx2 -march=haswell
+ * or
+ *   -O2 -mavx2 -mno-avx256-split-unaligned-load
+ * for decent performance, or to use Clang instead.
+ *
+ * Fortunately, we can control the first one with a pragma that forces GCC into
+ * -O2, but the other one we can't control without "failed to inline always
+ * inline function due to target mismatch" warnings.
+ */
+#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
+  && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
+  && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */
+#  pragma GCC push_options
+#  pragma GCC optimize("-O2")
+#endif
+
+
+#if XXH_VECTOR == XXH_NEON
+/*
+ * NEON's setup for vmlal_u32 is a little more complicated than it is on
+ * SSE2, AVX2, and VSX.
+ *
+ * While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast.
+ *
+ * To do the same operation, the 128-bit 'Q' register needs to be split into
+ * two 64-bit 'D' registers, performing this operation::
+ *
+ *   [                a                 |                 b                ]
+ *            |              '---------. .--------'                |
+ *            |                         x                          |
+ *            |              .---------' '--------.                |
+ *   [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[    a >> 32     |     b >> 32    ]
+ *
+ * Due to significant changes in aarch64, the fastest method for aarch64 is
+ * completely different than the fastest method for ARMv7-A.
+ *
+ * ARMv7-A treats D registers as unions overlaying Q registers, so modifying
+ * D11 will modify the high half of Q5. This is similar to how modifying AH
+ * will only affect bits 8-15 of AX on x86.
+ *
+ * VZIP takes two registers, and puts even lanes in one register and odd lanes
+ * in the other.
+ *
+ * On ARMv7-A, this strangely modifies both parameters in place instead of
+ * taking the usual 3-operand form.
+ *
+ * Therefore, if we want to do this, we can simply use a D-form VZIP.32 on the
+ * lower and upper halves of the Q register to end up with the high and low
+ * halves where we want - all in one instruction.
+ *
+ *   vzip.32   d10, d11       @ d10 = { d10[0], d11[0] }; d11 = { d10[1], d11[1] }
+ *
+ * Unfortunately we need inline assembly for this: Instructions modifying two
+ * registers at once is not possible in GCC or Clang's IR, and they have to
+ * create a copy.
+ *
+ * aarch64 requires a different approach.
+ *
+ * In order to make it easier to write a decent compiler for aarch64, many
+ * quirks were removed, such as conditional execution.
+ *
+ * NEON was also affected by this.
+ *
+ * aarch64 cannot access the high bits of a Q-form register, and writes to a
+ * D-form register zero the high bits, similar to how writes to W-form scalar
+ * registers (or DWORD registers on x86_64) work.
+ *
+ * The formerly free vget_high intrinsics now require a vext (with a few
+ * exceptions)
+ *
+ * Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the equivalent
+ * of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to only modify one
+ * operand.
+ *
+ * The equivalent of the VZIP.32 on the lower and upper halves would be this
+ * mess:
+ *
+ *   ext     v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0], v0[1] }
+ *   zip1    v1.2s, v0.2s, v2.2s     // v1 = { v0[0], v2[0] }
+ *   zip2    v0.2s, v0.2s, v1.2s     // v0 = { v0[1], v2[1] }
+ *
+ * Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64 (SHRN):
+ *
+ *   shrn    v1.2s, v0.2d, #32  // v1 = (uint32x2_t)(v0 >> 32);
+ *   xtn     v0.2s, v0.2d       // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF);
+ *
+ * This is available on ARMv7-A, but is less efficient than a single VZIP.32.
+ */
+
+/*!
+ * Function-like macro:
+ * void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi)
+ * {
+ *     outLo = (uint32x2_t)(in & 0xFFFFFFFF);
+ *     outHi = (uint32x2_t)(in >> 32);
+ *     in = UNDEFINED;
+ * }
+ */
+# if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \
+   && defined(__GNUC__) \
+   && !defined(__aarch64__) && !defined(__arm64__)
+#  define XXH_SPLIT_IN_PLACE(in, outLo, outHi)                                              \
+    do {                                                                                    \
+      /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \
+      /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */     \
+      /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \
+      __asm__("vzip.32  %e0, %f0" : "+w" (in));                                             \
+      (outLo) = vget_low_u32 (vreinterpretq_u32_u64(in));                                   \
+      (outHi) = vget_high_u32(vreinterpretq_u32_u64(in));                                   \
+   } while (0)
+# else
+#  define XXH_SPLIT_IN_PLACE(in, outLo, outHi)                                            \
+    do {                                                                                  \
+      (outLo) = vmovn_u64    (in);                                                        \
+      (outHi) = vshrn_n_u64  ((in), 32);                                                  \
+    } while (0)
+# endif
+#endif  /* XXH_VECTOR == XXH_NEON */
+
+/*
+ * VSX and Z Vector helpers.
+ *
+ * This is very messy, and any pull requests to clean this up are welcome.
+ *
+ * There are a lot of problems with supporting VSX and s390x, due to
+ * inconsistent intrinsics, spotty coverage, and multiple endiannesses.
+ */
+#if XXH_VECTOR == XXH_VSX
+#  if defined(__s390x__)
+#    include <s390intrin.h>
+#  else
+/* gcc's altivec.h can have the unwanted consequence to unconditionally
+ * #define bool, vector, and pixel keywords,
+ * with bad consequences for programs already using these keywords for other purposes.
+ * The paragraph defining these macros is skipped when __APPLE_ALTIVEC__ is defined.
+ * __APPLE_ALTIVEC__ is _generally_ defined automatically by the compiler,
+ * but it seems that, in some cases, it isn't.
+ * Force the build macro to be defined, so that keywords are not altered.
+ */
+#    if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__)
+#      define __APPLE_ALTIVEC__
+#    endif
+#    include <altivec.h>
+#  endif
+
+typedef __vector unsigned long long xxh_u64x2;
+typedef __vector unsigned char xxh_u8x16;
+typedef __vector unsigned xxh_u32x4;
+
+# ifndef XXH_VSX_BE
+#  if defined(__BIG_ENDIAN__) \
+  || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#    define XXH_VSX_BE 1
+#  elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__
+#    warning "-maltivec=be is not recommended. Please use native endianness."
+#    define XXH_VSX_BE 1
+#  else
+#    define XXH_VSX_BE 0
+#  endif
+# endif /* !defined(XXH_VSX_BE) */
+
+# if XXH_VSX_BE
+#  if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__))
+#    define XXH_vec_revb vec_revb
+#  else
+/*!
+ * A polyfill for POWER9's vec_revb().
+ */
+XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val)
+{
+    xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+                                  0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 };
+    return vec_perm(val, val, vByteSwap);
+}
+#  endif
+# endif /* XXH_VSX_BE */
+
+/*!
+ * Performs an unaligned vector load and byte swaps it on big endian.
+ */
+XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr)
+{
+    xxh_u64x2 ret;
+    memcpy(&ret, ptr, sizeof(xxh_u64x2));
+# if XXH_VSX_BE
+    ret = XXH_vec_revb(ret);
+# endif
+    return ret;
+}
+
+/*
+ * vec_mulo and vec_mule are very problematic intrinsics on PowerPC
+ *
+ * These intrinsics weren't added until GCC 8, despite existing for a while,
+ * and they are endian dependent. Also, their meaning swap depending on version.
+ * */
+# if defined(__s390x__)
+ /* s390x is always big endian, no issue on this platform */
+#  define XXH_vec_mulo vec_mulo
+#  define XXH_vec_mule vec_mule
+# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw)
+/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */
+#  define XXH_vec_mulo __builtin_altivec_vmulouw
+#  define XXH_vec_mule __builtin_altivec_vmuleuw
+# else
+/* gcc needs inline assembly */
+/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */
+XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b)
+{
+    xxh_u64x2 result;
+    __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b));
+    return result;
+}
+XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b)
+{
+    xxh_u64x2 result;
+    __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b));
+    return result;
+}
+# endif /* XXH_vec_mulo, XXH_vec_mule */
+#endif /* XXH_VECTOR == XXH_VSX */
+
+
+/* prefetch
+ * can be disabled, by declaring XXH_NO_PREFETCH build macro */
+#if defined(XXH_NO_PREFETCH)
+#  define XXH_PREFETCH(ptr)  (void)(ptr)  /* disabled */
+#else
+#  if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))  /* _mm_prefetch() not defined outside of x86/x64 */
+#    include <mmintrin.h>   /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
+#    define XXH_PREFETCH(ptr)  _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
+#  elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
+#    define XXH_PREFETCH(ptr)  __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
+#  else
+#    define XXH_PREFETCH(ptr) (void)(ptr)  /* disabled */
+#  endif
+#endif  /* XXH_NO_PREFETCH */
+
+
+/* ==========================================
+ * XXH3 default settings
+ * ========================================== */
+
+#define XXH_SECRET_DEFAULT_SIZE 192   /* minimum XXH3_SECRET_SIZE_MIN */
+
+#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN)
+#  error "default keyset is not large enough"
+#endif
+
+/*! Pseudorandom secret taken directly from FARSH. */
+XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = {
+    0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
+    0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
+    0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
+    0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
+    0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
+    0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
+    0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
+    0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
+    0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
+    0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
+    0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
+    0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
+};
+
+
+#ifdef XXH_OLD_NAMES
+#  define kSecret XXH3_kSecret
+#endif
+
+#ifdef XXH_DOXYGEN
+/*!
+ * @brief Calculates a 32-bit to 64-bit long multiply.
+ *
+ * Implemented as a macro.
+ *
+ * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't
+ * need to (but it shouldn't need to anyways, it is about 7 instructions to do
+ * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we
+ * use that instead of the normal method.
+ *
+ * If you are compiling for platforms like Thumb-1 and don't have a better option,
+ * you may also want to write your own long multiply routine here.
+ *
+ * @param x, y Numbers to be multiplied
+ * @return 64-bit product of the low 32 bits of @p x and @p y.
+ */
+XXH_FORCE_INLINE xxh_u64
+XXH_mult32to64(xxh_u64 x, xxh_u64 y)
+{
+   return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF);
+}
+#elif defined(_MSC_VER) && defined(_M_IX86)
+#    include <intrin.h>
+#    define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y))
+#else
+/*
+ * Downcast + upcast is usually better than masking on older compilers like
+ * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers.
+ *
+ * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands
+ * and perform a full 64x64 multiply -- entirely redundant on 32-bit.
+ */
+#    define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y))
+#endif
+
+/*!
+ * @brief Calculates a 64->128-bit long multiply.
+ *
+ * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar
+ * version.
+ *
+ * @param lhs, rhs The 64-bit integers to be multiplied
+ * @return The 128-bit result represented in an @ref XXH128_hash_t.
+ */
+static XXH128_hash_t
+XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs)
+{
+    /*
+     * GCC/Clang __uint128_t method.
+     *
+     * On most 64-bit targets, GCC and Clang define a __uint128_t type.
+     * This is usually the best way as it usually uses a native long 64-bit
+     * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64.
+     *
+     * Usually.
+     *
+     * Despite being a 32-bit platform, Clang (and emscripten) define this type
+     * despite not having the arithmetic for it. This results in a laggy
+     * compiler builtin call which calculates a full 128-bit multiply.
+     * In that case it is best to use the portable one.
+     * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677
+     */
+#if defined(__GNUC__) && !defined(__wasm__) \
+    && defined(__SIZEOF_INT128__) \
+    || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)
+
+    __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs;
+    XXH128_hash_t r128;
+    r128.low64  = (xxh_u64)(product);
+    r128.high64 = (xxh_u64)(product >> 64);
+    return r128;
+
+    /*
+     * MSVC for x64's _umul128 method.
+     *
+     * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct);
+     *
+     * This compiles to single operand MUL on x64.
+     */
+#elif defined(_M_X64) || defined(_M_IA64)
+
+#ifndef _MSC_VER
+#   pragma intrinsic(_umul128)
+#endif
+    xxh_u64 product_high;
+    xxh_u64 const product_low = _umul128(lhs, rhs, &product_high);
+    XXH128_hash_t r128;
+    r128.low64  = product_low;
+    r128.high64 = product_high;
+    return r128;
+
+#else
+    /*
+     * Portable scalar method. Optimized for 32-bit and 64-bit ALUs.
+     *
+     * This is a fast and simple grade school multiply, which is shown below
+     * with base 10 arithmetic instead of base 0x100000000.
+     *
+     *           9 3 // D2 lhs = 93
+     *         x 7 5 // D2 rhs = 75
+     *     ----------
+     *           1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15
+     *         4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45
+     *         2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21
+     *     + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63
+     *     ---------
+     *         2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27
+     *     + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67
+     *     ---------
+     *       6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975
+     *
+     * The reasons for adding the products like this are:
+     *  1. It avoids manual carry tracking. Just like how
+     *     (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX.
+     *     This avoids a lot of complexity.
+     *
+     *  2. It hints for, and on Clang, compiles to, the powerful UMAAL
+     *     instruction available in ARM's Digital Signal Processing extension
+     *     in 32-bit ARMv6 and later, which is shown below:
+     *
+     *         void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm)
+     *         {
+     *             xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm;
+     *             *RdLo = (xxh_u32)(product & 0xFFFFFFFF);
+     *             *RdHi = (xxh_u32)(product >> 32);
+     *         }
+     *
+     *     This instruction was designed for efficient long multiplication, and
+     *     allows this to be calculated in only 4 instructions at speeds
+     *     comparable to some 64-bit ALUs.
+     *
+     *  3. It isn't terrible on other platforms. Usually this will be a couple
+     *     of 32-bit ADD/ADCs.
+     */
+
+    /* First calculate all of the cross products. */
+    xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF);
+    xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32,        rhs & 0xFFFFFFFF);
+    xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32);
+    xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32,        rhs >> 32);
+
+    /* Now add the products together. These will never overflow. */
+    xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;
+    xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32)        + hi_hi;
+    xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF);
+
+    XXH128_hash_t r128;
+    r128.low64  = lower;
+    r128.high64 = upper;
+    return r128;
+#endif
+}
+
+/*!
+ * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it.
+ *
+ * The reason for the separate function is to prevent passing too many structs
+ * around by value. This will hopefully inline the multiply, but we don't force it.
+ *
+ * @param lhs, rhs The 64-bit integers to multiply
+ * @return The low 64 bits of the product XOR'd by the high 64 bits.
+ * @see XXH_mult64to128()
+ */
+static xxh_u64
+XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs)
+{
+    XXH128_hash_t product = XXH_mult64to128(lhs, rhs);
+    return product.low64 ^ product.high64;
+}
+
+/*! Seems to produce slightly better code on GCC for some reason. */
+XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift)
+{
+    XXH_ASSERT(0 <= shift && shift < 64);
+    return v64 ^ (v64 >> shift);
+}
+
+/*
+ * This is a fast avalanche stage,
+ * suitable when input bits are already partially mixed
+ */
+static XXH64_hash_t XXH3_avalanche(xxh_u64 h64)
+{
+    h64 = XXH_xorshift64(h64, 37);
+    h64 *= 0x165667919E3779F9ULL;
+    h64 = XXH_xorshift64(h64, 32);
+    return h64;
+}
+
+/*
+ * This is a stronger avalanche,
+ * inspired by Pelle Evensen's rrmxmx
+ * preferable when input has not been previously mixed
+ */
+static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len)
+{
+    /* this mix is inspired by Pelle Evensen's rrmxmx */
+    h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24);
+    h64 *= 0x9FB21C651E98DF25ULL;
+    h64 ^= (h64 >> 35) + len ;
+    h64 *= 0x9FB21C651E98DF25ULL;
+    return XXH_xorshift64(h64, 28);
+}
+
+
+/* ==========================================
+ * Short keys
+ * ==========================================
+ * One of the shortcomings of XXH32 and XXH64 was that their performance was
+ * sub-optimal on short lengths. It used an iterative algorithm which strongly
+ * favored lengths that were a multiple of 4 or 8.
+ *
+ * Instead of iterating over individual inputs, we use a set of single shot
+ * functions which piece together a range of lengths and operate in constant time.
+ *
+ * Additionally, the number of multiplies has been significantly reduced. This
+ * reduces latency, especially when emulating 64-bit multiplies on 32-bit.
+ *
+ * Depending on the platform, this may or may not be faster than XXH32, but it
+ * is almost guaranteed to be faster than XXH64.
+ */
+
+/*
+ * At very short lengths, there isn't enough input to fully hide secrets, or use
+ * the entire secret.
+ *
+ * There is also only a limited amount of mixing we can do before significantly
+ * impacting performance.
+ *
+ * Therefore, we use different sections of the secret and always mix two secret
+ * samples with an XOR. This should have no effect on performance on the
+ * seedless or withSeed variants because everything _should_ be constant folded
+ * by modern compilers.
+ *
+ * The XOR mixing hides individual parts of the secret and increases entropy.
+ *
+ * This adds an extra layer of strength for custom secrets.
+ */
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
+{
+    XXH_ASSERT(input != NULL);
+    XXH_ASSERT(1 <= len && len <= 3);
+    XXH_ASSERT(secret != NULL);
+    /*
+     * len = 1: combined = { input[0], 0x01, input[0], input[0] }
+     * len = 2: combined = { input[1], 0x02, input[0], input[1] }
+     * len = 3: combined = { input[2], 0x03, input[0], input[1] }
+     */
+    {   xxh_u8  const c1 = input[0];
+        xxh_u8  const c2 = input[len >> 1];
+        xxh_u8  const c3 = input[len - 1];
+        xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2  << 24)
+                               | ((xxh_u32)c3 <<  0) | ((xxh_u32)len << 8);
+        xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed;
+        xxh_u64 const keyed = (xxh_u64)combined ^ bitflip;
+        return XXH64_avalanche(keyed);
+    }
+}
+
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
+{
+    XXH_ASSERT(input != NULL);
+    XXH_ASSERT(secret != NULL);
+    XXH_ASSERT(4 <= len && len < 8);
+    seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32;
+    {   xxh_u32 const input1 = XXH_readLE32(input);
+        xxh_u32 const input2 = XXH_readLE32(input + len - 4);
+        xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed;
+        xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32);
+        xxh_u64 const keyed = input64 ^ bitflip;
+        return XXH3_rrmxmx(keyed, len);
+    }
+}
+
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
+{
+    XXH_ASSERT(input != NULL);
+    XXH_ASSERT(secret != NULL);
+    XXH_ASSERT(8 <= len && len <= 16);
+    {   xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed;
+        xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed;
+        xxh_u64 const input_lo = XXH_readLE64(input)           ^ bitflip1;
+        xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2;
+        xxh_u64 const acc = len
+                          + XXH_swap64(input_lo) + input_hi
+                          + XXH3_mul128_fold64(input_lo, input_hi);
+        return XXH3_avalanche(acc);
+    }
+}
+
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
+{
+    XXH_ASSERT(len <= 16);
+    {   if (XXH_likely(len >  8)) return XXH3_len_9to16_64b(input, len, secret, seed);
+        if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed);
+        if (len) return XXH3_len_1to3_64b(input, len, secret, seed);
+        return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64)));
+    }
+}
+
+/*
+ * DISCLAIMER: There are known *seed-dependent* multicollisions here due to
+ * multiplication by zero, affecting hashes of lengths 17 to 240.
+ *
+ * However, they are very unlikely.
+ *
+ * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all
+ * unseeded non-cryptographic hashes, it does not attempt to defend itself
+ * against specially crafted inputs, only random inputs.
+ *
+ * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes
+ * cancelling out the secret is taken an arbitrary number of times (addressed
+ * in XXH3_accumulate_512), this collision is very unlikely with random inputs
+ * and/or proper seeding:
+ *
+ * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a
+ * function that is only called up to 16 times per hash with up to 240 bytes of
+ * input.
+ *
+ * This is not too bad for a non-cryptographic hash function, especially with
+ * only 64 bit outputs.
+ *
+ * The 128-bit variant (which trades some speed for strength) is NOT affected
+ * by this, although it is always a good idea to use a proper seed if you care
+ * about strength.
+ */
+XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input,
+                                     const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64)
+{
+#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
+  && defined(__i386__) && defined(__SSE2__)  /* x86 + SSE2 */ \
+  && !defined(XXH_ENABLE_AUTOVECTORIZE)      /* Define to disable like XXH32 hack */
+    /*
+     * UGLY HACK:
+     * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in
+     * slower code.
+     *
+     * By forcing seed64 into a register, we disrupt the cost model and
+     * cause it to scalarize. See `XXH32_round()`
+     *
+     * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600,
+     * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on
+     * GCC 9.2, despite both emitting scalar code.
+     *
+     * GCC generates much better scalar code than Clang for the rest of XXH3,
+     * which is why finding a more optimal codepath is an interest.
+     */
+    __asm__ ("" : "+r" (seed64));
+#endif
+    {   xxh_u64 const input_lo = XXH_readLE64(input);
+        xxh_u64 const input_hi = XXH_readLE64(input+8);
+        return XXH3_mul128_fold64(
+            input_lo ^ (XXH_readLE64(secret)   + seed64),
+            input_hi ^ (XXH_readLE64(secret+8) - seed64)
+        );
+    }
+}
+
+/* For mid range keys, XXH3 uses a Mum-hash variant. */
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
+                     const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
+                     XXH64_hash_t seed)
+{
+    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;
+    XXH_ASSERT(16 < len && len <= 128);
+
+    {   xxh_u64 acc = len * XXH_PRIME64_1;
+        if (len > 32) {
+            if (len > 64) {
+                if (len > 96) {
+                    acc += XXH3_mix16B(input+48, secret+96, seed);
+                    acc += XXH3_mix16B(input+len-64, secret+112, seed);
+                }
+                acc += XXH3_mix16B(input+32, secret+64, seed);
+                acc += XXH3_mix16B(input+len-48, secret+80, seed);
+            }
+            acc += XXH3_mix16B(input+16, secret+32, seed);
+            acc += XXH3_mix16B(input+len-32, secret+48, seed);
+        }
+        acc += XXH3_mix16B(input+0, secret+0, seed);
+        acc += XXH3_mix16B(input+len-16, secret+16, seed);
+
+        return XXH3_avalanche(acc);
+    }
+}
+
+#define XXH3_MIDSIZE_MAX 240
+
+XXH_NO_INLINE XXH64_hash_t
+XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
+                      const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
+                      XXH64_hash_t seed)
+{
+    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;
+    XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
+
+    #define XXH3_MIDSIZE_STARTOFFSET 3
+    #define XXH3_MIDSIZE_LASTOFFSET  17
+
+    {   xxh_u64 acc = len * XXH_PRIME64_1;
+        int const nbRounds = (int)len / 16;
+        int i;
+        for (i=0; i<8; i++) {
+            acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed);
+        }
+        acc = XXH3_avalanche(acc);
+        XXH_ASSERT(nbRounds >= 8);
+#if defined(__clang__)                                /* Clang */ \
+    && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \
+    && !defined(XXH_ENABLE_AUTOVECTORIZE)             /* Define to disable */
+        /*
+         * UGLY HACK:
+         * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86.
+         * In everywhere else, it uses scalar code.
+         *
+         * For 64->128-bit multiplies, even if the NEON was 100% optimal, it
+         * would still be slower than UMAAL (see XXH_mult64to128).
+         *
+         * Unfortunately, Clang doesn't handle the long multiplies properly and
+         * converts them to the nonexistent "vmulq_u64" intrinsic, which is then
+         * scalarized into an ugly mess of VMOV.32 instructions.
+         *
+         * This mess is difficult to avoid without turning autovectorization
+         * off completely, but they are usually relatively minor and/or not
+         * worth it to fix.
+         *
+         * This loop is the easiest to fix, as unlike XXH32, this pragma
+         * _actually works_ because it is a loop vectorization instead of an
+         * SLP vectorization.
+         */
+        #pragma clang loop vectorize(disable)
+#endif
+        for (i=8 ; i < nbRounds; i++) {
+            acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed);
+        }
+        /* last bytes */
+        acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);
+        return XXH3_avalanche(acc);
+    }
+}
+
+
+/* =======     Long Keys     ======= */
+
+#define XXH_STRIPE_LEN 64
+#define XXH_SECRET_CONSUME_RATE 8   /* nb of secret bytes consumed at each accumulation */
+#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64))
+
+#ifdef XXH_OLD_NAMES
+#  define STRIPE_LEN XXH_STRIPE_LEN
+#  define ACC_NB XXH_ACC_NB
+#endif
+
+XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64)
+{
+    if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64);
+    memcpy(dst, &v64, sizeof(v64));
+}
+
+/* Several intrinsic functions below are supposed to accept __int64 as argument,
+ * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ .
+ * However, several environments do not define __int64 type,
+ * requiring a workaround.
+ */
+#if !defined (__VMS) \
+  && (defined (__cplusplus) \
+  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+    typedef int64_t xxh_i64;
+#else
+    /* the following type must have a width of 64-bit */
+    typedef long long xxh_i64;
+#endif
+
+/*
+ * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized.
+ *
+ * It is a hardened version of UMAC, based off of FARSH's implementation.
+ *
+ * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD
+ * implementations, and it is ridiculously fast.
+ *
+ * We harden it by mixing the original input to the accumulators as well as the product.
+ *
+ * This means that in the (relatively likely) case of a multiply by zero, the
+ * original input is preserved.
+ *
+ * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve
+ * cross-pollination, as otherwise the upper and lower halves would be
+ * essentially independent.
+ *
+ * This doesn't matter on 64-bit hashes since they all get merged together in
+ * the end, so we skip the extra step.
+ *
+ * Both XXH3_64bits and XXH3_128bits use this subroutine.
+ */
+
+#if (XXH_VECTOR == XXH_AVX512) \
+     || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0)
+
+#ifndef XXH_TARGET_AVX512
+# define XXH_TARGET_AVX512  /* disable attribute target */
+#endif
+
+XXH_FORCE_INLINE XXH_TARGET_AVX512 void
+XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc,
+                     const void* XXH_RESTRICT input,
+                     const void* XXH_RESTRICT secret)
+{
+    XXH_ALIGN(64) __m512i* const xacc = (__m512i *) acc;
+    XXH_ASSERT((((size_t)acc) & 63) == 0);
+    XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i));
+
+    {
+        /* data_vec    = input[0]; */
+        __m512i const data_vec    = _mm512_loadu_si512   (input);
+        /* key_vec     = secret[0]; */
+        __m512i const key_vec     = _mm512_loadu_si512   (secret);
+        /* data_key    = data_vec ^ key_vec; */
+        __m512i const data_key    = _mm512_xor_si512     (data_vec, key_vec);
+        /* data_key_lo = data_key >> 32; */
+        __m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1));
+        /* product     = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
+        __m512i const product     = _mm512_mul_epu32     (data_key, data_key_lo);
+        /* xacc[0] += swap(data_vec); */
+        __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2));
+        __m512i const sum       = _mm512_add_epi64(*xacc, data_swap);
+        /* xacc[0] += product; */
+        *xacc = _mm512_add_epi64(product, sum);
+    }
+}
+
+/*
+ * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing.
+ *
+ * Multiplication isn't perfect, as explained by Google in HighwayHash:
+ *
+ *  // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to
+ *  // varying degrees. In descending order of goodness, bytes
+ *  // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32.
+ *  // As expected, the upper and lower bytes are much worse.
+ *
+ * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291
+ *
+ * Since our algorithm uses a pseudorandom secret to add some variance into the
+ * mix, we don't need to (or want to) mix as often or as much as HighwayHash does.
+ *
+ * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid
+ * extraction.
+ *
+ * Both XXH3_64bits and XXH3_128bits use this subroutine.
+ */
+
+XXH_FORCE_INLINE XXH_TARGET_AVX512 void
+XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
+{
+    XXH_ASSERT((((size_t)acc) & 63) == 0);
+    XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i));
+    {   XXH_ALIGN(64) __m512i* const xacc = (__m512i*) acc;
+        const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1);
+
+        /* xacc[0] ^= (xacc[0] >> 47) */
+        __m512i const acc_vec     = *xacc;
+        __m512i const shifted     = _mm512_srli_epi64    (acc_vec, 47);
+        __m512i const data_vec    = _mm512_xor_si512     (acc_vec, shifted);
+        /* xacc[0] ^= secret; */
+        __m512i const key_vec     = _mm512_loadu_si512   (secret);
+        __m512i const data_key    = _mm512_xor_si512     (data_vec, key_vec);
+
+        /* xacc[0] *= XXH_PRIME32_1; */
+        __m512i const data_key_hi = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1));
+        __m512i const prod_lo     = _mm512_mul_epu32     (data_key, prime32);
+        __m512i const prod_hi     = _mm512_mul_epu32     (data_key_hi, prime32);
+        *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32));
+    }
+}
+
+XXH_FORCE_INLINE XXH_TARGET_AVX512 void
+XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
+{
+    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0);
+    XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64);
+    XXH_ASSERT(((size_t)customSecret & 63) == 0);
+    (void)(&XXH_writeLE64);
+    {   int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i);
+        __m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, -(xxh_i64)seed64);
+
+        XXH_ALIGN(64) const __m512i* const src  = (const __m512i*) XXH3_kSecret;
+        XXH_ALIGN(64)       __m512i* const dest = (      __m512i*) customSecret;
+        int i;
+        for (i=0; i < nbRounds; ++i) {
+            /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*',
+             * this will warn "discards ‘const’ qualifier". */
+            union {
+                XXH_ALIGN(64) const __m512i* cp;
+                XXH_ALIGN(64) void* p;
+            } remote_const_void;
+            remote_const_void.cp = src + i;
+            dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed);
+    }   }
+}
+
+#endif
+
+#if (XXH_VECTOR == XXH_AVX2) \
+    || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0)
+
+#ifndef XXH_TARGET_AVX2
+# define XXH_TARGET_AVX2  /* disable attribute target */
+#endif
+
+XXH_FORCE_INLINE XXH_TARGET_AVX2 void
+XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc,
+                    const void* XXH_RESTRICT input,
+                    const void* XXH_RESTRICT secret)
+{
+    XXH_ASSERT((((size_t)acc) & 31) == 0);
+    {   XXH_ALIGN(32) __m256i* const xacc    =       (__m256i *) acc;
+        /* Unaligned. This is mainly for pointer arithmetic, and because
+         * _mm256_loadu_si256 requires  a const __m256i * pointer for some reason. */
+        const         __m256i* const xinput  = (const __m256i *) input;
+        /* Unaligned. This is mainly for pointer arithmetic, and because
+         * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */
+        const         __m256i* const xsecret = (const __m256i *) secret;
+
+        size_t i;
+        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) {
+            /* data_vec    = xinput[i]; */
+            __m256i const data_vec    = _mm256_loadu_si256    (xinput+i);
+            /* key_vec     = xsecret[i]; */
+            __m256i const key_vec     = _mm256_loadu_si256   (xsecret+i);
+            /* data_key    = data_vec ^ key_vec; */
+            __m256i const data_key    = _mm256_xor_si256     (data_vec, key_vec);
+            /* data_key_lo = data_key >> 32; */
+            __m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
+            /* product     = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
+            __m256i const product     = _mm256_mul_epu32     (data_key, data_key_lo);
+            /* xacc[i] += swap(data_vec); */
+            __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2));
+            __m256i const sum       = _mm256_add_epi64(xacc[i], data_swap);
+            /* xacc[i] += product; */
+            xacc[i] = _mm256_add_epi64(product, sum);
+    }   }
+}
+
+XXH_FORCE_INLINE XXH_TARGET_AVX2 void
+XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
+{
+    XXH_ASSERT((((size_t)acc) & 31) == 0);
+    {   XXH_ALIGN(32) __m256i* const xacc = (__m256i*) acc;
+        /* Unaligned. This is mainly for pointer arithmetic, and because
+         * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */
+        const         __m256i* const xsecret = (const __m256i *) secret;
+        const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1);
+
+        size_t i;
+        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) {
+            /* xacc[i] ^= (xacc[i] >> 47) */
+            __m256i const acc_vec     = xacc[i];
+            __m256i const shifted     = _mm256_srli_epi64    (acc_vec, 47);
+            __m256i const data_vec    = _mm256_xor_si256     (acc_vec, shifted);
+            /* xacc[i] ^= xsecret; */
+            __m256i const key_vec     = _mm256_loadu_si256   (xsecret+i);
+            __m256i const data_key    = _mm256_xor_si256     (data_vec, key_vec);
+
+            /* xacc[i] *= XXH_PRIME32_1; */
+            __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
+            __m256i const prod_lo     = _mm256_mul_epu32     (data_key, prime32);
+            __m256i const prod_hi     = _mm256_mul_epu32     (data_key_hi, prime32);
+            xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32));
+        }
+    }
+}
+
+XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
+{
+    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0);
+    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6);
+    XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64);
+    (void)(&XXH_writeLE64);
+    XXH_PREFETCH(customSecret);
+    {   __m256i const seed = _mm256_set_epi64x(-(xxh_i64)seed64, (xxh_i64)seed64, -(xxh_i64)seed64, (xxh_i64)seed64);
+
+        XXH_ALIGN(64) const __m256i* const src  = (const __m256i*) XXH3_kSecret;
+        XXH_ALIGN(64)       __m256i*       dest = (      __m256i*) customSecret;
+
+#       if defined(__GNUC__) || defined(__clang__)
+        /*
+         * On GCC & Clang, marking 'dest' as modified will cause the compiler:
+         *   - do not extract the secret from sse registers in the internal loop
+         *   - use less common registers, and avoid pushing these reg into stack
+         * The asm hack causes Clang to assume that XXH3_kSecretPtr aliases with
+         * customSecret, and on aarch64, this prevented LDP from merging two
+         * loads together for free. Putting the loads together before the stores
+         * properly generates LDP.
+         */
+        __asm__("" : "+r" (dest));
+#       endif
+
+        /* GCC -O2 need unroll loop manually */
+        dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed);
+        dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed);
+        dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed);
+        dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed);
+        dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed);
+        dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed);
+    }
+}
+
+#endif
+
+/* x86dispatch always generates SSE2 */
+#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH)
+
+#ifndef XXH_TARGET_SSE2
+# define XXH_TARGET_SSE2  /* disable attribute target */
+#endif
+
+XXH_FORCE_INLINE XXH_TARGET_SSE2 void
+XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc,
+                    const void* XXH_RESTRICT input,
+                    const void* XXH_RESTRICT secret)
+{
+    /* SSE2 is just a half-scale version of the AVX2 version. */
+    XXH_ASSERT((((size_t)acc) & 15) == 0);
+    {   XXH_ALIGN(16) __m128i* const xacc    =       (__m128i *) acc;
+        /* Unaligned. This is mainly for pointer arithmetic, and because
+         * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
+        const         __m128i* const xinput  = (const __m128i *) input;
+        /* Unaligned. This is mainly for pointer arithmetic, and because
+         * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
+        const         __m128i* const xsecret = (const __m128i *) secret;
+
+        size_t i;
+        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) {
+            /* data_vec    = xinput[i]; */
+            __m128i const data_vec    = _mm_loadu_si128   (xinput+i);
+            /* key_vec     = xsecret[i]; */
+            __m128i const key_vec     = _mm_loadu_si128   (xsecret+i);
+            /* data_key    = data_vec ^ key_vec; */
+            __m128i const data_key    = _mm_xor_si128     (data_vec, key_vec);
+            /* data_key_lo = data_key >> 32; */
+            __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
+            /* product     = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
+            __m128i const product     = _mm_mul_epu32     (data_key, data_key_lo);
+            /* xacc[i] += swap(data_vec); */
+            __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2));
+            __m128i const sum       = _mm_add_epi64(xacc[i], data_swap);
+            /* xacc[i] += product; */
+            xacc[i] = _mm_add_epi64(product, sum);
+    }   }
+}
+
+XXH_FORCE_INLINE XXH_TARGET_SSE2 void
+XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
+{
+    XXH_ASSERT((((size_t)acc) & 15) == 0);
+    {   XXH_ALIGN(16) __m128i* const xacc = (__m128i*) acc;
+        /* Unaligned. This is mainly for pointer arithmetic, and because
+         * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
+        const         __m128i* const xsecret = (const __m128i *) secret;
+        const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1);
+
+        size_t i;
+        for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) {
+            /* xacc[i] ^= (xacc[i] >> 47) */
+            __m128i const acc_vec     = xacc[i];
+            __m128i const shifted     = _mm_srli_epi64    (acc_vec, 47);
+            __m128i const data_vec    = _mm_xor_si128     (acc_vec, shifted);
+            /* xacc[i] ^= xsecret[i]; */
+            __m128i const key_vec     = _mm_loadu_si128   (xsecret+i);
+            __m128i const data_key    = _mm_xor_si128     (data_vec, key_vec);
+
+            /* xacc[i] *= XXH_PRIME32_1; */
+            __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
+            __m128i const prod_lo     = _mm_mul_epu32     (data_key, prime32);
+            __m128i const prod_hi     = _mm_mul_epu32     (data_key_hi, prime32);
+            xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32));
+        }
+    }
+}
+
+XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
+{
+    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);
+    (void)(&XXH_writeLE64);
+    {   int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i);
+
+#       if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900
+        // MSVC 32bit mode does not support _mm_set_epi64x before 2015
+        XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, -(xxh_i64)seed64 };
+        __m128i const seed = _mm_load_si128((__m128i const*)seed64x2);
+#       else
+        __m128i const seed = _mm_set_epi64x(-(xxh_i64)seed64, (xxh_i64)seed64);
+#       endif
+        int i;
+
+        XXH_ALIGN(64)        const float* const src  = (float const*) XXH3_kSecret;
+        XXH_ALIGN(XXH_SEC_ALIGN) __m128i*       dest = (__m128i*) customSecret;
+#       if defined(__GNUC__) || defined(__clang__)
+        /*
+         * On GCC & Clang, marking 'dest' as modified will cause the compiler:
+         *   - do not extract the secret from sse registers in the internal loop
+         *   - use less common registers, and avoid pushing these reg into stack
+         */
+        __asm__("" : "+r" (dest));
+#       endif
+
+        for (i=0; i < nbRounds; ++i) {
+            dest[i] = _mm_add_epi64(_mm_castps_si128(_mm_load_ps(src+i*4)), seed);
+    }   }
+}
+
+#endif
+
+#if (XXH_VECTOR == XXH_NEON)
+
+XXH_FORCE_INLINE void
+XXH3_accumulate_512_neon( void* XXH_RESTRICT acc,
+                    const void* XXH_RESTRICT input,
+                    const void* XXH_RESTRICT secret)
+{
+    XXH_ASSERT((((size_t)acc) & 15) == 0);
+    {
+        XXH_ALIGN(16) uint64x2_t* const xacc = (uint64x2_t *) acc;
+        /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */
+        uint8_t const* const xinput = (const uint8_t *) input;
+        uint8_t const* const xsecret  = (const uint8_t *) secret;
+
+        size_t i;
+        for (i=0; i < XXH_STRIPE_LEN / sizeof(uint64x2_t); i++) {
+            /* data_vec = xinput[i]; */
+            uint8x16_t data_vec    = vld1q_u8(xinput  + (i * 16));
+            /* key_vec  = xsecret[i];  */
+            uint8x16_t key_vec     = vld1q_u8(xsecret + (i * 16));
+            uint64x2_t data_key;
+            uint32x2_t data_key_lo, data_key_hi;
+            /* xacc[i] += swap(data_vec); */
+            uint64x2_t const data64  = vreinterpretq_u64_u8(data_vec);
+            uint64x2_t const swapped = vextq_u64(data64, data64, 1);
+            xacc[i] = vaddq_u64 (xacc[i], swapped);
+            /* data_key = data_vec ^ key_vec; */
+            data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec));
+            /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF);
+             * data_key_hi = (uint32x2_t) (data_key >> 32);
+             * data_key = UNDEFINED; */
+            XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi);
+            /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */
+            xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi);
+
+        }
+    }
+}
+
+XXH_FORCE_INLINE void
+XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
+{
+    XXH_ASSERT((((size_t)acc) & 15) == 0);
+
+    {   uint64x2_t* xacc       = (uint64x2_t*) acc;
+        uint8_t const* xsecret = (uint8_t const*) secret;
+        uint32x2_t prime       = vdup_n_u32 (XXH_PRIME32_1);
+
+        size_t i;
+        for (i=0; i < XXH_STRIPE_LEN/sizeof(uint64x2_t); i++) {
+            /* xacc[i] ^= (xacc[i] >> 47); */
+            uint64x2_t acc_vec  = xacc[i];
+            uint64x2_t shifted  = vshrq_n_u64 (acc_vec, 47);
+            uint64x2_t data_vec = veorq_u64   (acc_vec, shifted);
+
+            /* xacc[i] ^= xsecret[i]; */
+            uint8x16_t key_vec  = vld1q_u8(xsecret + (i * 16));
+            uint64x2_t data_key = veorq_u64(data_vec, vreinterpretq_u64_u8(key_vec));
+
+            /* xacc[i] *= XXH_PRIME32_1 */
+            uint32x2_t data_key_lo, data_key_hi;
+            /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF);
+             * data_key_hi = (uint32x2_t) (xacc[i] >> 32);
+             * xacc[i] = UNDEFINED; */
+            XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi);
+            {   /*
+                 * prod_hi = (data_key >> 32) * XXH_PRIME32_1;
+                 *
+                 * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will
+                 * incorrectly "optimize" this:
+                 *   tmp     = vmul_u32(vmovn_u64(a), vmovn_u64(b));
+                 *   shifted = vshll_n_u32(tmp, 32);
+                 * to this:
+                 *   tmp     = "vmulq_u64"(a, b); // no such thing!
+                 *   shifted = vshlq_n_u64(tmp, 32);
+                 *
+                 * However, unlike SSE, Clang lacks a 64-bit multiply routine
+                 * for NEON, and it scalarizes two 64-bit multiplies instead.
+                 *
+                 * vmull_u32 has the same timing as vmul_u32, and it avoids
+                 * this bug completely.
+                 * See https://bugs.llvm.org/show_bug.cgi?id=39967
+                 */
+                uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime);
+                /* xacc[i] = prod_hi << 32; */
+                xacc[i] = vshlq_n_u64(prod_hi, 32);
+                /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */
+                xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime);
+            }
+    }   }
+}
+
+#endif
+
+#if (XXH_VECTOR == XXH_VSX)
+
+XXH_FORCE_INLINE void
+XXH3_accumulate_512_vsx(  void* XXH_RESTRICT acc,
+                    const void* XXH_RESTRICT input,
+                    const void* XXH_RESTRICT secret)
+{
+          xxh_u64x2* const xacc     =       (xxh_u64x2*) acc;    /* presumed aligned */
+    xxh_u64x2 const* const xinput   = (xxh_u64x2 const*) input;   /* no alignment restriction */
+    xxh_u64x2 const* const xsecret  = (xxh_u64x2 const*) secret;    /* no alignment restriction */
+    xxh_u64x2 const v32 = { 32, 32 };
+    size_t i;
+    for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {
+        /* data_vec = xinput[i]; */
+        xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i);
+        /* key_vec = xsecret[i]; */
+        xxh_u64x2 const key_vec  = XXH_vec_loadu(xsecret + i);
+        xxh_u64x2 const data_key = data_vec ^ key_vec;
+        /* shuffled = (data_key << 32) | (data_key >> 32); */
+        xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32);
+        /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */
+        xxh_u64x2 const product  = XXH_vec_mulo((xxh_u32x4)data_key, shuffled);
+        xacc[i] += product;
+
+        /* swap high and low halves */
+#ifdef __s390x__
+        xacc[i] += vec_permi(data_vec, data_vec, 2);
+#else
+        xacc[i] += vec_xxpermdi(data_vec, data_vec, 2);
+#endif
+    }
+}
+
+XXH_FORCE_INLINE void
+XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
+{
+    XXH_ASSERT((((size_t)acc) & 15) == 0);
+
+    {         xxh_u64x2* const xacc    =       (xxh_u64x2*) acc;
+        const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret;
+        /* constants */
+        xxh_u64x2 const v32  = { 32, 32 };
+        xxh_u64x2 const v47 = { 47, 47 };
+        xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 };
+        size_t i;
+        for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {
+            /* xacc[i] ^= (xacc[i] >> 47); */
+            xxh_u64x2 const acc_vec  = xacc[i];
+            xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47);
+
+            /* xacc[i] ^= xsecret[i]; */
+            xxh_u64x2 const key_vec  = XXH_vec_loadu(xsecret + i);
+            xxh_u64x2 const data_key = data_vec ^ key_vec;
+
+            /* xacc[i] *= XXH_PRIME32_1 */
+            /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF);  */
+            xxh_u64x2 const prod_even  = XXH_vec_mule((xxh_u32x4)data_key, prime);
+            /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32);  */
+            xxh_u64x2 const prod_odd  = XXH_vec_mulo((xxh_u32x4)data_key, prime);
+            xacc[i] = prod_odd + (prod_even << v32);
+    }   }
+}
+
+#endif
+
+/* scalar variants - universal */
+
+XXH_FORCE_INLINE void
+XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc,
+                     const void* XXH_RESTRICT input,
+                     const void* XXH_RESTRICT secret)
+{
+    XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */
+    const xxh_u8* const xinput  = (const xxh_u8*) input;  /* no alignment restriction */
+    const xxh_u8* const xsecret = (const xxh_u8*) secret;   /* no alignment restriction */
+    size_t i;
+    XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0);
+    for (i=0; i < XXH_ACC_NB; i++) {
+        xxh_u64 const data_val = XXH_readLE64(xinput + 8*i);
+        xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + i*8);
+        xacc[i ^ 1] += data_val; /* swap adjacent lanes */
+        xacc[i] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32);
+    }
+}
+
+XXH_FORCE_INLINE void
+XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
+{
+    XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc;   /* presumed aligned */
+    const xxh_u8* const xsecret = (const xxh_u8*) secret;   /* no alignment restriction */
+    size_t i;
+    XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0);
+    for (i=0; i < XXH_ACC_NB; i++) {
+        xxh_u64 const key64 = XXH_readLE64(xsecret + 8*i);
+        xxh_u64 acc64 = xacc[i];
+        acc64 = XXH_xorshift64(acc64, 47);
+        acc64 ^= key64;
+        acc64 *= XXH_PRIME32_1;
+        xacc[i] = acc64;
+    }
+}
+
+XXH_FORCE_INLINE void
+XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
+{
+    /*
+     * We need a separate pointer for the hack below,
+     * which requires a non-const pointer.
+     * Any decent compiler will optimize this out otherwise.
+     */
+    const xxh_u8* kSecretPtr = XXH3_kSecret;
+    XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);
+
+#if defined(__clang__) && defined(__aarch64__)
+    /*
+     * UGLY HACK:
+     * Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are
+     * placed sequentially, in order, at the top of the unrolled loop.
+     *
+     * While MOVK is great for generating constants (2 cycles for a 64-bit
+     * constant compared to 4 cycles for LDR), long MOVK chains stall the
+     * integer pipelines:
+     *   I   L   S
+     * MOVK
+     * MOVK
+     * MOVK
+     * MOVK
+     * ADD
+     * SUB      STR
+     *          STR
+     * By forcing loads from memory (as the asm line causes Clang to assume
+     * that XXH3_kSecretPtr has been changed), the pipelines are used more
+     * efficiently:
+     *   I   L   S
+     *      LDR
+     *  ADD LDR
+     *  SUB     STR
+     *          STR
+     * XXH3_64bits_withSeed, len == 256, Snapdragon 835
+     *   without hack: 2654.4 MB/s
+     *   with hack:    3202.9 MB/s
+     */
+    __asm__("" : "+r" (kSecretPtr));
+#endif
+    /*
+     * Note: in debug mode, this overrides the asm optimization
+     * and Clang will emit MOVK chains again.
+     */
+    XXH_ASSERT(kSecretPtr == XXH3_kSecret);
+
+    {   int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16;
+        int i;
+        for (i=0; i < nbRounds; i++) {
+            /*
+             * The asm hack causes Clang to assume that kSecretPtr aliases with
+             * customSecret, and on aarch64, this prevented LDP from merging two
+             * loads together for free. Putting the loads together before the stores
+             * properly generates LDP.
+             */
+            xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i)     + seed64;
+            xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64;
+            XXH_writeLE64((xxh_u8*)customSecret + 16*i,     lo);
+            XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi);
+    }   }
+}
+
+
+typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*);
+typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*);
+typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64);
+
+
+#if (XXH_VECTOR == XXH_AVX512)
+
+#define XXH3_accumulate_512 XXH3_accumulate_512_avx512
+#define XXH3_scrambleAcc    XXH3_scrambleAcc_avx512
+#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512
+
+#elif (XXH_VECTOR == XXH_AVX2)
+
+#define XXH3_accumulate_512 XXH3_accumulate_512_avx2
+#define XXH3_scrambleAcc    XXH3_scrambleAcc_avx2
+#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2
+
+#elif (XXH_VECTOR == XXH_SSE2)
+
+#define XXH3_accumulate_512 XXH3_accumulate_512_sse2
+#define XXH3_scrambleAcc    XXH3_scrambleAcc_sse2
+#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2
+
+#elif (XXH_VECTOR == XXH_NEON)
+
+#define XXH3_accumulate_512 XXH3_accumulate_512_neon
+#define XXH3_scrambleAcc    XXH3_scrambleAcc_neon
+#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
+
+#elif (XXH_VECTOR == XXH_VSX)
+
+#define XXH3_accumulate_512 XXH3_accumulate_512_vsx
+#define XXH3_scrambleAcc    XXH3_scrambleAcc_vsx
+#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
+
+#else /* scalar */
+
+#define XXH3_accumulate_512 XXH3_accumulate_512_scalar
+#define XXH3_scrambleAcc    XXH3_scrambleAcc_scalar
+#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
+
+#endif
+
+
+
+#ifndef XXH_PREFETCH_DIST
+#  ifdef __clang__
+#    define XXH_PREFETCH_DIST 320
+#  else
+#    if (XXH_VECTOR == XXH_AVX512)
+#      define XXH_PREFETCH_DIST 512
+#    else
+#      define XXH_PREFETCH_DIST 384
+#    endif
+#  endif  /* __clang__ */
+#endif  /* XXH_PREFETCH_DIST */
+
+/*
+ * XXH3_accumulate()
+ * Loops over XXH3_accumulate_512().
+ * Assumption: nbStripes will not overflow the secret size
+ */
+XXH_FORCE_INLINE void
+XXH3_accumulate(     xxh_u64* XXH_RESTRICT acc,
+                const xxh_u8* XXH_RESTRICT input,
+                const xxh_u8* XXH_RESTRICT secret,
+                      size_t nbStripes,
+                      XXH3_f_accumulate_512 f_acc512)
+{
+    size_t n;
+    for (n = 0; n < nbStripes; n++ ) {
+        const xxh_u8* const in = input + n*XXH_STRIPE_LEN;
+        XXH_PREFETCH(in + XXH_PREFETCH_DIST);
+        f_acc512(acc,
+                 in,
+                 secret + n*XXH_SECRET_CONSUME_RATE);
+    }
+}
+
+XXH_FORCE_INLINE void
+XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc,
+                      const xxh_u8* XXH_RESTRICT input, size_t len,
+                      const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
+                            XXH3_f_accumulate_512 f_acc512,
+                            XXH3_f_scrambleAcc f_scramble)
+{
+    size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE;
+    size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock;
+    size_t const nb_blocks = (len - 1) / block_len;
+
+    size_t n;
+
+    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
+
+    for (n = 0; n < nb_blocks; n++) {
+        XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512);
+        f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN);
+    }
+
+    /* last partial block */
+    XXH_ASSERT(len > XXH_STRIPE_LEN);
+    {   size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN;
+        XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE));
+        XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512);
+
+        /* last stripe */
+        {   const xxh_u8* const p = input + len - XXH_STRIPE_LEN;
+#define XXH_SECRET_LASTACC_START 7  /* not aligned on 8, last secret is different from acc & scrambler */
+            f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START);
+    }   }
+}
+
+XXH_FORCE_INLINE xxh_u64
+XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret)
+{
+    return XXH3_mul128_fold64(
+               acc[0] ^ XXH_readLE64(secret),
+               acc[1] ^ XXH_readLE64(secret+8) );
+}
+
+static XXH64_hash_t
+XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start)
+{
+    xxh_u64 result64 = start;
+    size_t i = 0;
+
+    for (i = 0; i < 4; i++) {
+        result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i);
+#if defined(__clang__)                                /* Clang */ \
+    && (defined(__arm__) || defined(__thumb__))       /* ARMv7 */ \
+    && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */  \
+    && !defined(XXH_ENABLE_AUTOVECTORIZE)             /* Define to disable */
+        /*
+         * UGLY HACK:
+         * Prevent autovectorization on Clang ARMv7-a. Exact same problem as
+         * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b.
+         * XXH3_64bits, len == 256, Snapdragon 835:
+         *   without hack: 2063.7 MB/s
+         *   with hack:    2560.7 MB/s
+         */
+        __asm__("" : "+r" (result64));
+#endif
+    }
+
+    return XXH3_avalanche(result64);
+}
+
+#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \
+                        XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 }
+
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len,
+                           const void* XXH_RESTRICT secret, size_t secretSize,
+                           XXH3_f_accumulate_512 f_acc512,
+                           XXH3_f_scrambleAcc f_scramble)
+{
+    XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
+
+    XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble);
+
+    /* converge into final hash */
+    XXH_STATIC_ASSERT(sizeof(acc) == 64);
+    /* do not align on 8, so that the secret is different from the accumulator */
+#define XXH_SECRET_MERGEACCS_START 11
+    XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
+    return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1);
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH64_hash_t
+XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len,
+                             XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
+{
+    (void)seed64;
+    return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc);
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ * Since the function is not inlined, the compiler may not be able to understand that,
+ * in some scenarios, its `secret` argument is actually a compile time constant.
+ * This variant enforces that the compiler can detect that,
+ * and uses this opportunity to streamline the generated code for better performance.
+ */
+XXH_NO_INLINE XXH64_hash_t
+XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len,
+                          XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
+{
+    (void)seed64; (void)secret; (void)secretLen;
+    return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc);
+}
+
+/*
+ * XXH3_hashLong_64b_withSeed():
+ * Generate a custom key based on alteration of default XXH3_kSecret with the seed,
+ * and then use this key for long mode hashing.
+ *
+ * This operation is decently fast but nonetheless costs a little bit of time.
+ * Try to avoid it whenever possible (typically when seed==0).
+ *
+ * It's important for performance that XXH3_hashLong is not inlined. Not sure
+ * why (uop cache maybe?), but the difference is large and easily measurable.
+ */
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len,
+                                    XXH64_hash_t seed,
+                                    XXH3_f_accumulate_512 f_acc512,
+                                    XXH3_f_scrambleAcc f_scramble,
+                                    XXH3_f_initCustomSecret f_initSec)
+{
+    if (seed == 0)
+        return XXH3_hashLong_64b_internal(input, len,
+                                          XXH3_kSecret, sizeof(XXH3_kSecret),
+                                          f_acc512, f_scramble);
+    {   XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
+        f_initSec(secret, seed);
+        return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret),
+                                          f_acc512, f_scramble);
+    }
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH64_hash_t
+XXH3_hashLong_64b_withSeed(const void* input, size_t len,
+                           XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen)
+{
+    (void)secret; (void)secretLen;
+    return XXH3_hashLong_64b_withSeed_internal(input, len, seed,
+                XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret);
+}
+
+
+typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t,
+                                          XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t);
+
+XXH_FORCE_INLINE XXH64_hash_t
+XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len,
+                     XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen,
+                     XXH3_hashLong64_f f_hashLong)
+{
+    XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);
+    /*
+     * If an action is to be taken if `secretLen` condition is not respected,
+     * it should be done here.
+     * For now, it's a contract pre-condition.
+     * Adding a check and a branch here would cost performance at every hash.
+     * Also, note that function signature doesn't offer room to return an error.
+     */
+    if (len <= 16)
+        return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64);
+    if (len <= 128)
+        return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
+    if (len <= XXH3_MIDSIZE_MAX)
+        return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
+    return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen);
+}
+
+
+/* ===   Public entry point   === */
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len)
+{
+    return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default);
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH64_hash_t
+XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize)
+{
+    return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret);
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH64_hash_t
+XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed)
+{
+    return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed);
+}
+
+
+/* ===   XXH3 streaming   === */
+
+/*
+ * Malloc's a pointer that is always aligned to align.
+ *
+ * This must be freed with `XXH_alignedFree()`.
+ *
+ * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte
+ * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2
+ * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON.
+ *
+ * This underalignment previously caused a rather obvious crash which went
+ * completely unnoticed due to XXH3_createState() not actually being tested.
+ * Credit to RedSpah for noticing this bug.
+ *
+ * The alignment is done manually: Functions like posix_memalign or _mm_malloc
+ * are avoided: To maintain portability, we would have to write a fallback
+ * like this anyways, and besides, testing for the existence of library
+ * functions without relying on external build tools is impossible.
+ *
+ * The method is simple: Overallocate, manually align, and store the offset
+ * to the original behind the returned pointer.
+ *
+ * Align must be a power of 2 and 8 <= align <= 128.
+ */
+static void* XXH_alignedMalloc(size_t s, size_t align)
+{
+    XXH_ASSERT(align <= 128 && align >= 8); /* range check */
+    XXH_ASSERT((align & (align-1)) == 0);   /* power of 2 */
+    XXH_ASSERT(s != 0 && s < (s + align));  /* empty/overflow */
+    {   /* Overallocate to make room for manual realignment and an offset byte */
+        xxh_u8* base = (xxh_u8*)XXH_malloc(s + align);
+        if (base != NULL) {
+            /*
+             * Get the offset needed to align this pointer.
+             *
+             * Even if the returned pointer is aligned, there will always be
+             * at least one byte to store the offset to the original pointer.
+             */
+            size_t offset = align - ((size_t)base & (align - 1)); /* base % align */
+            /* Add the offset for the now-aligned pointer */
+            xxh_u8* ptr = base + offset;
+
+            XXH_ASSERT((size_t)ptr % align == 0);
+
+            /* Store the offset immediately before the returned pointer. */
+            ptr[-1] = (xxh_u8)offset;
+            return ptr;
+        }
+        return NULL;
+    }
+}
+/*
+ * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass
+ * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout.
+ */
+static void XXH_alignedFree(void* p)
+{
+    if (p != NULL) {
+        xxh_u8* ptr = (xxh_u8*)p;
+        /* Get the offset byte we added in XXH_malloc. */
+        xxh_u8 offset = ptr[-1];
+        /* Free the original malloc'd pointer */
+        xxh_u8* base = ptr - offset;
+        XXH_free(base);
+    }
+}
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void)
+{
+    XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64);
+    if (state==NULL) return NULL;
+    XXH3_INITSTATE(state);
+    return state;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr)
+{
+    XXH_alignedFree(statePtr);
+    return XXH_OK;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API void
+XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state)
+{
+    memcpy(dst_state, src_state, sizeof(*dst_state));
+}
+
+static void
+XXH3_reset_internal(XXH3_state_t* statePtr,
+                           XXH64_hash_t seed,
+                           const void* secret, size_t secretSize)
+{
+    size_t const initStart = offsetof(XXH3_state_t, bufferedSize);
+    size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart;
+    XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart);
+    XXH_ASSERT(statePtr != NULL);
+    /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */
+    memset((char*)statePtr + initStart, 0, initLength);
+    statePtr->acc[0] = XXH_PRIME32_3;
+    statePtr->acc[1] = XXH_PRIME64_1;
+    statePtr->acc[2] = XXH_PRIME64_2;
+    statePtr->acc[3] = XXH_PRIME64_3;
+    statePtr->acc[4] = XXH_PRIME64_4;
+    statePtr->acc[5] = XXH_PRIME32_2;
+    statePtr->acc[6] = XXH_PRIME64_5;
+    statePtr->acc[7] = XXH_PRIME32_1;
+    statePtr->seed = seed;
+    statePtr->extSecret = (const unsigned char*)secret;
+    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
+    statePtr->secretLimit = secretSize - XXH_STRIPE_LEN;
+    statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH3_64bits_reset(XXH3_state_t* statePtr)
+{
+    if (statePtr == NULL) return XXH_ERROR;
+    XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
+    return XXH_OK;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize)
+{
+    if (statePtr == NULL) return XXH_ERROR;
+    XXH3_reset_internal(statePtr, 0, secret, secretSize);
+    if (secret == NULL) return XXH_ERROR;
+    if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
+    return XXH_OK;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed)
+{
+    if (statePtr == NULL) return XXH_ERROR;
+    if (seed==0) return XXH3_64bits_reset(statePtr);
+    if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed);
+    XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE);
+    return XXH_OK;
+}
+
+/* Note : when XXH3_consumeStripes() is invoked,
+ * there must be a guarantee that at least one more byte must be consumed from input
+ * so that the function can blindly consume all stripes using the "normal" secret segment */
+XXH_FORCE_INLINE void
+XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc,
+                    size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock,
+                    const xxh_u8* XXH_RESTRICT input, size_t nbStripes,
+                    const xxh_u8* XXH_RESTRICT secret, size_t secretLimit,
+                    XXH3_f_accumulate_512 f_acc512,
+                    XXH3_f_scrambleAcc f_scramble)
+{
+    XXH_ASSERT(nbStripes <= nbStripesPerBlock);  /* can handle max 1 scramble per invocation */
+    XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock);
+    if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) {
+        /* need a scrambling operation */
+        size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr;
+        size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock;
+        XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512);
+        f_scramble(acc, secret + secretLimit);
+        XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512);
+        *nbStripesSoFarPtr = nbStripesAfterBlock;
+    } else {
+        XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512);
+        *nbStripesSoFarPtr += nbStripes;
+    }
+}
+
+/*
+ * Both XXH3_64bits_update and XXH3_128bits_update use this routine.
+ */
+XXH_FORCE_INLINE XXH_errorcode
+XXH3_update(XXH3_state_t* state,
+            const xxh_u8* input, size_t len,
+            XXH3_f_accumulate_512 f_acc512,
+            XXH3_f_scrambleAcc f_scramble)
+{
+    if (input==NULL)
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+        return XXH_OK;
+#else
+        return XXH_ERROR;
+#endif
+
+    {   const xxh_u8* const bEnd = input + len;
+        const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
+
+        state->totalLen += len;
+        XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE);
+
+        if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) {  /* fill in tmp buffer */
+            XXH_memcpy(state->buffer + state->bufferedSize, input, len);
+            state->bufferedSize += (XXH32_hash_t)len;
+            return XXH_OK;
+        }
+        /* total input is now > XXH3_INTERNALBUFFER_SIZE */
+
+        #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN)
+        XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0);   /* clean multiple */
+
+        /*
+         * Internal buffer is partially filled (always, except at beginning)
+         * Complete it, then consume it.
+         */
+        if (state->bufferedSize) {
+            size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize;
+            XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize);
+            input += loadSize;
+            XXH3_consumeStripes(state->acc,
+                               &state->nbStripesSoFar, state->nbStripesPerBlock,
+                                state->buffer, XXH3_INTERNALBUFFER_STRIPES,
+                                secret, state->secretLimit,
+                                f_acc512, f_scramble);
+            state->bufferedSize = 0;
+        }
+        XXH_ASSERT(input < bEnd);
+
+        /* Consume input by a multiple of internal buffer size */
+        if (input+XXH3_INTERNALBUFFER_SIZE < bEnd) {
+            const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE;
+            do {
+                XXH3_consumeStripes(state->acc,
+                                   &state->nbStripesSoFar, state->nbStripesPerBlock,
+                                    input, XXH3_INTERNALBUFFER_STRIPES,
+                                    secret, state->secretLimit,
+                                    f_acc512, f_scramble);
+                input += XXH3_INTERNALBUFFER_SIZE;
+            } while (input<limit);
+            /* for last partial stripe */
+            memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);
+        }
+        XXH_ASSERT(input < bEnd);
+
+        /* Some remaining input (always) : buffer it */
+        XXH_memcpy(state->buffer, input, (size_t)(bEnd-input));
+        state->bufferedSize = (XXH32_hash_t)(bEnd-input);
+    }
+
+    return XXH_OK;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len)
+{
+    return XXH3_update(state, (const xxh_u8*)input, len,
+                       XXH3_accumulate_512, XXH3_scrambleAcc);
+}
+
+
+XXH_FORCE_INLINE void
+XXH3_digest_long (XXH64_hash_t* acc,
+                  const XXH3_state_t* state,
+                  const unsigned char* secret)
+{
+    /*
+     * Digest on a local copy. This way, the state remains unaltered, and it can
+     * continue ingesting more input afterwards.
+     */
+    memcpy(acc, state->acc, sizeof(state->acc));
+    if (state->bufferedSize >= XXH_STRIPE_LEN) {
+        size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN;
+        size_t nbStripesSoFar = state->nbStripesSoFar;
+        XXH3_consumeStripes(acc,
+                           &nbStripesSoFar, state->nbStripesPerBlock,
+                            state->buffer, nbStripes,
+                            secret, state->secretLimit,
+                            XXH3_accumulate_512, XXH3_scrambleAcc);
+        /* last stripe */
+        XXH3_accumulate_512(acc,
+                            state->buffer + state->bufferedSize - XXH_STRIPE_LEN,
+                            secret + state->secretLimit - XXH_SECRET_LASTACC_START);
+    } else {  /* bufferedSize < XXH_STRIPE_LEN */
+        xxh_u8 lastStripe[XXH_STRIPE_LEN];
+        size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize;
+        XXH_ASSERT(state->bufferedSize > 0);  /* there is always some input buffered */
+        memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize);
+        memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize);
+        XXH3_accumulate_512(acc,
+                            lastStripe,
+                            secret + state->secretLimit - XXH_SECRET_LASTACC_START);
+    }
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state)
+{
+    const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
+    if (state->totalLen > XXH3_MIDSIZE_MAX) {
+        XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];
+        XXH3_digest_long(acc, state, secret);
+        return XXH3_mergeAccs(acc,
+                              secret + XXH_SECRET_MERGEACCS_START,
+                              (xxh_u64)state->totalLen * XXH_PRIME64_1);
+    }
+    /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */
+    if (state->seed)
+        return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed);
+    return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen),
+                                  secret, state->secretLimit + XXH_STRIPE_LEN);
+}
+
+
+#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x))
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API void
+XXH3_generateSecret(void* secretBuffer, const void* customSeed, size_t customSeedSize)
+{
+    XXH_ASSERT(secretBuffer != NULL);
+    if (customSeedSize == 0) {
+        memcpy(secretBuffer, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
+        return;
+    }
+    XXH_ASSERT(customSeed != NULL);
+
+    {   size_t const segmentSize = sizeof(XXH128_hash_t);
+        size_t const nbSegments = XXH_SECRET_DEFAULT_SIZE / segmentSize;
+        XXH128_canonical_t scrambler;
+        XXH64_hash_t seeds[12];
+        size_t segnb;
+        XXH_ASSERT(nbSegments == 12);
+        XXH_ASSERT(segmentSize * nbSegments == XXH_SECRET_DEFAULT_SIZE); /* exact multiple */
+        XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0));
+
+        /*
+        * Copy customSeed to seeds[], truncating or repeating as necessary.
+        */
+        {   size_t toFill = XXH_MIN(customSeedSize, sizeof(seeds));
+            size_t filled = toFill;
+            memcpy(seeds, customSeed, toFill);
+            while (filled < sizeof(seeds)) {
+                toFill = XXH_MIN(filled, sizeof(seeds) - filled);
+                memcpy((char*)seeds + filled, seeds, toFill);
+                filled += toFill;
+        }   }
+
+        /* generate secret */
+        memcpy(secretBuffer, &scrambler, sizeof(scrambler));
+        for (segnb=1; segnb < nbSegments; segnb++) {
+            size_t const segmentStart = segnb * segmentSize;
+            XXH128_canonical_t segment;
+            XXH128_canonicalFromHash(&segment,
+                XXH128(&scrambler, sizeof(scrambler), XXH_readLE64(seeds + segnb) + segnb) );
+            memcpy((char*)secretBuffer + segmentStart, &segment, sizeof(segment));
+    }   }
+}
+
+
+/* ==========================================
+ * XXH3 128 bits (a.k.a XXH128)
+ * ==========================================
+ * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant,
+ * even without counting the significantly larger output size.
+ *
+ * For example, extra steps are taken to avoid the seed-dependent collisions
+ * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B).
+ *
+ * This strength naturally comes at the cost of some speed, especially on short
+ * lengths. Note that longer hashes are about as fast as the 64-bit version
+ * due to it using only a slight modification of the 64-bit loop.
+ *
+ * XXH128 is also more oriented towards 64-bit machines. It is still extremely
+ * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64).
+ */
+
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
+{
+    /* A doubled version of 1to3_64b with different constants. */
+    XXH_ASSERT(input != NULL);
+    XXH_ASSERT(1 <= len && len <= 3);
+    XXH_ASSERT(secret != NULL);
+    /*
+     * len = 1: combinedl = { input[0], 0x01, input[0], input[0] }
+     * len = 2: combinedl = { input[1], 0x02, input[0], input[1] }
+     * len = 3: combinedl = { input[2], 0x03, input[0], input[1] }
+     */
+    {   xxh_u8 const c1 = input[0];
+        xxh_u8 const c2 = input[len >> 1];
+        xxh_u8 const c3 = input[len - 1];
+        xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24)
+                                | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8);
+        xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13);
+        xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed;
+        xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed;
+        xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl;
+        xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph;
+        XXH128_hash_t h128;
+        h128.low64  = XXH64_avalanche(keyed_lo);
+        h128.high64 = XXH64_avalanche(keyed_hi);
+        return h128;
+    }
+}
+
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
+{
+    XXH_ASSERT(input != NULL);
+    XXH_ASSERT(secret != NULL);
+    XXH_ASSERT(4 <= len && len <= 8);
+    seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32;
+    {   xxh_u32 const input_lo = XXH_readLE32(input);
+        xxh_u32 const input_hi = XXH_readLE32(input + len - 4);
+        xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32);
+        xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed;
+        xxh_u64 const keyed = input_64 ^ bitflip;
+
+        /* Shift len to the left to ensure it is even, this avoids even multiplies. */
+        XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2));
+
+        m128.high64 += (m128.low64 << 1);
+        m128.low64  ^= (m128.high64 >> 3);
+
+        m128.low64   = XXH_xorshift64(m128.low64, 35);
+        m128.low64  *= 0x9FB21C651E98DF25ULL;
+        m128.low64   = XXH_xorshift64(m128.low64, 28);
+        m128.high64  = XXH3_avalanche(m128.high64);
+        return m128;
+    }
+}
+
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
+{
+    XXH_ASSERT(input != NULL);
+    XXH_ASSERT(secret != NULL);
+    XXH_ASSERT(9 <= len && len <= 16);
+    {   xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed;
+        xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed;
+        xxh_u64 const input_lo = XXH_readLE64(input);
+        xxh_u64       input_hi = XXH_readLE64(input + len - 8);
+        XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1);
+        /*
+         * Put len in the middle of m128 to ensure that the length gets mixed to
+         * both the low and high bits in the 128x64 multiply below.
+         */
+        m128.low64 += (xxh_u64)(len - 1) << 54;
+        input_hi   ^= bitfliph;
+        /*
+         * Add the high 32 bits of input_hi to the high 32 bits of m128, then
+         * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to
+         * the high 64 bits of m128.
+         *
+         * The best approach to this operation is different on 32-bit and 64-bit.
+         */
+        if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */
+            /*
+             * 32-bit optimized version, which is more readable.
+             *
+             * On 32-bit, it removes an ADC and delays a dependency between the two
+             * halves of m128.high64, but it generates an extra mask on 64-bit.
+             */
+            m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2);
+        } else {
+            /*
+             * 64-bit optimized (albeit more confusing) version.
+             *
+             * Uses some properties of addition and multiplication to remove the mask:
+             *
+             * Let:
+             *    a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF)
+             *    b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000)
+             *    c = XXH_PRIME32_2
+             *
+             *    a + (b * c)
+             * Inverse Property: x + y - x == y
+             *    a + (b * (1 + c - 1))
+             * Distributive Property: x * (y + z) == (x * y) + (x * z)
+             *    a + (b * 1) + (b * (c - 1))
+             * Identity Property: x * 1 == x
+             *    a + b + (b * (c - 1))
+             *
+             * Substitute a, b, and c:
+             *    input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1))
+             *
+             * Since input_hi.hi + input_hi.lo == input_hi, we get this:
+             *    input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1))
+             */
+            m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1);
+        }
+        /* m128 ^= XXH_swap64(m128 >> 64); */
+        m128.low64  ^= XXH_swap64(m128.high64);
+
+        {   /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */
+            XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2);
+            h128.high64 += m128.high64 * XXH_PRIME64_2;
+
+            h128.low64   = XXH3_avalanche(h128.low64);
+            h128.high64  = XXH3_avalanche(h128.high64);
+            return h128;
+    }   }
+}
+
+/*
+ * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN
+ */
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
+{
+    XXH_ASSERT(len <= 16);
+    {   if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed);
+        if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed);
+        if (len) return XXH3_len_1to3_128b(input, len, secret, seed);
+        {   XXH128_hash_t h128;
+            xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72);
+            xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88);
+            h128.low64 = XXH64_avalanche(seed ^ bitflipl);
+            h128.high64 = XXH64_avalanche( seed ^ bitfliph);
+            return h128;
+    }   }
+}
+
+/*
+ * A bit slower than XXH3_mix16B, but handles multiply by zero better.
+ */
+XXH_FORCE_INLINE XXH128_hash_t
+XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2,
+              const xxh_u8* secret, XXH64_hash_t seed)
+{
+    acc.low64  += XXH3_mix16B (input_1, secret+0, seed);
+    acc.low64  ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8);
+    acc.high64 += XXH3_mix16B (input_2, secret+16, seed);
+    acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8);
+    return acc;
+}
+
+
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
+                      const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
+                      XXH64_hash_t seed)
+{
+    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;
+    XXH_ASSERT(16 < len && len <= 128);
+
+    {   XXH128_hash_t acc;
+        acc.low64 = len * XXH_PRIME64_1;
+        acc.high64 = 0;
+        if (len > 32) {
+            if (len > 64) {
+                if (len > 96) {
+                    acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed);
+                }
+                acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed);
+            }
+            acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed);
+        }
+        acc = XXH128_mix32B(acc, input, input+len-16, secret, seed);
+        {   XXH128_hash_t h128;
+            h128.low64  = acc.low64 + acc.high64;
+            h128.high64 = (acc.low64    * XXH_PRIME64_1)
+                        + (acc.high64   * XXH_PRIME64_4)
+                        + ((len - seed) * XXH_PRIME64_2);
+            h128.low64  = XXH3_avalanche(h128.low64);
+            h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64);
+            return h128;
+        }
+    }
+}
+
+XXH_NO_INLINE XXH128_hash_t
+XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
+                       const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
+                       XXH64_hash_t seed)
+{
+    XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;
+    XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
+
+    {   XXH128_hash_t acc;
+        int const nbRounds = (int)len / 32;
+        int i;
+        acc.low64 = len * XXH_PRIME64_1;
+        acc.high64 = 0;
+        for (i=0; i<4; i++) {
+            acc = XXH128_mix32B(acc,
+                                input  + (32 * i),
+                                input  + (32 * i) + 16,
+                                secret + (32 * i),
+                                seed);
+        }
+        acc.low64 = XXH3_avalanche(acc.low64);
+        acc.high64 = XXH3_avalanche(acc.high64);
+        XXH_ASSERT(nbRounds >= 4);
+        for (i=4 ; i < nbRounds; i++) {
+            acc = XXH128_mix32B(acc,
+                                input + (32 * i),
+                                input + (32 * i) + 16,
+                                secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)),
+                                seed);
+        }
+        /* last bytes */
+        acc = XXH128_mix32B(acc,
+                            input + len - 16,
+                            input + len - 32,
+                            secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16,
+                            0ULL - seed);
+
+        {   XXH128_hash_t h128;
+            h128.low64  = acc.low64 + acc.high64;
+            h128.high64 = (acc.low64    * XXH_PRIME64_1)
+                        + (acc.high64   * XXH_PRIME64_4)
+                        + ((len - seed) * XXH_PRIME64_2);
+            h128.low64  = XXH3_avalanche(h128.low64);
+            h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64);
+            return h128;
+        }
+    }
+}
+
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len,
+                            const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
+                            XXH3_f_accumulate_512 f_acc512,
+                            XXH3_f_scrambleAcc f_scramble)
+{
+    XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
+
+    XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble);
+
+    /* converge into final hash */
+    XXH_STATIC_ASSERT(sizeof(acc) == 64);
+    XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
+    {   XXH128_hash_t h128;
+        h128.low64  = XXH3_mergeAccs(acc,
+                                     secret + XXH_SECRET_MERGEACCS_START,
+                                     (xxh_u64)len * XXH_PRIME64_1);
+        h128.high64 = XXH3_mergeAccs(acc,
+                                     secret + secretSize
+                                            - sizeof(acc) - XXH_SECRET_MERGEACCS_START,
+                                     ~((xxh_u64)len * XXH_PRIME64_2));
+        return h128;
+    }
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH128_hash_t
+XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len,
+                           XXH64_hash_t seed64,
+                           const void* XXH_RESTRICT secret, size_t secretLen)
+{
+    (void)seed64; (void)secret; (void)secretLen;
+    return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret),
+                                       XXH3_accumulate_512, XXH3_scrambleAcc);
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH128_hash_t
+XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len,
+                              XXH64_hash_t seed64,
+                              const void* XXH_RESTRICT secret, size_t secretLen)
+{
+    (void)seed64;
+    return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen,
+                                       XXH3_accumulate_512, XXH3_scrambleAcc);
+}
+
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len,
+                                XXH64_hash_t seed64,
+                                XXH3_f_accumulate_512 f_acc512,
+                                XXH3_f_scrambleAcc f_scramble,
+                                XXH3_f_initCustomSecret f_initSec)
+{
+    if (seed64 == 0)
+        return XXH3_hashLong_128b_internal(input, len,
+                                           XXH3_kSecret, sizeof(XXH3_kSecret),
+                                           f_acc512, f_scramble);
+    {   XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
+        f_initSec(secret, seed64);
+        return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret),
+                                           f_acc512, f_scramble);
+    }
+}
+
+/*
+ * It's important for performance that XXH3_hashLong is not inlined.
+ */
+XXH_NO_INLINE XXH128_hash_t
+XXH3_hashLong_128b_withSeed(const void* input, size_t len,
+                            XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen)
+{
+    (void)secret; (void)secretLen;
+    return XXH3_hashLong_128b_withSeed_internal(input, len, seed64,
+                XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret);
+}
+
+typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t,
+                                            XXH64_hash_t, const void* XXH_RESTRICT, size_t);
+
+XXH_FORCE_INLINE XXH128_hash_t
+XXH3_128bits_internal(const void* input, size_t len,
+                      XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen,
+                      XXH3_hashLong128_f f_hl128)
+{
+    XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);
+    /*
+     * If an action is to be taken if `secret` conditions are not respected,
+     * it should be done here.
+     * For now, it's a contract pre-condition.
+     * Adding a check and a branch here would cost performance at every hash.
+     */
+    if (len <= 16)
+        return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64);
+    if (len <= 128)
+        return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
+    if (len <= XXH3_MIDSIZE_MAX)
+        return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
+    return f_hl128(input, len, seed64, secret, secretLen);
+}
+
+
+/* ===   Public XXH128 API   === */
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len)
+{
+    return XXH3_128bits_internal(input, len, 0,
+                                 XXH3_kSecret, sizeof(XXH3_kSecret),
+                                 XXH3_hashLong_128b_default);
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t
+XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize)
+{
+    return XXH3_128bits_internal(input, len, 0,
+                                 (const xxh_u8*)secret, secretSize,
+                                 XXH3_hashLong_128b_withSecret);
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t
+XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed)
+{
+    return XXH3_128bits_internal(input, len, seed,
+                                 XXH3_kSecret, sizeof(XXH3_kSecret),
+                                 XXH3_hashLong_128b_withSeed);
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t
+XXH128(const void* input, size_t len, XXH64_hash_t seed)
+{
+    return XXH3_128bits_withSeed(input, len, seed);
+}
+
+
+/* ===   XXH3 128-bit streaming   === */
+
+/*
+ * All the functions are actually the same as for 64-bit streaming variant.
+ * The only difference is the finalization routine.
+ */
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH3_128bits_reset(XXH3_state_t* statePtr)
+{
+    if (statePtr == NULL) return XXH_ERROR;
+    XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
+    return XXH_OK;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize)
+{
+    if (statePtr == NULL) return XXH_ERROR;
+    XXH3_reset_internal(statePtr, 0, secret, secretSize);
+    if (secret == NULL) return XXH_ERROR;
+    if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
+    return XXH_OK;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed)
+{
+    if (statePtr == NULL) return XXH_ERROR;
+    if (seed==0) return XXH3_128bits_reset(statePtr);
+    if (seed != statePtr->seed) XXH3_initCustomSecret(statePtr->customSecret, seed);
+    XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE);
+    return XXH_OK;
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH_errorcode
+XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len)
+{
+    return XXH3_update(state, (const xxh_u8*)input, len,
+                       XXH3_accumulate_512, XXH3_scrambleAcc);
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state)
+{
+    const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
+    if (state->totalLen > XXH3_MIDSIZE_MAX) {
+        XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];
+        XXH3_digest_long(acc, state, secret);
+        XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
+        {   XXH128_hash_t h128;
+            h128.low64  = XXH3_mergeAccs(acc,
+                                         secret + XXH_SECRET_MERGEACCS_START,
+                                         (xxh_u64)state->totalLen * XXH_PRIME64_1);
+            h128.high64 = XXH3_mergeAccs(acc,
+                                         secret + state->secretLimit + XXH_STRIPE_LEN
+                                                - sizeof(acc) - XXH_SECRET_MERGEACCS_START,
+                                         ~((xxh_u64)state->totalLen * XXH_PRIME64_2));
+            return h128;
+        }
+    }
+    /* len <= XXH3_MIDSIZE_MAX : short code */
+    if (state->seed)
+        return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed);
+    return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen),
+                                   secret, state->secretLimit + XXH_STRIPE_LEN);
+}
+
+/* 128-bit utility functions */
+
+#include <string.h>   /* memcmp, memcpy */
+
+/* return : 1 is equal, 0 if different */
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2)
+{
+    /* note : XXH128_hash_t is compact, it has no padding byte */
+    return !(memcmp(&h1, &h2, sizeof(h1)));
+}
+
+/* This prototype is compatible with stdlib's qsort().
+ * return : >0 if *h128_1  > *h128_2
+ *          <0 if *h128_1  < *h128_2
+ *          =0 if *h128_1 == *h128_2  */
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2)
+{
+    XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1;
+    XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2;
+    int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64);
+    /* note : bets that, in most cases, hash values are different */
+    if (hcmp) return hcmp;
+    return (h1.low64 > h2.low64) - (h2.low64 > h1.low64);
+}
+
+
+/*======   Canonical representation   ======*/
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API void
+XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash)
+{
+    XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t));
+    if (XXH_CPU_LITTLE_ENDIAN) {
+        hash.high64 = XXH_swap64(hash.high64);
+        hash.low64  = XXH_swap64(hash.low64);
+    }
+    memcpy(dst, &hash.high64, sizeof(hash.high64));
+    memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64));
+}
+
+/*! @ingroup xxh3_family */
+XXH_PUBLIC_API XXH128_hash_t
+XXH128_hashFromCanonical(const XXH128_canonical_t* src)
+{
+    XXH128_hash_t h;
+    h.high64 = XXH_readBE64(src);
+    h.low64  = XXH_readBE64(src->digest + 8);
+    return h;
+}
+
+/* Pop our optimization override from above */
+#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
+  && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
+  && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */
+#  pragma GCC pop_options
+#endif
+
+#endif  /* XXH_NO_LONG_LONG */
+
+/*!
+ * @}
+ */
+#endif  /* XXH_IMPLEMENTATION */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/grpc/third_party/xxhash/xxhsum.1 b/grpc/third_party/xxhash/xxhsum.1
new file mode 100644
index 0000000..dd17108
--- /dev/null
+++ b/grpc/third_party/xxhash/xxhsum.1
@@ -0,0 +1,165 @@
+.
+.TH "XXHSUM" "1" "July 2020" "xxhsum 0.7.4" "User Commands"
+.
+.SH "NAME"
+\fBxxhsum\fR \- print or check xxHash non\-cryptographic checksums
+.
+.SH "SYNOPSIS"
+\fBxxhsum [<OPTION>] \.\.\. [<FILE>] \.\.\.\fR \fBxxhsum \-b [<OPTION>] \.\.\.\fR
+.
+.P
+\fBxxh32sum\fR is equivalent to \fBxxhsum \-H0\fR \fBxxh64sum\fR is equivalent to \fBxxhsum \-H1\fR \fBxxh128sum\fR is equivalent to \fBxxhsum \-H2\fR
+.
+.SH "DESCRIPTION"
+Print or check xxHash (32, 64 or 128 bits) checksums\. When no \fIFILE\fR, read standard input, except if it\'s the console\. When \fIFILE\fR is \fB\-\fR, read standard input even if it\'s the console\.
+.
+.P
+\fBxxhsum\fR supports a command line syntax similar but not identical to md5sum(1)\. Differences are: \fBxxhsum\fR doesn\'t have text/binary mode switch (\fB\-b\fR, \fB\-t\fR); \fBxxhsum\fR always treats files as binary file; \fBxxhsum\fR has a hash bit width switch (\fB\-H\fR);
+.
+.P
+As xxHash is a fast non\-cryptographic checksum algorithm, \fBxxhsum\fR should not be used for security related purposes\.
+.
+.P
+\fBxxhsum \-b\fR invokes benchmark mode\. See \fIOPTIONS\fR and \fIEXAMPLES\fR for details\.
+.
+.SH "OPTIONS"
+.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+Displays xxhsum version and exits
+.
+.TP
+\fB\-H\fR\fIHASHTYPE\fR
+Hash selection\. \fIHASHTYPE\fR means \fB0\fR=32bits, \fB1\fR=64bits, \fB2\fR=128bits\. Alternatively, \fIHASHTYPE\fR \fB32\fR=32bits, \fB64\fR=64bits, \fB128\fR=128bits\. Default value is \fB1\fR (64bits)
+.
+.TP
+\fB\-\-tag\fR
+Output in the BSD style\.
+.
+.TP
+\fB\-\-little\-endian\fR
+Set output hexadecimal checksum value as little endian convention\. By default, value is displayed as big endian\.
+.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Displays help and exits
+.
+.P
+\fBThe following four options are useful only when verifying checksums (\fB\-c\fR)\fR
+.
+.TP
+\fB\-c\fR, \fB\-\-check\fR \fIFILE\fR
+Read xxHash sums from \fIFILE\fR and check them
+.
+.TP
+\fB\-q\fR, \fB\-\-quiet\fR
+Don\'t print OK for each successfully verified file
+.
+.TP
+\fB\-\-strict\fR
+Return an error code if any line in the file is invalid, not just if some checksums are wrong\. This policy is disabled by default, though UI will prompt an informational message if any line in the file is detected invalid\.
+.
+.TP
+\fB\-\-status\fR
+Don\'t output anything\. Status code shows success\.
+.
+.TP
+\fB\-w\fR, \fB\-\-warn\fR
+Emit a warning message about each improperly formatted checksum line\.
+.
+.P
+\fBThe following options are useful only benchmark purpose\fR
+.
+.TP
+\fB\-b\fR
+Benchmark mode\. See \fIEXAMPLES\fR for details\.
+.
+.TP
+\fB\-b#\fR
+Specify ID of variant to be tested\. Multiple variants can be selected, separated by a \',\' comma\.
+.
+.TP
+\fB\-B\fR\fIBLOCKSIZE\fR
+Only useful for benchmark mode (\fB\-b\fR)\. See \fIEXAMPLES\fR for details\. \fIBLOCKSIZE\fR specifies benchmark mode\'s test data block size in bytes\. Default value is 102400
+.
+.TP
+\fB\-i\fR\fIITERATIONS\fR
+Only useful for benchmark mode (\fB\-b\fR)\. See \fIEXAMPLES\fR for details\. \fIITERATIONS\fR specifies number of iterations in benchmark\. Single iteration lasts approximately 1000 milliseconds\. Default value is 3
+.
+.SH "EXIT STATUS"
+\fBxxhsum\fR exit \fB0\fR on success, \fB1\fR if at least one file couldn\'t be read or doesn\'t have the same checksum as the \fB\-c\fR option\.
+.
+.SH "EXAMPLES"
+Output xxHash (64bit) checksum values of specific files to standard output
+.
+.IP "" 4
+.
+.nf
+
+$ xxhsum \-H1 foo bar baz
+.
+.fi
+.
+.IP "" 0
+.
+.P
+Output xxHash (32bit and 64bit) checksum values of specific files to standard output, and redirect it to \fBxyz\.xxh32\fR and \fBqux\.xxh64\fR
+.
+.IP "" 4
+.
+.nf
+
+$ xxhsum \-H0 foo bar baz > xyz\.xxh32
+$ xxhsum \-H1 foo bar baz > qux\.xxh64
+.
+.fi
+.
+.IP "" 0
+.
+.P
+Read xxHash sums from specific files and check them
+.
+.IP "" 4
+.
+.nf
+
+$ xxhsum \-c xyz\.xxh32 qux\.xxh64
+.
+.fi
+.
+.IP "" 0
+.
+.P
+Benchmark xxHash algorithm\. By default, \fBxxhsum\fR benchmarks xxHash main variants on a synthetic sample of 100 KB, and print results into standard output\. The first column is the algorithm, the second column is the source data size in bytes, the third column is the number of hashes generated per second (throughput), and finally the last column translates speed in megabytes per second\.
+.
+.IP "" 4
+.
+.nf
+
+$ xxhsum \-b
+.
+.fi
+.
+.IP "" 0
+.
+.P
+In the following example, the sample to hash is set to 16384 bytes, the variants to be benched are selected by their IDs, and each benchmark test is repeated 10 times, for increased accuracy\.
+.
+.IP "" 4
+.
+.nf
+
+$ xxhsum \-b1,2,3 \-i10 \-B16384
+.
+.fi
+.
+.IP "" 0
+.
+.SH "BUGS"
+Report bugs at: https://github\.com/Cyan4973/xxHash/issues/
+.
+.SH "AUTHOR"
+Yann Collet
+.
+.SH "SEE ALSO"
+md5sum(1)
diff --git a/grpc/third_party/xxhash/xxhsum.1.md b/grpc/third_party/xxhash/xxhsum.1.md
new file mode 100644
index 0000000..85cd8fa
--- /dev/null
+++ b/grpc/third_party/xxhash/xxhsum.1.md
@@ -0,0 +1,148 @@
+xxhsum(1) -- print or check xxHash non-cryptographic checksums
+==============================================================
+
+SYNOPSIS
+--------
+
+`xxhsum [<OPTION>] ... [<FILE>] ...`
+`xxhsum -b [<OPTION>] ...`
+
+`xxh32sum` is equivalent to `xxhsum -H0`
+`xxh64sum` is equivalent to `xxhsum -H1`
+`xxh128sum` is equivalent to `xxhsum -H2`
+
+
+DESCRIPTION
+-----------
+
+Print or check xxHash (32, 64 or 128 bits) checksums.
+When no <FILE>, read standard input, except if it's the console.
+When <FILE> is `-`, read standard input even if it's the console.
+
+`xxhsum` supports a command line syntax similar but not identical to md5sum(1).
+Differences are:
+`xxhsum` doesn't have text/binary mode switch (`-b`, `-t`);
+`xxhsum` always treats files as binary file;
+`xxhsum` has a hash bit width switch (`-H`);
+
+As xxHash is a fast non-cryptographic checksum algorithm,
+`xxhsum` should not be used for security related purposes.
+
+`xxhsum -b` invokes benchmark mode. See [OPTIONS](#OPTIONS) and [EXAMPLES](#EXAMPLES) for details.
+
+OPTIONS
+-------
+
+* `-V`, `--version`:
+  Displays xxhsum version and exits
+
+* `-H`<HASHTYPE>:
+  Hash selection. <HASHTYPE> means `0`=32bits, `1`=64bits, `2`=128bits.
+  Alternatively, <HASHTYPE> `32`=32bits, `64`=64bits, `128`=128bits.
+  Default value is `1` (64bits)
+
+* `--tag`:
+  Output in the BSD style.
+
+* `--little-endian`:
+  Set output hexadecimal checksum value as little endian convention.
+  By default, value is displayed as big endian.
+
+* `-h`, `--help`:
+  Displays help and exits
+
+**The following four options are useful only when verifying checksums (`-c`)**
+
+* `-c`, `--check` <FILE>:
+  Read xxHash sums from <FILE> and check them
+
+* `-q`, `--quiet`:
+  Don't print OK for each successfully verified file
+
+* `--strict`:
+  Return an error code if any line in the file is invalid,
+  not just if some checksums are wrong.
+  This policy is disabled by default,
+  though UI will prompt an informational message
+  if any line in the file is detected invalid.
+
+* `--status`:
+  Don't output anything. Status code shows success.
+
+* `-w`, `--warn`:
+  Emit a warning message about each improperly formatted checksum line.
+
+**The following options are useful only benchmark purpose**
+
+* `-b`:
+  Benchmark mode.  See [EXAMPLES](#EXAMPLES) for details.
+
+* `-b#`:
+  Specify ID of variant to be tested.
+  Multiple variants can be selected, separated by a ',' comma.
+
+* `-B`<BLOCKSIZE>:
+  Only useful for benchmark mode (`-b`). See [EXAMPLES](#EXAMPLES) for details.
+  <BLOCKSIZE> specifies benchmark mode's test data block size in bytes.
+  Default value is 102400
+
+* `-i`<ITERATIONS>:
+  Only useful for benchmark mode (`-b`). See [EXAMPLES](#EXAMPLES) for details.
+  <ITERATIONS> specifies number of iterations in benchmark. Single iteration
+  lasts approximately 1000 milliseconds. Default value is 3
+
+EXIT STATUS
+-----------
+
+`xxhsum` exit `0` on success, `1` if at least one file couldn't be read or
+doesn't have the same checksum as the `-c` option.
+
+EXAMPLES
+--------
+
+Output xxHash (64bit) checksum values of specific files to standard output
+
+    $ xxhsum -H1 foo bar baz
+
+Output xxHash (32bit and 64bit) checksum values of specific files to standard
+output, and redirect it to `xyz.xxh32` and `qux.xxh64`
+
+    $ xxhsum -H0 foo bar baz > xyz.xxh32
+    $ xxhsum -H1 foo bar baz > qux.xxh64
+
+Read xxHash sums from specific files and check them
+
+    $ xxhsum -c xyz.xxh32 qux.xxh64
+
+Benchmark xxHash algorithm.
+By default, `xxhsum` benchmarks xxHash main variants
+on a synthetic sample of 100 KB,
+and print results into standard output.
+The first column is the algorithm,
+the second column is the source data size in bytes,
+the third column is the number of hashes generated per second (throughput),
+and finally the last column translates speed in megabytes per second.
+
+    $ xxhsum -b
+
+In the following example,
+the sample to hash is set to 16384 bytes,
+the variants to be benched are selected by their IDs,
+and each benchmark test is repeated 10 times, for increased accuracy.
+
+    $ xxhsum -b1,2,3 -i10 -B16384
+
+BUGS
+----
+
+Report bugs at: https://github.com/Cyan4973/xxHash/issues/
+
+AUTHOR
+------
+
+Yann Collet
+
+SEE ALSO
+--------
+
+md5sum(1)
diff --git a/grpc/third_party/xxhash/xxhsum.c b/grpc/third_party/xxhash/xxhsum.c
new file mode 100644
index 0000000..8232409
--- /dev/null
+++ b/grpc/third_party/xxhash/xxhsum.c
@@ -0,0 +1,1503 @@
+/*
+ * xxhsum - Command line interface for xxhash algorithms
+ * Copyright (C) 2013-2020 Yann Collet
+ *
+ * GPL v2 License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can contact the author at:
+ *   - xxHash homepage: https://www.xxhash.com
+ *   - xxHash source repository: https://github.com/Cyan4973/xxHash
+ */
+
+/*
+ * xxhsum:
+ * Provides hash value of a file content, or a list of files, or stdin
+ * Display convention is Big Endian, for both 32 and 64 bits algorithms
+ */
+
+/* Transitional headers */
+#include "cli/xsum_config.h"
+#include "cli/xsum_arch.h"
+#include "cli/xsum_os_specific.h"
+#include "cli/xsum_output.h"
+#include "cli/xsum_sanity_check.h"
+#ifdef XXH_INLINE_ALL
+#  include "cli/xsum_os_specific.c"
+#  include "cli/xsum_output.c"
+#  include "cli/xsum_sanity_check.c"
+#endif
+
+/* ************************************
+ *  Includes
+ **************************************/
+#include <limits.h>
+#include <stdlib.h>     /* malloc, calloc, free, exit */
+#include <string.h>     /* strcmp, memcpy */
+#include <stdio.h>      /* fprintf, fopen, ftello64, fread, stdin, stdout, _fileno (when present) */
+#include <sys/types.h>  /* stat, stat64, _stat64 */
+#include <sys/stat.h>   /* stat, stat64, _stat64 */
+#include <time.h>       /* clock_t, clock, CLOCKS_PER_SEC */
+#include <assert.h>     /* assert */
+#include <errno.h>      /* errno */
+
+#define XXH_STATIC_LINKING_ONLY   /* *_state_t */
+#include "xxhash.h"
+
+#ifdef XXHSUM_DISPATCH
+#  include "xxh_x86dispatch.h"
+#endif
+
+static unsigned XSUM_isLittleEndian(void)
+{
+    const union { XSUM_U32 u; XSUM_U8 c[4]; } one = { 1 };   /* don't use static: performance detrimental  */
+    return one.c[0];
+}
+
+static const int g_nbBits = (int)(sizeof(void*)*8);
+static const char g_lename[] = "little endian";
+static const char g_bename[] = "big endian";
+#define ENDIAN_NAME (XSUM_isLittleEndian() ? g_lename : g_bename)
+static const char author[] = "Yann Collet";
+#define WELCOME_MESSAGE(exename) "%s %s by %s \n", exename, XSUM_PROGRAM_VERSION, author
+#define FULL_WELCOME_MESSAGE(exename) "%s %s by %s \n" \
+                    "compiled as %i-bit %s %s with " XSUM_CC_VERSION_FMT " \n", \
+                    exename, XSUM_PROGRAM_VERSION, author, \
+                    g_nbBits, XSUM_ARCH, ENDIAN_NAME, XSUM_CC_VERSION
+
+#define KB *( 1<<10)
+#define MB *( 1<<20)
+#define GB *(1U<<30)
+
+static size_t XSUM_DEFAULT_SAMPLE_SIZE = 100 KB;
+#define NBLOOPS    3                              /* Default number of benchmark iterations */
+#define TIMELOOP_S 1
+#define TIMELOOP  (TIMELOOP_S * CLOCKS_PER_SEC)   /* target timing per iteration */
+#define TIMELOOP_MIN (TIMELOOP / 2)               /* minimum timing to validate a result */
+#define XXHSUM32_DEFAULT_SEED 0                   /* Default seed for algo_xxh32 */
+#define XXHSUM64_DEFAULT_SEED 0                   /* Default seed for algo_xxh64 */
+
+#define MAX_MEM    (2 GB - 64 MB)
+
+static const char stdinName[] = "-";
+typedef enum { algo_xxh32=0, algo_xxh64=1, algo_xxh128=2 } AlgoSelected;
+static AlgoSelected g_defaultAlgo = algo_xxh64;    /* required within main() & XSUM_usage() */
+
+/* <16 hex char> <SPC> <SPC> <filename> <'\0'>
+ * '4096' is typical Linux PATH_MAX configuration. */
+#define DEFAULT_LINE_LENGTH (sizeof(XXH64_hash_t) * 2 + 2 + 4096 + 1)
+
+/* Maximum acceptable line length. */
+#define MAX_LINE_LENGTH (32 KB)
+
+
+/* ************************************
+ *  Display macros
+ **************************************/
+
+
+/* ************************************
+ *  Local variables
+ **************************************/
+static XSUM_U32 g_nbIterations = NBLOOPS;
+
+
+/* ************************************
+ *  Benchmark Functions
+ **************************************/
+static clock_t XSUM_clockSpan( clock_t start )
+{
+    return clock() - start;   /* works even if overflow; Typical max span ~ 30 mn */
+}
+
+static size_t XSUM_findMaxMem(XSUM_U64 requiredMem)
+{
+    size_t const step = 64 MB;
+    void* testmem = NULL;
+
+    requiredMem = (((requiredMem >> 26) + 1) << 26);
+    requiredMem += 2*step;
+    if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
+
+    while (!testmem) {
+        if (requiredMem > step) requiredMem -= step;
+        else requiredMem >>= 1;
+        testmem = malloc ((size_t)requiredMem);
+    }
+    free (testmem);
+
+    /* keep some space available */
+    if (requiredMem > step) requiredMem -= step;
+    else requiredMem >>= 1;
+
+    return (size_t)requiredMem;
+}
+
+/*
+ * Allocates a string containing s1 and s2 concatenated. Acts like strdup.
+ * The result must be freed.
+ */
+static char* XSUM_strcatDup(const char* s1, const char* s2)
+{
+    assert(s1 != NULL);
+    assert(s2 != NULL);
+    {   size_t len1 = strlen(s1);
+        size_t len2 = strlen(s2);
+        char* buf = (char*)malloc(len1 + len2 + 1);
+        if (buf != NULL) {
+            /* strcpy(buf, s1) */
+            memcpy(buf, s1, len1);
+            /* strcat(buf, s2) */
+            memcpy(buf + len1, s2, len2 + 1);
+        }
+        return buf;
+    }
+}
+
+
+/*
+ * A secret buffer used for benchmarking XXH3's withSecret variants.
+ *
+ * In order for the bench to be realistic, the secret buffer would need to be
+ * pre-generated.
+ *
+ * Adding a pointer to the parameter list would be messy.
+ */
+static XSUM_U8 g_benchSecretBuf[XXH3_SECRET_SIZE_MIN];
+
+/*
+ * Wrappers for the benchmark.
+ *
+ * If you would like to add other hashes to the bench, create a wrapper and add
+ * it to the g_hashesToBench table. It will automatically be added.
+ */
+typedef XSUM_U32 (*hashFunction)(const void* buffer, size_t bufferSize, XSUM_U32 seed);
+
+static XSUM_U32 localXXH32(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    return XXH32(buffer, bufferSize, seed);
+}
+static XSUM_U32 localXXH64(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    return (XSUM_U32)XXH64(buffer, bufferSize, seed);
+}
+static XSUM_U32 localXXH3_64b(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    (void)seed;
+    return (XSUM_U32)XXH3_64bits(buffer, bufferSize);
+}
+static XSUM_U32 localXXH3_64b_seeded(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    return (XSUM_U32)XXH3_64bits_withSeed(buffer, bufferSize, seed);
+}
+static XSUM_U32 localXXH3_64b_secret(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    (void)seed;
+    return (XSUM_U32)XXH3_64bits_withSecret(buffer, bufferSize, g_benchSecretBuf, sizeof(g_benchSecretBuf));
+}
+static XSUM_U32 localXXH3_128b(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    (void)seed;
+    return (XSUM_U32)(XXH3_128bits(buffer, bufferSize).low64);
+}
+static XSUM_U32 localXXH3_128b_seeded(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    return (XSUM_U32)(XXH3_128bits_withSeed(buffer, bufferSize, seed).low64);
+}
+static XSUM_U32 localXXH3_128b_secret(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    (void)seed;
+    return (XSUM_U32)(XXH3_128bits_withSecret(buffer, bufferSize, g_benchSecretBuf, sizeof(g_benchSecretBuf)).low64);
+}
+static XSUM_U32 localXXH3_stream(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    XXH3_state_t state;
+    (void)seed;
+    XXH3_64bits_reset(&state);
+    XXH3_64bits_update(&state, buffer, bufferSize);
+    return (XSUM_U32)XXH3_64bits_digest(&state);
+}
+static XSUM_U32 localXXH3_stream_seeded(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    XXH3_state_t state;
+    XXH3_INITSTATE(&state);
+    XXH3_64bits_reset_withSeed(&state, (XXH64_hash_t)seed);
+    XXH3_64bits_update(&state, buffer, bufferSize);
+    return (XSUM_U32)XXH3_64bits_digest(&state);
+}
+static XSUM_U32 localXXH128_stream(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    XXH3_state_t state;
+    (void)seed;
+    XXH3_128bits_reset(&state);
+    XXH3_128bits_update(&state, buffer, bufferSize);
+    return (XSUM_U32)(XXH3_128bits_digest(&state).low64);
+}
+static XSUM_U32 localXXH128_stream_seeded(const void* buffer, size_t bufferSize, XSUM_U32 seed)
+{
+    XXH3_state_t state;
+    XXH3_INITSTATE(&state);
+    XXH3_128bits_reset_withSeed(&state, (XXH64_hash_t)seed);
+    XXH3_128bits_update(&state, buffer, bufferSize);
+    return (XSUM_U32)(XXH3_128bits_digest(&state).low64);
+}
+
+
+typedef struct {
+    const char*  name;
+    hashFunction func;
+} hashInfo;
+
+#define NB_HASHFUNC 12
+static const hashInfo g_hashesToBench[NB_HASHFUNC] = {
+    { "XXH32",             &localXXH32 },
+    { "XXH64",             &localXXH64 },
+    { "XXH3_64b",          &localXXH3_64b },
+    { "XXH3_64b w/seed",   &localXXH3_64b_seeded },
+    { "XXH3_64b w/secret", &localXXH3_64b_secret },
+    { "XXH128",            &localXXH3_128b },
+    { "XXH128 w/seed",     &localXXH3_128b_seeded },
+    { "XXH128 w/secret",   &localXXH3_128b_secret },
+    { "XXH3_stream",       &localXXH3_stream },
+    { "XXH3_stream w/seed",&localXXH3_stream_seeded },
+    { "XXH128_stream",     &localXXH128_stream },
+    { "XXH128_stream w/seed",&localXXH128_stream_seeded },
+};
+
+#define NB_TESTFUNC (1 + 2 * NB_HASHFUNC)
+static char g_testIDs[NB_TESTFUNC] = { 0 };
+static const char k_testIDs_default[NB_TESTFUNC] = { 0,
+        1 /*XXH32*/, 0,
+        1 /*XXH64*/, 0,
+        1 /*XXH3*/, 0, 0, 0, 0, 0,
+        1 /*XXH128*/ };
+
+#define HASHNAME_MAX 29
+static void XSUM_benchHash(hashFunction h, const char* hName, int testID,
+                          const void* buffer, size_t bufferSize)
+{
+    XSUM_U32 nbh_perIteration = (XSUM_U32)((300 MB) / (bufferSize+1)) + 1;  /* first iteration conservatively aims for 300 MB/s */
+    unsigned iterationNb, nbIterations = g_nbIterations + !g_nbIterations /* min 1 */;
+    double fastestH = 100000000.;
+    assert(HASHNAME_MAX > 2);
+    XSUM_logVerbose(2, "\r%80s\r", "");       /* Clean display line */
+
+    for (iterationNb = 1; iterationNb <= nbIterations; iterationNb++) {
+        XSUM_U32 r=0;
+        clock_t cStart;
+
+        XSUM_logVerbose(2, "%2u-%-*.*s : %10u ->\r",
+                        iterationNb,
+                        HASHNAME_MAX, HASHNAME_MAX, hName,
+                        (unsigned)bufferSize);
+        cStart = clock();
+        while (clock() == cStart);   /* starts clock() at its exact beginning */
+        cStart = clock();
+
+        {   XSUM_U32 u;
+            for (u=0; u<nbh_perIteration; u++)
+                r += h(buffer, bufferSize, u);
+        }
+        if (r==0) XSUM_logVerbose(3,".\r");  /* do something with r to defeat compiler "optimizing" hash away */
+
+        {   clock_t const nbTicks = XSUM_clockSpan(cStart);
+            double const ticksPerHash = ((double)nbTicks / TIMELOOP) / nbh_perIteration;
+            /*
+             * clock() is the only decent portable timer, but it isn't very
+             * precise.
+             *
+             * Sometimes, this lack of precision is enough that the benchmark
+             * finishes before there are enough ticks to get a meaningful result.
+             *
+             * For example, on a Core 2 Duo (without any sort of Turbo Boost),
+             * the imprecise timer caused peculiar results like so:
+             *
+             *    XXH3_64b                   4800.0 MB/s // conveniently even
+             *    XXH3_64b unaligned         4800.0 MB/s
+             *    XXH3_64b seeded            9600.0 MB/s // magical 2x speedup?!
+             *    XXH3_64b seeded unaligned  4800.0 MB/s
+             *
+             * If we sense a suspiciously low number of ticks, we increase the
+             * iterations until we can get something meaningful.
+             */
+            if (nbTicks < TIMELOOP_MIN) {
+                /* Not enough time spent in benchmarking, risk of rounding bias */
+                if (nbTicks == 0) { /* faster than resolution timer */
+                    nbh_perIteration *= 100;
+                } else {
+                    /*
+                     * update nbh_perIteration so that the next round lasts
+                     * approximately 1 second.
+                     */
+                    double nbh_perSecond = (1 / ticksPerHash) + 1;
+                    if (nbh_perSecond > (double)(4000U<<20)) nbh_perSecond = (double)(4000U<<20);   /* avoid overflow */
+                    nbh_perIteration = (XSUM_U32)nbh_perSecond;
+                }
+                /* g_nbIterations==0 => quick evaluation, no claim of accuracy */
+                if (g_nbIterations>0) {
+                    iterationNb--;   /* new round for a more accurate speed evaluation */
+                    continue;
+                }
+            }
+            if (ticksPerHash < fastestH) fastestH = ticksPerHash;
+            if (fastestH>0.) { /* avoid div by zero */
+                XSUM_logVerbose(2, "%2u-%-*.*s : %10u -> %8.0f it/s (%7.1f MB/s) \r",
+                            iterationNb,
+                            HASHNAME_MAX, HASHNAME_MAX, hName,
+                            (unsigned)bufferSize,
+                            (double)1 / fastestH,
+                            ((double)bufferSize / (1 MB)) / fastestH);
+        }   }
+        {   double nbh_perSecond = (1 / fastestH) + 1;
+            if (nbh_perSecond > (double)(4000U<<20)) nbh_perSecond = (double)(4000U<<20);   /* avoid overflow */
+            nbh_perIteration = (XSUM_U32)nbh_perSecond;
+        }
+    }
+    XSUM_logVerbose(1, "%2i#%-*.*s : %10u -> %8.0f it/s (%7.1f MB/s) \n",
+                    testID,
+                    HASHNAME_MAX, HASHNAME_MAX, hName,
+                    (unsigned)bufferSize,
+                    (double)1 / fastestH,
+                    ((double)bufferSize / (1 MB)) / fastestH);
+    if (XSUM_logLevel<1)
+        XSUM_logVerbose(0, "%u, ", (unsigned)((double)1 / fastestH));
+}
+
+
+/*!
+ * XSUM_benchMem():
+ * buffer: Must be 16-byte aligned.
+ * The real allocated size of buffer is supposed to be >= (bufferSize+3).
+ * returns: 0 on success, 1 if error (invalid mode selected)
+ */
+static void XSUM_benchMem(const void* buffer, size_t bufferSize)
+{
+    assert((((size_t)buffer) & 15) == 0);  /* ensure alignment */
+    XSUM_fillTestBuffer(g_benchSecretBuf, sizeof(g_benchSecretBuf));
+    {   int i;
+        for (i = 1; i < NB_TESTFUNC; i++) {
+            int const hashFuncID = (i-1) / 2;
+            assert(g_hashesToBench[hashFuncID].name != NULL);
+            if (g_testIDs[i] == 0) continue;
+            /* aligned */
+            if ((i % 2) == 1) {
+                XSUM_benchHash(g_hashesToBench[hashFuncID].func, g_hashesToBench[hashFuncID].name, i, buffer, bufferSize);
+            }
+            /* unaligned */
+            if ((i % 2) == 0) {
+                /* Append "unaligned". */
+                char* const hashNameBuf = XSUM_strcatDup(g_hashesToBench[hashFuncID].name, " unaligned");
+                assert(hashNameBuf != NULL);
+                XSUM_benchHash(g_hashesToBench[hashFuncID].func, hashNameBuf, i, ((const char*)buffer)+3, bufferSize);
+                free(hashNameBuf);
+            }
+    }   }
+}
+
+static size_t XSUM_selectBenchedSize(const char* fileName)
+{
+    XSUM_U64 const inFileSize = XSUM_getFileSize(fileName);
+    size_t benchedSize = (size_t) XSUM_findMaxMem(inFileSize);
+    if ((XSUM_U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
+    if (benchedSize < inFileSize) {
+        XSUM_log("Not enough memory for '%s' full size; testing %i MB only...\n", fileName, (int)(benchedSize>>20));
+    }
+    return benchedSize;
+}
+
+
+static int XSUM_benchFiles(char*const* fileNamesTable, int nbFiles)
+{
+    int fileIdx;
+    for (fileIdx=0; fileIdx<nbFiles; fileIdx++) {
+        const char* const inFileName = fileNamesTable[fileIdx];
+        assert(inFileName != NULL);
+
+        {   FILE* const inFile = XSUM_fopen( inFileName, "rb" );
+            size_t const benchedSize = XSUM_selectBenchedSize(inFileName);
+            char* const buffer = (char*)calloc(benchedSize+16+3, 1);
+            void* const alignedBuffer = (buffer+15) - (((size_t)(buffer+15)) & 0xF);  /* align on next 16 bytes */
+
+            /* Checks */
+            if (inFile==NULL){
+                XSUM_log("Error: Could not open '%s': %s.\n", inFileName, strerror(errno));
+                free(buffer);
+                exit(11);
+            }
+            if(!buffer) {
+                XSUM_log("\nError: Out of memory.\n");
+                fclose(inFile);
+                exit(12);
+            }
+
+            /* Fill input buffer */
+            {   size_t const readSize = fread(alignedBuffer, 1, benchedSize, inFile);
+                fclose(inFile);
+                if(readSize != benchedSize) {
+                    XSUM_log("\nError: Could not read '%s': %s.\n", inFileName, strerror(errno));
+                    free(buffer);
+                    exit(13);
+            }   }
+
+            /* bench */
+            XSUM_benchMem(alignedBuffer, benchedSize);
+
+            free(buffer);
+    }   }
+    return 0;
+}
+
+
+static int XSUM_benchInternal(size_t keySize)
+{
+    void* const buffer = calloc(keySize+16+3, 1);
+    if (buffer == NULL) {
+        XSUM_log("\nError: Out of memory.\n");
+        exit(12);
+    }
+
+    {   const void* const alignedBuffer = ((char*)buffer+15) - (((size_t)((char*)buffer+15)) & 0xF);  /* align on next 16 bytes */
+
+        /* bench */
+        XSUM_logVerbose(1, "Sample of ");
+        if (keySize > 10 KB) {
+            XSUM_logVerbose(1, "%u KB", (unsigned)(keySize >> 10));
+        } else {
+            XSUM_logVerbose(1, "%u bytes", (unsigned)keySize);
+        }
+        XSUM_logVerbose(1, "...        \n");
+
+        XSUM_benchMem(alignedBuffer, keySize);
+        free(buffer);
+    }
+    return 0;
+}
+
+/* ********************************************************
+*  File Hashing
+**********************************************************/
+
+/* for support of --little-endian display mode */
+static void XSUM_display_LittleEndian(const void* ptr, size_t length)
+{
+    const XSUM_U8* const p = (const XSUM_U8*)ptr;
+    size_t idx;
+    for (idx=length-1; idx<length; idx--)    /* intentional underflow to negative to detect end */
+        XSUM_output("%02x", p[idx]);
+}
+
+static void XSUM_display_BigEndian(const void* ptr, size_t length)
+{
+    const XSUM_U8* const p = (const XSUM_U8*)ptr;
+    size_t idx;
+    for (idx=0; idx<length; idx++)
+        XSUM_output("%02x", p[idx]);
+}
+
+typedef union {
+    XXH32_hash_t   xxh32;
+    XXH64_hash_t   xxh64;
+    XXH128_hash_t xxh128;
+} Multihash;
+
+/*
+ * XSUM_hashStream:
+ * Reads data from `inFile`, generating an incremental hash of type hashType,
+ * using `buffer` of size `blockSize` for temporary storage.
+ */
+static Multihash
+XSUM_hashStream(FILE* inFile,
+                AlgoSelected hashType,
+                void* buffer, size_t blockSize)
+{
+    XXH32_state_t state32;
+    XXH64_state_t state64;
+    XXH3_state_t state128;
+
+    /* Init */
+    (void)XXH32_reset(&state32, XXHSUM32_DEFAULT_SEED);
+    (void)XXH64_reset(&state64, XXHSUM64_DEFAULT_SEED);
+    (void)XXH3_128bits_reset(&state128);
+
+    /* Load file & update hash */
+    {   size_t readSize;
+        while ((readSize = fread(buffer, 1, blockSize, inFile)) > 0) {
+            switch(hashType)
+            {
+            case algo_xxh32:
+                (void)XXH32_update(&state32, buffer, readSize);
+                break;
+            case algo_xxh64:
+                (void)XXH64_update(&state64, buffer, readSize);
+                break;
+            case algo_xxh128:
+                (void)XXH3_128bits_update(&state128, buffer, readSize);
+                break;
+            default:
+                assert(0);
+            }
+        }
+        if (ferror(inFile)) {
+            XSUM_log("Error: a failure occurred reading the input file.\n");
+            exit(1);
+    }   }
+
+    {   Multihash finalHash = {0};
+        switch(hashType)
+        {
+        case algo_xxh32:
+            finalHash.xxh32 = XXH32_digest(&state32);
+            break;
+        case algo_xxh64:
+            finalHash.xxh64 = XXH64_digest(&state64);
+            break;
+        case algo_xxh128:
+            finalHash.xxh128 = XXH3_128bits_digest(&state128);
+            break;
+        default:
+            assert(0);
+        }
+        return finalHash;
+    }
+}
+
+                                       /* algo_xxh32, algo_xxh64, algo_xxh128 */
+static const char* XSUM_algoName[] =    { "XXH32",    "XXH64",    "XXH128" };
+static const char* XSUM_algoLE_name[] = { "XXH32_LE", "XXH64_LE", "XXH128_LE" };
+static const size_t XSUM_algoLength[] = { 4,          8,          16 };
+
+#define XSUM_TABLE_ELT_SIZE(table)   (sizeof(table) / sizeof(*table))
+
+typedef void (*XSUM_displayHash_f)(const void*, size_t);  /* display function signature */
+
+static void XSUM_printLine_BSD_internal(const char* filename,
+                                        const void* canonicalHash, const AlgoSelected hashType,
+                                        const char* algoString[],
+                                        XSUM_displayHash_f f_displayHash)
+{
+    assert(0 <= hashType && hashType <= XSUM_TABLE_ELT_SIZE(XSUM_algoName));
+    {   const char* const typeString = algoString[hashType];
+        const size_t hashLength = XSUM_algoLength[hashType];
+        XSUM_output("%s (%s) = ", typeString, filename);
+        f_displayHash(canonicalHash, hashLength);
+        XSUM_output("\n");
+}   }
+
+static void XSUM_printLine_BSD_LE(const char* filename, const void* canonicalHash, const AlgoSelected hashType)
+{
+    XSUM_printLine_BSD_internal(filename, canonicalHash, hashType, XSUM_algoLE_name, XSUM_display_LittleEndian);
+}
+
+static void XSUM_printLine_BSD(const char* filename, const void* canonicalHash, const AlgoSelected hashType)
+{
+    XSUM_printLine_BSD_internal(filename, canonicalHash, hashType, XSUM_algoName, XSUM_display_BigEndian);
+}
+
+static void XSUM_printLine_GNU_internal(const char* filename,
+                               const void* canonicalHash, const AlgoSelected hashType,
+                               XSUM_displayHash_f f_displayHash)
+{
+    assert(0 <= hashType && hashType <= XSUM_TABLE_ELT_SIZE(XSUM_algoName));
+    {   const size_t hashLength = XSUM_algoLength[hashType];
+        f_displayHash(canonicalHash, hashLength);
+        XSUM_output("  %s\n", filename);
+}   }
+
+static void XSUM_printLine_GNU(const char* filename,
+                               const void* canonicalHash, const AlgoSelected hashType)
+{
+    XSUM_printLine_GNU_internal(filename, canonicalHash, hashType, XSUM_display_BigEndian);
+}
+
+static void XSUM_printLine_GNU_LE(const char* filename,
+                                  const void* canonicalHash, const AlgoSelected hashType)
+{
+    XSUM_printLine_GNU_internal(filename, canonicalHash, hashType, XSUM_display_LittleEndian);
+}
+
+typedef enum { big_endian, little_endian} Display_endianess;
+
+typedef enum { display_gnu, display_bsd } Display_convention;
+
+typedef void (*XSUM_displayLine_f)(const char*, const void*, AlgoSelected);  /* line display signature */
+
+static XSUM_displayLine_f XSUM_kDisplayLine_fTable[2][2] = {
+    { XSUM_printLine_GNU, XSUM_printLine_GNU_LE },
+    { XSUM_printLine_BSD, XSUM_printLine_BSD_LE }
+};
+
+static int XSUM_hashFile(const char* fileName,
+                         const AlgoSelected hashType,
+                         const Display_endianess displayEndianess,
+                         const Display_convention convention)
+{
+    size_t const blockSize = 64 KB;
+    XSUM_displayLine_f const f_displayLine = XSUM_kDisplayLine_fTable[convention][displayEndianess];
+    FILE* inFile;
+    Multihash hashValue;
+    assert(displayEndianess==big_endian || displayEndianess==little_endian);
+    assert(convention==display_gnu || convention==display_bsd);
+
+    /* Check file existence */
+    if (fileName == stdinName) {
+        inFile = stdin;
+        fileName = "stdin";
+        XSUM_setBinaryMode(stdin);
+    } else {
+        if (XSUM_isDirectory(fileName)) {
+            XSUM_log("xxhsum: %s: Is a directory \n", fileName);
+            return 1;
+        }
+        inFile = XSUM_fopen( fileName, "rb" );
+        if (inFile==NULL) {
+            XSUM_log("Error: Could not open '%s': %s. \n", fileName, strerror(errno));
+            return 1;
+    }   }
+
+    /* Memory allocation & streaming */
+    {   void* const buffer = malloc(blockSize);
+        if (buffer == NULL) {
+            XSUM_log("\nError: Out of memory.\n");
+            fclose(inFile);
+            return 1;
+        }
+
+        /* Stream file & update hash */
+        hashValue = XSUM_hashStream(inFile, hashType, buffer, blockSize);
+
+        fclose(inFile);
+        free(buffer);
+    }
+
+    /* display Hash value in selected format */
+    switch(hashType)
+    {
+    case algo_xxh32:
+        {   XXH32_canonical_t hcbe32;
+            (void)XXH32_canonicalFromHash(&hcbe32, hashValue.xxh32);
+            f_displayLine(fileName, &hcbe32, hashType);
+            break;
+        }
+    case algo_xxh64:
+        {   XXH64_canonical_t hcbe64;
+            (void)XXH64_canonicalFromHash(&hcbe64, hashValue.xxh64);
+            f_displayLine(fileName, &hcbe64, hashType);
+            break;
+        }
+    case algo_xxh128:
+        {   XXH128_canonical_t hcbe128;
+            (void)XXH128_canonicalFromHash(&hcbe128, hashValue.xxh128);
+            f_displayLine(fileName, &hcbe128, hashType);
+            break;
+        }
+    default:
+        assert(0);  /* not possible */
+    }
+
+    return 0;
+}
+
+
+/*
+ * XSUM_hashFiles:
+ * If fnTotal==0, read from stdin instead.
+ */
+static int XSUM_hashFiles(char*const * fnList, int fnTotal,
+                          AlgoSelected hashType,
+                          Display_endianess displayEndianess,
+                          Display_convention convention)
+{
+    int fnNb;
+    int result = 0;
+
+    if (fnTotal==0)
+        return XSUM_hashFile(stdinName, hashType, displayEndianess, convention);
+
+    for (fnNb=0; fnNb<fnTotal; fnNb++)
+        result |= XSUM_hashFile(fnList[fnNb], hashType, displayEndianess, convention);
+    XSUM_logVerbose(2, "\r%70s\r", "");
+    return result;
+}
+
+
+typedef enum {
+    GetLine_ok,
+    GetLine_eof,
+    GetLine_exceedMaxLineLength,
+    GetLine_outOfMemory
+} GetLineResult;
+
+typedef enum {
+    CanonicalFromString_ok,
+    CanonicalFromString_invalidFormat
+} CanonicalFromStringResult;
+
+typedef enum {
+    ParseLine_ok,
+    ParseLine_invalidFormat
+} ParseLineResult;
+
+typedef enum {
+    LineStatus_hashOk,
+    LineStatus_hashFailed,
+    LineStatus_failedToOpen
+} LineStatus;
+
+typedef union {
+    XXH32_canonical_t xxh32;
+    XXH64_canonical_t xxh64;
+    XXH128_canonical_t xxh128;
+} Canonical;
+
+typedef struct {
+    Canonical   canonical;
+    const char* filename;
+    int         xxhBits;    /* canonical type: 32:xxh32, 64:xxh64, 128:xxh128 */
+} ParsedLine;
+
+typedef struct {
+    unsigned long   nProperlyFormattedLines;
+    unsigned long   nImproperlyFormattedLines;
+    unsigned long   nMismatchedChecksums;
+    unsigned long   nOpenOrReadFailures;
+    unsigned long   nMixedFormatLines;
+    int             quit;
+} ParseFileReport;
+
+typedef struct {
+    const char*     inFileName;
+    FILE*           inFile;
+    int             lineMax;
+    char*           lineBuf;
+    size_t          blockSize;
+    char*           blockBuf;
+    XSUM_U32             strictMode;
+    XSUM_U32             statusOnly;
+    XSUM_U32             warn;
+    XSUM_U32             quiet;
+    ParseFileReport report;
+} ParseFileArg;
+
+
+/*
+ * Reads a line from stream `inFile`.
+ * Returns GetLine_ok, if it reads line successfully.
+ * Returns GetLine_eof, if stream reaches EOF.
+ * Returns GetLine_exceedMaxLineLength, if line length is longer than MAX_LINE_LENGTH.
+ * Returns GetLine_outOfMemory, if line buffer memory allocation failed.
+ */
+static GetLineResult XSUM_getLine(char** lineBuf, int* lineMax, FILE* inFile)
+{
+    GetLineResult result = GetLine_ok;
+    size_t len = 0;
+
+    if ((*lineBuf == NULL) || (*lineMax<1)) {
+        free(*lineBuf);  /* in case it's != NULL */
+        *lineMax = 0;
+        *lineBuf = (char*)malloc(DEFAULT_LINE_LENGTH);
+        if(*lineBuf == NULL) return GetLine_outOfMemory;
+        *lineMax = DEFAULT_LINE_LENGTH;
+    }
+
+    for (;;) {
+        const int c = fgetc(inFile);
+        if (c == EOF) {
+            /*
+             * If we meet EOF before first character, returns GetLine_eof,
+             * otherwise GetLine_ok.
+             */
+            if (len == 0) result = GetLine_eof;
+            break;
+        }
+
+        /* Make enough space for len+1 (for final NUL) bytes. */
+        if (len+1 >= (size_t)*lineMax) {
+            char* newLineBuf = NULL;
+            size_t newBufSize = (size_t)*lineMax;
+
+            newBufSize += (newBufSize/2) + 1; /* x 1.5 */
+            if (newBufSize > MAX_LINE_LENGTH) newBufSize = MAX_LINE_LENGTH;
+            if (len+1 >= newBufSize) return GetLine_exceedMaxLineLength;
+
+            newLineBuf = (char*) realloc(*lineBuf, newBufSize);
+            if (newLineBuf == NULL) return GetLine_outOfMemory;
+
+            *lineBuf = newLineBuf;
+            *lineMax = (int)newBufSize;
+        }
+
+        if (c == '\n') break;
+        (*lineBuf)[len++] = (char) c;
+    }
+
+    (*lineBuf)[len] = '\0';
+    return result;
+}
+
+
+/*
+ * Converts one hexadecimal character to integer.
+ * Returns -1 if the given character is not hexadecimal.
+ */
+static int charToHex(char c)
+{
+    int result = -1;
+    if (c >= '0' && c <= '9') {
+        result = (int) (c - '0');
+    } else if (c >= 'A' && c <= 'F') {
+        result = (int) (c - 'A') + 0x0a;
+    } else if (c >= 'a' && c <= 'f') {
+        result = (int) (c - 'a') + 0x0a;
+    }
+    return result;
+}
+
+
+/*
+ * Converts canonical ASCII hexadecimal string `hashStr`
+ * to the big endian binary representation in unsigned char array `dst`.
+ *
+ * Returns CanonicalFromString_invalidFormat if hashStr is not well formatted.
+ * Returns CanonicalFromString_ok if hashStr is parsed successfully.
+ */
+static CanonicalFromStringResult XSUM_canonicalFromString(unsigned char* dst,
+                                                          size_t dstSize,
+                                                          const char* hashStr,
+                                                          int reverseBytes)
+{
+    size_t i;
+    for (i = 0; i < dstSize; ++i) {
+        int h0, h1;
+        size_t j = reverseBytes ? dstSize - i - 1 : i;
+
+        h0 = charToHex(hashStr[j*2 + 0]);
+        if (h0 < 0) return CanonicalFromString_invalidFormat;
+
+        h1 = charToHex(hashStr[j*2 + 1]);
+        if (h1 < 0) return CanonicalFromString_invalidFormat;
+
+        dst[i] = (unsigned char) ((h0 << 4) | h1);
+    }
+    return CanonicalFromString_ok;
+}
+
+
+/*
+ * Parse single line of xxHash checksum file.
+ * Returns ParseLine_invalidFormat if the line is not well formatted.
+ * Returns ParseLine_ok if the line is parsed successfully.
+ * And members of XSUM_parseLine will be filled by parsed values.
+ *
+ *  - line must be terminated with '\0' without a trailing newline.
+ *  - Since parsedLine.filename will point within given argument `line`,
+ *    users must keep `line`s content when they are using parsedLine.
+ *  - The line may be modified to carve up the information it contains.
+ *
+ * xxHash checksum lines should have the following format:
+ *
+ *      <8, 16, or 32 hexadecimal char> <space> <space> <filename...> <'\0'>
+ *
+ * or:
+ *
+ *      <algorithm> <' ('> <filename> <') = '> <hexstring> <'\0'>
+ */
+static ParseLineResult XSUM_parseLine(ParsedLine* parsedLine, char* line, int rev)
+{
+    char* const firstSpace = strchr(line, ' ');
+    const char* hash_ptr;
+    size_t hash_len;
+
+    parsedLine->filename = NULL;
+    parsedLine->xxhBits = 0;
+
+    if (firstSpace == NULL || !firstSpace[1]) return ParseLine_invalidFormat;
+
+    if (firstSpace[1] == '(') {
+        char* lastSpace = strrchr(line, ' ');
+        if (lastSpace - firstSpace < 5) return ParseLine_invalidFormat;
+        if (lastSpace[-1] != '=' || lastSpace[-2] != ' ' || lastSpace[-3] != ')') return ParseLine_invalidFormat;
+        lastSpace[-3] = '\0'; /* Terminate the filename */
+        *firstSpace = '\0';
+        rev = strstr(line, "_LE") != NULL; /* was output little-endian */
+        hash_ptr = lastSpace + 1;
+        hash_len = strlen(hash_ptr);
+        /* NOTE: This currently ignores the hash description at the start of the string.
+         * In the future we should parse it and verify that it matches the hash length.
+         * It could also be used to allow both XXH64 & XXH3_64bits to be differentiated. */
+    } else {
+        hash_ptr = line;
+        hash_len = (size_t)(firstSpace - line);
+    }
+
+    switch (hash_len)
+    {
+    case 8:
+        {   XXH32_canonical_t* xxh32c = &parsedLine->canonical.xxh32;
+            if (XSUM_canonicalFromString(xxh32c->digest, sizeof(xxh32c->digest), hash_ptr, rev)
+                != CanonicalFromString_ok) {
+                return ParseLine_invalidFormat;
+            }
+            parsedLine->xxhBits = 32;
+            break;
+        }
+
+    case 16:
+        {   XXH64_canonical_t* xxh64c = &parsedLine->canonical.xxh64;
+            if (XSUM_canonicalFromString(xxh64c->digest, sizeof(xxh64c->digest), hash_ptr, rev)
+                != CanonicalFromString_ok) {
+                return ParseLine_invalidFormat;
+            }
+            parsedLine->xxhBits = 64;
+            break;
+        }
+
+    case 32:
+        {   XXH128_canonical_t* xxh128c = &parsedLine->canonical.xxh128;
+            if (XSUM_canonicalFromString(xxh128c->digest, sizeof(xxh128c->digest), hash_ptr, rev)
+                != CanonicalFromString_ok) {
+                return ParseLine_invalidFormat;
+            }
+            parsedLine->xxhBits = 128;
+            break;
+        }
+
+    default:
+            return ParseLine_invalidFormat;
+            break;
+    }
+
+    /* note : skipping second separation character, which can be anything,
+     * allowing insertion of custom markers such as '*' */
+    parsedLine->filename = firstSpace + 2;
+    return ParseLine_ok;
+}
+
+
+/*!
+ * Parse xxHash checksum file.
+ */
+static void XSUM_parseFile1(ParseFileArg* XSUM_parseFileArg, int rev)
+{
+    const char* const inFileName = XSUM_parseFileArg->inFileName;
+    ParseFileReport* const report = &XSUM_parseFileArg->report;
+
+    unsigned long lineNumber = 0;
+    memset(report, 0, sizeof(*report));
+
+    while (!report->quit) {
+        LineStatus lineStatus = LineStatus_hashFailed;
+        ParsedLine parsedLine;
+        memset(&parsedLine, 0, sizeof(parsedLine));
+
+        lineNumber++;
+        if (lineNumber == 0) {
+            /* This is unlikely happen, but md5sum.c has this error check. */
+            XSUM_log("%s: Error: Too many checksum lines\n", inFileName);
+            report->quit = 1;
+            break;
+        }
+
+        {   GetLineResult const XSUM_getLineResult = XSUM_getLine(&XSUM_parseFileArg->lineBuf,
+                                                        &XSUM_parseFileArg->lineMax,
+                                                         XSUM_parseFileArg->inFile);
+            if (XSUM_getLineResult != GetLine_ok) {
+                if (XSUM_getLineResult == GetLine_eof) break;
+
+                switch (XSUM_getLineResult)
+                {
+                case GetLine_ok:
+                case GetLine_eof:
+                    /* These cases never happen.  See above XSUM_getLineResult related "if"s.
+                       They exist just for make gcc's -Wswitch-enum happy. */
+                    assert(0);
+                    break;
+
+                default:
+                    XSUM_log("%s:%lu: Error: Unknown error.\n", inFileName, lineNumber);
+                    break;
+
+                case GetLine_exceedMaxLineLength:
+                    XSUM_log("%s:%lu: Error: Line too long.\n", inFileName, lineNumber);
+                    break;
+
+                case GetLine_outOfMemory:
+                    XSUM_log("%s:%lu: Error: Out of memory.\n", inFileName, lineNumber);
+                    break;
+                }
+                report->quit = 1;
+                break;
+        }   }
+
+        if (XSUM_parseLine(&parsedLine, XSUM_parseFileArg->lineBuf, rev) != ParseLine_ok) {
+            report->nImproperlyFormattedLines++;
+            if (XSUM_parseFileArg->warn) {
+                XSUM_log("%s:%lu: Error: Improperly formatted checksum line.\n",
+                        inFileName, lineNumber);
+            }
+            continue;
+        }
+
+        report->nProperlyFormattedLines++;
+
+        do {
+            FILE* const fp = XSUM_fopen(parsedLine.filename, "rb");
+            if (fp == NULL) {
+                lineStatus = LineStatus_failedToOpen;
+                break;
+            }
+            lineStatus = LineStatus_hashFailed;
+            switch (parsedLine.xxhBits)
+            {
+            case 32:
+                {   Multihash const xxh = XSUM_hashStream(fp, algo_xxh32, XSUM_parseFileArg->blockBuf, XSUM_parseFileArg->blockSize);
+                    if (xxh.xxh32 == XXH32_hashFromCanonical(&parsedLine.canonical.xxh32)) {
+                        lineStatus = LineStatus_hashOk;
+                }   }
+                break;
+
+            case 64:
+                {   Multihash const xxh = XSUM_hashStream(fp, algo_xxh64, XSUM_parseFileArg->blockBuf, XSUM_parseFileArg->blockSize);
+                    if (xxh.xxh64 == XXH64_hashFromCanonical(&parsedLine.canonical.xxh64)) {
+                        lineStatus = LineStatus_hashOk;
+                }   }
+                break;
+
+            case 128:
+                {   Multihash const xxh = XSUM_hashStream(fp, algo_xxh128, XSUM_parseFileArg->blockBuf, XSUM_parseFileArg->blockSize);
+                    if (XXH128_isEqual(xxh.xxh128, XXH128_hashFromCanonical(&parsedLine.canonical.xxh128))) {
+                        lineStatus = LineStatus_hashOk;
+                }   }
+                break;
+
+            default:
+                break;
+            }
+            fclose(fp);
+        } while (0);
+
+        switch (lineStatus)
+        {
+        default:
+            XSUM_log("%s: Error: Unknown error.\n", inFileName);
+            report->quit = 1;
+            break;
+
+        case LineStatus_failedToOpen:
+            report->nOpenOrReadFailures++;
+            if (!XSUM_parseFileArg->statusOnly) {
+                XSUM_output("%s:%lu: Could not open or read '%s': %s.\n",
+                    inFileName, lineNumber, parsedLine.filename, strerror(errno));
+            }
+            break;
+
+        case LineStatus_hashOk:
+        case LineStatus_hashFailed:
+            {   int b = 1;
+                if (lineStatus == LineStatus_hashOk) {
+                    /* If --quiet is specified, don't display "OK" */
+                    if (XSUM_parseFileArg->quiet) b = 0;
+                } else {
+                    report->nMismatchedChecksums++;
+                }
+
+                if (b && !XSUM_parseFileArg->statusOnly) {
+                    XSUM_output("%s: %s\n", parsedLine.filename
+                        , lineStatus == LineStatus_hashOk ? "OK" : "FAILED");
+            }   }
+            break;
+        }
+    }   /* while (!report->quit) */
+}
+
+
+/*  Parse xxHash checksum file.
+ *  Returns 1, if all procedures were succeeded.
+ *  Returns 0, if any procedures was failed.
+ *
+ *  If strictMode != 0, return error code if any line is invalid.
+ *  If statusOnly != 0, don't generate any output.
+ *  If warn != 0, print a warning message to stderr.
+ *  If quiet != 0, suppress "OK" line.
+ *
+ *  "All procedures are succeeded" means:
+ *    - Checksum file contains at least one line and less than SIZE_T_MAX lines.
+ *    - All files are properly opened and read.
+ *    - All hash values match with its content.
+ *    - (strict mode) All lines in checksum file are consistent and well formatted.
+ */
+static int XSUM_checkFile(const char* inFileName,
+                          const Display_endianess displayEndianess,
+                          XSUM_U32 strictMode,
+                          XSUM_U32 statusOnly,
+                          XSUM_U32 warn,
+                          XSUM_U32 quiet)
+{
+    int result = 0;
+    FILE* inFile = NULL;
+    ParseFileArg XSUM_parseFileArgBody;
+    ParseFileArg* const XSUM_parseFileArg = &XSUM_parseFileArgBody;
+    ParseFileReport* const report = &XSUM_parseFileArg->report;
+
+    /* note: stdinName is special constant pointer.  It is not a string. */
+    if (inFileName == stdinName) {
+        /*
+         * Note: Since we expect text input for xxhash -c mode,
+         * we don't set binary mode for stdin.
+         */
+        inFileName = "stdin";
+        inFile = stdin;
+    } else {
+        inFile = XSUM_fopen( inFileName, "rt" );
+    }
+
+    if (inFile == NULL) {
+        XSUM_log("Error: Could not open '%s': %s\n", inFileName, strerror(errno));
+        return 0;
+    }
+
+    XSUM_parseFileArg->inFileName  = inFileName;
+    XSUM_parseFileArg->inFile      = inFile;
+    XSUM_parseFileArg->lineMax     = DEFAULT_LINE_LENGTH;
+    XSUM_parseFileArg->lineBuf     = (char*) malloc((size_t)XSUM_parseFileArg->lineMax);
+    XSUM_parseFileArg->blockSize   = 64 * 1024;
+    XSUM_parseFileArg->blockBuf    = (char*) malloc(XSUM_parseFileArg->blockSize);
+    XSUM_parseFileArg->strictMode  = strictMode;
+    XSUM_parseFileArg->statusOnly  = statusOnly;
+    XSUM_parseFileArg->warn        = warn;
+    XSUM_parseFileArg->quiet       = quiet;
+
+    if ( (XSUM_parseFileArg->lineBuf == NULL)
+      || (XSUM_parseFileArg->blockBuf == NULL) ) {
+        XSUM_log("Error: : memory allocation failed \n");
+        exit(1);
+    }
+    XSUM_parseFile1(XSUM_parseFileArg, displayEndianess != big_endian);
+
+    free(XSUM_parseFileArg->blockBuf);
+    free(XSUM_parseFileArg->lineBuf);
+
+    if (inFile != stdin) fclose(inFile);
+
+    /* Show error/warning messages.  All messages are copied from md5sum.c
+     */
+    if (report->nProperlyFormattedLines == 0) {
+        XSUM_log("%s: no properly formatted xxHash checksum lines found\n", inFileName);
+    } else if (!statusOnly) {
+        if (report->nImproperlyFormattedLines) {
+            XSUM_output("%lu %s improperly formatted\n"
+                , report->nImproperlyFormattedLines
+                , report->nImproperlyFormattedLines == 1 ? "line is" : "lines are");
+        }
+        if (report->nOpenOrReadFailures) {
+            XSUM_output("%lu listed %s could not be read\n"
+                , report->nOpenOrReadFailures
+                , report->nOpenOrReadFailures == 1 ? "file" : "files");
+        }
+        if (report->nMismatchedChecksums) {
+            XSUM_output("%lu computed %s did NOT match\n"
+                , report->nMismatchedChecksums
+                , report->nMismatchedChecksums == 1 ? "checksum" : "checksums");
+    }   }
+
+    /* Result (exit) code logic is copied from
+     * gnu coreutils/src/md5sum.c digest_check() */
+    result =   report->nProperlyFormattedLines != 0
+            && report->nMismatchedChecksums == 0
+            && report->nOpenOrReadFailures == 0
+            && (!strictMode || report->nImproperlyFormattedLines == 0)
+            && report->quit == 0;
+    return result;
+}
+
+
+static int XSUM_checkFiles(char*const* fnList, int fnTotal,
+                           const Display_endianess displayEndianess,
+                           XSUM_U32 strictMode,
+                           XSUM_U32 statusOnly,
+                           XSUM_U32 warn,
+                           XSUM_U32 quiet)
+{
+    int ok = 1;
+
+    /* Special case for stdinName "-",
+     * note: stdinName is not a string.  It's special pointer. */
+    if (fnTotal==0) {
+        ok &= XSUM_checkFile(stdinName, displayEndianess, strictMode, statusOnly, warn, quiet);
+    } else {
+        int fnNb;
+        for (fnNb=0; fnNb<fnTotal; fnNb++)
+            ok &= XSUM_checkFile(fnList[fnNb], displayEndianess, strictMode, statusOnly, warn, quiet);
+    }
+    return ok ? 0 : 1;
+}
+
+
+/* ********************************************************
+*  Main
+**********************************************************/
+
+static int XSUM_usage(const char* exename)
+{
+    XSUM_log( WELCOME_MESSAGE(exename) );
+    XSUM_log( "Print or verify checksums using fast non-cryptographic algorithm xxHash \n\n" );
+    XSUM_log( "Usage: %s [options] [files] \n\n", exename);
+    XSUM_log( "When no filename provided or when '-' is provided, uses stdin as input. \n");
+    XSUM_log( "Options: \n");
+    XSUM_log( "  -H#         algorithm selection: 0,1,2 or 32,64,128 (default: %i) \n", (int)g_defaultAlgo);
+    XSUM_log( "  -c, --check read xxHash checksum from [files] and check them \n");
+    XSUM_log( "  -h, --help  display a long help page about advanced options \n");
+    return 0;
+}
+
+
+static int XSUM_usage_advanced(const char* exename)
+{
+    XSUM_usage(exename);
+    XSUM_log( "Advanced :\n");
+    XSUM_log( "  -V, --version        Display version information \n");
+    XSUM_log( "      --tag            Produce BSD-style checksum lines \n");
+    XSUM_log( "      --little-endian  Checksum values use little endian convention (default: big endian) \n");
+    XSUM_log( "  -b                   Run benchmark \n");
+    XSUM_log( "  -b#                  Bench only algorithm variant # \n");
+    XSUM_log( "  -i#                  Number of times to run the benchmark (default: %u) \n", (unsigned)g_nbIterations);
+    XSUM_log( "  -q, --quiet          Don't display version header in benchmark mode \n");
+    XSUM_log( "\n");
+    XSUM_log( "The following four options are useful only when verifying checksums (-c): \n");
+    XSUM_log( "  -q, --quiet          Don't print OK for each successfully verified file \n");
+    XSUM_log( "      --status         Don't output anything, status code shows success \n");
+    XSUM_log( "      --strict         Exit non-zero for improperly formatted checksum lines \n");
+    XSUM_log( "      --warn           Warn about improperly formatted checksum lines \n");
+    return 0;
+}
+
+static int XSUM_badusage(const char* exename)
+{
+    XSUM_log("Wrong parameters\n\n");
+    XSUM_usage(exename);
+    return 1;
+}
+
+static void errorOut(const char* msg)
+{
+    XSUM_log("%s \n", msg);
+    exit(1);
+}
+
+static const char* XSUM_lastNameFromPath(const char* path)
+{
+    const char* name = path;
+    if (strrchr(name, '/')) name = strrchr(name, '/') + 1;
+    if (strrchr(name, '\\')) name = strrchr(name, '\\') + 1; /* windows */
+    return name;
+}
+
+/*!
+ * XSUM_readU32FromCharChecked():
+ * @return 0 if success, and store the result in *value.
+ * Allows and interprets K, KB, KiB, M, MB and MiB suffix.
+ * Will also modify `*stringPtr`, advancing it to position where it stopped reading.
+ * @return 1 if an overflow error occurs
+ */
+static int XSUM_readU32FromCharChecked(const char** stringPtr, XSUM_U32* value)
+{
+    static const XSUM_U32 max = (((XSUM_U32)(-1)) / 10) - 1;
+    XSUM_U32 result = 0;
+    while ((**stringPtr >='0') && (**stringPtr <='9')) {
+        if (result > max) return 1; /* overflow error */
+        result *= 10;
+        result += (XSUM_U32)(**stringPtr - '0');
+        (*stringPtr)++ ;
+    }
+    if ((**stringPtr=='K') || (**stringPtr=='M')) {
+        XSUM_U32 const maxK = ((XSUM_U32)(-1)) >> 10;
+        if (result > maxK) return 1; /* overflow error */
+        result <<= 10;
+        if (**stringPtr=='M') {
+            if (result > maxK) return 1; /* overflow error */
+            result <<= 10;
+        }
+        (*stringPtr)++;  /* skip `K` or `M` */
+        if (**stringPtr=='i') (*stringPtr)++;
+        if (**stringPtr=='B') (*stringPtr)++;
+    }
+    *value = result;
+    return 0;
+}
+
+/*!
+ * XSUM_readU32FromChar():
+ * @return: unsigned integer value read from input in `char` format.
+ *  allows and interprets K, KB, KiB, M, MB and MiB suffix.
+ *  Will also modify `*stringPtr`, advancing it to position where it stopped reading.
+ *  Note: function will exit() program if digit sequence overflows
+ */
+static XSUM_U32 XSUM_readU32FromChar(const char** stringPtr) {
+    XSUM_U32 result;
+    if (XSUM_readU32FromCharChecked(stringPtr, &result)) {
+        static const char errorMsg[] = "Error: numeric value too large";
+        errorOut(errorMsg);
+    }
+    return result;
+}
+
+XSUM_API int XSUM_main(int argc, char* argv[])
+{
+    int i, filenamesStart = 0;
+    const char* const exename = XSUM_lastNameFromPath(argv[0]);
+    XSUM_U32 benchmarkMode = 0;
+    XSUM_U32 fileCheckMode = 0;
+    XSUM_U32 strictMode    = 0;
+    XSUM_U32 statusOnly    = 0;
+    XSUM_U32 warn          = 0;
+    int explicitStdin = 0;
+    XSUM_U32 selectBenchIDs= 0;  /* 0 == use default k_testIDs_default, kBenchAll == bench all */
+    static const XSUM_U32 kBenchAll = 99;
+    size_t keySize    = XSUM_DEFAULT_SAMPLE_SIZE;
+    AlgoSelected algo     = g_defaultAlgo;
+    Display_endianess displayEndianess = big_endian;
+    Display_convention convention = display_gnu;
+
+    /* special case: xxhNNsum default to NN bits checksum */
+    if (strstr(exename,  "xxh32sum") != NULL) algo = g_defaultAlgo = algo_xxh32;
+    if (strstr(exename,  "xxh64sum") != NULL) algo = g_defaultAlgo = algo_xxh64;
+    if (strstr(exename, "xxh128sum") != NULL) algo = g_defaultAlgo = algo_xxh128;
+
+    for (i=1; i<argc; i++) {
+        const char* argument = argv[i];
+        assert(argument != NULL);
+
+        if (!strcmp(argument, "--check")) { fileCheckMode = 1; continue; }
+        if (!strcmp(argument, "--benchmark-all")) { benchmarkMode = 1; selectBenchIDs = kBenchAll; continue; }
+        if (!strcmp(argument, "--bench-all")) { benchmarkMode = 1; selectBenchIDs = kBenchAll; continue; }
+        if (!strcmp(argument, "--quiet")) { XSUM_logLevel--; continue; }
+        if (!strcmp(argument, "--little-endian")) { displayEndianess = little_endian; continue; }
+        if (!strcmp(argument, "--strict")) { strictMode = 1; continue; }
+        if (!strcmp(argument, "--status")) { statusOnly = 1; continue; }
+        if (!strcmp(argument, "--warn")) { warn = 1; continue; }
+        if (!strcmp(argument, "--help")) { return XSUM_usage_advanced(exename); }
+        if (!strcmp(argument, "--version")) { XSUM_log(FULL_WELCOME_MESSAGE(exename)); XSUM_sanityCheck(); return 0; }
+        if (!strcmp(argument, "--tag")) { convention = display_bsd; continue; }
+
+        if (!strcmp(argument, "--")) {
+            if (filenamesStart==0 && i!=argc-1) filenamesStart=i+1; /* only supports a continuous list of filenames */
+            break;  /* treat rest of arguments as strictly file names */
+        }
+        if (*argument != '-') {
+            if (filenamesStart==0) filenamesStart=i;   /* only supports a continuous list of filenames */
+            break;  /* treat rest of arguments as strictly file names */
+        }
+
+        /* command selection */
+        argument++;   /* note: *argument=='-' */
+        if (*argument == 0) explicitStdin = 1;
+
+        while (*argument != 0) {
+            switch(*argument)
+            {
+            /* Display version */
+            case 'V':
+                XSUM_log(FULL_WELCOME_MESSAGE(exename)); return 0;
+
+            /* Display help on XSUM_usage */
+            case 'h':
+                return XSUM_usage_advanced(exename);
+
+            /* select hash algorithm */
+            case 'H': argument++;
+                switch(XSUM_readU32FromChar(&argument)) {
+                    case 0 :
+                    case 32: algo = algo_xxh32; break;
+                    case 1 :
+                    case 64: algo = algo_xxh64; break;
+                    case 2 :
+                    case 128: algo = algo_xxh128; break;
+                    default:
+                        return XSUM_badusage(exename);
+                }
+                break;
+
+            /* File check mode */
+            case 'c':
+                fileCheckMode=1;
+                argument++;
+                break;
+
+            /* Warning mode (file check mode only, alias of "--warning") */
+            case 'w':
+                warn=1;
+                argument++;
+                break;
+
+            /* Trigger benchmark mode */
+            case 'b':
+                argument++;
+                benchmarkMode = 1;
+                do {
+                    if (*argument == ',') argument++;
+                    selectBenchIDs = XSUM_readU32FromChar(&argument); /* select one specific test */
+                    if (selectBenchIDs < NB_TESTFUNC) {
+                        g_testIDs[selectBenchIDs] = 1;
+                    } else
+                        selectBenchIDs = kBenchAll;
+                } while (*argument == ',');
+                break;
+
+            /* Modify Nb Iterations (benchmark only) */
+            case 'i':
+                argument++;
+                g_nbIterations = XSUM_readU32FromChar(&argument);
+                break;
+
+            /* Modify Block size (benchmark only) */
+            case 'B':
+                argument++;
+                keySize = XSUM_readU32FromChar(&argument);
+                break;
+
+            /* Modify verbosity of benchmark output (hidden option) */
+            case 'q':
+                argument++;
+                XSUM_logLevel--;
+                break;
+
+            default:
+                return XSUM_badusage(exename);
+            }
+        }
+    }   /* for(i=1; i<argc; i++) */
+
+    /* Check benchmark mode */
+    if (benchmarkMode) {
+        XSUM_logVerbose(2, FULL_WELCOME_MESSAGE(exename) );
+        XSUM_sanityCheck();
+        if (selectBenchIDs == 0) memcpy(g_testIDs, k_testIDs_default, sizeof(g_testIDs));
+        if (selectBenchIDs == kBenchAll) memset(g_testIDs, 1, sizeof(g_testIDs));
+        if (filenamesStart==0) return XSUM_benchInternal(keySize);
+        return XSUM_benchFiles(argv+filenamesStart, argc-filenamesStart);
+    }
+
+    /* Check if input is defined as console; trigger an error in this case */
+    if ( (filenamesStart==0) && XSUM_isConsole(stdin) && !explicitStdin)
+        return XSUM_badusage(exename);
+
+    if (filenamesStart==0) filenamesStart = argc;
+    if (fileCheckMode) {
+        return XSUM_checkFiles(argv+filenamesStart, argc-filenamesStart,
+                          displayEndianess, strictMode, statusOnly, warn, (XSUM_logLevel < 2) /*quiet*/);
+    } else {
+        return XSUM_hashFiles(argv+filenamesStart, argc-filenamesStart, algo, displayEndianess, convention);
+    }
+}
diff --git a/grpc/tools/bazel b/grpc/tools/bazel
index 80633cc..aaa549a 100755
--- a/grpc/tools/bazel
+++ b/grpc/tools/bazel
@@ -55,6 +55,9 @@
   "Linux x86_64")
     suffix=linux-x86_64
     ;;
+  "Linux aarch64")
+    suffix=linux-arm64
+    ;;
   "Darwin x86_64")
     suffix=darwin-x86_64
     ;;
diff --git a/grpc/tools/bazel.rc b/grpc/tools/bazel.rc
index 8948e91..baf3c3d 100644
--- a/grpc/tools/bazel.rc
+++ b/grpc/tools/bazel.rc
@@ -9,6 +9,7 @@
 build:opt --copt=-Wframe-larger-than=16384
 
 build:dbg --compilation_mode=dbg
+build:dbg --copt=-Werror=return-stack-address
 
 build:windows_opt --compilation_mode=opt
 build:windows_dbg --compilation_mode=dbg
@@ -65,12 +66,12 @@
 build:tsan --action_env=TSAN_OPTIONS=suppressions=test/core/util/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
 
 build:ubsan --strip=never
-build:ubsan --copt=-fsanitize=undefined
+build:ubsan --copt=-fsanitize-link-c++-runtime
 build:ubsan --copt=-fno-omit-frame-pointer
 build:ubsan --copt=-DGRPC_UBSAN
 build:ubsan --copt=-DNDEBUG
 build:ubsan --copt=-fno-sanitize=function,vptr
-build:ubsan --linkopt=-fsanitize=undefined
+build:ubsan --linkopt=-fsanitize-link-c++-runtime
 build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1:suppressions=test/core/util/ubsan_suppressions.txt
 # For some reasons, these two stopped being propagated, so, redeclaring them here.
 # That's a hack that needs to be removed once we understand what's going on.
diff --git a/grpc/tools/buildgen/mako_renderer.py b/grpc/tools/buildgen/_mako_renderer.py
similarity index 75%
rename from grpc/tools/buildgen/mako_renderer.py
rename to grpc/tools/buildgen/_mako_renderer.py
index 06ee30f..77c3c49 100755
--- a/grpc/tools/buildgen/mako_renderer.py
+++ b/grpc/tools/buildgen/_mako_renderer.py
@@ -18,53 +18,61 @@
 """
 
 import getopt
+import glob
 import importlib.util
 import os
 import pickle
 import shutil
 import sys
+from typing import List
 
 import yaml
+from mako import exceptions
 from mako.lookup import TemplateLookup
 from mako.runtime import Context
 from mako.template import Template
 
-import bunch
+PROJECT_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..",
+                            "..")
+# TODO(lidiz) find a better way for plugins to reference each other
+sys.path.append(os.path.join(PROJECT_ROOT, 'tools', 'buildgen', 'plugins'))
 
 
-# Imports a plugin
-def import_plugin(path):
-    module_name = os.path.basename(path).replace('.py', '')
-    spec = importlib.util.spec_from_file_location(module_name, path)
-    module = importlib.util.module_from_spec(spec)
-    sys.modules[module_name] = module
-    spec.loader.exec_module(module)
-    return module
-
-
-def out(msg):
+def out(msg: str) -> None:
     print(msg, file=sys.stderr)
 
 
-def showhelp():
+def showhelp() -> None:
     out('mako-renderer.py [-o out] [-m cache] [-P preprocessed_input] [-d dict] [-d dict...]'
         ' [-t template] [-w preprocessed_output]')
 
 
-def main(argv):
+def render_template(template: Template, context: Context) -> None:
+    """Render the mako template with given context.
+
+    Prints an error template to indicate where and what in the template caused
+    the render failure.
+    """
+    try:
+        template.render_context(context)
+    except:
+        out(exceptions.text_error_template().render())
+        raise
+
+
+def main(argv: List[str]) -> None:
     got_input = False
     module_directory = None
     preprocessed_output = None
     dictionary = {}
     json_dict = {}
     got_output = False
-    plugins = []
     output_name = None
     got_preprocessed_input = False
     output_merged = None
 
     try:
-        opts, args = getopt.getopt(argv, 'hM:m:d:o:p:t:P:w:')
+        opts, args = getopt.getopt(argv, 'hM:m:o:t:P:')
     except getopt.GetoptError:
         out('Unknown option')
         showhelp()
@@ -97,36 +105,9 @@
         elif opt == '-P':
             assert not got_preprocessed_input
             assert json_dict == {}
-            sys.path.insert(
-                0,
-                os.path.abspath(
-                    os.path.join(os.path.dirname(sys.argv[0]), 'plugins')))
             with open(arg, 'rb') as dict_file:
                 dictionary = pickle.load(dict_file)
             got_preprocessed_input = True
-        elif opt == '-d':
-            assert not got_preprocessed_input
-            with open(arg, 'r') as dict_file:
-                bunch.merge_json(
-                    json_dict,
-                    yaml.load(dict_file.read(), Loader=yaml.FullLoader))
-        elif opt == '-p':
-            plugins.append(import_plugin(arg))
-        elif opt == '-w':
-            preprocessed_output = arg
-
-    if not got_preprocessed_input:
-        for plugin in plugins:
-            plugin.mako_plugin(json_dict)
-        if output_merged:
-            with open(output_merged, 'w') as yaml_file:
-                yaml_file.write(yaml.dump(json_dict))
-        for k, v in json_dict.items():
-            dictionary[k] = bunch.to_bunch(v)
-
-    if preprocessed_output:
-        with open(preprocessed_output, 'wb') as dict_file:
-            pickle.dump(dictionary, dict_file)
 
     cleared_dir = False
     for arg in args:
@@ -141,7 +122,8 @@
                                     module_directory=module_directory,
                                     lookup=TemplateLookup(directories=['.']))
                 with open(output_name, 'w') as output_file:
-                    template.render_context(Context(output_file, **dictionary))
+                    render_template(template, Context(output_file,
+                                                      **dictionary))
             else:
                 # we have optional control data: this template represents
                 # a directory
@@ -179,7 +161,7 @@
                         module_directory=module_directory,
                         lookup=TemplateLookup(directories=['.']))
                     with open(item_output_name, 'w') as output_file:
-                        template.render_context(Context(output_file, **args))
+                        render_template(template, Context(output_file, **args))
 
     if not got_input and not preprocessed_output:
         out('Got nothing to do')
diff --git a/grpc/tools/buildgen/_utils.py b/grpc/tools/buildgen/_utils.py
new file mode 100644
index 0000000..875d371
--- /dev/null
+++ b/grpc/tools/buildgen/_utils.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+# Copyright 2020 The 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.
+"""Utility functions for build file generation scripts."""
+
+import os
+import sys
+import types
+import importlib.util
+from typing import Any, Union, Mapping, List
+
+
+def import_python_module(path: str) -> types.ModuleType:
+    """Imports the Python file at the given path, returns a module object."""
+    module_name = os.path.basename(path).replace('.py', '')
+    spec = importlib.util.spec_from_file_location(module_name, path)
+    module = importlib.util.module_from_spec(spec)
+    sys.modules[module_name] = module
+    spec.loader.exec_module(module)
+    return module
+
+
+class Bunch(dict):
+    """Allows dot-accessible dictionaries."""
+
+    def __init__(self, d: Mapping):
+        dict.__init__(self, d)
+        self.__dict__.update(d)
+
+
+def to_bunch(var: Any) -> Any:
+    """Converts any kind of variable to a Bunch."""
+    if isinstance(var, list):
+        return [to_bunch(i) for i in var]
+    if isinstance(var, dict):
+        ret = {}
+        for k, v in var.items():
+            if isinstance(v, (list, dict)):
+                v = to_bunch(v)
+            ret[k] = v
+        return Bunch(ret)
+    else:
+        return var
+
+
+def merge_json(dst: Union[Mapping, List], add: Union[Mapping, List]) -> None:
+    """Merges JSON objects recursively."""
+    if isinstance(dst, dict) and isinstance(add, dict):
+        for k, v in add.items():
+            if k in dst:
+                if k.startswith('#'):
+                    continue
+                merge_json(dst[k], v)
+            else:
+                dst[k] = v
+    elif isinstance(dst, list) and isinstance(add, list):
+        dst.extend(add)
+    else:
+        raise TypeError(
+            'Tried to merge incompatible objects %s %s\n\n%r\n\n%r' %
+            (type(dst).__name__, type(add).__name__, dst, add))
diff --git a/grpc/tools/buildgen/build_cleaner.py b/grpc/tools/buildgen/build_cleaner.py
index b044cb7..19bcee6 100755
--- a/grpc/tools/buildgen/build_cleaner.py
+++ b/grpc/tools/buildgen/build_cleaner.py
@@ -48,15 +48,18 @@
         if key in indict:
             outdict[key] = indict[key]
     for key in sorted(indict.keys()):
-        if key in special_keys: continue
-        if '#' in key: continue
+        if key in special_keys:
+            continue
+        if '#' in key:
+            continue
         outdict[key] = indict[key]
     return outdict
 
 
 def _clean_elem(indict):
     for name in ['public_headers', 'headers', 'src']:
-        if name not in indict: continue
+        if name not in indict:
+            continue
         inlist = indict[name]
         protos = list(x for x in inlist if os.path.splitext(x)[1] == '.proto')
         others = set(x for x in inlist if x not in protos)
@@ -68,7 +71,8 @@
     """Takes dictionary which represents yaml file and returns the cleaned-up yaml string"""
     js = _rebuild_as_ordered_dict(indict, _TOP_LEVEL_KEYS)
     for grp in ['filegroups', 'libs', 'targets']:
-        if grp not in js: continue
+        if grp not in js:
+            continue
         js[grp] = sorted([_clean_elem(x) for x in js[grp]],
                          key=lambda x: (x.get('language', '_'), x['name']))
     output = yaml.dump(js, indent=2, width=80, default_flow_style=False)
diff --git a/grpc/tools/buildgen/bunch.py b/grpc/tools/buildgen/bunch.py
deleted file mode 100755
index f3bfc81..0000000
--- a/grpc/tools/buildgen/bunch.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright 2015 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.
-"""Allows dot-accessible dictionaries."""
-
-
-class Bunch(dict):
-
-    def __init__(self, d):
-        dict.__init__(self, d)
-        self.__dict__.update(d)
-
-
-# Converts any kind of variable to a Bunch
-def to_bunch(var):
-    if isinstance(var, list):
-        return [to_bunch(i) for i in var]
-    if isinstance(var, dict):
-        ret = {}
-        for k, v in var.items():
-            if isinstance(v, (list, dict)):
-                v = to_bunch(v)
-            ret[k] = v
-        return Bunch(ret)
-    else:
-        return var
-
-
-# Merges JSON 'add' into JSON 'dst'
-def merge_json(dst, add):
-    if isinstance(dst, dict) and isinstance(add, dict):
-        for k, v in add.items():
-            if k in dst:
-                if k == '#': continue
-                merge_json(dst[k], v)
-            else:
-                dst[k] = v
-    elif isinstance(dst, list) and isinstance(add, list):
-        dst.extend(add)
-    else:
-        raise Exception(
-            'Tried to merge incompatible objects %s %s\n\n%r\n\n%r' %
-            (type(dst).__name__, type(add).__name__, dst, add))
diff --git a/grpc/tools/buildgen/extract_metadata_from_bazel_xml.py b/grpc/tools/buildgen/extract_metadata_from_bazel_xml.py
index 63f8e2e..55b8dd1 100755
--- a/grpc/tools/buildgen/extract_metadata_from_bazel_xml.py
+++ b/grpc/tools/buildgen/extract_metadata_from_bazel_xml.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2020 The gRPC Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,14 +34,18 @@
 import yaml
 import xml.etree.ElementTree as ET
 import os
+import collections
 import sys
+import re
+from typing import List, Any, Dict, Optional, Iterable
 import build_cleaner
 
-_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
-os.chdir(_ROOT)
+BuildMetadata = Dict[str, Any]
+BuildDict = Dict[str, BuildMetadata]
+BuildYaml = Dict[str, Any]
 
 
-def _bazel_query_xml_tree(query):
+def _bazel_query_xml_tree(query: str) -> ET.Element:
     """Get xml output of bazel query invocation, parsed as XML tree"""
     output = subprocess.check_output(
         ['tools/bazel', 'query', '--noimplicit_deps', '--output', 'xml', query])
@@ -98,14 +102,14 @@
     return result
 
 
-def _get_bazel_label(target_name):
+def _get_bazel_label(target_name: str) -> str:
     if ':' in target_name:
         return '//%s' % target_name
     else:
         return '//:%s' % target_name
 
 
-def _extract_source_file_path(label):
+def _extract_source_file_path(label: str) -> str:
     """Gets relative path to source file from bazel deps listing"""
     if label.startswith('//'):
         label = label[len('//'):]
@@ -117,7 +121,7 @@
     return label
 
 
-def _extract_public_headers(bazel_rule):
+def _extract_public_headers(bazel_rule: BuildMetadata) -> List[str]:
     """Gets list of public headers from a bazel rule"""
     result = []
     for dep in bazel_rule['hdrs']:
@@ -126,7 +130,7 @@
     return list(sorted(result))
 
 
-def _extract_nonpublic_headers(bazel_rule):
+def _extract_nonpublic_headers(bazel_rule: BuildMetadata) -> List[str]:
     """Gets list of non-public headers from a bazel rule"""
     result = []
     for dep in bazel_rule['hdrs']:
@@ -136,7 +140,7 @@
     return list(sorted(result))
 
 
-def _extract_sources(bazel_rule):
+def _extract_sources(bazel_rule: BuildMetadata) -> List[str]:
     """Gets list of source files from a bazel rule"""
     result = []
     for dep in bazel_rule['srcs']:
@@ -146,12 +150,14 @@
     return list(sorted(result))
 
 
-def _extract_deps(bazel_rule):
+def _extract_deps(bazel_rule: BuildMetadata,
+                  bazel_rules: BuildDict) -> List[str]:
     """Gets list of deps from from a bazel rule"""
     return list(sorted(bazel_rule['deps']))
 
 
-def _create_target_from_bazel_rule(target_name, bazel_rules):
+def _create_target_from_bazel_rule(target_name: str,
+                                   bazel_rules: BuildDict) -> BuildMetadata:
     """Create build.yaml-like target definition from bazel metadata"""
     bazel_rule = bazel_rules[_get_bazel_label(target_name)]
 
@@ -164,71 +170,16 @@
         '_PUBLIC_HEADERS_BAZEL': _extract_public_headers(bazel_rule),
         '_HEADERS_BAZEL': _extract_nonpublic_headers(bazel_rule),
         '_SRC_BAZEL': _extract_sources(bazel_rule),
-        '_DEPS_BAZEL': _extract_deps(bazel_rule),
+        '_DEPS_BAZEL': _extract_deps(bazel_rule, bazel_rules),
+        'public_headers': bazel_rule['_COLLAPSED_PUBLIC_HEADERS'],
+        'headers': bazel_rule['_COLLAPSED_HEADERS'],
+        'src': bazel_rule['_COLLAPSED_SRCS'],
+        'deps': bazel_rule['_COLLAPSED_DEPS'],
     }
     return result
 
 
-def _sort_by_build_order(lib_names, lib_dict, deps_key_name, verbose=False):
-    """Sort library names to form correct build order. Use metadata from lib_dict"""
-    # we find correct build order by performing a topological sort
-    # expected output: if library B depends on A, A should be listed first
-
-    # all libs that are not in the dictionary are considered external.
-    external_deps = list(
-        sorted([lib_name for lib_name in lib_names if lib_name not in lib_dict
-               ]))
-    if verbose:
-        print('topo_ordering ' + str(lib_names))
-        print('    external_deps ' + str(external_deps))
-
-    result = list(external_deps)  # external deps will be listed first
-    while len(result) < len(lib_names):
-        more_results = []
-        for lib in lib_names:
-            if lib not in result:
-                dep_set = set(lib_dict[lib].get(deps_key_name, []))
-                dep_set = dep_set.intersection(lib_names)
-                # if lib only depends on what's already built, add it to the results
-                if not dep_set.difference(set(result)):
-                    more_results.append(lib)
-        if not more_results:
-            raise Exception(
-                'Cannot sort topologically, there seems to be a cyclic dependency'
-            )
-        if verbose:
-            print('    adding ' + str(more_results))
-        result = result + list(
-            sorted(more_results
-                  ))  # when build order doesn't matter, sort lexicographically
-    return result
-
-
-# TODO(jtattermusch): deduplicate with transitive_dependencies.py (which has a slightly different logic)
-def _populate_transitive_deps(bazel_rules):
-    """Add 'transitive_deps' field for each of the rules"""
-    transitive_deps = {}
-    for rule_name in bazel_rules.keys():
-        transitive_deps[rule_name] = set(bazel_rules[rule_name]['deps'])
-
-    while True:
-        deps_added = 0
-        for rule_name in bazel_rules.keys():
-            old_deps = transitive_deps[rule_name]
-            new_deps = set(old_deps)
-            for dep_name in old_deps:
-                new_deps.update(transitive_deps.get(dep_name, set()))
-            deps_added += len(new_deps) - len(old_deps)
-            transitive_deps[rule_name] = new_deps
-        # if none of the transitive dep sets has changed, we're done
-        if deps_added == 0:
-            break
-
-    for rule_name, bazel_rule in bazel_rules.items():
-        bazel_rule['transitive_deps'] = list(sorted(transitive_deps[rule_name]))
-
-
-def _external_dep_name_from_bazel_dependency(bazel_dep):
+def _external_dep_name_from_bazel_dependency(bazel_dep: str) -> Optional[str]:
     """Returns name of dependency if external bazel dependency is provided or None"""
     if bazel_dep.startswith('@com_google_absl//'):
         # special case for add dependency on one of the absl libraries (there is not just one absl library)
@@ -238,6 +189,8 @@
         return 'upb'
     elif bazel_dep == '//external:benchmark':
         return 'benchmark'
+    elif bazel_dep == '//external:libssl':
+        return 'libssl'
     else:
         # all the other external deps such as protobuf, cares, zlib
         # don't need to be listed explicitly, they are handled automatically
@@ -245,98 +198,186 @@
         return None
 
 
-def _expand_intermediate_deps(target_dict, public_dep_names, bazel_rules):
-    # Some of the libraries defined by bazel won't be exposed in build.yaml
-    # We call these "intermediate" dependencies. This method expands
-    # the intermediate deps for given target (populates library's
-    # headers, sources and dicts as if the intermediate dependency never existed)
+def _compute_transitive_metadata(
+        rule_name: str, bazel_rules: Any,
+        bazel_label_to_dep_name: Dict[str, str]) -> None:
+    """Computes the final build metadata for Bazel target with rule_name.
 
-    # use this dictionary to translate from bazel labels to dep names
+    The dependencies that will appear on the deps list are:
+
+    * Public build targets including binaries and tests;
+    * External targets, like absl, re2.
+
+    All other intermediate dependencies will be merged, which means their
+    source file, headers, etc. will be collected into one build target. This
+    step of processing will greatly reduce the complexity of the generated
+    build specifications for other build systems, like CMake, Make, setuptools.
+
+    The final build metadata are:
+    * _TRANSITIVE_DEPS: all the transitive dependencies including intermediate
+                        targets;
+    * _COLLAPSED_DEPS:  dependencies that fits our requirement above, and it
+                        will remove duplicated items and produce the shortest
+                        possible dependency list in alphabetical order;
+    * _COLLAPSED_SRCS:  the merged source files;
+    * _COLLAPSED_PUBLIC_HEADERS: the merged public headers;
+    * _COLLAPSED_HEADERS: the merged non-public headers;
+    * _EXCLUDE_DEPS: intermediate targets to exclude when performing collapsing
+      of sources and dependencies. 
+
+    For the collapsed_deps, the algorithm improved cases like:
+
+    The result in the past:
+        end2end_tests -> [grpc_test_util, grpc, gpr, address_sorting, upb]
+        grpc_test_util -> [grpc, gpr, address_sorting, upb, ...]
+        grpc -> [gpr, address_sorting, upb, ...]
+    
+    The result of the algorithm:
+        end2end_tests -> [grpc_test_util]
+        grpc_test_util -> [grpc]
+        grpc -> [gpr, address_sorting, upb, ...]
+    """
+    bazel_rule = bazel_rules[rule_name]
+    direct_deps = _extract_deps(bazel_rule, bazel_rules)
+    transitive_deps = set()
+    collapsed_deps = set()
+    exclude_deps = set()
+    collapsed_srcs = set(_extract_sources(bazel_rule))
+    collapsed_public_headers = set(_extract_public_headers(bazel_rule))
+    collapsed_headers = set(_extract_nonpublic_headers(bazel_rule))
+
+    for dep in direct_deps:
+        external_dep_name_maybe = _external_dep_name_from_bazel_dependency(dep)
+
+        if dep in bazel_rules:
+            # Descend recursively, but no need to do that for external deps
+            if external_dep_name_maybe is None:
+                if "_PROCESSING_DONE" not in bazel_rules[dep]:
+                    # This item is not processed before, compute now
+                    _compute_transitive_metadata(dep, bazel_rules,
+                                                 bazel_label_to_dep_name)
+
+                transitive_deps.update(bazel_rules[dep].get(
+                    '_TRANSITIVE_DEPS', []))
+                collapsed_deps.update(
+                    collapsed_deps, bazel_rules[dep].get('_COLLAPSED_DEPS', []))
+                exclude_deps.update(bazel_rules[dep].get('_EXCLUDE_DEPS', []))
+
+        # This dep is a public target, add it as a dependency
+        if dep in bazel_label_to_dep_name:
+            transitive_deps.update([bazel_label_to_dep_name[dep]])
+            collapsed_deps.update(collapsed_deps,
+                                  [bazel_label_to_dep_name[dep]])
+            # Add all the transitive deps of our every public dep to exclude
+            # list since we want to avoid building sources that are already
+            # built by our dependencies
+            exclude_deps.update(bazel_rules[dep]['_TRANSITIVE_DEPS'])
+            continue
+
+        # This dep is an external target, add it as a dependency
+        if external_dep_name_maybe is not None:
+            transitive_deps.update([external_dep_name_maybe])
+            collapsed_deps.update(collapsed_deps, [external_dep_name_maybe])
+            continue
+
+    # Direct dependencies are part of transitive dependencies
+    transitive_deps.update(direct_deps)
+
+    # Calculate transitive public deps (needed for collapsing sources)
+    transitive_public_deps = set(
+        filter(lambda x: x in bazel_label_to_dep_name, transitive_deps))
+
+    # Remove intermediate targets that our public dependencies already depend
+    # on. This is the step that further shorten the deps list.
+    collapsed_deps = set(filter(lambda x: x not in exclude_deps,
+                                collapsed_deps))
+
+    # Compute the final source files and headers for this build target whose
+    # name is `rule_name` (input argument of this function).
+    #
+    # Imaging a public target PX has transitive deps [IA, IB, PY, IC, PZ]. PX,
+    # PY and PZ are public build targets. And IA, IB, IC are intermediate
+    # targets. In addition, PY depends on IC.
+    #
+    # Translate the condition into dependency graph:
+    #   PX -> [IA, IB, PY, IC, PZ]
+    #   PY -> [IC]
+    #   Public targets: [PX, PY, PZ]
+    #
+    # The collapsed dependencies of PX: [PY, PZ].
+    # The excluded dependencies of X: [PY, IC, PZ].
+    # (IC is excluded as a dependency of PX. It is already included in PY, hence
+    # it would be redundant to include it again.)
+    #
+    # Target PX should include source files and headers of [PX, IA, IB] as final
+    # build metadata.
+    for dep in transitive_deps:
+        if dep not in exclude_deps and dep not in transitive_public_deps:
+            if dep in bazel_rules:
+                collapsed_srcs.update(_extract_sources(bazel_rules[dep]))
+                collapsed_public_headers.update(
+                    _extract_public_headers(bazel_rules[dep]))
+                collapsed_headers.update(
+                    _extract_nonpublic_headers(bazel_rules[dep]))
+
+    # This item is a "visited" flag
+    bazel_rule['_PROCESSING_DONE'] = True
+    # Following items are described in the docstinrg.
+    bazel_rule['_TRANSITIVE_DEPS'] = list(sorted(transitive_deps))
+    bazel_rule['_COLLAPSED_DEPS'] = list(sorted(collapsed_deps))
+    bazel_rule['_COLLAPSED_SRCS'] = list(sorted(collapsed_srcs))
+    bazel_rule['_COLLAPSED_PUBLIC_HEADERS'] = list(
+        sorted(collapsed_public_headers))
+    bazel_rule['_COLLAPSED_HEADERS'] = list(sorted(collapsed_headers))
+    bazel_rule['_EXCLUDE_DEPS'] = list(sorted(exclude_deps))
+
+
+# TODO(jtattermusch): deduplicate with transitive_dependencies.py (which has a slightly different logic)
+# TODO(jtattermusch): This is done to avoid introducing too many intermediate
+# libraries into the build.yaml-based builds (which might in cause issues
+# building language-specific artifacts) and also because the libraries
+# in build.yaml-based build are generally considered units of distributions
+# (= public libraries that are visible to the user and are installable),
+# while in bazel builds it is customary to define larger number of smaller
+# "sublibraries". The need for elision (and expansion)
+# of intermediate libraries can be re-evaluated in the future.
+def _populate_transitive_metadata(bazel_rules: Any,
+                                  public_dep_names: Iterable[str]) -> None:
+    """Add 'transitive_deps' field for each of the rules"""
+    # Create the map between Bazel label and public dependency name
     bazel_label_to_dep_name = {}
     for dep_name in public_dep_names:
         bazel_label_to_dep_name[_get_bazel_label(dep_name)] = dep_name
 
-    target_name = target_dict['name']
-    bazel_deps = target_dict['_DEPS_BAZEL']
-
-    # initial values
-    public_headers = set(target_dict['_PUBLIC_HEADERS_BAZEL'])
-    headers = set(target_dict['_HEADERS_BAZEL'])
-    src = set(target_dict['_SRC_BAZEL'])
-    deps = set()
-
-    expansion_blacklist = set()
-    to_expand = set(bazel_deps)
-    while to_expand:
-
-        # start with the last dependency to be built
-        build_order = _sort_by_build_order(list(to_expand), bazel_rules,
-                                           'transitive_deps')
-
-        bazel_dep = build_order[-1]
-        to_expand.remove(bazel_dep)
-
-        is_public = bazel_dep in bazel_label_to_dep_name
-        external_dep_name_maybe = _external_dep_name_from_bazel_dependency(
-            bazel_dep)
-
-        if is_public:
-            # this is not an intermediate dependency we so we add it
-            # to the list of public dependencies to the list, in the right format
-            deps.add(bazel_label_to_dep_name[bazel_dep])
-
-            # we do not want to expand any intermediate libraries that are already included
-            # by the dependency we just added
-            expansion_blacklist.update(
-                bazel_rules[bazel_dep]['transitive_deps'])
-
-        elif external_dep_name_maybe:
-            deps.add(external_dep_name_maybe)
-
-        elif bazel_dep.startswith(
-                '//external:') or not bazel_dep.startswith('//'):
-            # all the other external deps can be skipped
-            pass
-
-        elif bazel_dep in expansion_blacklist:
-            # do not expand if a public dependency that depends on this has already been expanded
-            pass
-
-        else:
-            if bazel_dep in bazel_rules:
-                # this is an intermediate library, expand it
-                public_headers.update(
-                    _extract_public_headers(bazel_rules[bazel_dep]))
-                headers.update(
-                    _extract_nonpublic_headers(bazel_rules[bazel_dep]))
-                src.update(_extract_sources(bazel_rules[bazel_dep]))
-
-                new_deps = _extract_deps(bazel_rules[bazel_dep])
-                to_expand.update(new_deps)
-            else:
-                raise Exception(bazel_dep + ' not in bazel_rules')
-
-    # make the 'deps' field transitive, but only list non-intermediate deps and selected external deps
-    bazel_transitive_deps = bazel_rules[_get_bazel_label(
-        target_name)]['transitive_deps']
-    for transitive_bazel_dep in bazel_transitive_deps:
-        public_name = bazel_label_to_dep_name.get(transitive_bazel_dep, None)
-        if public_name:
-            deps.add(public_name)
-        external_dep_name_maybe = _external_dep_name_from_bazel_dependency(
-            transitive_bazel_dep)
-        if external_dep_name_maybe:
-            # expanding all absl libraries is technically correct but creates too much noise
-            if not external_dep_name_maybe.startswith('absl'):
-                deps.add(external_dep_name_maybe)
-
-    target_dict['public_headers'] = list(sorted(public_headers))
-    target_dict['headers'] = list(sorted(headers))
-    target_dict['src'] = list(sorted(src))
-    target_dict['deps'] = list(sorted(deps))
+    # Make sure we reached all the Bazel rules
+    # TODO(lidiz) potentially we could only update a subset of rules
+    for rule_name in bazel_rules:
+        if '_PROCESSING_DONE' not in bazel_rules[rule_name]:
+            _compute_transitive_metadata(rule_name, bazel_rules,
+                                         bazel_label_to_dep_name)
 
 
-def _generate_build_metadata(build_extra_metadata, bazel_rules):
+def update_test_metadata_with_transitive_metadata(
+        all_extra_metadata: BuildDict, bazel_rules: BuildDict) -> None:
+    """Patches test build metadata with transitive metadata."""
+    for lib_name, lib_dict in all_extra_metadata.items():
+        # Skip if it isn't not an test
+        if lib_dict.get('build') != 'test' or lib_dict.get('_TYPE') != 'target':
+            continue
+
+        bazel_rule = bazel_rules[_get_bazel_label(lib_name)]
+
+        if '//external:benchmark' in bazel_rule['_TRANSITIVE_DEPS']:
+            lib_dict['benchmark'] = True
+            lib_dict['defaults'] = 'benchmark'
+
+        if '//external:gtest' in bazel_rule['_TRANSITIVE_DEPS']:
+            lib_dict['gtest'] = True
+            lib_dict['language'] = 'c++'
+
+
+def _generate_build_metadata(build_extra_metadata: BuildDict,
+                             bazel_rules: BuildDict) -> BuildDict:
     """Generate build metadata in build.yaml-like format bazel build metadata and build.yaml-specific "extra metadata"."""
     lib_names = list(build_extra_metadata.keys())
     result = {}
@@ -344,20 +385,6 @@
     for lib_name in lib_names:
         lib_dict = _create_target_from_bazel_rule(lib_name, bazel_rules)
 
-        # Figure out the final list of headers and sources for given target.
-        # While this is mostly based on bazel build metadata, build.yaml does
-        # not necessarily expose all the targets that are present in bazel build.
-        # These "intermediate dependencies" might get flattened.
-        # TODO(jtattermusch): This is done to avoid introducing too many intermediate
-        # libraries into the build.yaml-based builds (which might in cause issues
-        # building language-specific artifacts) and also because the libraries
-        # in build.yaml-based build are generally considered units of distributions
-        # (= public libraries that are visible to the user and are installable),
-        # while in bazel builds it is customary to define larger number of smaller
-        # "sublibraries". The need for elision (and expansion)
-        # of intermediate libraries can be re-evaluated in the future.
-        _expand_intermediate_deps(lib_dict, lib_names, bazel_rules)
-
         # populate extra properties from the build.yaml-specific "extra metadata"
         lib_dict.update(build_extra_metadata.get(lib_name, {}))
 
@@ -374,8 +401,8 @@
         if to_name:
             # store lib under the new name and also change its 'name' property
             if to_name in result:
-                raise Exception('Cannot rename target ' + lib_name + ', ' +
-                                to_name + ' already exists.')
+                raise Exception('Cannot rename target ' + str(lib_name) + ', ' +
+                                str(to_name) + ' already exists.')
             lib_dict = result.pop(lib_name)
             lib_dict['name'] = to_name
             result[to_name] = lib_dict
@@ -387,15 +414,10 @@
                     for dep in lib_dict_to_update['deps']
                 ])
 
-    # make sure deps are listed in reverse topological order (e.g. "grpc gpr" and not "gpr grpc")
-    for lib_dict in result.values():
-        lib_dict['deps'] = list(
-            reversed(_sort_by_build_order(lib_dict['deps'], result, 'deps')))
-
     return result
 
 
-def _convert_to_build_yaml_like(lib_dict):
+def _convert_to_build_yaml_like(lib_dict: BuildMetadata) -> BuildYaml:
     lib_names = [
         lib_name for lib_name in list(lib_dict.keys())
         if lib_dict[lib_name].get('_TYPE', 'library') == 'library'
@@ -438,7 +460,7 @@
     return build_yaml_like
 
 
-def _extract_cc_tests(bazel_rules):
+def _extract_cc_tests(bazel_rules: BuildDict) -> List[str]:
     """Gets list of cc_test tests from bazel rules"""
     result = []
     for bazel_rule in bazel_rules.values():
@@ -450,7 +472,7 @@
     return list(sorted(result))
 
 
-def _exclude_unwanted_cc_tests(tests):
+def _exclude_unwanted_cc_tests(tests: List[str]) -> List[str]:
     """Filters out bazel tests that we don't want to run with other build systems or we cannot build them reasonably"""
 
     # most qps tests are autogenerated, we are fine without them
@@ -516,7 +538,8 @@
     return tests
 
 
-def _generate_build_extra_metadata_for_tests(tests, bazel_rules):
+def _generate_build_extra_metadata_for_tests(
+        tests: List[str], bazel_rules: BuildDict) -> BuildDict:
     """For given tests, generate the "extra metadata" that we need for our "build.yaml"-like output. The extra metadata is generated from the bazel rule metadata by using a bunch of heuristics."""
     test_metadata = {}
     for test in tests:
@@ -565,19 +588,11 @@
                 platforms.append('windows')
             test_dict['platforms'] = platforms
 
-        if '//external:benchmark' in bazel_rule['transitive_deps']:
-            test_dict['benchmark'] = True
-            test_dict['defaults'] = 'benchmark'
-
         cmdline_args = bazel_rule['args']
         if cmdline_args:
             test_dict['args'] = list(cmdline_args)
 
-        uses_gtest = '//external:gtest' in bazel_rule['transitive_deps']
-        if uses_gtest:
-            test_dict['gtest'] = True
-
-        if test.startswith('test/cpp') or uses_gtest:
+        if test.startswith('test/cpp'):
             test_dict['language'] = 'c++'
 
         elif test.startswith('test/core'):
@@ -613,7 +628,7 @@
     return test_metadata
 
 
-def _detect_and_print_issues(build_yaml_like):
+def _detect_and_print_issues(build_yaml_like: BuildYaml) -> None:
     """Try detecting some unusual situations and warn about them."""
     for tgt in build_yaml_like['targets']:
         if tgt['build'] == 'test':
@@ -627,33 +642,26 @@
 # there are mostly extra properties that we weren't able to obtain from the bazel build
 # _TYPE: whether this is library, target or test
 # _RENAME: whether this target should be renamed to a different name (to match expectations of make and cmake builds)
-# NOTE: secure is 'check' by default, so setting secure = False below does matter
 _BUILD_EXTRA_METADATA = {
     'third_party/address_sorting:address_sorting': {
         'language': 'c',
         'build': 'all',
-        'secure': False,
         '_RENAME': 'address_sorting'
     },
     'gpr': {
         'language': 'c',
         'build': 'all',
-        'secure': False
     },
     'grpc': {
         'language': 'c',
         'build': 'all',
         'baselib': True,
-        'secure': True,
-        'deps_linkage': 'static',
-        'dll': True,
         'generate_plugin_registry': True
     },
     'grpc++': {
         'language': 'c++',
         'build': 'all',
         'baselib': True,
-        'dll': True
     },
     'grpc++_alts': {
         'language': 'c++',
@@ -672,23 +680,16 @@
         'language': 'c++',
         'build': 'all',
         'baselib': True,
-        'secure': False,
-        'dll': True
     },
     # TODO(jtattermusch): do we need to set grpc_csharp_ext's LDFLAGS for wrapping memcpy in the same way as in build.yaml?
     'grpc_csharp_ext': {
         'language': 'c',
         'build': 'all',
-        'deps_linkage': 'static',
-        'dll': 'only'
     },
     'grpc_unsecure': {
         'language': 'c',
         'build': 'all',
         'baselib': True,
-        'secure': False,
-        'deps_linkage': 'static',
-        'dll': True,
         'generate_plugin_registry': True
     },
     'grpcpp_channelz': {
@@ -702,55 +703,47 @@
     'src/compiler:grpc_plugin_support': {
         'language': 'c++',
         'build': 'protoc',
-        'secure': False,
         '_RENAME': 'grpc_plugin_support'
     },
     'src/compiler:grpc_cpp_plugin': {
         'language': 'c++',
         'build': 'protoc',
-        'secure': False,
         '_TYPE': 'target',
         '_RENAME': 'grpc_cpp_plugin'
     },
     'src/compiler:grpc_csharp_plugin': {
         'language': 'c++',
         'build': 'protoc',
-        'secure': False,
         '_TYPE': 'target',
         '_RENAME': 'grpc_csharp_plugin'
     },
     'src/compiler:grpc_node_plugin': {
         'language': 'c++',
         'build': 'protoc',
-        'secure': False,
         '_TYPE': 'target',
         '_RENAME': 'grpc_node_plugin'
     },
     'src/compiler:grpc_objective_c_plugin': {
         'language': 'c++',
         'build': 'protoc',
-        'secure': False,
         '_TYPE': 'target',
         '_RENAME': 'grpc_objective_c_plugin'
     },
     'src/compiler:grpc_php_plugin': {
         'language': 'c++',
         'build': 'protoc',
-        'secure': False,
         '_TYPE': 'target',
         '_RENAME': 'grpc_php_plugin'
     },
     'src/compiler:grpc_python_plugin': {
         'language': 'c++',
         'build': 'protoc',
-        'secure': False,
         '_TYPE': 'target',
         '_RENAME': 'grpc_python_plugin'
     },
     'src/compiler:grpc_ruby_plugin': {
         'language': 'c++',
         'build': 'protoc',
-        'secure': False,
         '_TYPE': 'target',
         '_RENAME': 'grpc_ruby_plugin'
     },
@@ -766,7 +759,6 @@
     'test/core/util:grpc_test_util_unsecure': {
         'language': 'c',
         'build': 'private',
-        'secure': False,
         '_RENAME': 'grpc_test_util_unsecure'
     },
     # TODO(jtattermusch): consider adding grpc++_test_util_unsecure - it doesn't seem to be used by bazel build (don't forget to set secure: False)
@@ -785,13 +777,11 @@
     'test/core/end2end:end2end_tests': {
         'language': 'c',
         'build': 'private',
-        'secure': True,
         '_RENAME': 'end2end_tests'
     },
     'test/core/end2end:end2end_nosec_tests': {
         'language': 'c',
         'build': 'private',
-        'secure': False,
         '_RENAME': 'end2end_nosec_tests'
     },
 
@@ -991,6 +981,8 @@
     'deps("//:all")',
     'deps("//src/compiler/...")',
     'deps("//src/proto/...")',
+    # The ^ is needed to differentiate proto_library from go_proto_library
+    'deps(kind("^proto_library", @envoy_api//envoy/...))',
 ]
 
 # Step 1: run a bunch of "bazel query --output xml" queries to collect
@@ -1010,14 +1002,6 @@
     bazel_rules.update(
         _extract_rules_from_bazel_xml(_bazel_query_xml_tree(query)))
 
-# Step 1a: Knowing the transitive closure of dependencies will make
-# the postprocessing simpler, so compute the info for all our rules.
-#
-# Example:
-# '//:grpc' : { ...,
-#               'transitive_deps': ['//:gpr_base', ...] }
-_populate_transitive_deps(bazel_rules)
-
 # Step 2: Extract the known bazel cc_test tests. While most tests
 # will be buildable with other build systems just fine, some of these tests
 # would be too difficult to build and run with other build systems,
@@ -1072,7 +1056,25 @@
 all_extra_metadata.update(
     _generate_build_extra_metadata_for_tests(tests, bazel_rules))
 
-# Step 4: Generate the final metadata for all the targets.
+# Step 4: Compute the build metadata that will be used in the final build.yaml.
+# The final build metadata includes transitive dependencies, and sources/headers
+# expanded without intermediate dependencies.
+# Example:
+# '//:grpc' : { ...,
+#               '_TRANSITIVE_DEPS': ['//:gpr_base', ...],
+#               '_COLLAPSED_DEPS': ['gpr', ...],
+#               '_COLLAPSED_SRCS': [...],
+#               '_COLLAPSED_PUBLIC_HEADERS': [...],
+#               '_COLLAPSED_HEADERS': [...]
+#             }
+_populate_transitive_metadata(bazel_rules, all_extra_metadata.keys())
+
+# Step 4a: Update the existing test metadata with the updated build metadata.
+# Certain build metadata of certain test targets depend on the transitive
+# metadata that wasn't available earlier.
+update_test_metadata_with_transitive_metadata(all_extra_metadata, bazel_rules)
+
+# Step 5: Generate the final metadata for all the targets.
 # This is done by combining the bazel build metadata and the "extra metadata"
 # we obtained in the previous step.
 # In this step, we also perform some interesting massaging of the target metadata
@@ -1102,7 +1104,7 @@
 #            ... }
 all_targets_dict = _generate_build_metadata(all_extra_metadata, bazel_rules)
 
-# Step 5: convert the dictionary with all the targets to a dict that has
+# Step 6: convert the dictionary with all the targets to a dict that has
 # the desired "build.yaml"-like layout.
 # TODO(jtattermusch): We use the custom "build.yaml"-like layout because
 # currently all other build systems use that format as their source of truth.
@@ -1119,7 +1121,7 @@
 # detect and report some suspicious situations we've seen before
 _detect_and_print_issues(build_yaml_like)
 
-# Step 6: Store the build_autogenerated.yaml in a deterministic (=sorted)
+# Step 7: Store the build_autogenerated.yaml in a deterministic (=sorted)
 # and cleaned-up form.
 # A basic overview of the resulting "build.yaml"-like format is here:
 # https://github.com/grpc/grpc/blob/master/templates/README.md
diff --git a/grpc/tools/buildgen/generate_build_additions.sh b/grpc/tools/buildgen/generate_build_additions.sh
index 0ed9b1e..46ff7e9 100755
--- a/grpc/tools/buildgen/generate_build_additions.sh
+++ b/grpc/tools/buildgen/generate_build_additions.sh
@@ -31,7 +31,7 @@
 gen_build_files=""
 for gen_build_yaml in $gen_build_yaml_dirs
 do
-  output_file=`mktemp /tmp/genXXXXXX`
+  output_file=$(mktemp /tmp/gen_$(echo $gen_build_yaml | tr '/' '_').yaml.XXXXX)
   python3 $gen_build_yaml/gen_build_yaml.py > $output_file
   gen_build_files="$gen_build_files $output_file"
 done
diff --git a/grpc/tools/buildgen/generate_projects.py b/grpc/tools/buildgen/generate_projects.py
index 841abbd..2e64484 100755
--- a/grpc/tools/buildgen/generate_projects.py
+++ b/grpc/tools/buildgen/generate_projects.py
@@ -14,99 +14,131 @@
 
 import argparse
 import glob
+import yaml
+import pickle
 import os
 import shutil
 import sys
 import tempfile
 import multiprocessing
-sys.path.append(
-    os.path.join(os.path.dirname(sys.argv[0]), '..', 'run_tests',
-                 'python_utils'))
+from typing import Union, Dict, List
 
-assert sys.argv[1:], 'run generate_projects.sh instead of this directly'
+import _utils
 
-import jobset
+PROJECT_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..",
+                            "..")
+os.chdir(PROJECT_ROOT)
+# TODO(lidiz) find a better way for plugins to reference each other
+sys.path.append(os.path.join(PROJECT_ROOT, 'tools', 'buildgen', 'plugins'))
 
-os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..', '..'))
+# from tools.run_tests.python_utils import jobset
+jobset = _utils.import_python_module(
+    os.path.join(PROJECT_ROOT, 'tools', 'run_tests', 'python_utils',
+                 'jobset.py'))
 
-argp = argparse.ArgumentParser()
-argp.add_argument('build_files', nargs='+', default=[])
-argp.add_argument('--templates', nargs='+', default=[])
-argp.add_argument('--output_merged', default=None, type=str)
-argp.add_argument('--jobs', '-j', default=multiprocessing.cpu_count(), type=int)
-argp.add_argument('--base', default='.', type=str)
-args = argp.parse_args()
-
-json = args.build_files
-
+PREPROCESSED_BUILD = '.preprocessed_build'
 test = {} if os.environ.get('TEST', 'false') == 'true' else None
 
-plugins = sorted(glob.glob('tools/buildgen/plugins/*.py'))
+assert sys.argv[1:], 'run generate_projects.sh instead of this directly'
+parser = argparse.ArgumentParser()
+parser.add_argument('build_files',
+                    nargs='+',
+                    default=[],
+                    help="build files describing build specs")
+parser.add_argument('--templates',
+                    nargs='+',
+                    default=[],
+                    help="mako template files to render")
+parser.add_argument('--output_merged',
+                    '-m',
+                    default='',
+                    type=str,
+                    help="merge intermediate results to a file")
+parser.add_argument('--jobs',
+                    '-j',
+                    default=multiprocessing.cpu_count(),
+                    type=int,
+                    help="maximum parallel jobs")
+parser.add_argument('--base',
+                    default='.',
+                    type=str,
+                    help="base path for generated files")
+args = parser.parse_args()
 
-templates = args.templates
-if not templates:
-    for root, dirs, files in os.walk('templates'):
-        for f in files:
-            templates.append(os.path.join(root, f))
 
-pre_jobs = []
-base_cmd = [sys.executable, 'tools/buildgen/mako_renderer.py']
-cmd = base_cmd[:]
-for plugin in plugins:
-    cmd.append('-p')
-    cmd.append(plugin)
-for js in json:
-    cmd.append('-d')
-    cmd.append(js)
-cmd.append('-w')
-preprocessed_build = '.preprocessed_build'
-cmd.append(preprocessed_build)
-if args.output_merged is not None:
-    cmd.append('-M')
-    cmd.append(args.output_merged)
-pre_jobs.append(
-    jobset.JobSpec(cmd, shortname='preprocess', timeout_seconds=None))
+def preprocess_build_files() -> _utils.Bunch:
+    """Merges build yaml into a one dictionary then pass it to plugins."""
+    build_spec = dict()
+    for build_file in args.build_files:
+        with open(build_file, 'r') as f:
+            _utils.merge_json(build_spec,
+                              yaml.load(f.read(), Loader=yaml.FullLoader))
+    # Executes plugins. Plugins update the build spec in-place.
+    for py_file in sorted(glob.glob('tools/buildgen/plugins/*.py')):
+        plugin = _utils.import_python_module(py_file)
+        plugin.mako_plugin(build_spec)
+    if args.output_merged:
+        with open(args.output_merged, 'w') as f:
+            f.write(yaml.dump(build_spec))
+    # Makes build_spec sort of immutable and dot-accessible
+    return _utils.to_bunch(build_spec)
 
-jobs = []
-for template in reversed(sorted(templates)):
-    root, f = os.path.split(template)
-    if os.path.splitext(f)[1] == '.template':
-        out_dir = args.base + root[len('templates'):]
-        out = out_dir + '/' + os.path.splitext(f)[0]
-        if not os.path.exists(out_dir):
-            os.makedirs(out_dir)
-        cmd = base_cmd[:]
-        cmd.append('-P')
-        cmd.append(preprocessed_build)
-        cmd.append('-o')
-        if test is None:
-            cmd.append(out)
-        else:
-            tf = tempfile.mkstemp()
-            test[out] = tf[1]
-            os.close(tf[0])
-            cmd.append(test[out])
-        cmd.append(args.base + '/' + root + '/' + f)
-        jobs.append(jobset.JobSpec(cmd, shortname=out, timeout_seconds=None))
 
-err_cnt, _ = jobset.run(pre_jobs, maxjobs=args.jobs)
-if err_cnt != 0:
-    print('ERROR: {count} error(s) encountered during preprocessing.'.format(
-        count=err_cnt),
-          file=sys.stderr)
-    sys.exit(1)
-err_cnt, _ = jobset.run(jobs, maxjobs=args.jobs)
-if err_cnt != 0:
-    print('ERROR: {count} error(s) found while generating projects.'.format(
-        count=err_cnt),
-          file=sys.stderr)
-    sys.exit(1)
+def generate_template_render_jobs(templates: List[str]) -> List[jobset.JobSpec]:
+    """Generate JobSpecs for each one of the template rendering work."""
+    jobs = []
+    base_cmd = [sys.executable, 'tools/buildgen/_mako_renderer.py']
+    for template in sorted(templates, reverse=True):
+        root, f = os.path.split(template)
+        if os.path.splitext(f)[1] == '.template':
+            out_dir = args.base + root[len('templates'):]
+            out = os.path.join(out_dir, os.path.splitext(f)[0])
+            if not os.path.exists(out_dir):
+                os.makedirs(out_dir)
+            cmd = base_cmd[:]
+            cmd.append('-P')
+            cmd.append(PREPROCESSED_BUILD)
+            cmd.append('-o')
+            if test is None:
+                cmd.append(out)
+            else:
+                tf = tempfile.mkstemp()
+                test[out] = tf[1]
+                os.close(tf[0])
+                cmd.append(test[out])
+            cmd.append(args.base + '/' + root + '/' + f)
+            jobs.append(jobset.JobSpec(cmd, shortname=out,
+                                       timeout_seconds=None))
+    return jobs
 
-if test is not None:
-    for s, g in test.items():
-        if os.path.isfile(g):
-            assert 0 == os.system('diff %s %s' % (s, g)), s
-            os.unlink(g)
-        else:
-            assert 0 == os.system('diff -r %s %s' % (s, g)), s
-            shutil.rmtree(g, ignore_errors=True)
+
+def main() -> None:
+    templates = args.templates
+    if not templates:
+        for root, _, files in os.walk('templates'):
+            for f in files:
+                templates.append(os.path.join(root, f))
+
+    build_spec = preprocess_build_files()
+    with open(PREPROCESSED_BUILD, 'wb') as f:
+        pickle.dump(build_spec, f)
+
+    err_cnt, _ = jobset.run(generate_template_render_jobs(templates),
+                            maxjobs=args.jobs)
+    if err_cnt != 0:
+        print('ERROR: %s error(s) found while generating projects.' % err_cnt,
+              file=sys.stderr)
+        sys.exit(1)
+
+    if test is not None:
+        for s, g in test.items():
+            if os.path.isfile(g):
+                assert 0 == os.system('diff %s %s' % (s, g)), s
+                os.unlink(g)
+            else:
+                assert 0 == os.system('diff -r %s %s' % (s, g)), s
+                shutil.rmtree(g, ignore_errors=True)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/grpc/tools/buildgen/generate_projects.sh b/grpc/tools/buildgen/generate_projects.sh
index 9b5c0f5..b98be3b 100755
--- a/grpc/tools/buildgen/generate_projects.sh
+++ b/grpc/tools/buildgen/generate_projects.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#! /bin/bash
 # Copyright 2015 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,15 +18,19 @@
 
 export TEST=${TEST:-false}
 
-# Upgrade Python's YAML library
-python3 -m pip install --upgrade --ignore-installed PyYAML --user
+YAML_OK=$(python3 -c "import yaml; print(yaml.__version__.split('.') >= ['5', '4', '1'])")
+
+if [[ "${YAML_OK}" != "True" ]]; then
+  # PyYAML dropped 3.5 support at 5.4.1, which makes 5.3.1 the latest version we
+  # can use.
+  python3 -m pip install --upgrade --ignore-installed PyYAML==5.3.1 --user
+fi
 
 echo "Generating build_autogenerated.yaml from bazel BUILD file"
 rm -f build_autogenerated.yaml
 python3 tools/buildgen/extract_metadata_from_bazel_xml.py
 
 cd `dirname $0`/../..
-mako_renderer=tools/buildgen/mako_renderer.py
 
 tools/buildgen/build_cleaner.py build_handwritten.yaml
 
@@ -38,6 +42,6 @@
 # Instead of generating from a single build.yaml, we've split it into
 # - build_handwritten.yaml: manually written metadata
 # - build_autogenerated.yaml: generated from bazel BUILD file
-python3 tools/buildgen/generate_projects.py build_handwritten.yaml build_autogenerated.yaml $gen_build_files $*
+python3 tools/buildgen/generate_projects.py build_handwritten.yaml build_autogenerated.yaml $gen_build_files "$@"
 
 rm $gen_build_files
diff --git a/grpc/tools/buildgen/plugins/expand_filegroups.py b/grpc/tools/buildgen/plugins/expand_filegroups.py
deleted file mode 100755
index b45e682..0000000
--- a/grpc/tools/buildgen/plugins/expand_filegroups.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# Copyright 2015 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.
-"""Buildgen expand filegroups plugin.
-
-This takes the list of libs from our yaml dictionary,
-and expands any and all filegroup.
-
-"""
-
-
-def excluded(filename, exclude_res):
-    for r in exclude_res:
-        if r.search(filename):
-            return True
-    return False
-
-
-def uniquify(lst):
-    out = []
-    for el in lst:
-        if el not in out:
-            out.append(el)
-    return out
-
-
-FILEGROUP_LISTS = ['src', 'headers', 'public_headers', 'deps']
-
-FILEGROUP_DEFAULTS = {
-    'language': 'c',
-    'boringssl': False,
-    'zlib': False,
-    'ares': False,
-}
-
-
-def mako_plugin(dictionary):
-    """The exported plugin code for expand_filegroups.
-
-  The list of libs in the build.yaml file can contain "filegroups" tags.
-  These refer to the filegroups in the root object. We will expand and
-  merge filegroups on the src, headers and public_headers properties.
-
-  """
-    libs = dictionary.get('libs')
-    targets = dictionary.get('targets')
-    filegroups_list = dictionary.get('filegroups')
-    filegroups_set = set(fg['name'] for fg in filegroups_list)
-    filegroups = {}
-
-    for fg in filegroups_list:
-        for lst in FILEGROUP_LISTS:
-            fg[lst] = fg.get(lst, [])
-            fg['own_%s' % lst] = list(fg[lst])
-        for attr, val in FILEGROUP_DEFAULTS.items():
-            if attr not in fg:
-                fg[attr] = val
-
-    todo = list(filegroups_list)
-    skips = 0
-
-    while todo:
-        assert skips != len(
-            todo), "infinite loop in filegroup uses clauses: %r" % [
-                t['name'] for t in todo
-            ]
-        # take the first element of the todo list
-        cur = todo[0]
-        todo = todo[1:]
-        # check all uses filegroups are present (if no, skip and come back later)
-        skip = False
-        for use in cur.get('uses', []):
-            assert use in filegroups_set, (
-                "filegroup(%s) uses non-existent %s" % (cur['name'], use))
-            if use not in filegroups:
-                skip = True
-        if skip:
-            skips += 1
-            todo.append(cur)
-        else:
-            skips = 0
-            assert 'plugins' not in cur
-            plugins = []
-            for uses in cur.get('uses', []):
-                for plugin in filegroups[uses]['plugins']:
-                    if plugin not in plugins:
-                        plugins.append(plugin)
-                for lst in FILEGROUP_LISTS:
-                    vals = cur.get(lst, [])
-                    vals.extend(filegroups[uses].get(lst, []))
-                    cur[lst] = vals
-            cur_plugin_name = cur.get('plugin')
-            if cur_plugin_name:
-                plugins.append(cur_plugin_name)
-            cur['plugins'] = plugins
-            filegroups[cur['name']] = cur
-
-    # build reverse dependency map
-    things = {}
-    for thing in dictionary['libs'] + dictionary['targets'] + dictionary[
-            'filegroups']:
-        things[thing['name']] = thing
-        thing['used_by'] = []
-    thing_deps = lambda t: t.get('uses', []) + t.get('filegroups', []) + t.get(
-        'deps', [])
-    for thing in things.values():
-        done = set()
-        todo = thing_deps(thing)
-        while todo:
-            cur = todo[0]
-            todo = todo[1:]
-            if cur in done: continue
-            things[cur]['used_by'].append(thing['name'])
-            todo.extend(thing_deps(things[cur]))
-            done.add(cur)
-
-    # the above expansion can introduce duplicate filenames: contract them here
-    for fg in filegroups.values():
-        for lst in FILEGROUP_LISTS:
-            fg[lst] = uniquify(fg.get(lst, []))
-
-    for tgt in dictionary['targets']:
-        for lst in FILEGROUP_LISTS:
-            tgt[lst] = tgt.get(lst, [])
-            tgt['own_%s' % lst] = list(tgt[lst])
-
-    for lib in libs + targets:
-        assert 'plugins' not in lib
-        plugins = []
-        for lst in FILEGROUP_LISTS:
-            vals = lib.get(lst, [])
-            lib[lst] = list(vals)
-            lib['own_%s' % lst] = list(vals)
-        for fg_name in lib.get('filegroups', []):
-            fg = filegroups[fg_name]
-            for plugin in fg['plugins']:
-                if plugin not in plugins:
-                    plugins.append(plugin)
-            for lst in FILEGROUP_LISTS:
-                vals = lib.get(lst, [])
-                vals.extend(fg.get(lst, []))
-                lib[lst] = vals
-            lib['plugins'] = plugins
-        if lib.get('generate_plugin_registry', False):
-            lib['src'].append('src/core/plugin_registry/%s_plugin_registry.cc' %
-                              lib['name'])
-        for lst in FILEGROUP_LISTS:
-            lib[lst] = uniquify(lib.get(lst, []))
diff --git a/grpc/tools/buildgen/plugins/generate_vsprojects.py b/grpc/tools/buildgen/plugins/generate_vsprojects.py
deleted file mode 100755
index 6fbad5e..0000000
--- a/grpc/tools/buildgen/plugins/generate_vsprojects.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright 2015 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.
-"""Buildgen vsprojects plugin.
-
-This parses the list of libraries, and generates globals "vsprojects"
-and "vsproject_dict", to be used by the visual studio generators.
-
-"""
-
-import hashlib
-import re
-
-
-def mako_plugin(dictionary):
-    """The exported plugin code for generate_vsprojeccts
-
-  We want to help the work of the visual studio generators.
-
-  """
-
-    libs = dictionary.get('libs', [])
-    targets = dictionary.get('targets', [])
-
-    for lib in libs:
-        lib['is_library'] = True
-    for target in targets:
-        target['is_library'] = False
-
-    projects = []
-    projects.extend(libs)
-    projects.extend(targets)
-    for target in projects:
-        if 'build' in target and target['build'] == 'test':
-            default_test_dir = 'test'
-        else:
-            default_test_dir = '.'
-        if 'vs_config_type' not in target:
-            if 'build' in target and target['build'] == 'test':
-                target['vs_config_type'] = 'Application'
-            else:
-                target['vs_config_type'] = 'StaticLibrary'
-        if 'vs_packages' not in target:
-            target['vs_packages'] = []
-        if 'vs_props' not in target:
-            target['vs_props'] = []
-        target['vs_proj_dir'] = target.get('vs_proj_dir', default_test_dir)
-        if target.get('vs_project_guid',
-                      None) is None and 'windows' in target.get(
-                          'platforms', ['windows']):
-            name = target['name']
-            guid = re.sub('(........)(....)(....)(....)(.*)',
-                          r'{\1-\2-\3-\4-\5}',
-                          hashlib.md5(name.encode('utf-8')).hexdigest())
-            target['vs_project_guid'] = guid.upper()
-    # Exclude projects without a visual project guid, such as the tests.
-    projects = [
-        project for project in projects if project.get('vs_project_guid', None)
-    ]
-
-    projects = [
-        project for project in projects
-        if project['language'] != 'c++' or project['build'] == 'all' or
-        project['build'] == 'protoc' or (project['language'] == 'c++' and (
-            project['build'] == 'test' or project['build'] == 'private'))
-    ]
-
-    project_dict = dict([(p['name'], p) for p in projects])
-
-    packages = dictionary.get('vspackages', [])
-    packages_dict = dict([(p['name'], p) for p in packages])
-
-    dictionary['vsprojects'] = projects
-    dictionary['vsproject_dict'] = project_dict
-    dictionary['vspackages_dict'] = packages_dict
diff --git a/grpc/tools/buildgen/plugins/make_fuzzer_tests.py b/grpc/tools/buildgen/plugins/make_fuzzer_tests.py
index 788a5f5..f691a22 100644
--- a/grpc/tools/buildgen/plugins/make_fuzzer_tests.py
+++ b/grpc/tools/buildgen/plugins/make_fuzzer_tests.py
@@ -28,15 +28,11 @@
             new_target['run'] = False
             new_target['src'].append(
                 'test/core/util/one_corpus_entry_fuzzer.cc')
-            new_target['own_src'].append(
-                'test/core/util/one_corpus_entry_fuzzer.cc')
 
             # avoid having two main() methods
             to_remove = 'test/core/util/fuzzer_corpus_test.cc'
             if to_remove in new_target['src']:
                 new_target['src'].remove(to_remove)
-            if to_remove in new_target['own_src']:
-                new_target['own_src'].remove(to_remove)
 
             targets.append(new_target)
             for corpus in new_target['corpus_dirs']:
diff --git a/grpc/tools/buildgen/plugins/transitive_dependencies.py b/grpc/tools/buildgen/plugins/transitive_dependencies.py
index 2a14526..0ca4f40 100644
--- a/grpc/tools/buildgen/plugins/transitive_dependencies.py
+++ b/grpc/tools/buildgen/plugins/transitive_dependencies.py
@@ -55,8 +55,12 @@
 
     for target_name, target_list in dictionary.items():
         for target in target_list:
-            if isinstance(target, dict) and 'deps' in target:
-                target['transitive_deps'] = transitive_deps(lib_map, target)
+            if isinstance(target, dict):
+                if 'deps' in target or target_name == 'libs':
+                    if not 'deps' in target:
+                        # make sure all the libs have the "deps" field populated
+                        target['deps'] = []
+                    target['transitive_deps'] = transitive_deps(lib_map, target)
 
     python_dependencies = dictionary.get('python_dependencies')
     python_dependencies['transitive_deps'] = transitive_deps(
diff --git a/grpc/tools/codegen/core/gen_header_frame.py b/grpc/tools/codegen/core/gen_header_frame.py
index e28a0bc..635b0b5 100755
--- a/grpc/tools/codegen/core/gen_header_frame.py
+++ b/grpc/tools/codegen/core/gen_header_frame.py
@@ -73,8 +73,10 @@
 vals = []
 for line in sys.stdin:
     line = line.strip()
-    if line == '': continue
-    if line[0] == '#': continue
+    if line == '':
+        continue
+    if line[0] == '#':
+        continue
     key_tail, value = line[1:].split(':')
     key = (line[0] + key_tail).strip()
     value = value.strip()
diff --git a/grpc/tools/codegen/core/gen_settings_ids.py b/grpc/tools/codegen/core/gen_settings_ids.py
index 644e80c..fb035ad 100755
--- a/grpc/tools/codegen/core/gen_settings_ids.py
+++ b/grpc/tools/codegen/core/gen_settings_ids.py
@@ -67,7 +67,8 @@
 with open(sys.argv[0]) as my_source:
     copyright = []
     for line in my_source:
-        if line[0] != '#': break
+        if line[0] != '#':
+            break
     for line in my_source:
         if line[0] == '#':
             copyright.append(line)
@@ -141,9 +142,12 @@
   switch (y) {
 """ % cgargs
 for i, r in enumerate(p.r):
-    if not r: continue
-    if r < 0: print >> C, 'case %d: h -= %d; break;' % (i, -r)
-    else: print >> C, 'case %d: h += %d; break;' % (i, r)
+    if not r:
+        continue
+    if r < 0:
+        print >> C, 'case %d: h -= %d; break;' % (i, -r)
+    else:
+        print >> C, 'case %d: h += %d; break;' % (i, r)
 print >> C, """
   }
   *out = (grpc_chttp2_setting_id)h;
diff --git a/grpc/tools/codegen/core/gen_stats_data.py b/grpc/tools/codegen/core/gen_stats_data.py
index 36e7408..f1bea06 100755
--- a/grpc/tools/codegen/core/gen_stats_data.py
+++ b/grpc/tools/codegen/core/gen_stats_data.py
@@ -82,10 +82,13 @@
     best = None
     for shift_bits in reversed(range(0, 64)):
         n = shift_works_until(mapped_bounds, shift_bits)
-        if n == 0: continue
+        if n == 0:
+            continue
         table_size = mapped_bounds[n - 1] >> shift_bits
-        if table_size > max_size: continue
-        if table_size > 65535: continue
+        if table_size > max_size:
+            continue
+        if table_size > 65535:
+            continue
         if best is None:
             best = (shift_bits, n, table_size)
         elif best[1] < n:
@@ -114,7 +117,8 @@
     global static_tables
     v = (type, values)
     for i, vp in enumerate(static_tables):
-        if v == vp: return i
+        if v == vp:
+            return i
     print "ADD TABLE: %s %r" % (type, values)
     r = len(static_tables)
     static_tables.append(v)
@@ -212,7 +216,8 @@
     with open(sys.argv[0]) as my_source:
         copyright = []
         for line in my_source:
-            if line[0] != '#': break
+            if line[0] != '#':
+                break
         for line in my_source:
             if line[0] == '#':
                 copyright.append(line)
@@ -304,7 +309,8 @@
     with open(sys.argv[0]) as my_source:
         copyright = []
         for line in my_source:
-            if line[0] != '#': break
+            if line[0] != '#':
+                break
         for line in my_source:
             if line[0] == '#':
                 copyright.append(line)
@@ -427,7 +433,8 @@
 with open('tools/run_tests/performance/massage_qps_stats.py', 'w') as P:
     with open(sys.argv[0]) as my_source:
         for line in my_source:
-            if line[0] != '#': break
+            if line[0] != '#':
+                break
         for line in my_source:
             if line[0] == '#':
                 print >> P, line.rstrip()
diff --git a/grpc/tools/codegen/core/gen_upb_api.sh b/grpc/tools/codegen/core/gen_upb_api.sh
index b4f7688..63ed717 100755
--- a/grpc/tools/codegen/core/gen_upb_api.sh
+++ b/grpc/tools/codegen/core/gen_upb_api.sh
@@ -43,9 +43,11 @@
 UPBDEFS_PLUGIN=$PWD/bazel-bin/external/upb/upbc/protoc-gen-upbdefs
 
 proto_files=( \
+  "envoy/admin/v3/config_dump.proto" \
   "envoy/annotations/deprecation.proto" \
   "envoy/annotations/resource.proto" \
   "envoy/config/accesslog/v3/accesslog.proto" \
+  "envoy/config/bootstrap/v3/bootstrap.proto" \
   "envoy/config/cluster/v3/circuit_breaker.proto" \
   "envoy/config/cluster/v3/cluster.proto" \
   "envoy/config/cluster/v3/filter.proto" \
@@ -70,11 +72,17 @@
   "envoy/config/listener/v3/listener.proto" \
   "envoy/config/listener/v3/listener_components.proto" \
   "envoy/config/listener/v3/udp_listener_config.proto" \
+  "envoy/config/metrics/v3/stats.proto" \
+  "envoy/config/overload/v3/overload.proto" \
   "envoy/config/rbac/v3/rbac.proto" \
   "envoy/config/route/v3/route.proto" \
   "envoy/config/route/v3/route_components.proto" \
   "envoy/config/route/v3/scoped_route.proto" \
   "envoy/config/trace/v3/http_tracer.proto" \
+  "envoy/extensions/clusters/aggregate/v3/cluster.proto" \
+  "envoy/extensions/filters/http/router/v3/router.proto" \
+  "envoy/extensions/filters/common/fault/v3/fault.proto" \
+  "envoy/extensions/filters/http/fault/v3/fault.proto" \
   "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto" \
   "envoy/extensions/transport_sockets/tls/v3/cert.proto" \
   "envoy/extensions/transport_sockets/tls/v3/common.proto" \
@@ -88,11 +96,14 @@
   "envoy/service/load_stats/v3/lrs.proto" \
   "envoy/service/route/v3/rds.proto" \
   "envoy/service/route/v3/srds.proto" \
+  "envoy/service/status/v3/csds.proto" \
   "envoy/type/matcher/v3/metadata.proto" \
+  "envoy/type/matcher/v3/node.proto" \
   "envoy/type/matcher/v3/number.proto" \
   "envoy/type/matcher/v3/path.proto" \
   "envoy/type/matcher/v3/regex.proto" \
   "envoy/type/matcher/v3/string.proto" \
+  "envoy/type/matcher/v3/struct.proto" \
   "envoy/type/matcher/v3/value.proto" \
   "envoy/type/metadata/v3/metadata.proto" \
   "envoy/type/tracing/v3/custom_tag.proto" \
@@ -112,6 +123,7 @@
   "google/protobuf/timestamp.proto" \
   "google/protobuf/wrappers.proto" \
   "google/rpc/status.proto" \
+  "src/proto/grpc/auth/v1/authz_policy.proto" \
   "src/proto/grpc/gcp/altscontext.proto" \
   "src/proto/grpc/gcp/handshaker.proto" \
   "src/proto/grpc/gcp/transport_security_common.proto" \
@@ -124,12 +136,13 @@
   "udpa/annotations/sensitive.proto" \
   "udpa/annotations/status.proto" \
   "udpa/annotations/versioning.proto" \
-  "udpa/core/v1/authority.proto" \
-  "udpa/core/v1/collection_entry.proto" \
-  "udpa/core/v1/context_params.proto" \
-  "udpa/core/v1/resource_locator.proto" \
-  "udpa/core/v1/resource_name.proto" \
-  "udpa/core/v1/resource.proto" \
+  "udpa/type/v1/typed_struct.proto" \
+  "xds/core/v3/authority.proto" \
+  "xds/core/v3/collection_entry.proto" \
+  "xds/core/v3/context_params.proto" \
+  "xds/core/v3/resource_locator.proto" \
+  "xds/core/v3/resource_name.proto" \
+  "xds/core/v3/resource.proto" \
   "validate/validate.proto")
 
 INCLUDE_OPTIONS="-I=$PWD/third_party/udpa \
diff --git a/grpc/tools/distrib/build_ruby_environment_macos.sh b/grpc/tools/distrib/build_ruby_environment_macos.sh
index fbbc1a7..5495799 100644
--- a/grpc/tools/distrib/build_ruby_environment_macos.sh
+++ b/grpc/tools/distrib/build_ruby_environment_macos.sh
@@ -17,15 +17,15 @@
 
 rm -rf ~/.rake-compiler
 
-CROSS_RUBY=$(mktemp tmpfile.XXXXXXXX)
+CROSS_RUBY="$(pwd)/$(mktemp tmpfile.XXXXXXXX)"
 
-curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/v1.1.0/tasks/bin/cross-ruby.rake > "$CROSS_RUBY"
+curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/v1.1.1/tasks/bin/cross-ruby.rake > "$CROSS_RUBY"
 
 # See https://github.com/grpc/grpc/issues/12161 for verconf.h patch details
 patch "$CROSS_RUBY" << EOF
---- cross-ruby.rake	2018-04-10 11:32:16.000000000 -0700
-+++ patched	2018-04-10 11:40:25.000000000 -0700
-@@ -133,8 +133,10 @@
+--- cross-ruby.rake	2021-03-05 12:04:09.898286632 -0800
++++ patched	2021-03-05 12:05:35.594318962 -0800
+@@ -111,10 +111,11 @@
      "--host=#{MINGW_HOST}",
      "--target=#{MINGW_TARGET}",
      "--build=#{RUBY_BUILD}",
@@ -34,12 +34,14 @@
 +    '--disable-shared',
      '--disable-install-doc',
 +    '--without-gmp',
-     '--with-ext='
+     '--with-ext=',
+-    'LDFLAGS=-pipe -s',
    ]
  
-@@ -151,6 +153,7 @@
+   # Force Winsock2 for Ruby 1.8, 1.9 defaults to it
+@@ -130,6 +131,7 @@
  # make
- file "#{USER_HOME}/builds/#{MINGW_HOST}/#{RUBY_CC_VERSION}/ruby.exe" => ["#{USER_HOME}/builds/#{MINGW_HOST}/#{RUBY_CC_VERSION}/Makefile"] do |t|
+ file "#{build_dir}/ruby.exe" => ["#{build_dir}/Makefile"] do |t|
    chdir File.dirname(t.prerequisites.first) do
 +    sh "test -s verconf.h || rm -f verconf.h"  # if verconf.h has size 0, make sure it gets re-built by make
      sh MAKE
@@ -49,22 +51,44 @@
 
 MAKE="make -j8"
 
+# Install ruby 3.0.0 for rake-compiler
+# Download ruby 3.0.0 sources outside of the cross-ruby.rake file, since the
+# latest rake-compiler/v1.1.1 cross-ruby.rake file requires tar.bz2 source
+# files.
+# TODO(apolcyn): remove this hack when tar.bz2 sources are available for ruby
+# 3.0.0 in https://ftp.ruby-lang.org/pub/ruby/3.0/. Also see
+# https://stackoverflow.com/questions/65477613/rvm-where-is-ruby-3-0-0.
 set +x # rvm commands are very verbose
 source ~/.rvm/scripts/rvm
+echo "rvm use 3.0.0"
+rvm use 3.0.0
+set -x
+RUBY_3_0_0_TAR="${HOME}/.rake-compiler/sources/ruby-3.0.0.tar.gz"
+mkdir -p "$(dirname $RUBY_3_0_0_TAR)"
+curl -L "https://ftp.ruby-lang.org/pub/ruby/3.0/$(basename $RUBY_3_0_0_TAR)" -o "$RUBY_3_0_0_TAR"
+ccache -c
+ruby --version | grep 'ruby 3.0.0'
+rake -f "$CROSS_RUBY" cross-ruby VERSION=3.0.0 HOST=x86_64-darwin11 MAKE="$MAKE" SOURCE="$RUBY_3_0_0_TAR"
+echo "installed ruby 3.0.0 build targets"
+# Install ruby 2.7.0 for rake-compiler
+set +x
+echo "rvm use 2.7.0"
 rvm use 2.7.0
 set -x
 ruby --version | grep 'ruby 2.7.0'
-for v in 2.7.0 ; do
-  ccache -c
-  rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin11 MAKE="$MAKE"
-done
+ccache -c
+rake -f "$CROSS_RUBY" cross-ruby VERSION=2.7.0 HOST=x86_64-darwin11 MAKE="$MAKE"
+echo "installed ruby 2.7.0 build targets"
+# Install ruby 2.4-2.6 for rake-compiler
 set +x
+echo "rvm use 2.5.0"
 rvm use 2.5.0
 set -x
 ruby --version | grep 'ruby 2.5.0'
-for v in 2.6.0 2.5.0 2.4.0 2.3.0 2.2.2 ; do
+for v in 2.6.0 2.5.0 2.4.0 ; do
   ccache -c
   rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin11 MAKE="$MAKE"
+  echo "installed ruby $v build targets"
 done
 
 sed 's/x86_64-darwin-11/universal-darwin/' ~/.rake-compiler/config.yml > "$CROSS_RUBY"
diff --git a/grpc/tools/distrib/c-ish/check_documentation.py b/grpc/tools/distrib/c-ish/check_documentation.py
index fef8f4e..d17d7eb 100755
--- a/grpc/tools/distrib/c-ish/check_documentation.py
+++ b/grpc/tools/distrib/c-ish/check_documentation.py
@@ -46,7 +46,8 @@
                 printed_banner = True
             print root
             errors += 1
-if printed_banner: print
+if printed_banner:
+    print
 printed_banner = False
 for target_dir in _TARGET_DIRS:
     for root, dirs, filenames in os.walk(target_dir):
diff --git a/grpc/tools/distrib/check_copyright.py b/grpc/tools/distrib/check_copyright.py
index 905725d..b8cc7a8 100755
--- a/grpc/tools/distrib/check_copyright.py
+++ b/grpc/tools/distrib/check_copyright.py
@@ -130,7 +130,8 @@
 
 
 def log(cond, why, filename):
-    if not cond: return
+    if not cond:
+        return
     if args.output == 'details':
         print('%s: %s' % (why, filename))
     else:
diff --git a/grpc/tools/distrib/check_include_guards.py b/grpc/tools/distrib/check_include_guards.py
index 91fe46e..d34251c 100755
--- a/grpc/tools/distrib/check_include_guards.py
+++ b/grpc/tools/distrib/check_include_guards.py
@@ -48,9 +48,12 @@
         self.endif_re = re.compile(r'#endif  // ([A-Z][A-Z_1-9]*)')
         self.failed = False
 
+    def _is_c_core_header(self, fpath):
+        return 'include' in fpath and not ('grpc++' in fpath or 'grpcpp'
+                                           in fpath or 'event_engine' in fpath)
+
     def fail(self, fpath, regexp, fcontents, match_txt, correct, fix):
-        c_core_header = 'include' in fpath and not ('grpc++' in fpath or
-                                                    'grpcpp' in fpath)
+        c_core_header = self._is_c_core_header(fpath)
         self.failed = True
         invalid_guards_msg_template = (
             '{0}: Missing preprocessor guards (RE {1}). '
@@ -81,8 +84,7 @@
         return fcontents
 
     def check(self, fpath, fix):
-        c_core_header = 'include' in fpath and not ('grpc++' in fpath or
-                                                    'grpcpp' in fpath)
+        c_core_header = self._is_c_core_header(fpath)
         valid_guard = build_valid_guard(fpath)
 
         fcontents = load(fpath)
@@ -101,13 +103,15 @@
         if not running_guard.endswith('_H'):
             fcontents = self.fail(fpath, match.re, match.string, match.group(1),
                                   valid_guard, fix)
-            if fix: save(fpath, fcontents)
+            if fix:
+                save(fpath, fcontents)
 
         # Is it the expected one based on the file path?
         if running_guard != valid_guard:
             fcontents = self.fail(fpath, match.re, match.string, match.group(1),
                                   valid_guard, fix)
-            if fix: save(fpath, fcontents)
+            if fix:
+                save(fpath, fcontents)
 
         # Is there a #define? Is it the same as the #ifndef one?
         match = self.define_re.search(fcontents)
@@ -120,7 +124,8 @@
         if match.group(1) != running_guard:
             fcontents = self.fail(fpath, match.re, match.string, match.group(1),
                                   valid_guard, fix)
-            if fix: save(fpath, fcontents)
+            if fix:
+                save(fpath, fcontents)
 
         # Is there a properly commented #endif?
         flines = fcontents.rstrip().splitlines()
@@ -146,9 +151,10 @@
                     flines[-1], '', '', False)
         elif match.group(1) != running_guard:
             # Is the #endif guard the same as the #ifndef and #define guards?
-            fcontents = self.fail(fpath, endif_re, fcontents, match.group(1),
-                                  valid_guard, fix)
-            if fix: save(fpath, fcontents)
+            fcontents = self.fail(fpath, self.endif_re, fcontents,
+                                  match.group(1), valid_guard, fix)
+            if fix:
+                save(fpath, fcontents)
 
         return not self.failed  # Did the check succeed? (ie, not failed)
 
diff --git a/grpc/tools/distrib/format_bazel.sh b/grpc/tools/distrib/format_bazel.sh
index 9aa98cb..d1c722c 100755
--- a/grpc/tools/distrib/format_bazel.sh
+++ b/grpc/tools/distrib/format_bazel.sh
@@ -23,7 +23,7 @@
 PYTHON=${VIRTUAL_ENV}/bin/python
 "$PYTHON" -m pip install --upgrade pip==19.3.1
 "$PYTHON" -m pip install --upgrade futures
-"$PYTHON" -m pip install yapf==0.28.0
+"$PYTHON" -m pip install yapf==0.30.0
 
 pushd "$(dirname "${0}")/../.."
 FILES=$(find . -path ./third_party -prune -o -name '*.bzl' -print)
diff --git a/grpc/tools/distrib/python/.gitignore b/grpc/tools/distrib/python/.gitignore
index 8ff3b08..266a230 100644
--- a/grpc/tools/distrib/python/.gitignore
+++ b/grpc/tools/distrib/python/.gitignore
@@ -1 +1,9 @@
 distrib_virtualenv/
+__init__.py
+generated_file_import_test.py
+envoy/
+udpa/
+validate/
+google/
+opencensus/
+xds/
diff --git a/grpc/tools/distrib/python/grpc_prefixed/generate.py b/grpc/tools/distrib/python/grpc_prefixed/generate.py
index 864971f..c685a1e 100644
--- a/grpc/tools/distrib/python/grpc_prefixed/generate.py
+++ b/grpc/tools/distrib/python/grpc_prefixed/generate.py
@@ -134,6 +134,16 @@
                     name_long='gRPC Health Checking',
                     destination_package='grpcio-health-checking'))
 
+    generate_package(
+        PackageMeta(name='grpc-csds',
+                    name_long='gRPC Client Status Discovery Service',
+                    destination_package='grpcio-csds'))
+
+    generate_package(
+        PackageMeta(name='grpc-admin',
+                    name_long='gRPC Admin Interface',
+                    destination_package='grpcio-admin'))
+
 
 if __name__ == "__main__":
     logging.basicConfig(level=logging.INFO)
diff --git a/grpc/tools/distrib/python/grpc_version.py b/grpc/tools/distrib/python/grpc_version.py
index d4ca1bc..8a17e74 100644
--- a/grpc/tools/distrib/python/grpc_version.py
+++ b/grpc/tools/distrib/python/grpc_version.py
@@ -14,5 +14,5 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION = '1.35.0'
-PROTOBUF_VERSION = '3.14.0'
+VERSION = '1.38.0'
+PROTOBUF_VERSION = '3.15.8'
diff --git a/grpc/tools/distrib/python/grpcio_tools/grpc_tools/protoc.py b/grpc/tools/distrib/python/grpcio_tools/grpc_tools/protoc.py
index 48f853a..0982451 100644
--- a/grpc/tools/distrib/python/grpcio_tools/grpc_tools/protoc.py
+++ b/grpc/tools/distrib/python/grpcio_tools/grpc_tools/protoc.py
@@ -42,6 +42,7 @@
 if sys.version_info >= (3, 5, 0):
     import contextlib
     import importlib
+    import importlib.abc
     import importlib.machinery
     import threading
 
diff --git a/grpc/tools/distrib/python/grpcio_tools/grpc_version.py b/grpc/tools/distrib/python/grpcio_tools/grpc_version.py
index 3aab128..0b3c4c8 100644
--- a/grpc/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/grpc/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -14,5 +14,5 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION = '1.35.0'
-PROTOBUF_VERSION = '3.14.0'
+VERSION = '1.38.0'
+PROTOBUF_VERSION = '3.15.8'
diff --git a/grpc/tools/distrib/python/grpcio_tools/protoc_lib_deps.py b/grpc/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
index 2851f9e..66b5270 100644
--- a/grpc/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
+++ b/grpc/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
@@ -20,4 +20,4 @@
 CC_INCLUDE='third_party/protobuf/src'
 PROTO_INCLUDE='third_party/protobuf/src'
 
-PROTOBUF_SUBMODULE_VERSION="19fb89416f3fdc2d6668f3738f444885575285bc"
+PROTOBUF_SUBMODULE_VERSION="436bd7880e458532901c58f4d9d1ea23fa7edd52"
diff --git a/grpc/tools/distrib/python/grpcio_tools/setup.py b/grpc/tools/distrib/python/grpcio_tools/setup.py
index a316038..c64f777 100644
--- a/grpc/tools/distrib/python/grpcio_tools/setup.py
+++ b/grpc/tools/distrib/python/grpcio_tools/setup.py
@@ -66,10 +66,26 @@
 
 PY3 = sys.version_info.major == 3
 
+
+def _env_bool_value(env_name, default):
+    """Parses a bool option from an environment variable"""
+    return os.environ.get(env_name, default).upper() not in ['FALSE', '0', '']
+
+
 # Environment variable to determine whether or not the Cython extension should
 # *use* Cython or use the generated C files. Note that this requires the C files
 # to have been generated by building first *with* Cython support.
-BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
+BUILD_WITH_CYTHON = _env_bool_value('GRPC_PYTHON_BUILD_WITH_CYTHON', 'False')
+
+# Export this variable to force building the python extension with a statically linked libstdc++.
+# At least on linux, this is normally not needed as we can build manylinux-compatible wheels on linux just fine
+# without statically linking libstdc++ (which leads to a slight increase in the wheel size).
+# This option is useful when crosscompiling wheels for aarch64 where
+# it's difficult to ensure that the crosscompilation toolchain has a high-enough version
+# of GCC (we require >4.9) but still uses old-enough libstdc++ symbols.
+# TODO(jtattermusch): remove this workaround once issues with crosscompiler version are resolved.
+BUILD_WITH_STATIC_LIBSTDCXX = _env_bool_value(
+    'GRPC_PYTHON_BUILD_WITH_STATIC_LIBSTDCXX', 'False')
 
 
 def check_linker_need_libatomic():
@@ -95,6 +111,24 @@
     return cpp_test.returncode == 0
 
 
+class BuildExt(build_ext.build_ext):
+    """Custom build_ext command."""
+
+    def get_ext_filename(self, ext_name):
+        # since python3.5, python extensions' shared libraries use a suffix that corresponds to the value
+        # of sysconfig.get_config_var('EXT_SUFFIX') and contains info about the architecture the library targets.
+        # E.g. on x64 linux the suffix is ".cpython-XYZ-x86_64-linux-gnu.so"
+        # When crosscompiling python wheels, we need to be able to override this suffix
+        # so that the resulting file name matches the target architecture and we end up with a well-formed
+        # wheel.
+        filename = build_ext.build_ext.get_ext_filename(self, ext_name)
+        orig_ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
+        new_ext_suffix = os.getenv('GRPC_PYTHON_OVERRIDE_EXT_SUFFIX')
+        if new_ext_suffix and filename.endswith(orig_ext_suffix):
+            filename = filename[:-len(orig_ext_suffix)] + new_ext_suffix
+        return filename
+
+
 # There are some situations (like on Windows) where CC, CFLAGS, and LDFLAGS are
 # entirely ignored/dropped/forgotten by distutils and its Cygwin/MinGW support.
 # We use these environment variables to thus get around that without locking
@@ -159,6 +193,9 @@
 EXTRA_COMPILE_ARGS = shlex.split(EXTRA_ENV_COMPILE_ARGS)
 EXTRA_LINK_ARGS = shlex.split(EXTRA_ENV_LINK_ARGS)
 
+if BUILD_WITH_STATIC_LIBSTDCXX:
+    EXTRA_LINK_ARGS.append('-static-libstdc++')
+
 CC_FILES = [os.path.normpath(cc_file) for cc_file in protoc_lib_deps.CC_FILES]
 PROTO_FILES = [
     os.path.normpath(proto_file) for proto_file in protoc_lib_deps.PROTO_FILES
@@ -245,22 +282,23 @@
         return extensions
 
 
-setuptools.setup(
-    name='grpcio-tools',
-    version=grpc_version.VERSION,
-    description='Protobuf code generator for gRPC',
-    long_description=open(_README_PATH, 'r').read(),
-    author='The gRPC Authors',
-    author_email='grpc-io@googlegroups.com',
-    url='https://grpc.io',
-    license='Apache License 2.0',
-    classifiers=CLASSIFIERS,
-    ext_modules=extension_modules(),
-    packages=setuptools.find_packages('.'),
-    install_requires=[
-        'protobuf>=3.5.0.post1, < 4.0dev',
-        'grpcio>={version}'.format(version=grpc_version.VERSION),
-        'setuptools',
-    ],
-    package_data=package_data(),
-)
+setuptools.setup(name='grpcio-tools',
+                 version=grpc_version.VERSION,
+                 description='Protobuf code generator for gRPC',
+                 long_description=open(_README_PATH, 'r').read(),
+                 author='The gRPC Authors',
+                 author_email='grpc-io@googlegroups.com',
+                 url='https://grpc.io',
+                 license='Apache License 2.0',
+                 classifiers=CLASSIFIERS,
+                 ext_modules=extension_modules(),
+                 packages=setuptools.find_packages('.'),
+                 install_requires=[
+                     'protobuf>=3.5.0.post1, < 4.0dev',
+                     'grpcio>={version}'.format(version=grpc_version.VERSION),
+                     'setuptools',
+                 ],
+                 package_data=package_data(),
+                 cmdclass={
+                     'build_ext': BuildExt,
+                 })
diff --git a/grpc/tools/distrib/python/xds_protos/README.rst b/grpc/tools/distrib/python/xds_protos/README.rst
new file mode 100644
index 0000000..698144e
--- /dev/null
+++ b/grpc/tools/distrib/python/xds_protos/README.rst
@@ -0,0 +1,10 @@
+Package "xds-protos" is a collection of ProtoBuf generated Python files for xDS protos (or the `data-plane-api <https://github.com/envoyproxy/data-plane-api>`_). You can find the source code of this project in `grpc/grpc <https://github.com/grpc/grpc>`_. For any question or suggestion, please post to https://github.com/grpc/grpc/issues.
+
+Each generated Python file can be imported according to their proto package. For example, if we are trying to import a proto located at "envoy/service/status/v3/csds.proto", whose proto package is "package envoy.service.status.v3", then we can import it as:
+
+::
+
+  # Import the message definitions
+  from envoy.service.status.v3 import csds_pb2
+  # Import the gRPC service and stub
+  from envoy.service.status.v3 import csds_pb2_grpc
diff --git a/grpc/tools/distrib/python/xds_protos/build.py b/grpc/tools/distrib/python/xds_protos/build.py
new file mode 100644
index 0000000..8b793f2
--- /dev/null
+++ b/grpc/tools/distrib/python/xds_protos/build.py
@@ -0,0 +1,139 @@
+#! /usr/bin/env python3
+# Copyright 2021 The 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.
+"""Builds the content of xds-protos package"""
+
+import os
+import pkg_resources
+from grpc_tools import protoc
+
+# We might not want to compile all the protos
+EXCLUDE_PROTO_PACKAGES_LIST = [
+    # Requires extra dependency to Prometheus protos
+    'envoy/service/metrics/v2',
+    'envoy/service/metrics/v3',
+    'envoy/service/metrics/v4alpha',
+]
+
+# Compute the pathes
+WORK_DIR = os.path.dirname(os.path.abspath(__file__))
+GRPC_ROOT = os.path.abspath(os.path.join(WORK_DIR, '..', '..', '..', '..'))
+XDS_PROTO_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'envoy-api')
+UDPA_PROTO_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'udpa')
+GOOGLEAPIS_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'googleapis')
+VALIDATE_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'protoc-gen-validate')
+OPENCENSUS_PROTO_ROOT = os.path.join(GRPC_ROOT, 'third_party',
+                                     'opencensus-proto', 'src')
+WELL_KNOWN_PROTOS_INCLUDE = pkg_resources.resource_filename(
+    'grpc_tools', '_proto')
+OUTPUT_PATH = WORK_DIR
+
+# Prepare the test file generation
+TEST_FILE_NAME = 'generated_file_import_test.py'
+TEST_IMPORTS = []
+
+# The pkgutil-style namespace packaging __init__.py
+PKGUTIL_STYLE_INIT = "__path__ = __import__('pkgutil').extend_path(__path__, __name__)\n"
+NAMESPACE_PACKAGES = ["google"]
+
+
+def add_test_import(proto_package_path: str,
+                    file_name: str,
+                    service: bool = False):
+    TEST_IMPORTS.append("from %s import %s\n" % (proto_package_path.replace(
+        '/', '.'), file_name.replace('.proto', '_pb2')))
+    if service:
+        TEST_IMPORTS.append("from %s import %s\n" % (proto_package_path.replace(
+            '/', '.'), file_name.replace('.proto', '_pb2_grpc')))
+
+
+# Prepare Protoc command
+COMPILE_PROTO_ONLY = [
+    'grpc_tools.protoc',
+    '--proto_path={}'.format(XDS_PROTO_ROOT),
+    '--proto_path={}'.format(UDPA_PROTO_ROOT),
+    '--proto_path={}'.format(GOOGLEAPIS_ROOT),
+    '--proto_path={}'.format(VALIDATE_ROOT),
+    '--proto_path={}'.format(WELL_KNOWN_PROTOS_INCLUDE),
+    '--proto_path={}'.format(OPENCENSUS_PROTO_ROOT),
+    '--python_out={}'.format(OUTPUT_PATH),
+]
+COMPILE_BOTH = COMPILE_PROTO_ONLY + ['--grpc_python_out={}'.format(OUTPUT_PATH)]
+
+
+def has_grpc_service(proto_package_path: str) -> bool:
+    return proto_package_path.startswith('envoy/service')
+
+
+def compile_protos(proto_root: str, sub_dir: str = '.') -> None:
+    for root, _, files in os.walk(os.path.join(proto_root, sub_dir)):
+        proto_package_path = os.path.relpath(root, proto_root)
+        if proto_package_path in EXCLUDE_PROTO_PACKAGES_LIST:
+            print(f'Skipping package {proto_package_path}')
+            continue
+        for file_name in files:
+            if file_name.endswith('.proto'):
+                # Compile proto
+                if has_grpc_service(proto_package_path):
+                    return_code = protoc.main(COMPILE_BOTH +
+                                              [os.path.join(root, file_name)])
+                    add_test_import(proto_package_path, file_name, service=True)
+                else:
+                    return_code = protoc.main(COMPILE_PROTO_ONLY +
+                                              [os.path.join(root, file_name)])
+                    add_test_import(proto_package_path,
+                                    file_name,
+                                    service=False)
+                if return_code != 0:
+                    raise Exception('error: {} failed'.format(COMPILE_BOTH))
+
+
+def create_init_file(path: str, package_path: str = "") -> None:
+    with open(os.path.join(path, "__init__.py"), 'w') as f:
+        # Apply the pkgutil-style namespace packaging, which is compatible for 2
+        # and 3. Here is the full table of namespace compatibility:
+        # https://github.com/pypa/sample-namespace-packages/blob/master/table.md
+        if package_path in NAMESPACE_PACKAGES:
+            f.write(PKGUTIL_STYLE_INIT)
+
+
+def main():
+    # Compile xDS protos
+    compile_protos(XDS_PROTO_ROOT)
+    compile_protos(UDPA_PROTO_ROOT)
+    # We don't want to compile the entire GCP surface API, just the essential ones
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'api'))
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'rpc'))
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'longrunning'))
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'logging'))
+    compile_protos(GOOGLEAPIS_ROOT, os.path.join('google', 'type'))
+    compile_protos(VALIDATE_ROOT, 'validate')
+    compile_protos(OPENCENSUS_PROTO_ROOT)
+
+    # Generate __init__.py files for all modules
+    create_init_file(WORK_DIR)
+    for proto_root_module in [
+            'envoy', 'google', 'opencensus', 'udpa', 'validate', 'xds'
+    ]:
+        for root, _, _ in os.walk(os.path.join(WORK_DIR, proto_root_module)):
+            package_path = os.path.relpath(root, WORK_DIR)
+            create_init_file(root, package_path)
+
+    # Generate test file
+    with open(os.path.join(WORK_DIR, TEST_FILE_NAME), 'w') as f:
+        f.writelines(TEST_IMPORTS)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/grpc/tools/distrib/python/xds_protos/build_validate_upload.sh b/grpc/tools/distrib/python/xds_protos/build_validate_upload.sh
new file mode 100755
index 0000000..4218940
--- /dev/null
+++ b/grpc/tools/distrib/python/xds_protos/build_validate_upload.sh
@@ -0,0 +1,47 @@
+#! /bin/bash
+# Copyright 2021 The 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.
+
+set -ex
+
+WORK_DIR=$(pwd)/"$(dirname "$0")"
+cd ${WORK_DIR}
+
+# Remove existing wheels
+rm -rf ${WORK_DIR}/dist
+
+# Generate the package content then build the source wheel
+python3 build.py
+python3 setup.py sdist
+python2 setup.py bdist_wheel
+python3 setup.py bdist_wheel
+
+# Run the tests to ensure all protos are importable, also avoid confusing normal
+# imports with relative imports
+pushd $(mktemp -d '/tmp/test_xds_protos.XXXXXX')
+python2 -m virtualenv env
+env/bin/python -m pip install ${WORK_DIR}/dist/xds-protos-*.tar.gz
+cp ${WORK_DIR}/generated_file_import_test.py generated_file_import_test.py
+env/bin/python generated_file_import_test.py
+popd
+pushd $(mktemp -d '/tmp/test_xds_protos.XXXXXX')
+python3 -m virtualenv env
+env/bin/python -m pip install ${WORK_DIR}/dist/xds-protos-*.tar.gz
+cp ${WORK_DIR}/generated_file_import_test.py generated_file_import_test.py
+env/bin/python generated_file_import_test.py
+popd
+
+# Upload the package
+python3 -m twine check dist/*
+python3 -m twine upload dist/*
diff --git a/grpc/tools/distrib/python/xds_protos/setup.py b/grpc/tools/distrib/python/xds_protos/setup.py
new file mode 100644
index 0000000..2ed04c4
--- /dev/null
+++ b/grpc/tools/distrib/python/xds_protos/setup.py
@@ -0,0 +1,52 @@
+#! /usr/bin/env python3
+# Copyright 2021 The 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.
+"""A PyPI package for xDS protos generated Python code."""
+
+import os
+import setuptools
+
+WORK_DIR = os.path.dirname(os.path.abspath(__file__))
+EXCLUDE_PYTHON_FILES = ['generated_file_import_test.py', 'build.py']
+
+# Use setuptools to build Python package
+with open(os.path.join(WORK_DIR, 'README.rst'), 'r') as f:
+    LONG_DESCRIPTION = f.read()
+PACKAGES = setuptools.find_packages(where=".", exclude=EXCLUDE_PYTHON_FILES)
+CLASSIFIERS = [
+    'Development Status :: 3 - Alpha',
+    'Programming Language :: Python',
+    'Programming Language :: Python :: 2',
+    'Programming Language :: Python :: 3',
+    'License :: OSI Approved :: Apache Software License',
+]
+INSTALL_REQUIRES = [
+    'grpcio',
+    'protobuf',
+]
+SETUP_REQUIRES = INSTALL_REQUIRES + ['grpcio-tools']
+setuptools.setup(
+    name='xds-protos',
+    version='0.0.8',
+    packages=PACKAGES,
+    description='Generated Python code from envoyproxy/data-plane-api',
+    long_description_content_type='text/x-rst',
+    long_description=LONG_DESCRIPTION,
+    author='The gRPC Authors',
+    author_email='grpc-io@googlegroups.com',
+    url='https://grpc.io',
+    license='Apache License 2.0',
+    install_requires=INSTALL_REQUIRES,
+    setup_requires=SETUP_REQUIRES,
+    classifiers=CLASSIFIERS)
diff --git a/grpc/tools/distrib/run_clang_tidy.py b/grpc/tools/distrib/run_clang_tidy.py
index 345dd00..e956536 100755
--- a/grpc/tools/distrib/run_clang_tidy.py
+++ b/grpc/tools/distrib/run_clang_tidy.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 # Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/grpc/tools/distrib/yapf_code.sh b/grpc/tools/distrib/yapf_code.sh
index cd4e722..4e3767a 100755
--- a/grpc/tools/distrib/yapf_code.sh
+++ b/grpc/tools/distrib/yapf_code.sh
@@ -33,8 +33,6 @@
 
 python3 -m virtualenv $VIRTUALENV -p $(which python3)
 PYTHON=${VIRTUALENV}/bin/python
-"$PYTHON" -m pip install --upgrade pip==19.3.1
-"$PYTHON" -m pip install --upgrade futures
-"$PYTHON" -m pip install yapf==0.28.0
+"$PYTHON" -m pip install yapf==0.30.0
 
-$PYTHON -m yapf $ACTION --recursive --style=setup.cfg "${DIRS[@]}"
+$PYTHON -m yapf $ACTION --parallel --recursive --style=setup.cfg "${DIRS[@]}"
diff --git a/grpc/tools/dockerfile/distribtest/cpp_stretch_aarch64_cross_x64/Dockerfile b/grpc/tools/dockerfile/distribtest/cpp_stretch_aarch64_cross_x64/Dockerfile
new file mode 100644
index 0000000..e20df95
--- /dev/null
+++ b/grpc/tools/dockerfile/distribtest/cpp_stretch_aarch64_cross_x64/Dockerfile
@@ -0,0 +1,29 @@
+# Copyright 2021 The 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.
+
+FROM debian:stretch
+
+# gRPC C++ dependencies based on https://github.com/grpc/grpc/blob/master/BUILDING.md
+RUN apt-get update && apt-get install -y build-essential autoconf libtool pkg-config && apt-get clean
+
+# debian stretch has cmake 3.7: https://packages.debian.org/stretch/cmake
+RUN apt-get update && apt-get install -y cmake && apt-get clean
+
+# C++ distribtests are setup in a way that requires git
+RUN apt-get update && apt-get install -y git && apt-get clean
+
+# aarch cross-compiler
+RUN apt-get update && apt-get install -y g++-6-aarch64-linux-gnu
+
+CMD ["bash"]
diff --git a/grpc/tools/dockerfile/distribtest/csharp_dotnet5_x64/Dockerfile b/grpc/tools/dockerfile/distribtest/csharp_dotnet5_x64/Dockerfile
index 60ce55b..3f95ef1 100644
--- a/grpc/tools/dockerfile/distribtest/csharp_dotnet5_x64/Dockerfile
+++ b/grpc/tools/dockerfile/distribtest/csharp_dotnet5_x64/Dockerfile
@@ -12,8 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# "5.0" tag uses debian buster
-FROM mcr.microsoft.com/dotnet/sdk:5.0
+# "5.0.x" tag uses debian buster
+# we use the full version number to make docker image version updates explicit
+FROM mcr.microsoft.com/dotnet/sdk:5.0.103
 
 RUN apt-get update && apt-get install -y unzip && apt-get clean
 
diff --git a/grpc/tools/dockerfile/distribtest/python_dev_alpine3.7_x64/Dockerfile b/grpc/tools/dockerfile/distribtest/python_dev_alpine3.7_x64/Dockerfile
index a208ae0..b51cad9 100644
--- a/grpc/tools/dockerfile/distribtest/python_dev_alpine3.7_x64/Dockerfile
+++ b/grpc/tools/dockerfile/distribtest/python_dev_alpine3.7_x64/Dockerfile
@@ -12,9 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM alpine:3.9
+FROM alpine:3.11
 
-RUN apk add --update build-base linux-headers python python-dev py-pip
+RUN apk add --update build-base linux-headers python python2-dev py2-pip
 
 RUN pip install --upgrade pip==19.3.1
 
diff --git a/grpc/tools/dockerfile/distribtest/python_dev_centos7_x64/Dockerfile b/grpc/tools/dockerfile/distribtest/python_dev_centos7_x64/Dockerfile
index 18e3c7b..df5ca64 100644
--- a/grpc/tools/dockerfile/distribtest/python_dev_centos7_x64/Dockerfile
+++ b/grpc/tools/dockerfile/distribtest/python_dev_centos7_x64/Dockerfile
@@ -18,7 +18,7 @@
 RUN yum install -y python-devel
 RUN yum install -y epel-release
 RUN yum install -y python-pip
-RUN pip install --upgrade pip
+RUN pip install --upgrade pip==19.3.1
 RUN pip install -U virtualenv
 
 # The default gcc of CentOS 7 is gcc 4.8 which is older than gcc 4.9,
diff --git a/grpc/tools/dockerfile/distribtest/python_python38_buster_aarch64/Dockerfile b/grpc/tools/dockerfile/distribtest/python_python38_buster_aarch64/Dockerfile
new file mode 100644
index 0000000..8b14a43
--- /dev/null
+++ b/grpc/tools/dockerfile/distribtest/python_python38_buster_aarch64/Dockerfile
@@ -0,0 +1,18 @@
+# Copyright 2021 The 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.
+
+# this an aarch64 image, qemu emulator will be used to run the tests
+FROM arm64v8/python:3.8-buster
+
+RUN pip install virtualenv
diff --git a/grpc/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile b/grpc/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
index f1a5c79..d00c7b4 100644
--- a/grpc/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
+++ b/grpc/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
@@ -16,4 +16,10 @@
 
 RUN apt-get update -y && apt-get install -y python python-pip
 
-RUN pip install virtualenv
+# Necessary to fix virtualenv compatibility problems with python2.7
+RUN pip install --upgrade pip==19.3.1
+
+# Ubuntu's python-pip package installs pip to /usr/bin, whereas the upgraded
+# pip lives at /usr/local/bin/pip. We'll use the absolute path for now, since
+# this will all be replaced with python3.
+RUN /usr/local/bin/pip install virtualenv
diff --git a/grpc/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile b/grpc/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
index fc4eabb..b781e92 100644
--- a/grpc/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
+++ b/grpc/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
@@ -14,18 +14,18 @@
 
 FROM centos:7
 
-RUN yum update && yum install -y curl tar which
+RUN yum update -y && yum install -y curl tar which
 
 # Install rvm
 RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
 RUN curl -sSL https://get.rvm.io | bash -s stable
 
 # Install Ruby 2.3
-RUN /bin/bash -l -c "rvm install ruby-2.3.8"
-RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
+RUN /bin/bash -l -c "rvm install ruby-2.4.9"
+RUN /bin/bash -l -c "rvm use --default ruby-2.4.9"
 RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.gemrc"
 RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.3.8' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.4.9' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
 
 RUN mkdir /var/local/jenkins
diff --git a/grpc/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile b/grpc/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
index f586ae3..56c564f 100644
--- a/grpc/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
+++ b/grpc/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
@@ -27,11 +27,11 @@
 RUN curl -sSL https://get.rvm.io | bash -s stable
 
 # Install Ruby 2.3
-RUN /bin/bash -l -c "rvm install ruby-2.3.8"
-RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
+RUN /bin/bash -l -c "rvm install ruby-2.4.9"
+RUN /bin/bash -l -c "rvm use --default ruby-2.4.9"
 RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.gemrc"
 RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.3.8' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.4.9' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
 
 RUN mkdir /var/local/jenkins
diff --git a/grpc/tools/dockerfile/distribtest/ruby_jessie_x64_ruby_2_3/Dockerfile b/grpc/tools/dockerfile/distribtest/ruby_jessie_x64_ruby_2_3/Dockerfile
deleted file mode 100644
index 9deff06..0000000
--- a/grpc/tools/dockerfile/distribtest/ruby_jessie_x64_ruby_2_3/Dockerfile
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2015 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.
-
-FROM debian:jessie
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  curl \
-  gcc && apt-get clean
-
-#==================
-# Ruby dependencies
-
-# Install rvm
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.3
-RUN /bin/bash -l -c "rvm install ruby-2.3.8"
-RUN /bin/bash -l -c "rvm use --default ruby-2.3.8"
-RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.3.8' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem update --system"
-RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/grpc/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile b/grpc/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
index 512f800..3d3b04b 100644
--- a/grpc/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
+++ b/grpc/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
@@ -14,6 +14,22 @@
 
 FROM ubuntu:16.04
 
-RUN apt-get update -y && apt-get install -y ruby-full
+# Install Git and basic packages.
+RUN apt-get update -y && apt-get install -y \
+  curl \
+  gcc && apt-get clean
 
-RUN gem install bundler
+#==================
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.4
+RUN /bin/bash -l -c "rvm install ruby-2.4.9"
+RUN /bin/bash -l -c "rvm use --default ruby-2.4.9"
+RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.4.9' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
diff --git a/grpc/tools/dockerfile/grpc_artifact_linux_armv6/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_linux_armv6/Dockerfile
deleted file mode 100644
index e2c4065..0000000
--- a/grpc/tools/dockerfile/grpc_artifact_linux_armv6/Dockerfile
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2017 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.
-
-# Docker file for building gRPC Raspbian binaries
-
-# TODO(https://github.com/grpc/grpc/issues/19199): Move off of this image.
-FROM quay.io/grpc/raspbian_armv6
-
-# Place any extra build instructions between these commands
-# Recommend modifying upstream docker image (quay.io/grpc/raspbian_armv6)
-# for build steps because running them under QEMU is very slow
-# (https://github.com/kpayson64/armv7hf-debian-qemu)
-RUN [ "cross-build-start" ]
-RUN find /usr/local/bin -regex '.*python[0-9]+\.[0-9]+' | xargs -n1 -i{} bash -c "{} -m pip install --upgrade wheel setuptools"
-RUN [ "cross-build-end" ]
diff --git a/grpc/tools/dockerfile/grpc_artifact_linux_armv7/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_linux_armv7/Dockerfile
deleted file mode 100644
index 735c2e8..0000000
--- a/grpc/tools/dockerfile/grpc_artifact_linux_armv7/Dockerfile
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2017 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.
-
-# Docker file for building gRPC Raspbian binaries
-
-# TODO(https://github.com/grpc/grpc/issues/19199): Move off of this base image.
-FROM quay.io/grpc/raspbian_armv7
-
-# Place any extra build instructions between these commands
-# Recommend modifying upstream docker image (quay.io/grpc/raspbian_armv7)
-# for build steps because running them under QEMU is very slow
-# (https://github.com/kpayson64/armv7hf-debian-qemu)
-RUN [ "cross-build-start" ]
-RUN find /usr/local/bin -regex '.*python[0-9]+\.[0-9]+' | xargs -n1 -i{} bash -c "{} -m pip install --upgrade wheel setuptools"
-RUN [ "cross-build-end" ]
diff --git a/grpc/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
deleted file mode 100644
index 922e61b..0000000
--- a/grpc/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright 2016 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Docker file for building gRPC artifacts.
-
-FROM debian:jessie
-RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  clang \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-
-##################
-# Ruby dependencies
-
-# Install rvm
-RUN apt-get update && apt-get install -y gnupg2
-RUN gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.1
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
-RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
-
-##################
-# C# dependencies (needed to build grpc_csharp_ext)
-
-# Use cmake 3.6 from jessie-backports
-RUN echo "deb http://archive.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
-RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf
-RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list
-RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
-
-
-##################
-# Python AuditWheel dependencies (needed to check manylinux1 compatibility)
-
-RUN apt-get install -y python3 python3-pip
-RUN pip3 install auditwheel==2.1.1
-
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/grpc/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
deleted file mode 100644
index 8738137..0000000
--- a/grpc/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright 2016 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Docker file for building gRPC artifacts.
-
-FROM i386/debian:jessie
-RUN sed -i '/deb http:\/\/http.debian.net\/debian jessie-updates main/d' /etc/apt/sources.list
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  clang \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-
-##################
-# Ruby dependencies
-
-# Install rvm
-RUN apt-get update && apt-get install -y gnupg2
-RUN gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.1
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
-RUN /bin/bash -l -c "echo 'gem: --no-document' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler -v 1.17.3 --no-document"
-
-
-##################
-# C# dependencies (needed to build grpc_csharp_ext)
-
-# Use cmake 3.6 from jessie-backports
-RUN echo "deb http://archive.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
-RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf
-RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list
-RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
-
-
-##################
-# Python AuditWheel dependencies (needed to check manylinux1 compatibility)
-
-RUN apt-get install -y python3 python3-pip
-RUN pip3 install auditwheel==2.1.1
-
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/grpc/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile
new file mode 100644
index 0000000..9af7874
--- /dev/null
+++ b/grpc/tools/dockerfile/grpc_artifact_python_linux_armv7/Dockerfile
@@ -0,0 +1,31 @@
+# Copyright 2020 The 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.
+
+# The aarch64 wheels are being crosscompiled to allow running the build
+# on x64 machine. The dockcross/linux-armv7 image is a x86_64
+# image with crosscompilation toolchain installed
+FROM dockcross/linux-armv7
+
+RUN apt update && apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev \
+                                 libnss3-dev libssl-dev libreadline-dev libffi-dev && apt-get clean
+
+ADD install_python_for_wheel_crosscompilation.sh /scripts/install_python_for_wheel_crosscompilation.sh
+
+RUN /scripts/install_python_for_wheel_crosscompilation.sh 3.6.13 /opt/python/cp36-cp36m
+RUN /scripts/install_python_for_wheel_crosscompilation.sh 3.7.10 /opt/python/cp37-cp37m
+RUN /scripts/install_python_for_wheel_crosscompilation.sh 3.8.8 /opt/python/cp38-cp38
+RUN /scripts/install_python_for_wheel_crosscompilation.sh 3.9.2 /opt/python/cp39-cp39
+
+ENV AUDITWHEEL_ARCH armv7l
+ENV AUDITWHEEL_PLAT linux_armv7l
diff --git a/grpc/tools/dockerfile/grpc_artifact_python_linux_armv7/install_python_for_wheel_crosscompilation.sh b/grpc/tools/dockerfile/grpc_artifact_python_linux_armv7/install_python_for_wheel_crosscompilation.sh
new file mode 100755
index 0000000..cc7349b
--- /dev/null
+++ b/grpc/tools/dockerfile/grpc_artifact_python_linux_armv7/install_python_for_wheel_crosscompilation.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright 2021 The 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.
+
+set -ex
+
+# ARGUMENTS
+# $1 - python version in "3.X.Y" format
+# $2 - python tags (as in manylinx images) e.g. "/opt/python/cp37-cp37m"
+PYTHON_VERSION="$1"
+PYTHON_PREFIX="$2"
+
+curl -O "https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz"
+tar -xf "Python-${PYTHON_VERSION}.tar.xz"
+pushd "Python-${PYTHON_VERSION}"
+
+# In this step, we are building python that can run on the architecture where the build runs (x64).
+# Since the CC, CXX and other env vars are set by default to point to the crosscompilation toolchain,
+# we explicitly unset them to end up with x64 python binaries.
+(unset AS AR CC CPP CXX LD && ./configure --prefix="${PYTHON_PREFIX}" && make -j 4 && make install)
+
+# When building the crosscompiled native extension, python will automatically add its include directory
+# that contains "Python.h" and other headers. But since we are going to be crosscompiling
+# the wheels, we need the pyconfig.h that corresponds to the target architecture.
+# Since pyconfig.h is the only generated header and python itself (once built) doesn't
+# really need this header anymore, we simply generate a new pyconfig.h using our crosscompilation
+# toolchain and overwrite the current ("wrong") version in the python's include directory.
+./configure && cp pyconfig.h "${PYTHON_PREFIX}"/include/python*
+
+popd
+# remove the build directory to decrease the overall docker image size
+rm -rf "Python-${PYTHON_VERSION}"
+
+# install cython and wheel
+"${PYTHON_PREFIX}/bin/pip3" install --upgrade cython wheel
diff --git a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2010_x64/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2010_x64/Dockerfile
index 84fa461..ff31e31 100644
--- a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2010_x64/Dockerfile
+++ b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2010_x64/Dockerfile
@@ -13,13 +13,14 @@
 # limitations under the License.
 
 # Docker file for building gRPC manylinux Python artifacts.
-# Updated: 2020-10-08
 
-FROM quay.io/pypa/manylinux2010_x86_64
+# python2.7 was removed from the manylinux2010 image.
+# Use the latest version that still has python2.7
+# TODO(jtattermusch): Stop building python2.7 wheels.
+FROM quay.io/pypa/manylinux2010_x86_64:2021-02-06-3d322a5
 
-# Update the package manager
-RUN yum update -y
-RUN yum install -y curl-devel expat-devel gettext-devel linux-headers openssl-devel zlib-devel gcc
+# TODO(jtattermusch): revisit which of the deps are really required
+RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel linux-headers openssl-devel zlib-devel gcc
 
 ###################################
 # Install Python build requirements
diff --git a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2010_x86/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2010_x86/Dockerfile
index b375792..0896ac4 100644
--- a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2010_x86/Dockerfile
+++ b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2010_x86/Dockerfile
@@ -13,13 +13,14 @@
 # limitations under the License.
 
 # Docker file for building gRPC manylinux Python artifacts.
-# Updated: 2020-10-08
 
-FROM quay.io/pypa/manylinux2010_i686
+# python2.7 was removed from the manylinux2010 image.
+# Use the latest version that still has python2.7
+# TODO(jtattermusch): Stop building python2.7 wheels.
+FROM quay.io/pypa/manylinux2010_i686:2021-02-06-3d322a5
 
-# Update the package manager
-RUN yum update -y
-RUN yum install -y curl-devel expat-devel gettext-devel linux-headers openssl-devel zlib-devel gcc
+# TODO(jtattermusch): revisit which of the deps are really required
+RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel linux-headers openssl-devel zlib-devel gcc
 
 ###################################
 # Install Python build requirements
diff --git a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile
new file mode 100644
index 0000000..db98443
--- /dev/null
+++ b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64/Dockerfile
@@ -0,0 +1,35 @@
+# Copyright 2020 The 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.
+
+# The aarch64 wheels are being crosscompiled to allow running the build
+# on x64 machine. The dockcross/manylinux2014-aarch64 image is a x86_64
+# image with crosscompilation toolchain installed.
+# Use an older version of dockcross image that has gcc4.9.4 because it was built
+# before https://github.com/dockcross/dockcross/pull/449
+FROM dockcross/manylinux2014-aarch64:20200929-608e6ac
+
+###################################
+# Install Python build requirements
+RUN /opt/python/cp35-cp35m/bin/pip install --upgrade cython
+RUN /opt/python/cp36-cp36m/bin/pip install --upgrade cython
+RUN /opt/python/cp37-cp37m/bin/pip install --upgrade cython
+RUN /opt/python/cp38-cp38/bin/pip install --upgrade cython
+RUN /opt/python/cp39-cp39/bin/pip install --upgrade cython
+
+# the dockcross docker image sets variables like CC, CXX etc.
+# to point to the crosscompilation toolchain, but doesn't set corresponding
+# variables for the "strip" and "objcopy" tools.
+# see https://github.com/dockcross/dockcross/blob/4349cb4999401cbf22a90f46f5052d29be240e50/manylinux2014-aarch64/Dockerfile.in#L23
+ENV STRIP=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-strip \
+    OBJCOPY=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-objcopy
diff --git a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile
index 1ded6e7..7747552 100644
--- a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile
+++ b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_x64/Dockerfile
@@ -17,9 +17,8 @@
 
 FROM quay.io/pypa/manylinux2014_x86_64
 
-# Update the package manager
-RUN yum update -y
-RUN yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel
+# TODO(jtattermusch): revisit which of the deps are really required
+RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel
 
 ###################################
 # Install Python build requirements
diff --git a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile
index 2f25e29..45f64ac 100644
--- a/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile
+++ b/grpc/tools/dockerfile/grpc_artifact_python_manylinux2014_x86/Dockerfile
@@ -17,9 +17,8 @@
 
 FROM quay.io/pypa/manylinux2014_i686
 
-# Update the package manager
-RUN yum update -y
-RUN yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel
+# TODO(jtattermusch): revisit which of the deps are really required
+RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel
 
 ###################################
 # Install Python build requirements
diff --git a/grpc/tools/dockerfile/grpc_clang_format/Dockerfile b/grpc/tools/dockerfile/grpc_clang_format/Dockerfile
index acc784a..bb8979e 100644
--- a/grpc/tools/dockerfile/grpc_clang_format/Dockerfile
+++ b/grpc/tools/dockerfile/grpc_clang_format/Dockerfile
@@ -12,14 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM debian:10
-
-# Add buster-backports for more recent clang packages
-RUN echo "deb http://deb.debian.org/debian buster-backports main" | tee /etc/apt/sources.list.d/buster-backports.list
+FROM debian:bullseye
 
 # Install clang-format
-RUN apt-get update && apt-get install -y clang-format-8
-ENV CLANG_FORMAT=clang-format-8
+RUN apt-get update && apt-get install -y clang-format-11
+ENV CLANG_FORMAT=clang-format-11
 
 ADD clang_format_all_the_things.sh /
 
diff --git a/grpc/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh b/grpc/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
index eb17e73..ff6f2f5 100755
--- a/grpc/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
+++ b/grpc/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
@@ -16,7 +16,7 @@
 set -e
 
 # directories to run against
-DIRS="src/core/lib src/core/tsi src/core/ext src/cpp test/core test/cpp include src/compiler src/csharp src/ruby third_party/address_sorting src/objective-c tools/distrib/python"
+DIRS="examples/cpp src/core/lib src/core/tsi src/core/ext src/cpp test/core test/cpp include src/compiler src/csharp src/ruby third_party/address_sorting src/objective-c tools/distrib/python"
 
 # file matching patterns to check
 GLOB="*.h *.c *.cc *.m *.mm"
diff --git a/grpc/tools/dockerfile/grpc_clang_tidy/Dockerfile b/grpc/tools/dockerfile/grpc_clang_tidy/Dockerfile
index 662ff8a..adc91d1 100644
--- a/grpc/tools/dockerfile/grpc_clang_tidy/Dockerfile
+++ b/grpc/tools/dockerfile/grpc_clang_tidy/Dockerfile
@@ -12,61 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM debian:10
-  
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  dnsutils \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
+FROM debian:bullseye
 
-#================
-# Build profiling
-RUN apt-get update && apt-get install -y time && apt-get clean
-
-# Install Python 2.7
-RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
-
-# Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
-
-
-RUN mkdir /var/local/jenkins
-
-
-
-# Add buster-backports for more recent clang packages
-RUN echo "deb http://deb.debian.org/debian buster-backports main" | tee /etc/apt/sources.list.d/buster-backports.list
-
-# Install clang-tidy 7
-RUN apt-get update && apt-get install -y clang-tidy-8 jq
-ENV CLANG_TIDY=clang-tidy-8
+# Install clang-tidy 11
+RUN apt-get update && apt-get install -y clang-tidy-11 jq
+ENV CLANG_TIDY=clang-tidy-11
 
 ADD clang_tidy_all_the_things.sh /
 
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh b/grpc/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh
index 20a61c0..ab3382b 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh
@@ -39,5 +39,5 @@
 
 # Cloning from a local path sets RepositoryUrl to a path and breaks Source Link.
 # Override RepositoryUrl to a URL to fix Source Link. The value doesn't matter.
-dotnet build --configuration Debug --output ./output/InteropTestsWebsite testassets/InteropTestsWebsite/InteropTestsWebsite.csproj -p:RepositoryUrl=https://github.com/grpc/grpc-dotnet.git
-dotnet build --configuration Debug --output ./output/InteropTestsClient testassets/InteropTestsClient/InteropTestsClient.csproj -p:RepositoryUrl=https://github.com/grpc/grpc-dotnet.git
+dotnet build --configuration Debug --output ./output/InteropTestsWebsite testassets/InteropTestsWebsite/InteropTestsWebsite.csproj -p:RepositoryUrl=https://github.com/grpc/grpc-dotnet.git -p:LatestFramework=true
+dotnet build --configuration Debug --output ./output/InteropTestsClient testassets/InteropTestsClient/InteropTestsClient.csproj -p:RepositoryUrl=https://github.com/grpc/grpc-dotnet.git -p:LatestFramework=true
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index 6c65771..89a4261 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -60,7 +60,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
index 6c65771..89a4261 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
@@ -60,7 +60,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
index 6a2863a..e256ae9 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
@@ -61,7 +61,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_client b/grpc/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_client
new file mode 100644
index 0000000..f0796a4
--- /dev/null
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_client
@@ -0,0 +1,38 @@
+# Copyright 2021 The 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.
+
+# Dockerfile for building //test/cpp/interop:xds_interop_client
+
+FROM phusion/baseimage:master@sha256:65ea10d5f757e5e86272625f8675d437dd83d8db64bdb429e2354d58f5462750
+
+RUN apt-get update -y && \
+        apt-get install -y \
+            build-essential \
+            clang \
+            python3 \
+            python3-dev
+
+WORKDIR /workdir
+
+RUN ln -s /usr/bin/python3 /usr/bin/python
+RUN mkdir /artifacts
+
+COPY . .
+RUN tools/bazel build //test/cpp/interop:xds_interop_client
+RUN cp -rL /workdir/bazel-bin/test/cpp/interop/xds_interop_client /artifacts/
+
+FROM phusion/baseimage:master@sha256:65ea10d5f757e5e86272625f8675d437dd83d8db64bdb429e2354d58f5462750
+COPY --from=0 /artifacts ./
+
+ENTRYPOINT ["/xds_interop_client"]
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_server b/grpc/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_server
new file mode 100644
index 0000000..cd081e1
--- /dev/null
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_server
@@ -0,0 +1,38 @@
+# Copyright 2021 The 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.
+
+# Dockerfile for building //test/cpp/interop:xds_interop_client
+
+FROM phusion/baseimage:master@sha256:65ea10d5f757e5e86272625f8675d437dd83d8db64bdb429e2354d58f5462750
+
+RUN apt-get update -y && \
+        apt-get install -y \
+            build-essential \
+            clang \
+            python3 \
+            python3-dev
+
+WORKDIR /workdir
+
+RUN ln -s /usr/bin/python3 /usr/bin/python
+RUN mkdir /artifacts
+
+COPY . .
+RUN tools/bazel build //test/cpp/interop:xds_interop_server
+RUN cp -rL /workdir/bazel-bin/test/cpp/interop/xds_interop_server /artifacts/
+
+FROM phusion/baseimage:master@sha256:65ea10d5f757e5e86272625f8675d437dd83d8db64bdb429e2354d58f5462750
+COPY --from=0 /artifacts ./
+
+ENTRYPOINT ["/xds_interop_server"]
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
index 279df5b..6ff5734 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM google/dart:2.10
+FROM google/dart:2.12
 
 # Define the default command.
 CMD ["bash"]
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
index 62c68b1..3863cde 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015 gRPC authors.
+# Copyright 2021 The gRPC Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM golang:1.11
+FROM golang:1.16
 
 # Using login shell removes Go from path, so we add it.
 RUN ln -s /usr/local/go/bin/go /usr/local/bin
@@ -28,7 +28,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_go1.11/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_go1.11/Dockerfile
index 146af2d..e067d31 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_go1.11/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_go1.11/Dockerfile
@@ -28,7 +28,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile
new file mode 100644
index 0000000..3863cde
--- /dev/null
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_go1.16/Dockerfile
@@ -0,0 +1,37 @@
+# Copyright 2021 The 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.
+
+FROM golang:1.16
+
+# Using login shell removes Go from path, so we add it.
+RUN ln -s /usr/local/go/bin/go /usr/local/bin
+
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-setuptools
+
+# Install Python packages from PyPI
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
+RUN pip install --upgrade pip==19.3.1
+RUN pip install virtualenv==16.7.9
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
+
+# Define the default command.
+CMD ["bash"]
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh b/grpc/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh
new file mode 100644
index 0000000..309340c
--- /dev/null
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_go1.16/build_interop.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2015 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.
+#
+# Builds Go interop server and client in a base image.
+set -e
+
+# Turn on support for Go modules.
+export GO111MODULE=on
+
+# Clone just the grpc-go source code without any dependencies.
+# We are cloning from a local git repo that contains the right revision
+# to test instead of using "go get" to download from Github directly.
+git clone --recursive /var/local/jenkins/grpc-go src/google.golang.org/grpc
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+# Build the interop client and server
+(cd src/google.golang.org/grpc/interop/client && go install)
+(cd src/google.golang.org/grpc/interop/server && go install)
+  
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
index 45fd264..4ceff25 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
@@ -28,7 +28,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
index ef13d2d..30bf79e 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
@@ -28,7 +28,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
index 5754ead..d71f43c 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
@@ -61,7 +61,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
index 8793d5f..90ba56c 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
@@ -51,10 +51,10 @@
 
 # Install Python 2.7
 RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 # Add Debian 'buster' repository, we will need it for installing newer versions of python
 RUN echo 'deb http://ftp.de.debian.org/debian buster main' >> /etc/apt/sources.list
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_pythonasyncio/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_pythonasyncio/Dockerfile
index 8793d5f..90ba56c 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_pythonasyncio/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_pythonasyncio/Dockerfile
@@ -51,10 +51,10 @@
 
 # Install Python 2.7
 RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 # Add Debian 'buster' repository, we will need it for installing newer versions of python
 RUN echo 'deb http://ftp.de.debian.org/debian buster main' >> /etc/apt/sources.list
diff --git a/grpc/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile b/grpc/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
index 7ea3d3b..6db1f56 100644
--- a/grpc/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
+++ b/grpc/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
@@ -60,7 +60,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/test/bazel/Dockerfile b/grpc/tools/dockerfile/test/bazel/Dockerfile
index 984a394..b333d85 100644
--- a/grpc/tools/dockerfile/test/bazel/Dockerfile
+++ b/grpc/tools/dockerfile/test/bazel/Dockerfile
@@ -12,7 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM gcr.io/oss-fuzz-base/base-builder
+# Pinned version of the base image is used to avoid regressions caused
+# by rebuilding of this docker image. To see available versions, you can run
+# "gcloud container images list-tags gcr.io/oss-fuzz-base/base-builder"
+# TODO(jtattermusch): with the latest version we'd get clang12+
+# which makes our build fail due to new warnings being treated
+# as errors.
+FROM gcr.io/oss-fuzz-base/base-builder@sha256:de220fd2433cd53bd06b215770dcd14a5e74632e0215acea7401fee8cafb18da
 
 # -------------------------- WARNING --------------------------------------
 # If you are making changes to this file, consider changing
@@ -44,7 +50,7 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
diff --git a/grpc/tools/dockerfile/test/csharp_stretch_x64/Dockerfile b/grpc/tools/dockerfile/test/csharp_stretch_x64/Dockerfile
index 609b34f..892be06 100644
--- a/grpc/tools/dockerfile/test/csharp_stretch_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/csharp_stretch_x64/Dockerfile
@@ -60,13 +60,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #================
 # C# dependencies
diff --git a/grpc/tools/dockerfile/test/cxx_alpine_x64/Dockerfile b/grpc/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
index cfff38e..7bd7eed 100644
--- a/grpc/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM alpine:3.9
+FROM alpine:3.11
 
 # Install Git and basic packages.
 RUN apk update && apk add \
@@ -30,9 +30,8 @@
   make \
   perl \
   strace \
-  python-dev \
-  py-pip \
-  py-yaml \
+  python2-dev \
+  py2-pip \
   unzip \
   wget \
   zip
@@ -40,10 +39,11 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.15.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
+RUN pip install --upgrade --ignore-installed PyYAML==5.4.1 --user
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 
 RUN mkdir /var/local/jenkins
diff --git a/grpc/tools/dockerfile/test/cxx_buster_x64/Dockerfile b/grpc/tools/dockerfile/test/cxx_buster_x64/Dockerfile
index 7ab7392..c26c5a5 100644
--- a/grpc/tools/dockerfile/test/cxx_buster_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/cxx_buster_x64/Dockerfile
@@ -60,13 +60,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #=================
 # C++ dependencies
diff --git a/grpc/tools/dockerfile/test/cxx_jessie_x64/Dockerfile b/grpc/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
index a9a6124..bd59939 100644
--- a/grpc/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -61,13 +61,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #=================
 # C++ dependencies
diff --git a/grpc/tools/dockerfile/test/cxx_jessie_x86/Dockerfile b/grpc/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
index 3d5cf6d..d5291bf 100644
--- a/grpc/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
+++ b/grpc/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
@@ -61,13 +61,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #=================
 # C++ dependencies
diff --git a/grpc/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile b/grpc/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
index 043b1a6..b5dfa6d 100644
--- a/grpc/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
@@ -60,13 +60,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #=================
 # C++ dependencies
@@ -82,10 +82,8 @@
 RUN mkdir /var/local/jenkins
 
 
-# The clang-3.6 symlink for the default clang version was added
-# to Ubuntu 16.04 recently, so make sure it's installed.
-# Also install clang3.7.
-RUN apt-get update && apt-get -y install clang-3.6 clang-3.7 && apt-get clean
+# Installs clang 4.0 and 5.0, the clang++ is included in clang packages
+RUN apt-get update && apt-get -y install clang-4.0 clang-5.0 && apt-get clean
 
 # Define the default command.
 CMD ["bash"]
diff --git a/grpc/tools/dockerfile/test/cxx_ubuntu1804_x64/Dockerfile b/grpc/tools/dockerfile/test/cxx_ubuntu1804_x64/Dockerfile
index 7928ef0..db927f8 100644
--- a/grpc/tools/dockerfile/test/cxx_ubuntu1804_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/cxx_ubuntu1804_x64/Dockerfile
@@ -60,13 +60,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #=================
 # C++ dependencies
diff --git a/grpc/tools/dockerfile/test/fuzzer/Dockerfile b/grpc/tools/dockerfile/test/fuzzer/Dockerfile
deleted file mode 100644
index 3e776f0..0000000
--- a/grpc/tools/dockerfile/test/fuzzer/Dockerfile
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright 2015 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.
-
-FROM debian:jessie
-
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  dnsutils \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-#================
-# Build profiling
-RUN apt-get update && apt-get install -y time && apt-get clean
-
-#====================
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
-    python-all-dev \
-    python3-all-dev \
-    python-setuptools
-
-# Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
-RUN pip install --upgrade pip==19.3.1
-RUN pip install virtualenv==16.7.9
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
-
-# Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
-
-#=================
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
-
-#=================
-# Use cmake 3.6 from jessie-backports
-# should only be used for images based on debian jessie.
-
-RUN echo "deb http://archive.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
-RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf
-RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list
-RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
-
-#=================
-# Update clang to a version with improved tsan and fuzzing capabilities
-
-RUN git clone -n -b release_38 http://llvm.org/git/llvm.git && \
-  cd llvm && git checkout ad57503 && cd ..
-RUN git clone -n -b release_38 http://llvm.org/git/clang.git && \
-  cd clang && git checkout ad2c56e && cd ..
-RUN git clone -n -b release_38 http://llvm.org/git/compiler-rt.git && \
-  cd compiler-rt && git checkout 3176922 && cd ..
-RUN git clone -n -b release_38 \
-  http://llvm.org/git/clang-tools-extra.git && cd clang-tools-extra && \
-  git checkout c288525 && cd ..
-RUN git clone -n -b release_38 http://llvm.org/git/libcxx.git && \
-  cd libcxx && git checkout fda3549  && cd ..
-RUN git clone -n -b release_38 http://llvm.org/git/libcxxabi.git && \
-  cd libcxxabi && git checkout 8d4e51d && cd ..
-
-RUN mv clang llvm/tools
-RUN mv compiler-rt llvm/projects
-RUN mv clang-tools-extra llvm/tools/clang/tools
-RUN mv libcxx llvm/projects
-RUN mv libcxxabi llvm/projects
-
-RUN mkdir llvm-build
-RUN cd llvm-build && cmake \
-  -DCMAKE_BUILD_TYPE:STRING=Release \
-  -DCMAKE_INSTALL_PREFIX:STRING=/usr \
-  -DLLVM_TARGETS_TO_BUILD:STRING=X86 \
-  ../llvm
-RUN make -C llvm-build -j 12 && make -C llvm-build install && rm -rf llvm-build
-
-
-RUN mkdir /var/local/jenkins
-
-RUN clang++ -c -g -O2 -std=c++11 llvm/lib/Fuzzer/*.cpp -IFuzzer
-RUN ar ruv libFuzzer.a Fuzzer*.o
-RUN mv libFuzzer.a /usr/lib
-RUN rm -f Fuzzer*.o
-# Define the default command.
-CMD ["bash"]
diff --git a/grpc/tools/dockerfile/test/node_jessie_x64/Dockerfile b/grpc/tools/dockerfile/test/node_jessie_x64/Dockerfile
index 5936a81..35e07a8 100644
--- a/grpc/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -72,13 +72,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #==================
 # Node dependencies
diff --git a/grpc/tools/dockerfile/test/php7_jessie_x64/Dockerfile b/grpc/tools/dockerfile/test/php7_jessie_x64/Dockerfile
index 2e456a1..2d6021c 100644
--- a/grpc/tools/dockerfile/test/php7_jessie_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/php7_jessie_x64/Dockerfile
@@ -72,13 +72,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #=================	
 # PHP Test dependencies	
diff --git a/grpc/tools/dockerfile/test/python_alpine_x64/Dockerfile b/grpc/tools/dockerfile/test/python_alpine_x64/Dockerfile
index b36b134..bf5f07a 100644
--- a/grpc/tools/dockerfile/test/python_alpine_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/python_alpine_x64/Dockerfile
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM alpine:3.9
+FROM alpine:3.11
 
 # Install Git and basic packages.
 RUN apk update && apk add \
@@ -30,8 +30,8 @@
   make \
   perl \
   strace \
-  python-dev \
-  py-pip \
+  python2-dev \
+  py2-pip \
   unzip \
   wget \
   zip
@@ -39,10 +39,10 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.15.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 RUN mkdir -p /var/local/jenkins
 
diff --git a/grpc/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile b/grpc/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile
index 876c5dc..eb618da 100644
--- a/grpc/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile
@@ -51,10 +51,10 @@
 
 # Install Python 2.7
 RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 # Add Debian 'buster' repository, we will need it for installing newer versions of python
 RUN echo 'deb http://ftp.de.debian.org/debian buster main' >> /etc/apt/sources.list
diff --git a/grpc/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile b/grpc/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile
index 5e4ca94..0871723 100644
--- a/grpc/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile
@@ -51,10 +51,10 @@
 
 # Install Python 2.7
 RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 # Add Debian 'buster' repository, we will need it for installing newer versions of python
 RUN echo 'deb http://ftp.de.debian.org/debian buster main' >> /etc/apt/sources.list
@@ -65,4 +65,4 @@
 
 
 RUN apt-get update && apt-get install -y python3.5 python3-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.5
+RUN curl https://bootstrap.pypa.io/pip/3.5/get-pip.py | python3.5
diff --git a/grpc/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile b/grpc/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile
index bc92bd6..6efa2b8 100644
--- a/grpc/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile
@@ -51,10 +51,10 @@
 
 # Install Python 2.7
 RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 # Add Debian 'buster' repository, we will need it for installing newer versions of python
 RUN echo 'deb http://ftp.de.debian.org/debian buster main' >> /etc/apt/sources.list
diff --git a/grpc/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile b/grpc/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile
index 00edc45..9f51844 100644
--- a/grpc/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile
@@ -51,10 +51,10 @@
 
 # Install Python 2.7
 RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 # Add Debian 'buster' repository, we will need it for installing newer versions of python
 RUN echo 'deb http://ftp.de.debian.org/debian buster main' >> /etc/apt/sources.list
diff --git a/grpc/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile b/grpc/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile
index 3202eb0..4060dea 100644
--- a/grpc/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/python_stretch_3.8_x64/Dockerfile
@@ -51,10 +51,10 @@
 
 # Install Python 2.7
 RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 # Add Debian 'buster' repository, we will need it for installing newer versions of python
 RUN echo 'deb http://ftp.de.debian.org/debian buster main' >> /etc/apt/sources.list
diff --git a/grpc/tools/dockerfile/test/python_stretch_default_x64/Dockerfile b/grpc/tools/dockerfile/test/python_stretch_default_x64/Dockerfile
index 9cde174..e9de095 100644
--- a/grpc/tools/dockerfile/test/python_stretch_default_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/python_stretch_default_x64/Dockerfile
@@ -51,10 +51,10 @@
 
 # Install Python 2.7
 RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 # Add Debian 'buster' repository, we will need it for installing newer versions of python
 RUN echo 'deb http://ftp.de.debian.org/debian buster main' >> /etc/apt/sources.list
@@ -105,7 +105,7 @@
 
 
 RUN apt-get update && apt-get install -y python3.5 python3.5-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.5
+RUN curl https://bootstrap.pypa.io/pip/3.5/get-pip.py | python3.5
 
 RUN apt-get update && apt-get -t buster install -y python3.7 python3-all-dev
 RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
diff --git a/grpc/tools/dockerfile/test/ruby_buster_x64/Dockerfile b/grpc/tools/dockerfile/test/ruby_buster_x64/Dockerfile
index feef5d9..80b9c33 100644
--- a/grpc/tools/dockerfile/test/ruby_buster_x64/Dockerfile
+++ b/grpc/tools/dockerfile/test/ruby_buster_x64/Dockerfile
@@ -60,13 +60,13 @@
     python-setuptools
 
 # Install Python packages from PyPI
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2.7
 RUN pip install --upgrade pip==19.3.1
 RUN pip install virtualenv==16.7.9
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.15.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 #==================
 # Ruby dependencies
diff --git a/grpc/tools/dockerfile/test/sanity/Dockerfile b/grpc/tools/dockerfile/test/sanity/Dockerfile
index 41b265a..a0bbbb4 100644
--- a/grpc/tools/dockerfile/test/sanity/Dockerfile
+++ b/grpc/tools/dockerfile/test/sanity/Dockerfile
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM debian:10
+FROM debian:bullseye
   
 # Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
@@ -37,9 +37,6 @@
   make \
   perl \
   strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
   telnet \
   unzip \
   wget \
@@ -49,12 +46,25 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+# Install Python 3.7 from source (and installed as a default python3)
+# (Bullseye comes with Python 3.9 which isn't supported by pytype yet)
+RUN apt update && apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev \
+                                 libnss3-dev libssl-dev libreadline-dev libffi-dev
+RUN curl -O https://www.python.org/ftp/python/3.7.9/Python-3.7.9.tar.xz && \
+    tar -xf Python-3.7.9.tar.xz && \
+    cd Python-3.7.9 && \
+    ./configure && \
+    make -j 4 && \
+    make install
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3
+
 # Install Python 2.7
-RUN apt-get update && apt-get install -y python2.7 python-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+RUN apt-get update && apt-get install -y python2 python2-dev
+RUN ln -s /usr/bin/python2 /usr/bin/python
+RUN curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python2
 
 # Google Cloud platform API libraries
-RUN pip install --upgrade google-api-python-client oauth2client
+RUN pip install --upgrade google-auth==1.24.0 google-api-python-client==1.12.8 oauth2client==4.1.0
 
 
 RUN mkdir /var/local/jenkins
@@ -67,11 +77,7 @@
 
 #========================
 # Sanity test dependencies
-RUN apt-get update && apt-get -t buster install -y python3.7 python3-all-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
 
-# Make Python 3.7 the default Python 3 version
-RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 1
 RUN apt-get update && apt-get install -y \
       autoconf \
       automake \
@@ -81,13 +87,14 @@
 RUN python2 -m pip install simplejson mako virtualenv==16.7.9 lxml
 RUN python3 -m pip install simplejson mako virtualenv==16.7.9 lxml six
 
-# Add buster-backports for more recent clang packages
-RUN echo "deb http://deb.debian.org/debian buster-backports main" | tee /etc/apt/sources.list.d/buster-backports.list
+# Upgrade Python's YAML library
+RUN python2 -m pip install --upgrade --ignore-installed PyYAML==5.4.1 --user
+RUN python3 -m pip install --upgrade --ignore-installed PyYAML==5.4.1 --user
 
 # Install clang, clang-format, and clang-tidy
-RUN apt-get update && apt-get install -y clang clang-format-8 clang-tidy-8 jq
-ENV CLANG_FORMAT=clang-format-8
-ENV CLANG_TIDY=clang-tidy-8
+RUN apt-get update && apt-get install -y clang clang-format-11 clang-tidy-11 jq
+ENV CLANG_FORMAT=clang-format-11
+ENV CLANG_TIDY=clang-tidy-11
 
 
 #========================
diff --git a/grpc/tools/doxygen/Doxyfile.c++ b/grpc/tools/doxygen/Doxyfile.c++
index d90ee96..2ce385e 100644
--- a/grpc/tools/doxygen/Doxyfile.c++
+++ b/grpc/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.35.0
+PROJECT_NUMBER         = 1.38.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -881,6 +881,10 @@
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/event_engine/channel_args.h \
+include/grpc/event_engine/event_engine.h \
+include/grpc/event_engine/port.h \
+include/grpc/event_engine/slice_allocator.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -975,6 +979,7 @@
 include/grpcpp/impl/codegen/message_allocator.h \
 include/grpcpp/impl/codegen/metadata_map.h \
 include/grpcpp/impl/codegen/method_handler.h \
+include/grpcpp/impl/codegen/method_handler_impl.h \
 include/grpcpp/impl/codegen/proto_buffer_reader.h \
 include/grpcpp/impl/codegen/proto_buffer_writer.h \
 include/grpcpp/impl/codegen/proto_utils.h \
diff --git a/grpc/tools/doxygen/Doxyfile.c++.internal b/grpc/tools/doxygen/Doxyfile.c++.internal
index a576eb9..0e0fdbd 100644
--- a/grpc/tools/doxygen/Doxyfile.c++.internal
+++ b/grpc/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.35.0
+PROJECT_NUMBER         = 1.38.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -881,6 +881,10 @@
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/event_engine/channel_args.h \
+include/grpc/event_engine/event_engine.h \
+include/grpc/event_engine/port.h \
+include/grpc/event_engine/slice_allocator.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -975,6 +979,7 @@
 include/grpcpp/impl/codegen/message_allocator.h \
 include/grpcpp/impl/codegen/metadata_map.h \
 include/grpcpp/impl/codegen/method_handler.h \
+include/grpcpp/impl/codegen/method_handler_impl.h \
 include/grpcpp/impl/codegen/proto_buffer_reader.h \
 include/grpcpp/impl/codegen/proto_buffer_writer.h \
 include/grpcpp/impl/codegen/proto_utils.h \
@@ -1085,6 +1090,8 @@
 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 \
@@ -1119,6 +1126,7 @@
 src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \
 src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
 src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h \
+src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \
 src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
 src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
 src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h \
@@ -1127,6 +1135,10 @@
 src/core/ext/filters/client_channel/resolver_registry.h \
 src/core/ext/filters/client_channel/resolver_result_parsing.cc \
 src/core/ext/filters/client_channel/resolver_result_parsing.h \
+src/core/ext/filters/client_channel/retry_filter.cc \
+src/core/ext/filters/client_channel/retry_filter.h \
+src/core/ext/filters/client_channel/retry_service_config.cc \
+src/core/ext/filters/client_channel/retry_service_config.h \
 src/core/ext/filters/client_channel/retry_throttle.cc \
 src/core/ext/filters/client_channel/retry_throttle.h \
 src/core/ext/filters/client_channel/server_address.cc \
@@ -1145,6 +1157,10 @@
 src/core/ext/filters/client_idle/client_idle_filter.cc \
 src/core/ext/filters/deadline/deadline_filter.cc \
 src/core/ext/filters/deadline/deadline_filter.h \
+src/core/ext/filters/fault_injection/fault_injection_filter.cc \
+src/core/ext/filters/fault_injection/fault_injection_filter.h \
+src/core/ext/filters/fault_injection/service_config_parser.cc \
+src/core/ext/filters/fault_injection/service_config_parser.h \
 src/core/ext/filters/http/client/http_client_filter.cc \
 src/core/ext/filters/http/client/http_client_filter.h \
 src/core/ext/filters/http/client_authority_filter.cc \
@@ -1225,12 +1241,16 @@
 src/core/ext/transport/inproc/inproc_plugin.cc \
 src/core/ext/transport/inproc/inproc_transport.cc \
 src/core/ext/transport/inproc/inproc_transport.h \
+src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c \
+src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h \
 src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c \
 src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h \
 src/core/ext/upb-generated/envoy/annotations/resource.upb.c \
 src/core/ext/upb-generated/envoy/annotations/resource.upb.h \
 src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c \
 src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h \
+src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c \
+src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h \
 src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c \
 src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h \
 src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c \
@@ -1279,6 +1299,10 @@
 src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h \
 src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c \
 src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h \
+src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c \
+src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h \
+src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c \
+src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h \
 src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c \
 src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h \
 src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c \
@@ -1289,6 +1313,14 @@
 src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h \
 src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c \
 src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h \
+src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c \
+src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h \
+src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c \
+src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h \
+src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c \
+src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h \
+src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c \
+src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h \
 src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c \
 src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h \
 src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c \
@@ -1315,8 +1347,12 @@
 src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h \
 src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c \
 src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h \
+src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c \
+src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c \
 src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h \
+src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c \
+src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c \
 src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c \
@@ -1325,6 +1361,8 @@
 src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c \
 src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h \
+src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c \
+src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c \
 src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h \
 src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c \
@@ -1381,28 +1419,34 @@
 src/core/ext/upb-generated/udpa/annotations/status.upb.h \
 src/core/ext/upb-generated/udpa/annotations/versioning.upb.c \
 src/core/ext/upb-generated/udpa/annotations/versioning.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/authority.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/authority.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/resource.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/resource.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h \
 src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
 src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h \
+src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c \
+src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h \
 src/core/ext/upb-generated/validate/validate.upb.c \
 src/core/ext/upb-generated/validate/validate.upb.h \
+src/core/ext/upb-generated/xds/core/v3/authority.upb.c \
+src/core/ext/upb-generated/xds/core/v3/authority.upb.h \
+src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c \
+src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h \
+src/core/ext/upb-generated/xds/core/v3/context_params.upb.c \
+src/core/ext/upb-generated/xds/core/v3/context_params.upb.h \
+src/core/ext/upb-generated/xds/core/v3/resource.upb.c \
+src/core/ext/upb-generated/xds/core/v3/resource.upb.h \
+src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c \
+src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h \
+src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c \
+src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h \
+src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c \
@@ -1451,6 +1495,10 @@
 src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c \
@@ -1459,6 +1507,14 @@
 src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c \
@@ -1485,8 +1541,12 @@
 src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c \
@@ -1495,6 +1555,8 @@
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c \
@@ -1515,8 +1577,6 @@
 src/core/ext/upbdefs-generated/google/api/http.upbdefs.h \
 src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c \
 src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.h \
-src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c \
-src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.h \
 src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c \
 src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.h \
 src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c \
@@ -1539,20 +1599,22 @@
 src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h \
 src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c \
 src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h \
+src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c \
+src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h \
 src/core/ext/upbdefs-generated/validate/validate.upbdefs.c \
 src/core/ext/upbdefs-generated/validate/validate.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h \
 src/core/ext/xds/certificate_provider_factory.h \
 src/core/ext/xds/certificate_provider_registry.cc \
 src/core/ext/xds/certificate_provider_registry.h \
@@ -1571,7 +1633,15 @@
 src/core/ext/xds/xds_client.h \
 src/core/ext/xds/xds_client_stats.cc \
 src/core/ext/xds/xds_client_stats.h \
+src/core/ext/xds/xds_http_fault_filter.cc \
+src/core/ext/xds/xds_http_fault_filter.h \
+src/core/ext/xds/xds_http_filters.cc \
+src/core/ext/xds/xds_http_filters.h \
 src/core/ext/xds/xds_server_config_fetcher.cc \
+src/core/lib/address_utils/parse_address.cc \
+src/core/lib/address_utils/parse_address.h \
+src/core/lib/address_utils/sockaddr_utils.cc \
+src/core/lib/address_utils/sockaddr_utils.h \
 src/core/lib/avl/avl.cc \
 src/core/lib/avl/avl.h \
 src/core/lib/backoff/backoff.cc \
@@ -1618,6 +1688,8 @@
 src/core/lib/debug/stats_data.h \
 src/core/lib/debug/trace.cc \
 src/core/lib/debug/trace.h \
+src/core/lib/event_engine/slice_allocator.cc \
+src/core/lib/event_engine/sockaddr.cc \
 src/core/lib/gpr/alloc.cc \
 src/core/lib/gpr/alloc.h \
 src/core/lib/gpr/arena.h \
@@ -1691,10 +1763,14 @@
 src/core/lib/gprpp/stat.h \
 src/core/lib/gprpp/stat_posix.cc \
 src/core/lib/gprpp/stat_windows.cc \
+src/core/lib/gprpp/status_helper.cc \
+src/core/lib/gprpp/status_helper.h \
 src/core/lib/gprpp/sync.h \
 src/core/lib/gprpp/thd.h \
 src/core/lib/gprpp/thd_posix.cc \
 src/core/lib/gprpp/thd_windows.cc \
+src/core/lib/gprpp/time_util.cc \
+src/core/lib/gprpp/time_util.h \
 src/core/lib/http/format_request.cc \
 src/core/lib/http/format_request.h \
 src/core/lib/http/httpcli.cc \
@@ -1766,7 +1842,6 @@
 src/core/lib/iomgr/iomgr_internal.cc \
 src/core/lib/iomgr/iomgr_internal.h \
 src/core/lib/iomgr/iomgr_posix.cc \
-src/core/lib/iomgr/iomgr_posix.h \
 src/core/lib/iomgr/iomgr_posix_cfstream.cc \
 src/core/lib/iomgr/iomgr_uv.cc \
 src/core/lib/iomgr/iomgr_windows.cc \
@@ -1777,10 +1852,6 @@
 src/core/lib/iomgr/lockfree_event.cc \
 src/core/lib/iomgr/lockfree_event.h \
 src/core/lib/iomgr/nameser.h \
-src/core/lib/iomgr/parse_address.cc \
-src/core/lib/iomgr/parse_address.h \
-src/core/lib/iomgr/poller/eventmanager_libuv.cc \
-src/core/lib/iomgr/poller/eventmanager_libuv.h \
 src/core/lib/iomgr/polling_entity.cc \
 src/core/lib/iomgr/polling_entity.h \
 src/core/lib/iomgr/pollset.cc \
@@ -1810,8 +1881,6 @@
 src/core/lib/iomgr/sockaddr.h \
 src/core/lib/iomgr/sockaddr_custom.h \
 src/core/lib/iomgr/sockaddr_posix.h \
-src/core/lib/iomgr/sockaddr_utils.cc \
-src/core/lib/iomgr/sockaddr_utils.h \
 src/core/lib/iomgr/sockaddr_windows.h \
 src/core/lib/iomgr/socket_factory_posix.cc \
 src/core/lib/iomgr/socket_factory_posix.h \
@@ -1881,19 +1950,11 @@
 src/core/lib/json/json_util.cc \
 src/core/lib/json/json_util.h \
 src/core/lib/json/json_writer.cc \
+src/core/lib/matchers/matchers.cc \
+src/core/lib/matchers/matchers.h \
 src/core/lib/profiling/basic_timers.cc \
 src/core/lib/profiling/stap_timers.cc \
 src/core/lib/profiling/timers.h \
-src/core/lib/security/authorization/authorization_engine.cc \
-src/core/lib/security/authorization/authorization_engine.h \
-src/core/lib/security/authorization/evaluate_args.cc \
-src/core/lib/security/authorization/evaluate_args.h \
-src/core/lib/security/authorization/mock_cel/activation.h \
-src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h \
-src/core/lib/security/authorization/mock_cel/cel_expression.h \
-src/core/lib/security/authorization/mock_cel/cel_value.h \
-src/core/lib/security/authorization/mock_cel/evaluator_core.h \
-src/core/lib/security/authorization/mock_cel/flat_expr_builder.h \
 src/core/lib/security/context/security_context.cc \
 src/core/lib/security/context/security_context.h \
 src/core/lib/security/credentials/alts/alts_credentials.cc \
@@ -2180,7 +2241,8 @@
 src/cpp/util/byte_buffer_cc.cc \
 src/cpp/util/status.cc \
 src/cpp/util/string_ref.cc \
-src/cpp/util/time_cc.cc
+src/cpp/util/time_cc.cc \
+third_party/xxhash/xxhash.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/grpc/tools/doxygen/Doxyfile.core b/grpc/tools/doxygen/Doxyfile.core
index ff7e77f..1db9688 100644
--- a/grpc/tools/doxygen/Doxyfile.core
+++ b/grpc/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 14.0.0
+PROJECT_NUMBER         = 16.0.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -811,6 +811,10 @@
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/event_engine/channel_args.h \
+include/grpc/event_engine/event_engine.h \
+include/grpc/event_engine/port.h \
+include/grpc/event_engine/slice_allocator.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
diff --git a/grpc/tools/doxygen/Doxyfile.core.internal b/grpc/tools/doxygen/Doxyfile.core.internal
index 7b9ca54..ebf1a4d 100644
--- a/grpc/tools/doxygen/Doxyfile.core.internal
+++ b/grpc/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 14.0.0
+PROJECT_NUMBER         = 16.0.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -811,6 +811,10 @@
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/event_engine/channel_args.h \
+include/grpc/event_engine/event_engine.h \
+include/grpc/event_engine/port.h \
+include/grpc/event_engine/slice_allocator.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -911,6 +915,8 @@
 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 \
@@ -947,6 +953,7 @@
 src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \
 src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
 src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h \
+src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc \
 src/core/ext/filters/client_channel/resolver/sockaddr/README.md \
 src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
 src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
@@ -956,6 +963,10 @@
 src/core/ext/filters/client_channel/resolver_registry.h \
 src/core/ext/filters/client_channel/resolver_result_parsing.cc \
 src/core/ext/filters/client_channel/resolver_result_parsing.h \
+src/core/ext/filters/client_channel/retry_filter.cc \
+src/core/ext/filters/client_channel/retry_filter.h \
+src/core/ext/filters/client_channel/retry_service_config.cc \
+src/core/ext/filters/client_channel/retry_service_config.h \
 src/core/ext/filters/client_channel/retry_throttle.cc \
 src/core/ext/filters/client_channel/retry_throttle.h \
 src/core/ext/filters/client_channel/server_address.cc \
@@ -974,6 +985,10 @@
 src/core/ext/filters/client_idle/client_idle_filter.cc \
 src/core/ext/filters/deadline/deadline_filter.cc \
 src/core/ext/filters/deadline/deadline_filter.h \
+src/core/ext/filters/fault_injection/fault_injection_filter.cc \
+src/core/ext/filters/fault_injection/fault_injection_filter.h \
+src/core/ext/filters/fault_injection/service_config_parser.cc \
+src/core/ext/filters/fault_injection/service_config_parser.h \
 src/core/ext/filters/http/client/http_client_filter.cc \
 src/core/ext/filters/http/client/http_client_filter.h \
 src/core/ext/filters/http/client_authority_filter.cc \
@@ -1061,12 +1076,16 @@
 src/core/ext/transport/inproc/inproc_plugin.cc \
 src/core/ext/transport/inproc/inproc_transport.cc \
 src/core/ext/transport/inproc/inproc_transport.h \
+src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.c \
+src/core/ext/upb-generated/envoy/admin/v3/config_dump.upb.h \
 src/core/ext/upb-generated/envoy/annotations/deprecation.upb.c \
 src/core/ext/upb-generated/envoy/annotations/deprecation.upb.h \
 src/core/ext/upb-generated/envoy/annotations/resource.upb.c \
 src/core/ext/upb-generated/envoy/annotations/resource.upb.h \
 src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.c \
 src/core/ext/upb-generated/envoy/config/accesslog/v3/accesslog.upb.h \
+src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.c \
+src/core/ext/upb-generated/envoy/config/bootstrap/v3/bootstrap.upb.h \
 src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.c \
 src/core/ext/upb-generated/envoy/config/cluster/v3/circuit_breaker.upb.h \
 src/core/ext/upb-generated/envoy/config/cluster/v3/cluster.upb.c \
@@ -1115,6 +1134,10 @@
 src/core/ext/upb-generated/envoy/config/listener/v3/listener_components.upb.h \
 src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.c \
 src/core/ext/upb-generated/envoy/config/listener/v3/udp_listener_config.upb.h \
+src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.c \
+src/core/ext/upb-generated/envoy/config/metrics/v3/stats.upb.h \
+src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.c \
+src/core/ext/upb-generated/envoy/config/overload/v3/overload.upb.h \
 src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.c \
 src/core/ext/upb-generated/envoy/config/rbac/v3/rbac.upb.h \
 src/core/ext/upb-generated/envoy/config/route/v3/route.upb.c \
@@ -1125,6 +1148,14 @@
 src/core/ext/upb-generated/envoy/config/route/v3/scoped_route.upb.h \
 src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.c \
 src/core/ext/upb-generated/envoy/config/trace/v3/http_tracer.upb.h \
+src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.c \
+src/core/ext/upb-generated/envoy/extensions/clusters/aggregate/v3/cluster.upb.h \
+src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.c \
+src/core/ext/upb-generated/envoy/extensions/filters/common/fault/v3/fault.upb.h \
+src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.c \
+src/core/ext/upb-generated/envoy/extensions/filters/http/fault/v3/fault.upb.h \
+src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.c \
+src/core/ext/upb-generated/envoy/extensions/filters/http/router/v3/router.upb.h \
 src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.c \
 src/core/ext/upb-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h \
 src/core/ext/upb-generated/envoy/extensions/transport_sockets/tls/v3/cert.upb.c \
@@ -1151,8 +1182,12 @@
 src/core/ext/upb-generated/envoy/service/route/v3/rds.upb.h \
 src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.c \
 src/core/ext/upb-generated/envoy/service/route/v3/srds.upb.h \
+src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.c \
+src/core/ext/upb-generated/envoy/service/status/v3/csds.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.c \
 src/core/ext/upb-generated/envoy/type/matcher/v3/metadata.upb.h \
+src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.c \
+src/core/ext/upb-generated/envoy/type/matcher/v3/node.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.c \
 src/core/ext/upb-generated/envoy/type/matcher/v3/number.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/path.upb.c \
@@ -1161,6 +1196,8 @@
 src/core/ext/upb-generated/envoy/type/matcher/v3/regex.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.c \
 src/core/ext/upb-generated/envoy/type/matcher/v3/string.upb.h \
+src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.c \
+src/core/ext/upb-generated/envoy/type/matcher/v3/struct.upb.h \
 src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.c \
 src/core/ext/upb-generated/envoy/type/matcher/v3/value.upb.h \
 src/core/ext/upb-generated/envoy/type/metadata/v3/metadata.upb.c \
@@ -1217,28 +1254,34 @@
 src/core/ext/upb-generated/udpa/annotations/status.upb.h \
 src/core/ext/upb-generated/udpa/annotations/versioning.upb.c \
 src/core/ext/upb-generated/udpa/annotations/versioning.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/authority.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/authority.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/collection_entry.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/context_params.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/context_params.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/resource.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/resource.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/resource_locator.upb.h \
-src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.c \
-src/core/ext/upb-generated/udpa/core/v1/resource_name.upb.h \
 src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
 src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.h \
+src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.c \
+src/core/ext/upb-generated/udpa/type/v1/typed_struct.upb.h \
 src/core/ext/upb-generated/validate/validate.upb.c \
 src/core/ext/upb-generated/validate/validate.upb.h \
+src/core/ext/upb-generated/xds/core/v3/authority.upb.c \
+src/core/ext/upb-generated/xds/core/v3/authority.upb.h \
+src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.c \
+src/core/ext/upb-generated/xds/core/v3/collection_entry.upb.h \
+src/core/ext/upb-generated/xds/core/v3/context_params.upb.c \
+src/core/ext/upb-generated/xds/core/v3/context_params.upb.h \
+src/core/ext/upb-generated/xds/core/v3/resource.upb.c \
+src/core/ext/upb-generated/xds/core/v3/resource.upb.h \
+src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c \
+src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h \
+src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c \
+src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h \
+src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/admin/v3/config_dump.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/annotations/deprecation.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/annotations/resource.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/accesslog/v3/accesslog.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/config/bootstrap/v3/bootstrap.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/cluster/v3/circuit_breaker.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/cluster/v3/cluster.upbdefs.c \
@@ -1287,6 +1330,10 @@
 src/core/ext/upbdefs-generated/envoy/config/listener/v3/listener_components.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/listener/v3/udp_listener_config.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/config/metrics/v3/stats.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/config/overload/v3/overload.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/route/v3/route.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/route/v3/route_components.upbdefs.c \
@@ -1295,6 +1342,14 @@
 src/core/ext/upbdefs-generated/envoy/config/route/v3/scoped_route.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/config/trace/v3/http_tracer.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/common/fault/v3/fault.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/http/fault/v3/fault.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/extensions/filters/http/router/v3/router.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c \
@@ -1321,8 +1376,12 @@
 src/core/ext/upbdefs-generated/envoy/service/route/v3/rds.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/service/route/v3/srds.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/service/status/v3/csds.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/metadata.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/type/matcher/v3/node.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/number.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/path.upbdefs.c \
@@ -1331,6 +1390,8 @@
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/regex.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/string.upbdefs.h \
+src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.c \
+src/core/ext/upbdefs-generated/envoy/type/matcher/v3/struct.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.c \
 src/core/ext/upbdefs-generated/envoy/type/matcher/v3/value.upbdefs.h \
 src/core/ext/upbdefs-generated/envoy/type/metadata/v3/metadata.upbdefs.c \
@@ -1351,8 +1412,6 @@
 src/core/ext/upbdefs-generated/google/api/http.upbdefs.h \
 src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.c \
 src/core/ext/upbdefs-generated/google/protobuf/any.upbdefs.h \
-src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c \
-src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.h \
 src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.c \
 src/core/ext/upbdefs-generated/google/protobuf/duration.upbdefs.h \
 src/core/ext/upbdefs-generated/google/protobuf/empty.upbdefs.c \
@@ -1375,20 +1434,22 @@
 src/core/ext/upbdefs-generated/udpa/annotations/status.upbdefs.h \
 src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.c \
 src/core/ext/upbdefs-generated/udpa/annotations/versioning.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/authority.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/collection_entry.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/context_params.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource_locator.upbdefs.h \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.c \
-src/core/ext/upbdefs-generated/udpa/core/v1/resource_name.upbdefs.h \
+src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.c \
+src/core/ext/upbdefs-generated/udpa/type/v1/typed_struct.upbdefs.h \
 src/core/ext/upbdefs-generated/validate/validate.upbdefs.c \
 src/core/ext/upbdefs-generated/validate/validate.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/authority.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/collection_entry.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/context_params.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/resource.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/resource_locator.upbdefs.h \
+src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.c \
+src/core/ext/upbdefs-generated/xds/core/v3/resource_name.upbdefs.h \
 src/core/ext/xds/certificate_provider_factory.h \
 src/core/ext/xds/certificate_provider_registry.cc \
 src/core/ext/xds/certificate_provider_registry.h \
@@ -1407,8 +1468,16 @@
 src/core/ext/xds/xds_client.h \
 src/core/ext/xds/xds_client_stats.cc \
 src/core/ext/xds/xds_client_stats.h \
+src/core/ext/xds/xds_http_fault_filter.cc \
+src/core/ext/xds/xds_http_fault_filter.h \
+src/core/ext/xds/xds_http_filters.cc \
+src/core/ext/xds/xds_http_filters.h \
 src/core/ext/xds/xds_server_config_fetcher.cc \
 src/core/lib/README.md \
+src/core/lib/address_utils/parse_address.cc \
+src/core/lib/address_utils/parse_address.h \
+src/core/lib/address_utils/sockaddr_utils.cc \
+src/core/lib/address_utils/sockaddr_utils.h \
 src/core/lib/avl/avl.cc \
 src/core/lib/avl/avl.h \
 src/core/lib/backoff/backoff.cc \
@@ -1456,6 +1525,8 @@
 src/core/lib/debug/stats_data.h \
 src/core/lib/debug/trace.cc \
 src/core/lib/debug/trace.h \
+src/core/lib/event_engine/slice_allocator.cc \
+src/core/lib/event_engine/sockaddr.cc \
 src/core/lib/gpr/README.md \
 src/core/lib/gpr/alloc.cc \
 src/core/lib/gpr/alloc.h \
@@ -1531,10 +1602,14 @@
 src/core/lib/gprpp/stat.h \
 src/core/lib/gprpp/stat_posix.cc \
 src/core/lib/gprpp/stat_windows.cc \
+src/core/lib/gprpp/status_helper.cc \
+src/core/lib/gprpp/status_helper.h \
 src/core/lib/gprpp/sync.h \
 src/core/lib/gprpp/thd.h \
 src/core/lib/gprpp/thd_posix.cc \
 src/core/lib/gprpp/thd_windows.cc \
+src/core/lib/gprpp/time_util.cc \
+src/core/lib/gprpp/time_util.h \
 src/core/lib/http/format_request.cc \
 src/core/lib/http/format_request.h \
 src/core/lib/http/httpcli.cc \
@@ -1607,7 +1682,6 @@
 src/core/lib/iomgr/iomgr_internal.cc \
 src/core/lib/iomgr/iomgr_internal.h \
 src/core/lib/iomgr/iomgr_posix.cc \
-src/core/lib/iomgr/iomgr_posix.h \
 src/core/lib/iomgr/iomgr_posix_cfstream.cc \
 src/core/lib/iomgr/iomgr_uv.cc \
 src/core/lib/iomgr/iomgr_windows.cc \
@@ -1618,10 +1692,6 @@
 src/core/lib/iomgr/lockfree_event.cc \
 src/core/lib/iomgr/lockfree_event.h \
 src/core/lib/iomgr/nameser.h \
-src/core/lib/iomgr/parse_address.cc \
-src/core/lib/iomgr/parse_address.h \
-src/core/lib/iomgr/poller/eventmanager_libuv.cc \
-src/core/lib/iomgr/poller/eventmanager_libuv.h \
 src/core/lib/iomgr/polling_entity.cc \
 src/core/lib/iomgr/polling_entity.h \
 src/core/lib/iomgr/pollset.cc \
@@ -1651,8 +1721,6 @@
 src/core/lib/iomgr/sockaddr.h \
 src/core/lib/iomgr/sockaddr_custom.h \
 src/core/lib/iomgr/sockaddr_posix.h \
-src/core/lib/iomgr/sockaddr_utils.cc \
-src/core/lib/iomgr/sockaddr_utils.h \
 src/core/lib/iomgr/sockaddr_windows.h \
 src/core/lib/iomgr/socket_factory_posix.cc \
 src/core/lib/iomgr/socket_factory_posix.h \
@@ -1722,19 +1790,11 @@
 src/core/lib/json/json_util.cc \
 src/core/lib/json/json_util.h \
 src/core/lib/json/json_writer.cc \
+src/core/lib/matchers/matchers.cc \
+src/core/lib/matchers/matchers.h \
 src/core/lib/profiling/basic_timers.cc \
 src/core/lib/profiling/stap_timers.cc \
 src/core/lib/profiling/timers.h \
-src/core/lib/security/authorization/authorization_engine.cc \
-src/core/lib/security/authorization/authorization_engine.h \
-src/core/lib/security/authorization/evaluate_args.cc \
-src/core/lib/security/authorization/evaluate_args.h \
-src/core/lib/security/authorization/mock_cel/activation.h \
-src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h \
-src/core/lib/security/authorization/mock_cel/cel_expression.h \
-src/core/lib/security/authorization/mock_cel/cel_value.h \
-src/core/lib/security/authorization/mock_cel/evaluator_core.h \
-src/core/lib/security/authorization/mock_cel/flat_expr_builder.h \
 src/core/lib/security/context/security_context.cc \
 src/core/lib/security/context/security_context.h \
 src/core/lib/security/credentials/alts/alts_credentials.cc \
@@ -1962,7 +2022,8 @@
 src/core/tsi/transport_security.h \
 src/core/tsi/transport_security_grpc.cc \
 src/core/tsi/transport_security_grpc.h \
-src/core/tsi/transport_security_interface.h
+src/core/tsi/transport_security_interface.h \
+third_party/xxhash/xxhash.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/grpc/tools/doxygen/Doxyfile.objc b/grpc/tools/doxygen/Doxyfile.objc
index a9c096f..d137440 100644
--- a/grpc/tools/doxygen/Doxyfile.objc
+++ b/grpc/tools/doxygen/Doxyfile.objc
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.35.0
+PROJECT_NUMBER         = 1.38.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/grpc/tools/doxygen/Doxyfile.objc.internal b/grpc/tools/doxygen/Doxyfile.objc.internal
index 7fc91c0..6e72d91 100644
--- a/grpc/tools/doxygen/Doxyfile.objc.internal
+++ b/grpc/tools/doxygen/Doxyfile.objc.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.35.0
+PROJECT_NUMBER         = 1.38.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/grpc/tools/doxygen/Doxyfile.php b/grpc/tools/doxygen/Doxyfile.php
index 1aef67c..09797ba 100644
--- a/grpc/tools/doxygen/Doxyfile.php
+++ b/grpc/tools/doxygen/Doxyfile.php
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.35.0
+PROJECT_NUMBER         = 1.38.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -812,10 +812,15 @@
 src/php/lib/Grpc/Constants.php \
 src/php/lib/Grpc/DefaultCallInvoker.php \
 src/php/lib/Grpc/Interceptor.php \
+src/php/lib/Grpc/MethodDescriptor.php \
 src/php/lib/Grpc/RpcServer.php \
 src/php/lib/Grpc/Server.php \
+src/php/lib/Grpc/ServerCallReader.php \
+src/php/lib/Grpc/ServerCallWriter.php \
+src/php/lib/Grpc/ServerContext.php \
 src/php/lib/Grpc/ServerCredentials.php \
 src/php/lib/Grpc/ServerStreamingCall.php \
+src/php/lib/Grpc/Status.php \
 src/php/lib/Grpc/Timeval.php \
 src/php/lib/Grpc/UnaryCall.php
 
diff --git a/grpc/tools/gce/linux_kokoro_performance_worker_init.sh b/grpc/tools/gce/linux_kokoro_performance_worker_init.sh
index e81ba21..14083a2 100755
--- a/grpc/tools/gce/linux_kokoro_performance_worker_init.sh
+++ b/grpc/tools/gce/linux_kokoro_performance_worker_init.sh
@@ -200,7 +200,7 @@
 git clone -v https://github.com/brendangregg/FlameGraph ~/FlameGraph
 
 # Install scipy and numpy for benchmarking scripts
-sudo apt-get install -y python-scipy python-numpy
+sudo apt-get install -y python3-scipy python3-numpy
 
 # Install docker
 curl -sSL https://get.docker.com/ | sh
diff --git a/grpc/tools/github/pr_latency.py b/grpc/tools/github/pr_latency.py
index da3b985..efd57f9 100644
--- a/grpc/tools/github/pr_latency.py
+++ b/grpc/tools/github/pr_latency.py
@@ -118,17 +118,24 @@
     failures = 0
     errors = 0
     latest_datetime = None
-    if not statuses: return None
-    if system == 'kokoro': string_in_target_url = 'kokoro'
-    elif system == 'jenkins': string_in_target_url = 'grpc-testing'
+    if not statuses:
+        return None
+    if system == 'kokoro':
+        string_in_target_url = 'kokoro'
+    elif system == 'jenkins':
+        string_in_target_url = 'grpc-testing'
     for status in statuses['statuses']:
         if not status['target_url'] or string_in_target_url not in status[
                 'target_url']:
             continue  # Ignore jenkins
-        if status['state'] == 'pending': return None
-        elif status['state'] == 'success': successes += 1
-        elif status['state'] == 'failure': failures += 1
-        elif status['state'] == 'error': errors += 1
+        if status['state'] == 'pending':
+            return None
+        elif status['state'] == 'success':
+            successes += 1
+        elif status['state'] == 'failure':
+            failures += 1
+        elif status['state'] == 'error':
+            errors += 1
         if not latest_datetime:
             latest_datetime = parse_timestamp(status['updated_at'])
         else:
@@ -174,7 +181,8 @@
     args_parser = build_args_parser()
     args = args_parser.parse_args()
     TOKEN = args.token
-    if args.format == 'csv': print_csv_header()
+    if args.format == 'csv':
+        print_csv_header()
     for pr_data in get_pr_data():
         commit_data = get_commits_data(pr_data['number'])
         # PR with a single commit -> use the PRs creation time.
diff --git a/grpc/tools/http2_interop/go.mod b/grpc/tools/http2_interop/go.mod
new file mode 100644
index 0000000..149c38e
--- /dev/null
+++ b/grpc/tools/http2_interop/go.mod
@@ -0,0 +1,3 @@
+module github.com/grpc/grpc/tools/http2_interop
+
+go 1.16
diff --git a/grpc/tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc b/grpc/tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
index bd8c300..ab871dc 100644
--- a/grpc/tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
+++ b/grpc/tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
@@ -19,9 +19,10 @@
 ulimit -n 32768
 ulimit -c unlimited
 
-sudo pip install tabulate
+python3 -m pip install pip==19.3.1
 
 # Python dependencies for tools/run_tests/python_utils/check_on_pr.py
-time python2.7 -m pip install pyjwt cryptography requests --user
+DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
+time python3 -m pip install --user -r $DIR/requirements.linux_perf.txt
 
 git submodule update --init
diff --git a/grpc/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/grpc/tools/internal_ci/helper_scripts/prepare_build_macos_rc
index f469d57..6ea523c 100644
--- a/grpc/tools/internal_ci/helper_scripts/prepare_build_macos_rc
+++ b/grpc/tools/internal_ci/helper_scripts/prepare_build_macos_rc
@@ -37,6 +37,7 @@
 # Add GCP credentials for BQ access
 pip install --user google-api-python-client oauth2client six==1.15.0
 export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json
+DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
 
 # If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests
 if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ]; then
@@ -45,9 +46,21 @@
 
 if [ "${PREPARE_BUILD_INSTALL_DEPS_RUBY}" == "true" ]
 then
+  # Fetch keys per https://rvm.io/rvm/install
+  # Force use of an IPv4 key server to avoid running into https://github.com/rvm/rvm/issues/4215
+  gpg_recv_keys_success=0
+  for ((i=0;i<5;i++)); do
+    KEYSERVER_IPV4_ADDRESS="$(host pool.sks-keyservers.net | grep 'has address' | head -n1 | awk '{print $4}')"
+    gpg --keyserver "hkp://${KEYSERVER_IPV4_ADDRESS}" --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB \
+      && gpg_recv_keys_success=1
+    [[ "$gpg_recv_keys_success" == 1 ]] && break
+    sleep 3
+  done
+  [[ "$gpg_recv_keys_success" == 1 ]] || exit 1
+  rvm get stable # Per https://stackoverflow.com/questions/65477613/rvm-where-is-ruby-3-0-0
   source $HOME/.rvm/scripts/rvm
-  for RUBY_VERSION in 2.5.0 2.7.0; do
-    time rvm install "$RUBY_VERSION"
+  for RUBY_VERSION in 2.5.0 2.7.0 3.0.0; do
+    time rvm install "ruby-${RUBY_VERSION}"
     time gem install bundler -v 1.17.3 --no-document
     time gem install rake-compiler --no-document
   done;
@@ -67,7 +80,7 @@
   time git clone --depth 1 https://github.com/CocoaPods/Specs.git ~/.cocoapods/repos/master
 
   # Needed for ios-binary-size
-  time pip install --user pyyaml pyjwt==1.7.1 pyOpenSSL cryptography requests
+  time pip install --user -r $DIR/requirements.macos.txt
 
   # Store intermediate build files of ObjC tests into /tmpfs
   # TODO(jtattermusch): this has likely been done to avoid running
@@ -84,8 +97,8 @@
 if [ "${PREPARE_BUILD_INSTALL_DEPS_PYTHON}" == "true" ]
 then
   # python
-  time pip install --user virtualenv
-  time pip install --user --upgrade Mako tox setuptools==44.1.1 twisted pyyaml pyjwt==1.7.1 pyOpenSSL cryptography requests
+  time pip install --user -r $DIR/requirements.macos.txt
+  time pip install --user --upgrade virtualenv Mako tox setuptools==44.1.1 twisted
 
   # Install Python 3.7 if it doesn't exist
   if [ ! -f "/usr/local/bin/python3.7" ]; then
diff --git a/grpc/tools/internal_ci/helper_scripts/prepare_qemu_rc b/grpc/tools/internal_ci/helper_scripts/prepare_qemu_rc
new file mode 100644
index 0000000..55bffcc
--- /dev/null
+++ b/grpc/tools/internal_ci/helper_scripts/prepare_qemu_rc
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2021 The 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.
+
+# Source this rc script to setup and configure qemu userspace emulator on kokoro worker so that we can seamlessly emulate processes running
+# inside docker containers.
+
+# show pre-existing qemu registration
+cat /proc/sys/fs/binfmt_misc/qemu-aarch64
+
+# Kokoro ubuntu1604 workers have already qemu-user and qemu-user-static packages installed, but it's and old version that:
+# * prints warning about some syscalls (e.g "qemu: Unsupported syscall: 278")
+# * doesn't register with binfmt_misc with the persistent ("F") flag we need (see below)
+#
+# To overcome the above limitations, we use the https://github.com/multiarch/qemu-user-static
+# docker image to provide a new enough version of qemu-user-static and register it with
+# the desired binfmt_misc flags. The most important flag we need is "F" (set by "--persistent yes"),
+# which allows the qemu-aarch64-static binary to be loaded eagerly at the time of registration with binfmt_misc.
+# That way, we can emulate aarch64 binaries running inside docker containers transparently, without needing the emulator
+# binary to be accessible from the docker image we're emulating.
+# Note that on newer distributions (such as glinux), simply "apt install qemu-user-static" is sufficient
+# to install qemu-user-static with the right flags.
+docker run --rm --privileged multiarch/qemu-user-static:5.2.0-2 --reset --credential yes --persistent yes
+
+# Print current qemu reqistration to make sure everything is setup correctly.
+cat /proc/sys/fs/binfmt_misc/qemu-aarch64
diff --git a/grpc/tools/internal_ci/helper_scripts/requirements.linux_perf.txt b/grpc/tools/internal_ci/helper_scripts/requirements.linux_perf.txt
new file mode 100644
index 0000000..761d8eb
--- /dev/null
+++ b/grpc/tools/internal_ci/helper_scripts/requirements.linux_perf.txt
@@ -0,0 +1,5 @@
+cryptography==3.4.6
+PyJWT==2.0.1
+requests==2.25.1
+scipy==1.5.4
+tabulate==0.8.9
diff --git a/grpc/tools/internal_ci/helper_scripts/requirements.macos.txt b/grpc/tools/internal_ci/helper_scripts/requirements.macos.txt
new file mode 100644
index 0000000..35572fb
--- /dev/null
+++ b/grpc/tools/internal_ci/helper_scripts/requirements.macos.txt
@@ -0,0 +1,5 @@
+cryptography==3.4.6
+PyJWT==2.0.1
+pyOpenSSL==20.0.1
+PyYAML==5.4.1
+requests==2.25.1
diff --git a/grpc/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
index 60d5fc3..623086a 100755
--- a/grpc/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
+++ b/grpc/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh
@@ -25,7 +25,14 @@
 ${name}')
 cd /var/local/git/grpc
 
-bazel build :all //test/... //examples/...
+# Build all basic targets using the strict warning option which leverages the
+# clang compiler to check if sources can pass a set of warning options.
+bazel build --define=use_strict_warning=true \
+	:all \
+	//src/core/... \
+	//src/compiler/... \
+	//test/... \
+	//examples/...
 
 # TODO(jtattersmusch): Adding a build here for --define=grpc_no_xds is not ideal
 # and we should find a better place for this. Refer
diff --git a/grpc/tools/internal_ci/linux/grpc_bazel_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_bazel_test_in_docker.sh
index f65ac7a..639a085 100755
--- a/grpc/tools/internal_ci/linux/grpc_bazel_test_in_docker.sh
+++ b/grpc/tools/internal_ci/linux/grpc_bazel_test_in_docker.sh
@@ -26,3 +26,4 @@
 cd /var/local/git/grpc
 
 bazel test //test/...
+bazel test //test/cpp/end2end:admin_services_end2end_test --define=grpc_no_xds=true
diff --git a/grpc/tools/internal_ci/linux/grpc_build_abseil-cpp_at_head.cfg b/grpc/tools/internal_ci/linux/grpc_build_abseil-cpp_at_head.cfg
index 7983cd3..8421298 100644
--- a/grpc/tools/internal_ci/linux/grpc_build_abseil-cpp_at_head.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_build_abseil-cpp_at_head.cfg
@@ -24,7 +24,7 @@
   }
 }
 
-# Tiny hack: misusing an already whitelisted env var to pass submodule name
+# Tiny hack: misusing an already allowlisted env var to pass submodule name
 env_vars {
   key: "RUN_TESTS_FLAGS"
   value: "abseil-cpp"
diff --git a/grpc/tools/internal_ci/linux/grpc_build_artifacts.cfg b/grpc/tools/internal_ci/linux/grpc_build_artifacts.cfg
index 1e04a1e..433860f 100644
--- a/grpc/tools/internal_ci/linux/grpc_build_artifacts.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_build_artifacts.cfg
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_build_artifacts.sh"
-timeout_mins: 120
+timeout_mins: 180
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
diff --git a/grpc/tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg b/grpc/tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg
index eae125d..e7f8abe 100644
--- a/grpc/tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg
@@ -24,13 +24,13 @@
   }
 }
 
-# Tiny hack: misusing an already whitelisted env var to pass submodule name
+# Tiny hack: misusing an already allowlisted env var to pass submodule name
 env_vars {
   key: "RUN_TESTS_FLAGS"
   value: "boringssl-with-bazel"
 }
 
-# Tiny hack: misusing an already whitelisted env var to pass branch name to checkout
+# Tiny hack: misusing an already allowlisted env var to pass branch name to checkout
 env_vars {
   key: "BAZEL_FLAGS"
   value: "master-with-bazel"
diff --git a/grpc/tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg b/grpc/tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg
index 0ec016e..75f0dae 100644
--- a/grpc/tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg
@@ -24,7 +24,7 @@
   }
 }
 
-# Tiny hack: misusing an already whitelisted env var to pass submodule name
+# Tiny hack: misusing an already allowlisted env var to pass submodule name
 env_vars {
   key: "RUN_TESTS_FLAGS"
   value: "protobuf"
diff --git a/grpc/tools/internal_ci/linux/grpc_build_submodule_at_head.sh b/grpc/tools/internal_ci/linux/grpc_build_submodule_at_head.sh
index ea96edc..58aa5e7 100755
--- a/grpc/tools/internal_ci/linux/grpc_build_submodule_at_head.sh
+++ b/grpc/tools/internal_ci/linux/grpc_build_submodule_at_head.sh
@@ -55,4 +55,4 @@
 # commit so that changes are passed to Docker
 git -c user.name='foo' -c user.email='foo@google.com' commit -a -m 'Update submodule' --allow-empty
 
-tools/run_tests/run_tests_matrix.py -f linux --inner_jobs 4 -j 4 --internal_ci --build_only
+tools/run_tests/run_tests_matrix.py -f linux --inner_jobs 8 -j 4 --internal_ci --build_only
diff --git a/grpc/tools/internal_ci/linux/grpc_distribtests.sh b/grpc/tools/internal_ci/linux/grpc_distribtests.sh
index 47e4bf8..b2ec2bf 100644
--- a/grpc/tools/internal_ci/linux/grpc_distribtests.sh
+++ b/grpc/tools/internal_ci/linux/grpc_distribtests.sh
@@ -20,6 +20,11 @@
 
 source tools/internal_ci/helper_scripts/prepare_build_linux_rc
 
+# some distribtests use a pre-registered binfmt_misc hook
+# to automatically execute foreign binaries (such as aarch64)
+# under qemu emulator.
+source tools/internal_ci/helper_scripts/prepare_qemu_rc
+
 set +ex
 [[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
 set -e  # rvm commands are very verbose
diff --git a/grpc/tools/internal_ci/linux/grpc_distribtests_python.cfg b/grpc/tools/internal_ci/linux/grpc_distribtests_python.cfg
new file mode 100644
index 0000000..307b3b6
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_distribtests_python.cfg
@@ -0,0 +1,26 @@
+# Copyright 2021 The 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_distribtests_python.sh"
+timeout_mins: 240
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.*"
+    regex: "github/grpc/reports/**"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_distribtests_python.sh b/grpc/tools/internal_ci/linux/grpc_distribtests_python.sh
new file mode 100755
index 0000000..aef9181
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_distribtests_python.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+# Copyright 2021 The 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.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# some distribtests use a pre-registered binfmt_misc hook
+# to automatically execute foreign binaries (such as aarch64)
+# under qemu emulator.
+source tools/internal_ci/helper_scripts/prepare_qemu_rc
+
+# Build all python linux artifacts (this step actually builds all the binary wheels and source archives)
+tools/run_tests/task_runner.py -f artifact linux python -j 6 -x build_artifacts/sponge_log.xml || FAILED="true"
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/* input_artifacts/ || true
+rm -rf artifacts_from_build_artifacts_step
+mv artifacts artifacts_from_build_artifacts_step || true
+
+# This step mostly just copies artifacts from input_artifacts (but it also does some wheel stripping)
+tools/run_tests/task_runner.py -f package linux python -x build_packages/sponge_log.xml || FAILED="true"
+
+# the next step expects to find the artifacts from the previous step in the "input_artifacts" folder.
+# in addition to that, preserve the contents of "artifacts" directory since we want kokoro
+# to upload its contents as job output artifacts
+rm -rf input_artifacts
+mkdir -p input_artifacts
+cp -r artifacts/* input_artifacts/ || true
+
+# Run all python linux distribtests
+# We run the distribtests even if some of the artifacts have failed to build, since that gives
+# a better signal about which distribtest are affected by the currently broken artifact builds.
+tools/run_tests/task_runner.py -f distribtest linux python -j 6 -x distribtests/sponge_log.xml || FAILED="true"
+
+if [ "$FAILED" != "" ]
+then
+  exit 1
+fi
diff --git a/grpc/tools/internal_ci/linux/grpc_e2e_performance_v2.cfg b/grpc/tools/internal_ci/linux/grpc_e2e_performance_v2.cfg
new file mode 100644
index 0000000..8974fb2
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_e2e_performance_v2.cfg
@@ -0,0 +1,25 @@
+# Copyright 2021 The 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_e2e_performance_v2.sh"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.*"
+    regex: "**/perf_reports/**"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_e2e_performance_v2.sh b/grpc/tools/internal_ci/linux/grpc_e2e_performance_v2.sh
new file mode 100755
index 0000000..63d2650
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_e2e_performance_v2.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# Copyright 2021 The 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.
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# This is to ensure we can push and pull images from gcr.io. We do not
+# necessarily need it to run load tests, but will need it when we employ
+# pre-built images in the optimization.
+gcloud auth configure-docker
+
+# Connect to benchmarks-prod cluster.
+gcloud config set project grpc-testing
+gcloud container clusters get-credentials benchmarks-prod \
+    --zone us-central1-b --project grpc-testing
+
+# This is subject to change. Runs a single test and does not wait for the
+# result.
+tools/run_tests/performance/loadtest_config.py -l c++ -l go \
+    -t ./tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml \
+    -s client_pool=workers-8core -s server_pool=workers-8core \
+    -s big_query_table=e2e_benchmarks.experimental_results \
+    -s timeout_seconds=900 --prefix="kokoro-test" -u "$(date +%Y%m%d%H%M%S)" \
+    -r '(go_generic_sync_streaming_ping_pong_secure|go_protobuf_sync_unary_ping_pong_secure|cpp_protobuf_async_streaming_qps_unconstrained_secure)$' \
+    -o ./loadtest.yaml
+
+# Dump the contents of the loadtest.yaml (since loadtest_config.py doesn't
+# list the scenarios that will be run).
+cat ./loadtest.yaml
+
+# The original version of the client is a bit old, update to the latest release
+# version v1.21.0.
+kubectl version --client
+curl -sSL -O https://dl.k8s.io/release/v1.21.0/bin/linux/amd64/kubectl
+sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
+chmod +x kubectl
+sudo mv kubectl $(which kubectl)
+kubectl version --client
+
+kubectl apply -f ./loadtest.yaml
diff --git a/grpc/tools/internal_ci/linux/grpc_microbenchmark_diff.sh b/grpc/tools/internal_ci/linux/grpc_microbenchmark_diff.sh
index c03383d..580c184 100755
--- a/grpc/tools/internal_ci/linux/grpc_microbenchmark_diff.sh
+++ b/grpc/tools/internal_ci/linux/grpc_microbenchmark_diff.sh
@@ -31,7 +31,7 @@
   -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" \
   -b $BENCHMARKS_TO_RUN || FAILED="true"
 
-# kill port_server.py to prevent the build from hanging
+# kill port_server.py to prevent the build from freezing
 ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
 
 if [ "$FAILED" != "" ]
diff --git a/grpc/tools/internal_ci/linux/grpc_performance_profile_daily.sh b/grpc/tools/internal_ci/linux/grpc_performance_profile_daily.sh
index 5fe47ff..013f1ab 100755
--- a/grpc/tools/internal_ci/linux/grpc_performance_profile_daily.sh
+++ b/grpc/tools/internal_ci/linux/grpc_performance_profile_daily.sh
@@ -20,13 +20,13 @@
 
 source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
 
-CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
+CPUS=`python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())'`
 
 ./tools/run_tests/start_port_server.py || true
 
 tools/run_tests/run_microbenchmark.py --collect summary --bigquery_upload || FAILED="true"
 
-# kill port_server.py to prevent the build from hanging
+# kill port_server.py to prevent the build from freezing
 ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
 
 if [ "$FAILED" != "" ]
diff --git a/grpc/tools/internal_ci/linux/grpc_performance_profile_master.sh b/grpc/tools/internal_ci/linux/grpc_performance_profile_master.sh
index fbff174..93454b7 100755
--- a/grpc/tools/internal_ci/linux/grpc_performance_profile_master.sh
+++ b/grpc/tools/internal_ci/linux/grpc_performance_profile_master.sh
@@ -22,7 +22,7 @@
 
 tools/internal_ci/linux/run_performance_profile_hourly.sh || FAILED="true"
 
-# kill port_server.py to prevent the build from hanging
+# kill port_server.py to prevent the build from freezing
 ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
 
 if [ "$FAILED" != "" ]
diff --git a/grpc/tools/internal_ci/linux/grpc_portability_build_only.cfg b/grpc/tools/internal_ci/linux/grpc_portability_build_only.cfg
index fab9dde..c4fa6c6 100644
--- a/grpc/tools/internal_ci/linux/grpc_portability_build_only.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_portability_build_only.cfg
@@ -26,5 +26,5 @@
 
 env_vars {
   key: "RUN_TESTS_FLAGS"
-  value: "-f portability linux --inner_jobs 4 -j 4 --internal_ci --build_only"
+  value: "-f portability linux --inner_jobs 8 -j 4 --internal_ci --build_only"
 }
diff --git a/grpc/tools/internal_ci/linux/grpc_publish_packages.sh b/grpc/tools/internal_ci/linux/grpc_publish_packages.sh
index 1aa66bc..1cf639b 100755
--- a/grpc/tools/internal_ci/linux/grpc_publish_packages.sh
+++ b/grpc/tools/internal_ci/linux/grpc_publish_packages.sh
@@ -49,7 +49,7 @@
 do
   zip -jr "$PROTOC_PLUGINS_ZIPPED_PACKAGES/grpc-$zip_dir-$GRPC_VERSION.zip" "$INPUT_ARTIFACTS/$zip_dir/"*
 done
-for tar_dir in protoc_{linux,macos}_{x86,x64}
+for tar_dir in protoc_linux_{x86,x64} protoc_macos_x64
 do
   chmod +x "$INPUT_ARTIFACTS/$tar_dir"/*
   tar -cvzf "$PROTOC_PLUGINS_ZIPPED_PACKAGES/grpc-$tar_dir-$GRPC_VERSION.tar.gz" -C "$INPUT_ARTIFACTS/$tar_dir" .
@@ -57,7 +57,8 @@
 
 PROTOC_PACKAGES=(
   "$PROTOC_PLUGINS_ZIPPED_PACKAGES"/grpc-protoc_windows_{x86,x64}-"$GRPC_VERSION.zip"
-  "$PROTOC_PLUGINS_ZIPPED_PACKAGES"/grpc-protoc_{linux,macos}_{x86,x64}-"$GRPC_VERSION.tar.gz"
+  "$PROTOC_PLUGINS_ZIPPED_PACKAGES"/grpc-protoc_linux_{x86,x64}-"$GRPC_VERSION.tar.gz"
+  "$PROTOC_PLUGINS_ZIPPED_PACKAGES"/grpc-protoc_macos_x64-"$GRPC_VERSION.tar.gz"
 )
 
 # C#
diff --git a/grpc/tools/internal_ci/linux/grpc_trickle_diff.sh b/grpc/tools/internal_ci/linux/grpc_trickle_diff.sh
index 49c3d4b..a764095 100755
--- a/grpc/tools/internal_ci/linux/grpc_trickle_diff.sh
+++ b/grpc/tools/internal_ci/linux/grpc_trickle_diff.sh
@@ -33,7 +33,7 @@
   --no-counters \
   --pr_comment_name trickle || FAILED="true"
 
-# kill port_server.py to prevent the build from hanging
+# kill port_server.py to prevent the build from freezing
 ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
 
 if [ "$FAILED" != "" ]
diff --git a/grpc/tools/internal_ci/linux/grpc_xds.cfg b/grpc/tools/internal_ci/linux/grpc_xds.cfg
index ed3e0f5..2a7cbdd 100644
--- a/grpc/tools/internal_ci/linux/grpc_xds.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_xds.cfg
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds.sh"
-timeout_mins: 120
+timeout_mins: 360
 env_vars {
   key: "BAZEL_SCRIPT"
   value: "tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh"
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh
index dcf83ee..6fb22b8 100755
--- a/grpc/tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh
+++ b/grpc/tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh
@@ -23,10 +23,10 @@
 cd /var/local/git/grpc
 
 VIRTUAL_ENV=$(mktemp -d)
-virtualenv "$VIRTUAL_ENV"
+virtualenv "$VIRTUAL_ENV" -p python3
 PYTHON="$VIRTUAL_ENV"/bin/python
-"$PYTHON" -m pip install --upgrade pip
-"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
 
 # Prepare generated Python code.
 TOOLS_DIR=tools/run_tests
@@ -64,10 +64,12 @@
 # because not all interop clients in all languages support these new tests.
 GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
   tools/run_tests/run_xds_tests.py \
-    --test_case="all,path_matching,header_matching,circuit_breaking" \
+    --test_case="all,circuit_breaking,timeout,fault_injection" \
     --project_id=grpc-testing \
-    --source_image=projects/grpc-testing/global/images/xds-test-server-3 \
+    --project_num=830293263384 \
+    --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
     --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
     --gcp_suffix=$(date '+%s') \
     --verbose \
-    --client_cmd='bazel run --test_env="PYTHONUNBUFFERED=true" //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_client -- --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} --verbose {rpcs_to_send} {metadata_to_send}'
+    ${XDS_V3_OPT-} \
+    --client_cmd='bazel run --test_env="PYTHONUNBUFFERED=true" //src/python/grpcio_tests/tests_py3_only/interop:xds_interop_client -- --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {rpcs_to_send} {metadata_to_send}'
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh
index 7057ade..8825719 100755
--- a/grpc/tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh
+++ b/grpc/tools/internal_ci/linux/grpc_xds_bazel_test_in_docker.sh
@@ -23,10 +23,10 @@
 cd /var/local/git/grpc
 
 VIRTUAL_ENV=$(mktemp -d)
-virtualenv "$VIRTUAL_ENV"
+virtualenv "$VIRTUAL_ENV" -p python3
 PYTHON="$VIRTUAL_ENV"/bin/python
-"$PYTHON" -m pip install --upgrade pip
-"$PYTHON" -m pip install --upgrade grpcio grpcio-tools google-api-python-client google-auth-httplib2 oauth2client
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
 
 # Prepare generated Python code.
 TOOLS_DIR=tools/run_tests
@@ -67,12 +67,14 @@
 # they are added into "all".
 GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
   tools/run_tests/run_xds_tests.py \
-    --test_case="all,path_matching,header_matching,circuit_breaking" \
+    --test_case="all,circuit_breaking,timeout,fault_injection,csds" \
     --project_id=grpc-testing \
-    --source_image=projects/grpc-testing/global/images/xds-test-server-3 \
+    --project_num=830293263384 \
+    --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
     --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
     --gcp_suffix=$(date '+%s') \
     --verbose \
+    ${XDS_V3_OPT-} \
     --client_cmd='bazel-bin/test/cpp/interop/xds_interop_client --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {fail_on_failed_rpc} \
       {rpcs_to_send} \
       {metadata_to_send}'
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_csharp.cfg b/grpc/tools/internal_ci/linux/grpc_xds_csharp.cfg
index 1f6ab28..0208f9b 100644
--- a/grpc/tools/internal_ci/linux/grpc_xds_csharp.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_xds_csharp.cfg
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_csharp.sh"
-timeout_mins: 120
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_csharp_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_csharp_test_in_docker.sh
index 83a539d..21b0d4e 100755
--- a/grpc/tools/internal_ci/linux/grpc_xds_csharp_test_in_docker.sh
+++ b/grpc/tools/internal_ci/linux/grpc_xds_csharp_test_in_docker.sh
@@ -23,10 +23,10 @@
 cd /var/local/git/grpc
 
 VIRTUAL_ENV=$(mktemp -d)
-virtualenv "$VIRTUAL_ENV"
+virtualenv "$VIRTUAL_ENV" -p python3
 PYTHON="$VIRTUAL_ENV"/bin/python
-"$PYTHON" -m pip install --upgrade pip
-"$PYTHON" -m pip install --upgrade grpcio grpcio-tools google-api-python-client google-auth-httplib2 oauth2client
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
 
 # Prepare generated Python code.
 TOOLS_DIR=tools/run_tests
@@ -69,8 +69,10 @@
   tools/run_tests/run_xds_tests.py \
     --test_case="all,path_matching,header_matching" \
     --project_id=grpc-testing \
+    --project_num=830293263384 \
     --source_image=projects/grpc-testing/global/images/xds-test-server-2 \
     --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
     --gcp_suffix=$(date '+%s') \
     --verbose \
+    ${XDS_V3_OPT-} \
     --client_cmd='dotnet exec src/csharp/Grpc.IntegrationTesting.XdsClient/bin/Release/netcoreapp2.1/Grpc.IntegrationTesting.XdsClient.dll -- --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {rpcs_to_send} {metadata_to_send}'
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_k8s.cfg b/grpc/tools/internal_ci/linux/grpc_xds_k8s.cfg
new file mode 100644
index 0000000..c59a357
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_k8s.cfg
@@ -0,0 +1,26 @@
+# Copyright 2021 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_xds_k8s.sh"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "artifacts/**/*sponge_log.xml"
+    regex: "artifacts/**/*sponge_log.log"
+    strip_prefix: "artifacts"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_k8s.sh b/grpc/tools/internal_ci/linux/grpc_xds_k8s.sh
new file mode 100755
index 0000000..a8cbf5d
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_k8s.sh
@@ -0,0 +1,149 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+set -ex -o igncr || set -ex
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+# GKE Cluster
+readonly GKE_CLUSTER_NAME="interop-test-psm-sec-v2-us-central1-a"
+readonly GKE_CLUSTER_ZONE="us-central1-a"
+## xDS test server/client Docker images
+readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-server"
+readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-client"
+readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
+readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
+
+#######################################
+# Builds test app Docker images and pushes them to GCR
+# Globals:
+#   BUILD_APP_PATH
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `gcloud builds submit` to stdout, stderr
+#######################################
+build_test_app_docker_images() {
+  echo "Building C++ xDS interop test app Docker images"
+  docker build -f "${SRC_DIR}/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_client" -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" "${SRC_DIR}"
+  docker build -f "${SRC_DIR}/tools/dockerfile/interoptest/grpc_interop_cxx_xds/Dockerfile.xds_server" -t "${SERVER_IMAGE_NAME}:${GIT_COMMIT}" "${SRC_DIR}"
+  gcloud -q auth configure-docker
+  docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}"
+  docker push "${SERVER_IMAGE_NAME}:${GIT_COMMIT}"
+}
+
+#######################################
+# Builds test app and its docker images unless they already exist
+# Globals:
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+#   FORCE_IMAGE_BUILD
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output to stdout, stderr
+#######################################
+build_docker_images_if_needed() {
+  # Check if images already exist
+  server_tags="$(gcloud_gcr_list_image_tags "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}")"
+  printf "Server image: %s:%s\n" "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}"
+  echo "${server_tags:-Server image not found}"
+
+  client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")"
+  printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}"
+  echo "${client_tags:-Client image not found}"
+
+  # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1
+  if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${server_tags}" || -z "${client_tags}" ]]; then
+    build_test_app_docker_images
+  else
+    echo "Skipping C++ test app build"
+  fi
+}
+
+#######################################
+# Executes the test case
+# Globals:
+#   TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+#   KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+#   TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+#   Test case name
+# Outputs:
+#   Writes the output of test execution to stdout, stderr
+#   Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+  # Test driver usage:
+  # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+  local test_name="${1:?Usage: run_test test_name}"
+  set -x
+  python -m "tests.${test_name}" \
+    --flagfile="${TEST_DRIVER_FLAGFILE}" \
+    --kube_context="${KUBE_CONTEXT}" \
+    --server_image="${SERVER_IMAGE_NAME}:${GIT_COMMIT}" \
+    --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+    --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \
+    --force_cleanup \
+    --nocheck_local_certs
+  set +x
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+#   KOKORO_ARTIFACTS_DIR
+#   GITHUB_REPOSITORY_NAME
+#   SRC_DIR: Populated with absolute path to the source repo
+#   TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+#                         the test driver
+#   TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+#   TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+#   TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+#   GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+#   GIT_COMMIT: Populated with the SHA-1 of git commit being built
+#   GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+#   KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+  local script_dir
+  script_dir="$(dirname "$0")"
+  # shellcheck source=tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh
+  source "${script_dir}/grpc_xds_k8s_install_test_driver.sh"
+  set -x
+  if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+    kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+  else
+    local_setup_test_driver "${script_dir}"
+  fi
+  build_docker_images_if_needed
+  # Run tests
+  cd "${TEST_DRIVER_FULL_DIR}"
+  run_test baseline_test
+  run_test security_test
+}
+
+main "$@"
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh b/grpc/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh
new file mode 100644
index 0000000..d7f50fb
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh
@@ -0,0 +1,363 @@
+#!/usr/bin/env bash
+# Copyright 2020 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.
+# TODO(sergiitk): move to grpc/grpc when implementing support of other languages
+set -eo pipefail
+
+# Constants
+readonly PYTHON_VERSION="3.6"
+# Test driver
+readonly TEST_DRIVER_REPO_NAME="grpc"
+readonly TEST_DRIVER_REPO_URL="https://github.com/grpc/grpc.git"
+readonly TEST_DRIVER_BRANCH="${TEST_DRIVER_BRANCH:-master}"
+readonly TEST_DRIVER_PATH="tools/run_tests/xds_k8s_test_driver"
+readonly TEST_DRIVER_PROTOS_PATH="src/proto/grpc/testing"
+
+#######################################
+# Run command end report its exit code. Doesn't exit on non-zero exit code.
+# Globals:
+#   None
+# Arguments:
+#   Command to execute
+# Outputs:
+#   Writes the output of given command to stdout, stderr
+#######################################
+run_ignore_exit_code() {
+  local exit_code=-1
+  "$@" || exit_code=$?
+  echo "Exit code: ${exit_code}"
+}
+
+#######################################
+# Parses information about git repository at given path to global variables.
+# Globals:
+#   GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+#   GIT_COMMIT: Populated with the SHA-1 of git commit being built
+#   GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# Arguments:
+#   Git source dir
+#######################################
+parse_src_repo_git_info() {
+  local src_dir="${SRC_DIR:?SRC_DIR must be set}"
+  readonly GIT_ORIGIN_URL=$(git -C "${src_dir}" remote get-url origin)
+  readonly GIT_COMMIT=$(git -C "${src_dir}" rev-parse HEAD)
+  readonly GIT_COMMIT_SHORT=$(git -C "${src_dir}" rev-parse --short HEAD)
+}
+
+#######################################
+# List GCR image tags matching given tag name.
+# Arguments:
+#   Image name
+#   Tag name
+# Outputs:
+#   Writes the table with the list of found tags to stdout.
+#   If no tags found, the output is an empty string.
+#######################################
+gcloud_gcr_list_image_tags() {
+  gcloud container images list-tags --format="table[box](tags,digest,timestamp.date())" --filter="tags:$2" "$1"
+}
+
+#######################################
+# A helper to execute `gcloud -q components update`.
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `gcloud` command to stdout, stderr
+#######################################
+gcloud_update() {
+  echo "Update gcloud components:"
+  gcloud -q components update
+}
+
+#######################################
+# Create kube context authenticated with GKE cluster, saves context name.
+# to KUBE_CONTEXT
+# Globals:
+#   GKE_CLUSTER_NAME
+#   GKE_CLUSTER_ZONE
+#   KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `gcloud` command to stdout, stderr
+#   Writes authorization info $HOME/.kube/config
+#######################################
+gcloud_get_cluster_credentials() {
+  gcloud container clusters get-credentials "${GKE_CLUSTER_NAME}" --zone "${GKE_CLUSTER_ZONE}"
+  readonly KUBE_CONTEXT="$(kubectl config current-context)"
+}
+
+#######################################
+# Clone the source code of the test driver to $TEST_DRIVER_REPO_DIR, unless
+# given folder exists.
+# Globals:
+#   TEST_DRIVER_REPO_URL
+#   TEST_DRIVER_BRANCH
+#   TEST_DRIVER_REPO_DIR: path to the repo containing the test driver
+#   TEST_DRIVER_REPO_DIR_USE_EXISTING: set non-empty value to use exiting
+#      clone of the driver repo located at $TEST_DRIVER_REPO_DIR.
+#      Useful for debugging the build script locally.
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `git` command to stdout, stderr
+#   Writes driver source code to $TEST_DRIVER_REPO_DIR
+#######################################
+test_driver_get_source() {
+  if [[ -n "${TEST_DRIVER_REPO_DIR_USE_EXISTING}" && -d "${TEST_DRIVER_REPO_DIR}" ]]; then
+    echo "Using exiting driver directory: ${TEST_DRIVER_REPO_DIR}."
+  else
+    echo "Cloning driver to ${TEST_DRIVER_REPO_URL} branch ${TEST_DRIVER_BRANCH} to ${TEST_DRIVER_REPO_DIR}"
+    git clone -b "${TEST_DRIVER_BRANCH}" --depth=1 "${TEST_DRIVER_REPO_URL}" "${TEST_DRIVER_REPO_DIR}"
+  fi
+}
+
+#######################################
+# Install Python modules from required in $TEST_DRIVER_FULL_DIR/requirements.txt
+# to Python virtual environment. Creates and activates Python venv if necessary.
+# Globals:
+#   TEST_DRIVER_FULL_DIR
+#   PYTHON_VERSION
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `python`, `pip` commands to stdout, stderr
+#   Writes the list of installed modules to stdout
+#######################################
+test_driver_pip_install() {
+  echo "Install python dependencies"
+  cd "${TEST_DRIVER_FULL_DIR}"
+
+  # Create and activate virtual environment unless already using one
+  if [[ -z "${VIRTUAL_ENV}" ]]; then
+    local venv_dir="${TEST_DRIVER_FULL_DIR}/venv"
+    if [[ -d "${venv_dir}" ]]; then
+      echo "Found python virtual environment directory: ${venv_dir}"
+    else
+      echo "Creating python virtual environment: ${venv_dir}"
+      "python${PYTHON_VERSION} -m venv ${venv_dir}"
+    fi
+    # Intentional: No need to check python venv activate script.
+    # shellcheck source=/dev/null
+    source "${venv_dir}/bin/activate"
+  fi
+
+  pip install -r requirements.txt
+  echo "Installed Python packages:"
+  pip list
+}
+
+#######################################
+# Compile proto-files needed for the test driver
+# Globals:
+#   TEST_DRIVER_REPO_DIR
+#   TEST_DRIVER_FULL_DIR
+#   TEST_DRIVER_PROTOS_PATH
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `python -m grpc_tools.protoc` to stdout, stderr
+#   Writes the list if compiled python code to stdout
+#   Writes compiled python code with proto messages and grpc services to
+#   $TEST_DRIVER_FULL_DIR/src/proto
+#######################################
+test_driver_compile_protos() {
+  declare -a protos
+  protos=(
+    "${TEST_DRIVER_PROTOS_PATH}/test.proto"
+    "${TEST_DRIVER_PROTOS_PATH}/messages.proto"
+    "${TEST_DRIVER_PROTOS_PATH}/empty.proto"
+  )
+  echo "Generate python code from grpc.testing protos: ${protos[*]}"
+  cd "${TEST_DRIVER_REPO_DIR}"
+  python -m grpc_tools.protoc \
+    --proto_path=. \
+    --python_out="${TEST_DRIVER_FULL_DIR}" \
+    --grpc_python_out="${TEST_DRIVER_FULL_DIR}" \
+    "${protos[@]}"
+  local protos_out_dir="${TEST_DRIVER_FULL_DIR}/${TEST_DRIVER_PROTOS_PATH}"
+  echo "Generated files ${protos_out_dir}:"
+  ls -Fl "${protos_out_dir}"
+}
+
+#######################################
+# Installs the test driver and it's requirements.
+# https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#installation
+# Globals:
+#   TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+#                         the test driver
+#   TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+# Arguments:
+#   The directory for test driver's source code
+# Outputs:
+#   Writes the output to stdout, stderr
+#######################################
+test_driver_install() {
+  readonly TEST_DRIVER_REPO_DIR="${1:?Usage test_driver_install TEST_DRIVER_REPO_DIR}"
+  readonly TEST_DRIVER_FULL_DIR="${TEST_DRIVER_REPO_DIR}/${TEST_DRIVER_PATH}"
+  test_driver_get_source
+  test_driver_pip_install
+  test_driver_compile_protos
+}
+
+#######################################
+# Outputs Kokoro image version and Ubuntu's lsb_release
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output to stdout
+#######################################
+kokoro_print_version() {
+  echo "Kokoro VM version:"
+  if [[ -f /VERSION ]]; then
+    cat /VERSION
+  fi
+  run_ignore_exit_code lsb_release -a
+}
+
+#######################################
+# Report extra information about the job via sponge properties.
+# Globals:
+#   KOKORO_ARTIFACTS_DIR
+#   GIT_ORIGIN_URL
+#   GIT_COMMIT_SHORT
+#   TESTGRID_EXCLUDE
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output to stdout
+#   Writes job properties to $KOKORO_ARTIFACTS_DIR/custom_sponge_config.csv
+#######################################
+kokoro_write_sponge_properties() {
+  # CSV format: "property_name","property_value"
+  # Bump TESTS_FORMAT_VERSION when reported test name changed enough to when it
+  # makes more sense to discard previous test results from a testgrid board.
+  # Use GIT_ORIGIN_URL to exclude test runs executed against repo forks from
+  # testgrid reports.
+  cat >"${KOKORO_ARTIFACTS_DIR}/custom_sponge_config.csv" <<EOF
+TESTS_FORMAT_VERSION,2
+TESTGRID_EXCLUDE,${TESTGRID_EXCLUDE:-0}
+GIT_ORIGIN_URL,${GIT_ORIGIN_URL:?GIT_ORIGIN_URL must be set}
+GIT_COMMIT_SHORT,${GIT_COMMIT_SHORT:?GIT_COMMIT_SHORT must be set}
+EOF
+  echo "Sponge properties:"
+  cat "${KOKORO_ARTIFACTS_DIR}/custom_sponge_config.csv"
+}
+
+#######################################
+# Configure Python virtual environment on Kokoro VM.
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `pyenv` commands to stdout
+#######################################
+kokoro_setup_python_virtual_environment() {
+  # Kokoro provides pyenv, so use it instead of `python -m venv`
+  echo "Setup pyenv environment"
+  eval "$(pyenv init -)"
+  eval "$(pyenv virtualenv-init -)"
+  py_latest_patch="$(pyenv versions --bare --skip-aliases | grep -E "^${PYTHON_VERSION}\.[0-9]{1,2}$" | sort --version-sort | tail -n 1)"
+  echo "Activating python ${py_latest_patch} virtual environment"
+  pyenv virtualenv --no-pip "${py_latest_patch}" k8s_xds_test_runner
+  pyenv local k8s_xds_test_runner
+  pyenv activate k8s_xds_test_runner
+  python -m ensurepip
+  # pip is fixed to 21.0.1 due to issue https://github.com/pypa/pip/pull/9835
+  # internal details: b/186411224
+  # TODO(sergiitk): revert https://github.com/grpc/grpc/pull/26087 when 21.1.1 released
+  python -m pip install -U pip==21.0.1
+  pip --version
+}
+
+#######################################
+# Installs and configures the test driver on Kokoro VM.
+# Globals:
+#   KOKORO_ARTIFACTS_DIR
+#   TEST_DRIVER_REPO_NAME
+#   SRC_DIR: Populated with absolute path to the source repo on Kokoro VM
+#   TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+#                         the test driver
+#   TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+#   TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+#   TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+#   KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+#   GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+#   GIT_COMMIT: Populated with the SHA-1 of git commit being built
+#   GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+# Arguments:
+#   The name of github repository being built
+# Outputs:
+#   Writes the output to stdout, stderr, files
+#######################################
+kokoro_setup_test_driver() {
+  local src_repository_name="${1:?Usage kokoro_setup_test_driver GITHUB_REPOSITORY_NAME}"
+  # Capture Kokoro VM version info in the log.
+  kokoro_print_version
+
+  # Kokoro clones repo to ${KOKORO_ARTIFACTS_DIR}/github/${GITHUB_REPOSITORY}
+  local github_root="${KOKORO_ARTIFACTS_DIR}/github"
+  readonly SRC_DIR="${github_root}/${src_repository_name}"
+  local test_driver_repo_dir
+  test_driver_repo_dir="${TEST_DRIVER_REPO_DIR:-$(mktemp -d)/${TEST_DRIVER_REPO_NAME}}"
+  parse_src_repo_git_info SRC_DIR
+  kokoro_write_sponge_properties
+  kokoro_setup_python_virtual_environment
+
+  # gcloud requires python, so this should be executed after pyenv setup
+  gcloud_update
+  gcloud_get_cluster_credentials
+  test_driver_install "${test_driver_repo_dir}"
+  # shellcheck disable=SC2034  # Used in the main script
+  readonly TEST_DRIVER_FLAGFILE="config/grpc-testing.cfg"
+  # Test artifacts dir: xml reports, logs, etc.
+  local artifacts_dir="${KOKORO_ARTIFACTS_DIR}/artifacts"
+  # Folders after $artifacts_dir reported as target name
+  readonly TEST_XML_OUTPUT_DIR="${artifacts_dir}/${KOKORO_JOB_NAME}"
+  mkdir -p "${artifacts_dir}" "${TEST_XML_OUTPUT_DIR}"
+}
+
+#######################################
+# Installs and configures the test driver for testing build script locally.
+# Globals:
+#   TEST_DRIVER_REPO_NAME
+#   TEST_DRIVER_REPO_DIR: Unless provided, populated with a temporary dir with
+#                         the path to the test driver repo
+#   SRC_DIR: Populated with absolute path to the source repo
+#   TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+#   TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+#   TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+#   GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+#   GIT_COMMIT: Populated with the SHA-1 of git commit being built
+#   GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+#   KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+#   The path to the folder containing the build script
+# Outputs:
+#   Writes the output to stdout, stderr, files
+#######################################
+local_setup_test_driver() {
+  local script_dir="${1:?Usage: local_setup_test_driver SCRIPT_DIR}"
+  readonly SRC_DIR="$(git -C "${script_dir}" rev-parse --show-toplevel)"
+  parse_src_repo_git_info SRC_DIR
+  readonly KUBE_CONTEXT="${KUBE_CONTEXT:-$(kubectl config current-context)}"
+  local test_driver_repo_dir
+  test_driver_repo_dir="${TEST_DRIVER_REPO_DIR:-$(mktemp -d)/${TEST_DRIVER_REPO_NAME}}"
+  test_driver_install "${test_driver_repo_dir}"
+  # shellcheck disable=SC2034  # Used in the main script
+  readonly TEST_DRIVER_FLAGFILE="config/local-dev.cfg"
+  # Test out
+  readonly TEST_XML_OUTPUT_DIR="${TEST_DRIVER_FULL_DIR}/out"
+  mkdir -p "${TEST_XML_OUTPUT_DIR}"
+}
+
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_k8s_python.cfg b/grpc/tools/internal_ci/linux/grpc_xds_k8s_python.cfg
new file mode 100644
index 0000000..82826f1
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_k8s_python.cfg
@@ -0,0 +1,26 @@
+# Copyright 2021 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_xds_k8s_python.sh"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "artifacts/**/*sponge_log.xml"
+    regex: "artifacts/**/*sponge_log.log"
+    strip_prefix: "artifacts"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_k8s_python.sh b/grpc/tools/internal_ci/linux/grpc_xds_k8s_python.sh
new file mode 100755
index 0000000..b6bbfc2
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_k8s_python.sh
@@ -0,0 +1,163 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+set -ex -o igncr || set -ex
+
+# Constants
+readonly GITHUB_REPOSITORY_NAME="grpc"
+# GKE Cluster
+readonly GKE_CLUSTER_NAME="interop-test-psm-sec-v2-us-central1-a"
+readonly GKE_CLUSTER_ZONE="us-central1-a"
+## xDS test server/client Docker images
+readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-server"
+readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-client"
+readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}"
+readonly BUILD_APP_PATH="interop-testing/build/install/grpc-interop-testing"
+readonly LANGUAGE_NAME="Python"
+
+#######################################
+# Builds test app Docker images and pushes them to GCR
+# Globals:
+#   BUILD_APP_PATH
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of `gcloud builds submit` to stdout, stderr
+#######################################
+build_test_app_docker_images() {
+  echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images"
+
+  pushd "${SRC_DIR}"
+  docker build \
+    -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client \
+    -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+    .
+
+  docker build \
+    -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.server \
+    -t "${SERVER_IMAGE_NAME}:${GIT_COMMIT}" \
+    .
+
+  popd
+
+  gcloud -q auth configure-docker
+
+  docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}"
+  docker push "${SERVER_IMAGE_NAME}:${GIT_COMMIT}"
+}
+
+#######################################
+# Builds test app and its docker images unless they already exist
+# Globals:
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+#   FORCE_IMAGE_BUILD
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output to stdout, stderr
+#######################################
+build_docker_images_if_needed() {
+  # Check if images already exist
+  server_tags="$(gcloud_gcr_list_image_tags "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}")"
+  printf "Server image: %s:%s\n" "${SERVER_IMAGE_NAME}" "${GIT_COMMIT}"
+  echo "${server_tags:-Server image not found}"
+
+  client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")"
+  printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}"
+  echo "${client_tags:-Client image not found}"
+
+  # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1
+  if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${server_tags}" || -z "${client_tags}" ]]; then
+    build_test_app_docker_images
+  else
+    echo "Skipping ${LANGUAGE_NAME} test app build"
+  fi
+}
+
+#######################################
+# Executes the test case
+# Globals:
+#   TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile
+#   KUBE_CONTEXT: The name of kubectl context with GKE cluster access
+#   TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report
+#   SERVER_IMAGE_NAME: Test server Docker image name
+#   CLIENT_IMAGE_NAME: Test client Docker image name
+#   GIT_COMMIT: SHA-1 of git commit being built
+# Arguments:
+#   Test case name
+# Outputs:
+#   Writes the output of test execution to stdout, stderr
+#   Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml
+#######################################
+run_test() {
+  # Test driver usage:
+  # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage
+  local test_name="${1:?Usage: run_test test_name}"
+  set -x
+  python -m "tests.${test_name}" \
+    --flagfile="${TEST_DRIVER_FLAGFILE}" \
+    --kube_context="${KUBE_CONTEXT}" \
+    --server_image="${SERVER_IMAGE_NAME}:${GIT_COMMIT}" \
+    --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \
+    --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \
+    --force_cleanup \
+    --nocheck_local_certs
+  set +x
+}
+
+#######################################
+# Main function: provision software necessary to execute tests, and run them
+# Globals:
+#   KOKORO_ARTIFACTS_DIR
+#   GITHUB_REPOSITORY_NAME
+#   SRC_DIR: Populated with absolute path to the source repo
+#   TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing
+#                         the test driver
+#   TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code
+#   TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile
+#   TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report
+#   GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build
+#   GIT_COMMIT: Populated with the SHA-1 of git commit being built
+#   GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built
+#   KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access
+# Arguments:
+#   None
+# Outputs:
+#   Writes the output of test execution to stdout, stderr
+#######################################
+main() {
+  local script_dir
+  script_dir="$(dirname "$0")"
+  # shellcheck source=tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh
+  source "${script_dir}/grpc_xds_k8s_install_test_driver.sh"
+  set -x
+  if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then
+    kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}"
+  else
+    local_setup_test_driver "${script_dir}"
+  fi
+  build_docker_images_if_needed
+  # Run tests
+  cd "${TEST_DRIVER_FULL_DIR}"
+  run_test baseline_test
+  run_test security_test
+}
+
+main "$@"
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_php.cfg b/grpc/tools/internal_ci/linux/grpc_xds_php.cfg
index f7a12b4..af8d24c 100644
--- a/grpc/tools/internal_ci/linux/grpc_xds_php.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_xds_php.cfg
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_php.sh"
-timeout_mins: 180
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_php_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_php_test_in_docker.sh
index 125f6a5..9d87920 100755
--- a/grpc/tools/internal_ci/linux/grpc_xds_php_test_in_docker.sh
+++ b/grpc/tools/internal_ci/linux/grpc_xds_php_test_in_docker.sh
@@ -23,10 +23,10 @@
 cd /var/local/git/grpc
 
 VIRTUAL_ENV=$(mktemp -d)
-virtualenv "$VIRTUAL_ENV"
+virtualenv "$VIRTUAL_ENV" -p python3
 PYTHON="$VIRTUAL_ENV"/bin/python
-"$PYTHON" -m pip install --upgrade pip
-"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
 
 # Prepare generated Python code.
 TOOLS_DIR=tools/run_tests
@@ -72,10 +72,25 @@
 
 GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
   tools/run_tests/run_xds_tests.py \
-  --test_case="all,path_matching,header_matching" \
+  --test_case="timeout,fault_injection" \
   --project_id=grpc-testing \
-  --source_image=projects/grpc-testing/global/images/xds-test-server-2 \
+  --project_num=830293263384 \
+  --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
   --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
   --gcp_suffix=$(date '+%s') \
   --verbose \
+  --qps=20 \
+  ${XDS_V3_OPT-} \
+  --client_cmd='./src/php/bin/run_xds_client.sh --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {fail_on_failed_rpc} {rpcs_to_send} {metadata_to_send}'
+
+GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
+  tools/run_tests/run_xds_tests.py \
+  --test_case="all,path_matching,header_matching" \
+  --project_id=grpc-testing \
+  --project_num=830293263384 \
+  --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
+  --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
+  --gcp_suffix=$(date '+%s') \
+  --verbose \
+  ${XDS_V3_OPT-} \
   --client_cmd='php -d extension=grpc.so -d extension=pthreads.so src/php/tests/interop/xds_client.php --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {fail_on_failed_rpc} {rpcs_to_send} {metadata_to_send}'
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_python.cfg b/grpc/tools/internal_ci/linux/grpc_xds_python.cfg
index 8eea6fe..88a7ae5 100644
--- a/grpc/tools/internal_ci/linux/grpc_xds_python.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_xds_python.cfg
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds.sh"
-timeout_mins: 120
+timeout_mins: 360
 env_vars {
   key: "BAZEL_SCRIPT"
   value: "tools/internal_ci/linux/grpc_xds_bazel_python_test_in_docker.sh"
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_ruby.cfg b/grpc/tools/internal_ci/linux/grpc_xds_ruby.cfg
index 87401ba..d723f85 100644
--- a/grpc/tools/internal_ci/linux/grpc_xds_ruby.cfg
+++ b/grpc/tools/internal_ci/linux/grpc_xds_ruby.cfg
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_xds_ruby.sh"
-timeout_mins: 180
+timeout_mins: 360
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_ruby_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_ruby_test_in_docker.sh
old mode 100644
new mode 100755
index b7b7455..6c76f92
--- a/grpc/tools/internal_ci/linux/grpc_xds_ruby_test_in_docker.sh
+++ b/grpc/tools/internal_ci/linux/grpc_xds_ruby_test_in_docker.sh
@@ -23,10 +23,10 @@
 cd /var/local/git/grpc
 
 VIRTUAL_ENV=$(mktemp -d)
-virtualenv "$VIRTUAL_ENV"
+virtualenv "$VIRTUAL_ENV" -p python3
 PYTHON="$VIRTUAL_ENV"/bin/python
-"$PYTHON" -m pip install --upgrade pip
-"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client
+"$PYTHON" -m pip install --upgrade pip==19.3.1
+"$PYTHON" -m pip install --upgrade grpcio-tools google-api-python-client google-auth-httplib2 oauth2client xds-protos
 
 # Prepare generated Python code.
 TOOLS_DIR=tools/run_tests
@@ -62,10 +62,12 @@
 
 GRPC_VERBOSITY=debug GRPC_TRACE=xds_client,xds_resolver,xds_cluster_manager_lb,cds_lb,xds_cluster_resolver_lb,priority_lb,xds_cluster_impl_lb,weighted_target_lb "$PYTHON" \
   tools/run_tests/run_xds_tests.py \
-    --test_case="all,path_matching,header_matching,circuit_breaking" \
+    --test_case="all,circuit_breaking,timeout,fault_injection" \
     --project_id=grpc-testing \
-    --source_image=projects/grpc-testing/global/images/xds-test-server-3 \
+    --project_num=830293263384 \
+    --source_image=projects/grpc-testing/global/images/xds-test-server-4 \
     --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \
     --gcp_suffix=$(date '+%s') \
     --verbose \
+    ${XDS_V3_OPT-} \
     --client_cmd='ruby src/ruby/pb/test/xds_client.rb --server=xds:///{server_uri} --stats_port={stats_port} --qps={qps} {fail_on_failed_rpc} {rpcs_to_send} {metadata_to_send}'
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3.cfg b/grpc/tools/internal_ci/linux/grpc_xds_v3.cfg
new file mode 100644
index 0000000..56aaa3a
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3.cfg
@@ -0,0 +1,29 @@
+# Copyright 2021 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_xds.sh"
+timeout_mins: 360
+env_vars {
+  key: "BAZEL_SCRIPT"
+  value: "tools/internal_ci/linux/grpc_xds_v3_bazel_test_in_docker.sh"
+}
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.*"
+    regex: "github/grpc/reports/**"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_bazel_python_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_v3_bazel_python_test_in_docker.sh
new file mode 100755
index 0000000..dcaecea
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_bazel_python_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_bazel_python_test_in_docker.sh
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_bazel_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_v3_bazel_test_in_docker.sh
new file mode 100755
index 0000000..d7218aa
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_bazel_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_bazel_test_in_docker.sh
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp.cfg b/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp.cfg
new file mode 100644
index 0000000..5ca9153
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp.cfg
@@ -0,0 +1,25 @@
+# Copyright 2021 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_xds_v3_csharp.sh"
+timeout_mins: 360
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.*"
+    regex: "github/grpc/reports/**"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp.sh b/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp.sh
new file mode 100755
index 0000000..64b986c
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/csharp_stretch_x64
+export DOCKER_RUN_SCRIPT=tools/internal_ci/linux/grpc_xds_v3_csharp_test_in_docker.sh
+export OUTPUT_DIR=reports
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp_test_in_docker.sh
new file mode 100755
index 0000000..6ea3d41
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_csharp_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_csharp_test_in_docker.sh
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_php.cfg b/grpc/tools/internal_ci/linux/grpc_xds_v3_php.cfg
new file mode 100644
index 0000000..39f6406
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_php.cfg
@@ -0,0 +1,25 @@
+# Copyright 2021 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_xds_v3_php.sh"
+timeout_mins: 360
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.*"
+    regex: "github/grpc/reports/**"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_php.sh b/grpc/tools/internal_ci/linux/grpc_xds_v3_php.sh
new file mode 100755
index 0000000..eebbc28
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_php.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/php73_zts_stretch_x64
+export DOCKER_RUN_SCRIPT=tools/internal_ci/linux/grpc_xds_v3_php_test_in_docker.sh
+export OUTPUT_DIR=reports
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_php_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_v3_php_test_in_docker.sh
new file mode 100755
index 0000000..23337de
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_php_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_php_test_in_docker.sh
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_python.cfg b/grpc/tools/internal_ci/linux/grpc_xds_v3_python.cfg
new file mode 100644
index 0000000..fc9078a
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_python.cfg
@@ -0,0 +1,29 @@
+# Copyright 2021 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_xds.sh"
+timeout_mins: 360
+env_vars {
+  key: "BAZEL_SCRIPT"
+  value: "tools/internal_ci/linux/grpc_xds_v3_bazel_python_test_in_docker.sh"
+}
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.*"
+    regex: "github/grpc/reports/**"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby.cfg b/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby.cfg
new file mode 100644
index 0000000..f512b59
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby.cfg
@@ -0,0 +1,25 @@
+# Copyright 2021 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_xds_v3_ruby.sh"
+timeout_mins: 360
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.*"
+    regex: "github/grpc/reports/**"
+  }
+}
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby.sh b/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby.sh
new file mode 100644
index 0000000..32aee71
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+export DOCKERFILE_DIR=tools/dockerfile/test/ruby_buster_x64
+export DOCKER_RUN_SCRIPT=tools/internal_ci/linux/grpc_xds_v3_ruby_test_in_docker.sh
+export OUTPUT_DIR=reports
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby_test_in_docker.sh b/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby_test_in_docker.sh
new file mode 100755
index 0000000..c380e33
--- /dev/null
+++ b/grpc/tools/internal_ci/linux/grpc_xds_v3_ruby_test_in_docker.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+XDS_V3_OPT="--xds_v3_support" `dirname $0`/grpc_xds_ruby_test_in_docker.sh
diff --git a/grpc/tools/internal_ci/linux/run_if_c_cpp_modified.sh b/grpc/tools/internal_ci/linux/run_if_c_cpp_modified.sh
index 2414dcc..c0e782a 100755
--- a/grpc/tools/internal_ci/linux/run_if_c_cpp_modified.sh
+++ b/grpc/tools/internal_ci/linux/run_if_c_cpp_modified.sh
@@ -20,7 +20,7 @@
 # Enter the gRPC repo root
 cd $(dirname $0)/../../..
 
-AFFECTS_C_CPP=`python -c 'import os; \
+AFFECTS_C_CPP=`python3 -c 'import os; \
                import sys; \
                sys.path.insert(0, "tools/run_tests/python_utils"); \
                import filter_pull_request_tests as filter; \
diff --git a/grpc/tools/internal_ci/macos/grpc_run_bazel_isolated_tests.sh b/grpc/tools/internal_ci/macos/grpc_run_bazel_isolated_tests.sh
index 7e13477..e213105 100644
--- a/grpc/tools/internal_ci/macos/grpc_run_bazel_isolated_tests.sh
+++ b/grpc/tools/internal_ci/macos/grpc_run_bazel_isolated_tests.sh
@@ -38,6 +38,6 @@
 # The "local" execution strategy is required because the test runs sudo and that doesn't work in a sandboxed environment (the default on mac)
 tools/bazel test $RUN_TESTS_FLAGS --genrule_strategy=local --test_output=all //test/cpp/common:time_jump_test
 
-# kill port_server.py to prevent the build from hanging
+# kill port_server.py to prevent the build from freezing
 ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
 
diff --git a/grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh b/grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh
index 7636a31..b74508b 100755
--- a/grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh
+++ b/grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh
@@ -22,7 +22,7 @@
 
 tools/run_tests/run_tests_matrix.py $RUN_TESTS_FLAGS || FAILED="true"
 
-# kill port_server.py to prevent the build from hanging
+# kill port_server.py to prevent the build from freezing
 ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
 
 tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true
diff --git a/grpc/tools/internal_ci/windows/grpc_build_artifacts.cfg b/grpc/tools/internal_ci/windows/grpc_build_artifacts.cfg
index 9097849..ec94788 100644
--- a/grpc/tools/internal_ci/windows/grpc_build_artifacts.cfg
+++ b/grpc/tools/internal_ci/windows/grpc_build_artifacts.cfg
@@ -16,7 +16,7 @@
 
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/windows/grpc_build_artifacts.bat"
-timeout_mins: 180
+timeout_mins: 240
 action {
   define_artifacts {
     regex: "**/*sponge_log.*"
diff --git a/grpc/tools/interop_matrix/README.md b/grpc/tools/interop_matrix/README.md
index 2b37ee7..20913f5 100644
--- a/grpc/tools/interop_matrix/README.md
+++ b/grpc/tools/interop_matrix/README.md
@@ -17,7 +17,9 @@
 - Verify the just-created docker client image would pass backward compatibility test (it should).  For example,
   - `gcloud docker -- pull gcr.io/grpc-testing/grpc_interop_java:v1.9.9` followed by
   - `docker_image=gcr.io/grpc-testing/grpc_interop_java:v1.9.9 tools/interop_matrix/testcases/java__master`
-- git commit the change and merge it to upstream/master.
+- Commit the change and create a PR to upstream/master.
+- Trigger an adhoc run of interop matrix tests: https://fusion.corp.google.com/projectanalysis/summary/KOKORO/prod:grpc%2Fcore%2Fexperimental%2Flinux%2Fgrpc_interop_matrix_adhoc
+- Once tests pass, request a PR review.
 - (Optional) clean up the tmp directory to where grpc source is cloned at `/export/hda3/tmp/grpc_matrix/`.
 For more details on each step, refer to sections below.
 
diff --git a/grpc/tools/interop_matrix/client_matrix.py b/grpc/tools/interop_matrix/client_matrix.py
index 16e1ebd..5cd532e 100644
--- a/grpc/tools/interop_matrix/client_matrix.py
+++ b/grpc/tools/interop_matrix/client_matrix.py
@@ -54,7 +54,7 @@
 # Dictionary of default runtimes per language
 LANG_RUNTIME_MATRIX = {
     'cxx': ['cxx'],  # This is actually debian8.
-    'go': ['go1.8', 'go1.11'],
+    'go': ['go1.8', 'go1.11', 'go1.16'],
     'java': ['java'],
     'python': ['python', 'pythonasyncio'],
     'node': ['node'],
@@ -110,6 +110,9 @@
             ('v1.32.0', ReleaseInfo()),
             ('v1.33.2', ReleaseInfo()),
             ('v1.34.0', ReleaseInfo()),
+            ('v1.35.0', ReleaseInfo()),
+            ('v1.36.3', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
     'go':
         OrderedDict([
@@ -180,6 +183,10 @@
             ('v1.33.1',
              ReleaseInfo(runtimes=['go1.11'], testcases_file='go__v1.20.0')),
             ('v1.34.0', ReleaseInfo(runtimes=['go1.11'])),
+            ('v1.35.0', ReleaseInfo(runtimes=['go1.11'])),
+            ('v1.36.0', ReleaseInfo(runtimes=['go1.11'])),
+            ('v1.37.0', ReleaseInfo(runtimes=['go1.11'])),
+            # NOTE: starting from release v1.38.0, use runtimes=['go1.16']
         ]),
     'java':
         OrderedDict([
@@ -244,10 +251,13 @@
             ('v1.28.1', ReleaseInfo()),
             ('v1.29.0', ReleaseInfo()),
             ('v1.30.2', ReleaseInfo()),
-            ('v1.31.1', ReleaseInfo()),
-            ('v1.32.2', ReleaseInfo()),
+            ('v1.31.2', ReleaseInfo()),
+            ('v1.32.3', ReleaseInfo()),
             ('v1.33.1', ReleaseInfo()),
             ('v1.34.1', ReleaseInfo()),
+            ('v1.35.1', ReleaseInfo()),
+            ('v1.36.1', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
     'python':
         OrderedDict([
@@ -308,6 +318,9 @@
             ('v1.32.0', ReleaseInfo(runtimes=['python'])),
             ('v1.33.2', ReleaseInfo(runtimes=['python'])),
             ('v1.34.0', ReleaseInfo(runtimes=['python'])),
+            ('v1.35.0', ReleaseInfo(runtimes=['python'])),
+            ('v1.36.3', ReleaseInfo(runtimes=['python'])),
+            ('v1.37.0', ReleaseInfo(runtimes=['python'])),
         ]),
     'node':
         OrderedDict([
@@ -371,6 +384,9 @@
             ('v1.32.0', ReleaseInfo()),
             ('v1.33.2', ReleaseInfo()),
             ('v1.34.0', ReleaseInfo()),
+            ('v1.35.0', ReleaseInfo()),
+            ('v1.36.3', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
     'php':
         OrderedDict([
@@ -407,6 +423,9 @@
             ('v1.32.0', ReleaseInfo()),
             ('v1.33.2', ReleaseInfo()),
             ('v1.34.0', ReleaseInfo()),
+            ('v1.35.0', ReleaseInfo()),
+            ('v1.36.3', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
     'csharp':
         OrderedDict([
@@ -448,5 +467,8 @@
             ('v1.32.0', ReleaseInfo()),
             ('v1.33.2', ReleaseInfo()),
             ('v1.34.0', ReleaseInfo()),
+            ('v1.35.0', ReleaseInfo()),
+            ('v1.36.3', ReleaseInfo()),
+            ('v1.37.0', ReleaseInfo()),
         ]),
 }
diff --git a/grpc/tools/line_count/yaml2csv.py b/grpc/tools/line_count/yaml2csv.py
index 14f4a39..bf2baf3 100755
--- a/grpc/tools/line_count/yaml2csv.py
+++ b/grpc/tools/line_count/yaml2csv.py
@@ -32,9 +32,12 @@
     writer = csv.DictWriter(
         outf, ['date', 'name', 'language', 'code', 'comment', 'blank'])
     for key, value in data.iteritems():
-        if key == 'header': continue
-        if key == 'SUM': continue
-        if key.startswith('third_party/'): continue
+        if key == 'header':
+            continue
+        if key == 'SUM':
+            continue
+        if key.startswith('third_party/'):
+            continue
         row = {'name': key, 'date': args.date}
         row.update(value)
         writer.writerow(row)
diff --git a/grpc/tools/mkowners/mkowners.py b/grpc/tools/mkowners/mkowners.py
index d071c2e..030bbf5 100755
--- a/grpc/tools/mkowners/mkowners.py
+++ b/grpc/tools/mkowners/mkowners.py
@@ -67,8 +67,10 @@
     for line in src:
         line = line.strip()
         # line := directive | comment
-        if not line: continue
-        if line[0] == '#': continue
+        if not line:
+            continue
+        if line[0] == '#':
+            continue
         # it's a directive
         directive = None
         if line == 'set noparent':
@@ -102,11 +104,13 @@
         best_parent = None
         best_parent_score = None
         for possible_parent in owners_data:
-            if possible_parent is owners: continue
+            if possible_parent is owners:
+                continue
             rel = os.path.relpath(owners.dir, possible_parent.dir)
             # '..' ==> we had to walk up from possible_parent to get to owners
             #      ==> not a parent
-            if '..' in rel: continue
+            if '..' in rel:
+                continue
             depth = len(rel.split(os.sep))
             if not best_parent or depth < best_parent_score:
                 best_parent = possible_parent
@@ -134,7 +138,8 @@
 
 def git_glob(glob):
     global gg_cache
-    if glob in gg_cache: return gg_cache[glob]
+    if glob in gg_cache:
+        return gg_cache[glob]
     r = set(
         subprocess.check_output([
             'git', 'ls-files', os.path.join(git_root, glob)
@@ -176,7 +181,8 @@
 
 
 def add_parent_to_globs(parent, globs, globs_dir):
-    if not parent: return
+    if not parent:
+        return
     for owners in owners_data:
         if owners.dir == parent:
             owners_globs = expand_directives(owners.dir, owners.directives)
diff --git a/grpc/tools/profiling/bloat/bloat_diff.py b/grpc/tools/profiling/bloat/bloat_diff.py
index 3dd4dbe..b6bd1de 100755
--- a/grpc/tools/profiling/bloat/bloat_diff.py
+++ b/grpc/tools/profiling/bloat/bloat_diff.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 #
 # Copyright 2017 gRPC authors.
 #
diff --git a/grpc/tools/profiling/latency_profile/profile_analyzer.py b/grpc/tools/profiling/latency_profile/profile_analyzer.py
index 1966622..facc024 100755
--- a/grpc/tools/profiling/latency_profile/profile_analyzer.py
+++ b/grpc/tools/profiling/latency_profile/profile_analyzer.py
@@ -16,13 +16,14 @@
 import argparse
 import collections
 import hashlib
-import itertools
 import json
 import math
 import sys
-import tabulate
 import time
 
+from six.moves import zip
+import tabulate
+
 SELF_TIME = object()
 TIME_FROM_SCOPE_START = object()
 TIME_TO_SCOPE_END = object()
@@ -107,8 +108,8 @@
 
     def add(self, line):
         line_type = line['type']
-        self.signature.update(line_type)
-        self.signature.update(line['tag'])
+        self.signature.update(line_type.encode('UTF-8'))
+        self.signature.update(line['tag'].encode('UTF-8'))
         if line_type == '{':
             self.stk.append(ScopeBuilder(self, line))
             return False
@@ -143,15 +144,15 @@
         assert self.signature == call_stack_builder.signature
         self.count += 1
         assert len(self.lines) == len(call_stack_builder.lines)
-        for lsum, line in itertools.izip(self.lines, call_stack_builder.lines):
+        for lsum, line in zip(self.lines, call_stack_builder.lines):
             assert lsum.tag == line.tag
             assert lsum.times.keys() == line.times.keys()
-            for k, lst in lsum.times.iteritems():
+            for k, lst in lsum.times.items():
                 lst.append(line.times[k])
 
     def finish(self):
         for line in self.lines:
-            for lst in line.times.itervalues():
+            for lst in line.times.values():
                 lst.sort()
 
 
@@ -247,18 +248,18 @@
     out = open(args.out, 'w')
 
 if args.fmt == 'html':
-    print >> out, '<html>'
-    print >> out, '<head>'
-    print >> out, '<title>Profile Report</title>'
-    print >> out, '</head>'
+    out.write('<html>')
+    out.write('<head>')
+    out.write('<title>Profile Report</title>')
+    out.write('</head>')
 
 accounted_for = 0
 for cs in call_stacks:
-    print >> out, '\n'
+    out.write('\n')
     if args.fmt in BANNER:
-        print >> out, BANNER[args.fmt] % {
+        out.write(BANNER[args.fmt] % {
             'count': cs.count,
-        }
+        })
     header, _ = zip(*FORMAT)
     table = []
     for line in cs.lines:
@@ -266,10 +267,10 @@
         for _, fn in FORMAT:
             fields.append(fn(line))
         table.append(fields)
-    print >> out, tabulate.tabulate(table, header, tablefmt=args.fmt)
+    out.write(tabulate.tabulate(table, header, tablefmt=args.fmt))
     accounted_for += cs.count
     if accounted_for > .99 * total_stacks:
         break
 
 if args.fmt == 'html':
-    print '</html>'
+    print('</html>')
diff --git a/grpc/tools/profiling/microbenchmarks/bm2bq.py b/grpc/tools/profiling/microbenchmarks/bm2bq.py
index c5307c5..fe2e49a 100755
--- a/grpc/tools/profiling/microbenchmarks/bm2bq.py
+++ b/grpc/tools/profiling/microbenchmarks/bm2bq.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 #
 # Copyright 2017 gRPC authors.
 #
@@ -41,7 +41,7 @@
 }
 
 if sys.argv[1] == '--schema':
-    print ',\n'.join('%s:%s' % (k, t.upper()) for k, t in columns)
+    print(',\n'.join('%s:%s' % (k, t.upper()) for k, t in columns))
     sys.exit(0)
 
 with open(sys.argv[1]) as f:
@@ -60,6 +60,7 @@
     sane_row = {}
     for name, sql_type in columns:
         if name in row:
-            if row[name] == '': continue
+            if row[name] == '':
+                continue
             sane_row[name] = SANITIZE[sql_type](row[name])
     writer.writerow(sane_row)
diff --git a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_build.py b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_build.py
index 8cd993e..072ab53 100755
--- a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_build.py
+++ b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_build.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 #
 # Copyright 2017 gRPC authors.
 #
@@ -15,13 +15,13 @@
 # limitations under the License.
 """ Python utility to build opt and counters benchmarks """
 
-import bm_constants
-
 import argparse
-import subprocess
 import multiprocessing
 import os
 import shutil
+import subprocess
+
+import bm_constants
 
 
 def _args():
diff --git a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_constants.py b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_constants.py
index c8b6c1e..ef60873 100644
--- a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_constants.py
+++ b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_constants.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 #
 # Copyright 2017 gRPC authors.
 #
diff --git a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_diff.py b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_diff.py
index 846682d..01b622d 100755
--- a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_diff.py
+++ b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_diff.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 #
 # Copyright 2017 gRPC authors.
 #
@@ -15,20 +15,19 @@
 # limitations under the License.
 """ Computes the diff between two bm runs and outputs significant results """
 
-import bm_constants
-import bm_speedup
-
-import sys
-import os
-
-sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..'))
-import bm_json
-
-import json
-import tabulate
 import argparse
 import collections
+import json
+import os
 import subprocess
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..'))
+
+import bm_constants
+import bm_json
+import bm_speedup
+import tabulate
 
 verbose = False
 
@@ -38,9 +37,9 @@
     ary = sorted(ary)
     n = len(ary)
     if n % 2 == 0:
-        return (ary[(n - 1) / 2] + ary[(n - 1) / 2 + 1]) / 2.0
+        return (ary[(n - 1) // 2] + ary[(n - 1) // 2 + 1]) / 2.0
     else:
-        return ary[n / 2]
+        return ary[n // 2]
 
 
 def _args():
@@ -82,14 +81,16 @@
                       help='Print details of before/after')
     args = argp.parse_args()
     global verbose
-    if args.verbose: verbose = True
+    if args.verbose:
+        verbose = True
     assert args.new
     assert args.old
     return args
 
 
 def _maybe_print(str):
-    if verbose: print str
+    if verbose:
+        print(str)
 
 
 class Benchmark:
@@ -110,7 +111,8 @@
         for f in sorted(track):
             new = self.samples[True][f]
             old = self.samples[False][f]
-            if not new or not old: continue
+            if not new or not old:
+                continue
             mdn_diff = abs(_median(new) - _median(old))
             _maybe_print('%s: %s=%r %s=%r mdn_diff=%r' %
                          (f, new_name, new, old_name, old, mdn_diff))
@@ -133,14 +135,14 @@
         with open(filename) as f:
             r = f.read()
             return json.loads(r)
-    except IOError, e:
+    except IOError as e:
         if stripped in nonexistant_files:
             nonexistant_files[stripped] += 1
         else:
             nonexistant_files[stripped] = 1
         return None
-    except ValueError, e:
-        print r
+    except ValueError as e:
+        print(r)
         if stripped in badjson_files:
             badjson_files[stripped] += 1
         else:
@@ -163,6 +165,7 @@
                     'bm_diff_%s/opt/%s' % (old, bm), '--benchmark_list_tests',
                     '--benchmark_filter=%s' % regex
             ]).splitlines():
+                line = line.decode('UTF-8')
                 stripped_line = line.strip().replace("/", "_").replace(
                     "<", "_").replace(">", "_").replace(", ", "_")
                 js_new_opt = _read_json(
@@ -204,7 +207,8 @@
     headers = ['Benchmark'] + fields
     rows = []
     for name in sorted(benchmarks.keys()):
-        if benchmarks[name].skip(): continue
+        if benchmarks[name].skip():
+            continue
         rows.append([name] + benchmarks[name].row(fields))
     note = None
     if len(badjson_files):
diff --git a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_main.py b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_main.py
index 9add95f..816e286 100755
--- a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_main.py
+++ b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_main.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 #
 # Copyright 2017 gRPC authors.
 #
@@ -15,26 +15,26 @@
 # limitations under the License.
 """ Runs the entire bm_*.py pipeline, and possible comments on the PR """
 
-import bm_constants
-import bm_build
-import bm_run
-import bm_diff
-
-import sys
-import os
-import random
 import argparse
 import multiprocessing
+import os
+import random
 import subprocess
+import sys
 
 sys.path.append(
     os.path.join(os.path.dirname(sys.argv[0]), '..', '..', 'run_tests',
                  'python_utils'))
-import check_on_pr
 
 sys.path.append(
     os.path.join(os.path.dirname(sys.argv[0]), '..', '..', '..', 'run_tests',
                  'python_utils'))
+
+import bm_build
+import bm_constants
+import bm_diff
+import bm_run
+import check_on_pr
 import jobset
 
 
diff --git a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_run.py b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_run.py
index 27fe0a1..04e95ab 100755
--- a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_run.py
+++ b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_run.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 #
 # Copyright 2017 gRPC authors.
 #
@@ -15,20 +15,20 @@
 # limitations under the License.
 """ Python utility to run opt and counters benchmarks and save json output """
 
-import bm_constants
-
 import argparse
-import subprocess
-import multiprocessing
-import random
 import itertools
-import sys
+import multiprocessing
 import os
+import random
+import subprocess
+import sys
+
+import bm_constants
+import jobset
 
 sys.path.append(
     os.path.join(os.path.dirname(sys.argv[0]), '..', '..', '..', 'run_tests',
                  'python_utils'))
-import jobset
 
 
 def _args():
@@ -70,7 +70,8 @@
     args = argp.parse_args()
     assert args.name
     if args.loops < 3:
-        print "WARNING: This run will likely be noisy. Increase loops to at least 3."
+        print("WARNING: This run will likely be noisy. Increase loops to at "
+              "least 3.")
     return args
 
 
@@ -80,6 +81,7 @@
             'bm_diff_%s/%s/%s' % (name, cfg, bm), '--benchmark_list_tests',
             '--benchmark_filter=%s' % regex
     ]).splitlines():
+        line = line.decode('UTF-8')
         stripped_line = line.strip().replace("/",
                                              "_").replace("<", "_").replace(
                                                  ">", "_").replace(", ", "_")
diff --git a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_speedup.py b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_speedup.py
index 2a77040..1e474cb 100755
--- a/grpc/tools/profiling/microbenchmarks/bm_diff/bm_speedup.py
+++ b/grpc/tools/profiling/microbenchmarks/bm_diff/bm_speedup.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python3
 #
 # Copyright 2017 gRPC authors.
 #
@@ -14,9 +14,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from scipy import stats
 import math
 
+from scipy import stats
+
 _DEFAULT_THRESHOLD = 1e-10
 
 
@@ -29,25 +30,33 @@
 
 
 def speedup(new, old, threshold=_DEFAULT_THRESHOLD):
-    if (len(set(new))) == 1 and new == old: return 0
+    if (len(set(new))) == 1 and new == old:
+        return 0
     s0, p0 = cmp(new, old)
-    if math.isnan(p0): return 0
-    if s0 == 0: return 0
-    if p0 > threshold: return 0
+    if math.isnan(p0):
+        return 0
+    if s0 == 0:
+        return 0
+    if p0 > threshold:
+        return 0
     if s0 < 0:
         pct = 1
         while pct < 100:
             sp, pp = cmp(new, scale(old, 1 - pct / 100.0))
-            if sp > 0: break
-            if pp > threshold: break
+            if sp > 0:
+                break
+            if pp > threshold:
+                break
             pct += 1
         return -(pct - 1)
     else:
         pct = 1
         while pct < 10000:
             sp, pp = cmp(new, scale(old, 1 + pct / 100.0))
-            if sp < 0: break
-            if pp > threshold: break
+            if sp < 0:
+                break
+            if pp > threshold:
+                break
             pct += 1
         return pct - 1
 
@@ -55,5 +64,5 @@
 if __name__ == "__main__":
     new = [0.0, 0.0, 0.0, 0.0]
     old = [2.96608e-06, 3.35076e-06, 3.45384e-06, 3.34407e-06]
-    print speedup(new, old, 1e-5)
-    print speedup(old, new, 1e-5)
+    print(speedup(new, old, 1e-5))
+    print(speedup(old, new, 1e-5))
diff --git a/grpc/tools/profiling/microbenchmarks/bm_json.py b/grpc/tools/profiling/microbenchmarks/bm_json.py
index 2f5eb70..0f5aab5 100644
--- a/grpc/tools/profiling/microbenchmarks/bm_json.py
+++ b/grpc/tools/profiling/microbenchmarks/bm_json.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
 # Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -120,7 +121,8 @@
 
 def numericalize(s):
     """Convert abbreviations like '100M' or '10k' to a number."""
-    if not s: return ''
+    if not s:
+        return ''
     if s[-1] == 'k':
         return float(s[:-1]) * 1024
     if s[-1] == 'M':
@@ -177,8 +179,10 @@
 
 
 def expand_json(js, js2=None):
-    if not js and not js2: raise StopIteration()
-    if not js: js = js2
+    if not js and not js2:
+        raise StopIteration()
+    if not js:
+        js = js2
     for bm in js['benchmarks']:
         if bm['name'].endswith('_stddev') or bm['name'].endswith('_mean'):
             continue
diff --git a/grpc/tools/release/backport_pr.sh b/grpc/tools/release/backport_pr.sh
new file mode 100755
index 0000000..3860f37
--- /dev/null
+++ b/grpc/tools/release/backport_pr.sh
@@ -0,0 +1,160 @@
+#!/bin/bash
+#Copyright 2021 The 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.
+
+set -euo pipefail
+
+ensure_command () {
+  if command -v "$1" 1>/dev/null 2>&1; then
+    return 0
+  else
+    echo "$1 is not installed. Please install it to proceed." 1>&2
+    exit 1
+  fi
+}
+
+display_usage () {
+  cat << EOF >/dev/stderr
+USAGE: $0 PR_ID GITHUB_USER BACKPORT_BRANCHES REVIEWERS [-c PER_BACKPORT_COMMAND]
+   PR_ID: The ID of the PR to be backported.
+   GITHUB_USER: Your GitHub username.
+   BACKPORT_BRANCHES: A space-separated list of branches to which the source PR will be backported.
+   REVIEWERS: A comma-separated list of users to add as both reviewer and assignee.
+   PER_BACKPORT_COMMAND : An optional command to run after cherrypicking the PR to the target branch.
+     If you use this option, ensure your working directory is clean, as "git add -A" will be used to
+     incorporate any generated files. Try running "git clean -xdff" beforehand.
+
+Example: $0 25456 gnossen "v1.30.x v1.31.x v1.32.x v1.33.x v1.34.x v1.35.x v1.36.x" "menghanl,gnossen"
+Example: $0 25493 gnossen "\$(seq 30 33 | xargs -n1 printf 'v1.%s.x ')" "menghanl" -c ./tools/dockerfile/push_testing_images.sh
+EOF
+  exit 1
+}
+
+ensure_command "curl"
+ensure_command "egrep"
+ensure_command "hub"
+ensure_command "jq"
+
+if [ "$#" -lt "4" ]; then
+  display_usage
+fi
+
+PR_ID="$1"
+GITHUB_USER="$2"
+BACKPORT_BRANCHES="$3"
+REVIEWERS="$4"
+shift 4
+
+PER_BACKPORT_COMMAND=""
+while getopts "c:" OPT; do
+  case "$OPT" in
+    c )
+      PER_BACKPORT_COMMAND="$OPTARG"
+      ;;
+    \? )
+      echo "Invalid option: $OPTARG" >/dev/stderr
+      display_usage
+      ;;
+    : )
+      echo "Invalid option: $OPTARG requires an argument." >/dev/stderr
+      display_usage
+      ;;
+  esac
+done
+
+if [[ ! -z "$(git status --porcelain)" && ! -z "$PER_BACKPORT_COMMAND" ]]; then
+  echo "Your working directory is not clean. Try running `git clean -xdff`. Warning: This is irreversible." > /dev/stderr
+  exit 1
+fi
+
+if [ -z "$GITHUB_TOKEN" ]; then
+  echo "A GitHub token is required to run this script. See " \
+         "https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token" \
+         " for more information" >/dev/stderr
+  exit 1
+fi
+
+echo "This script will create a collection of backport PRs. You will probably " \
+       "have to touch your gnubby a frustrating number of times. C'est la vie."
+printf "Press any key to continue."
+read -r RESPONSE </dev/tty
+printf "\n"
+
+
+PR_DATA=$(curl -s -u "$GITHUB_USER:$GITHUB_TOKEN" \
+          -H "Accept: application/vnd.github.v3+json" \
+          "https://api.github.com/repos/grpc/grpc/pulls/$PR_ID")
+
+STATE=$(echo "$PR_DATA" | jq -r '.state')
+if [ "$STATE" != "open" ]; then
+  TARGET_COMMITS=$(echo "$PR_DATA" | jq -r '.merge_commit_sha')
+  FETCH_HEAD_REF=$(echo "$PR_DATA" | jq -r '.base.ref')
+  SOURCE_REPO=$(echo "$PR_DATA" | jq -r '.base.repo.full_name')
+else
+  COMMITS_URL=$(echo "$PR_DATA" | jq -r '.commits_url')
+  COMMITS_DATA=$(curl -s -u "$GITHUB_USER:$GITHUB_TOKEN" \
+                 -H "Accept: application/vnd.github.v3+json" \
+                 "$COMMITS_URL")
+  TARGET_COMMITS=$(echo "$COMMITS_DATA" | jq -r '. | map(.sha) | join(" ")')
+  FETCH_HEAD_REF=$(echo "$PR_DATA" | jq -r '.head.sha')
+  SOURCE_REPO=$(echo "$PR_DATA" | jq -r '.head.repo.full_name')
+fi
+PR_TITLE=$(echo "$PR_DATA" | jq -r '.title')
+PR_DESCRIPTION=$(echo "$PR_DATA" | jq -r '.body')
+LABELS=$(echo "$PR_DATA" | jq -r '.labels | map(.name) | join(",")')
+
+set -x
+
+git fetch "git@github.com:$SOURCE_REPO.git" "$FETCH_HEAD_REF"
+
+BACKPORT_PRS=""
+for BACKPORT_BRANCH in $BACKPORT_BRANCHES; do
+  echo "Backporting $TARGET_COMMITS to $BACKPORT_BRANCH."
+
+  git checkout "origin/$BACKPORT_BRANCH"
+
+  BRANCH_NAME="backport_${PR_ID}_to_${BACKPORT_BRANCH}"
+
+  # To make the script idempotent.
+  git branch -D "$BRANCH_NAME" || true
+  git checkout "$BACKPORT_BRANCH"
+  git checkout -b "$BRANCH_NAME"
+
+  for TARGET_COMMIT in $TARGET_COMMITS; do
+    git cherry-pick -m 1 "$TARGET_COMMIT"
+  done
+
+  if [[ ! -z "$PER_BACKPORT_COMMAND" ]]; then
+    git submodule update --init --recursive
+
+    # To remove dangling submodules.
+    git clean -xdff
+    eval "$PER_BACKPORT_COMMAND"
+    git add -A
+    git commit --amend --no-edit
+  fi
+
+  BACKPORT_PR=$(hub pull-request -p -m "[Backport] $PR_TITLE" \
+                  -m "*Beep boop. This is an automatically generated backport of #${PR_ID}.*" \
+                  -m "$PR_DESCRIPTION" \
+                  -l "$LABELS" \
+                  -b "$GITHUB_USER:$BACKPORT_BRANCH" \
+                  -r "$REVIEWERS" \
+                  -a "$REVIEWERS" | tail -n 1)
+  BACKPORT_PRS+="$BACKPORT_PR\n"
+
+  # TODO: Turn on automerge once the Github API allows it.
+done
+
+printf "Your backport PRs have been created:\n$BACKPORT_PRS"
diff --git a/grpc/tools/release/release_notes.py b/grpc/tools/release/release_notes.py
index 511c93e..f2af8ed 100644
--- a/grpc/tools/release/release_notes.py
+++ b/grpc/tools/release/release_notes.py
@@ -83,15 +83,15 @@
 
 
 def get_commit_log(prevRelLabel, relBranch):
-    """Return the output of 'git log --pretty=online --merges prevRelLabel..relBranch' """
+    """Return the output of 'git log prevRelLabel..relBranch' """
 
     import subprocess
-    print("Running git log --pretty=oneline --merges " + prevRelLabel + ".." +
-          relBranch)
-    return subprocess.check_output([
-        "git", "log", "--pretty=oneline", "--merges",
+    glg_command = [
+        "git", "log", "--pretty=oneline", "--committer=GitHub",
         "%s..%s" % (prevRelLabel, relBranch)
-    ])
+    ]
+    print("Running ", " ".join(glg_command))
+    return subprocess.check_output(glg_command)
 
 
 def get_pr_data(pr_num):
@@ -120,11 +120,19 @@
 def get_pr_titles(gitLogs):
     import re
     error_count = 0
-    match = b"Merge pull request #(\d+)"
-    prlist = re.findall(match, gitLogs, re.MULTILINE)
+    # PRs with merge commits
+    match_merge_pr = b"Merge pull request #(\d+)"
+    prlist_merge_pr = re.findall(match_merge_pr, gitLogs, re.MULTILINE)
     print("\nPRs matching 'Merge pull request #<num>':")
-    print(prlist)
+    print(prlist_merge_pr)
     print("\n")
+    # PRs using Github's squash & merge feature
+    match_sq = b"\(#(\d+)\)$"
+    prlist_sq = re.findall(match_sq, gitLogs, re.MULTILINE)
+    print("\nPRs matching '[PR Description](#<num>)$'")
+    print(prlist_sq)
+    print("\n")
+    prlist = prlist_merge_pr + prlist_sq
     langs_pr = defaultdict(list)
     for pr_num in prlist:
         pr_num = str(pr_num)
diff --git a/grpc/tools/remote_build/mac.bazelrc b/grpc/tools/remote_build/mac.bazelrc
index cc20156..4ff71d8 100644
--- a/grpc/tools/remote_build/mac.bazelrc
+++ b/grpc/tools/remote_build/mac.bazelrc
@@ -33,3 +33,6 @@
 
 # print output for tests that fail (default is "summary")
 build --test_output=errors
+
+# Enable strict warnings to keep it warning-free.
+build --define=use_strict_warning=true
diff --git a/grpc/tools/run_tests/artifacts/artifact_targets.py b/grpc/tools/run_tests/artifacts/artifact_targets.py
index a8f9013..7ba3269 100644
--- a/grpc/tools/run_tests/artifacts/artifact_targets.py
+++ b/grpc/tools/run_tests/artifacts/artifact_targets.py
@@ -30,7 +30,6 @@
                           flake_retries=0,
                           timeout_retries=0,
                           timeout_seconds=30 * 60,
-                          docker_base_image=None,
                           extra_docker_args=None,
                           verbose_success=False):
     """Creates jobspec for a task running under docker."""
@@ -46,9 +45,6 @@
         'DOCKER_RUN_SCRIPT': 'tools/run_tests/dockerize/docker_run.sh',
         'OUTPUT_DIR': 'artifacts'
     }
-
-    if docker_base_image is not None:
-        docker_env['DOCKER_BASE_IMAGE'] = docker_base_image
     if extra_docker_args is not None:
         docker_env['EXTRA_DOCKER_ARGS'] = extra_docker_args
     jobspec = jobset.JobSpec(
@@ -118,24 +114,27 @@
     def build_jobspec(self):
         environ = {}
         if self.platform == 'linux_extra':
-            # Raspberry Pi build
-            environ['PYTHON'] = '/usr/local/bin/python{}'.format(
+            # Crosscompilation build for armv7 (e.g. Raspberry Pi)
+            environ['PYTHON'] = '/opt/python/{}/bin/python3'.format(
                 self.py_version)
-            environ['PIP'] = '/usr/local/bin/pip{}'.format(self.py_version)
-            # https://github.com/resin-io-projects/armv7hf-debian-qemu/issues/9
-            # A QEMU bug causes submodule update to hang, so we copy directly
-            environ['RELATIVE_COPY_PATH'] = '.'
-            # Parallel builds are counterproductive in emulated environment
-            environ['GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS'] = '1'
-            extra_args = ' --entrypoint=/usr/bin/qemu-arm-static '
+            environ['PIP'] = '/opt/python/{}/bin/pip3'.format(self.py_version)
+            environ['GRPC_SKIP_PIP_CYTHON_UPGRADE'] = 'TRUE'
+            environ['GRPC_SKIP_TWINE_CHECK'] = 'TRUE'
+            # when crosscompiling, we need to force statically linking libstdc++
+            # otherwise libstdc++ symbols would be too new and the resulting
+            # wheel wouldn't pass the auditwheel check.
+            # This is needed because C core won't build with GCC 4.8 that's
+            # included in the default dockcross toolchain and we needed
+            # to opt into using a slighly newer version of GCC.
+            environ['GRPC_PYTHON_BUILD_WITH_STATIC_LIBSTDCXX'] = 'TRUE'
+
             return create_docker_jobspec(
                 self.name,
-                'tools/dockerfile/grpc_artifact_linux_{}'.format(self.arch),
+                'tools/dockerfile/grpc_artifact_python_linux_{}'.format(
+                    self.arch),
                 'tools/run_tests/artifacts/build_artifact_python.sh',
                 environ=environ,
-                timeout_seconds=60 * 60 * 5,
-                docker_base_image='quay.io/grpc/raspbian_{}'.format(self.arch),
-                extra_docker_args=extra_args)
+                timeout_seconds=60 * 60)
         elif 'manylinux' in self.platform:
             if self.arch == 'x86':
                 environ['SETARCH_CMD'] = 'linux32'
@@ -144,17 +143,32 @@
             environ['PYTHON'] = '/opt/python/{}/bin/python'.format(
                 self.py_version)
             environ['PIP'] = '/opt/python/{}/bin/pip'.format(self.py_version)
-            environ['GRPC_BUILD_GRPCIO_TOOLS_DEPENDENTS'] = 'TRUE'
-            environ['GRPC_BUILD_MANYLINUX_WHEEL'] = 'TRUE'
+            environ['GRPC_SKIP_PIP_CYTHON_UPGRADE'] = 'TRUE'
+            if self.arch == 'aarch64':
+                environ['GRPC_SKIP_TWINE_CHECK'] = 'TRUE'
+                # when crosscompiling, we need to force statically linking libstdc++
+                # otherwise libstdc++ symbols would be too new and the resulting
+                # wheel wouldn't pass the auditwheel check.
+                # This is needed because C core won't build with GCC 4.8 that's
+                # included in the default dockcross toolchain and we needed
+                # to opt into using a slighly newer version of GCC.
+                environ['GRPC_PYTHON_BUILD_WITH_STATIC_LIBSTDCXX'] = 'TRUE'
+
+            else:
+                # only run auditwheel if we're not crosscompiling
+                environ['GRPC_RUN_AUDITWHEEL_REPAIR'] = 'TRUE'
+                # only build the packages that depend on grpcio-tools
+                # if we're not crosscompiling.
+                # - they require protoc to run on current architecture
+                # - they only have sdist packages anyway, so it's useless to build them again
+                environ['GRPC_BUILD_GRPCIO_TOOLS_DEPENDENTS'] = 'TRUE'
             return create_docker_jobspec(
                 self.name,
-                # NOTE(rbellevi): Do *not* update this without also ensuring the
-                # base_docker_image attribute is accurate.
                 'tools/dockerfile/grpc_artifact_python_%s_%s' %
                 (self.platform, self.arch),
                 'tools/run_tests/artifacts/build_artifact_python.sh',
                 environ=environ,
-                timeout_seconds=60 * 60)
+                timeout_seconds=60 * 60 * 2)
         elif self.platform == 'windows':
             if 'Python27' in self.py_version:
                 environ['EXT_COMPILER'] = 'mingw32'
@@ -233,39 +247,31 @@
             return create_jobspec(
                 self.name,
                 ['tools/run_tests/artifacts/build_artifact_csharp_ios.sh'],
-                timeout_seconds=45 * 60,
+                timeout_seconds=60 * 60,
                 use_workspace=True)
         elif self.platform == 'windows':
             return create_jobspec(self.name, [
                 'tools\\run_tests\\artifacts\\build_artifact_csharp.bat',
                 self.arch
             ],
+                                  timeout_seconds=45 * 60,
                                   use_workspace=True)
         else:
             if self.platform == 'linux':
-                cmake_arch_option = ''  # x64 is the default architecture
-                if self.arch == 'x86':
-                    # TODO(jtattermusch): more work needed to enable
-                    # boringssl assembly optimizations for 32-bit linux.
-                    # Problem: currently we are building the artifact under
-                    # 32-bit docker image, but CMAKE_SYSTEM_PROCESSOR is still
-                    # set to x86_64, so the resulting boringssl binary
-                    # would have undefined symbols.
-                    cmake_arch_option = '-DOPENSSL_NO_ASM=ON'
+                dockerfile_dir = 'tools/dockerfile/grpc_artifact_centos6_{}'.format(
+                    self.arch)
+                if self.arch == 'aarch64':
+                    # for aarch64, use a dockcross manylinux image that will
+                    # give us both ready to use crosscompiler and sufficient backward compatibility
+                    dockerfile_dir = 'tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64'
                 return create_docker_jobspec(
-                    self.name,
-                    'tools/dockerfile/grpc_artifact_centos6_{}'.format(
-                        self.arch),
-                    'tools/run_tests/artifacts/build_artifact_csharp.sh',
-                    environ={'CMAKE_ARCH_OPTION': cmake_arch_option})
+                    self.name, dockerfile_dir,
+                    'tools/run_tests/artifacts/build_artifact_csharp.sh')
             else:
-                cmake_arch_option = ''  # x64 is the default architecture
-                if self.arch == 'x86':
-                    cmake_arch_option = '-DCMAKE_OSX_ARCHITECTURES=i386'
                 return create_jobspec(
                     self.name,
                     ['tools/run_tests/artifacts/build_artifact_csharp.sh'],
-                    environ={'CMAKE_ARCH_OPTION': cmake_arch_option},
+                    timeout_seconds=45 * 60,
                     use_workspace=True)
 
     def __str__(self):
@@ -307,11 +313,16 @@
         if self.platform != 'windows':
             environ = {'CXXFLAGS': '', 'LDFLAGS': ''}
             if self.platform == 'linux':
+                dockerfile_dir = 'tools/dockerfile/grpc_artifact_centos6_{}'.format(
+                    self.arch)
+                if self.arch == 'aarch64':
+                    # for aarch64, use a dockcross manylinux image that will
+                    # give us both ready to use crosscompiler and sufficient backward compatibility
+                    dockerfile_dir = 'tools/dockerfile/grpc_artifact_python_manylinux2014_aarch64'
                 environ['LDFLAGS'] += ' -static-libgcc -static-libstdc++ -s'
                 return create_docker_jobspec(
                     self.name,
-                    'tools/dockerfile/grpc_artifact_centos6_{}'.format(
-                        self.arch),
+                    dockerfile_dir,
                     'tools/run_tests/artifacts/build_artifact_protoc.sh',
                     environ=environ)
             else:
@@ -340,10 +351,12 @@
     return [
         ProtocArtifact('linux', 'x64'),
         ProtocArtifact('linux', 'x86'),
+        ProtocArtifact('linux', 'aarch64'),
         ProtocArtifact('macos', 'x64'),
         ProtocArtifact('windows', 'x64'),
         ProtocArtifact('windows', 'x86'),
         CSharpExtArtifact('linux', 'x64'),
+        CSharpExtArtifact('linux', 'aarch64'),
         CSharpExtArtifact('macos', 'x64'),
         CSharpExtArtifact('windows', 'x64'),
         CSharpExtArtifact('windows', 'x86'),
@@ -375,12 +388,14 @@
         PythonArtifact('manylinux2010', 'x86', 'cp37-cp37m'),
         PythonArtifact('manylinux2010', 'x86', 'cp38-cp38'),
         PythonArtifact('manylinux2010', 'x86', 'cp39-cp39'),
-        PythonArtifact('linux_extra', 'armv7', '2.7'),
-        PythonArtifact('linux_extra', 'armv7', '3.5'),
-        PythonArtifact('linux_extra', 'armv7', '3.6'),
-        PythonArtifact('linux_extra', 'armv6', '2.7'),
-        PythonArtifact('linux_extra', 'armv6', '3.5'),
-        PythonArtifact('linux_extra', 'armv6', '3.6'),
+        PythonArtifact('manylinux2014', 'aarch64', 'cp36-cp36m'),
+        PythonArtifact('manylinux2014', 'aarch64', 'cp37-cp37m'),
+        PythonArtifact('manylinux2014', 'aarch64', 'cp38-cp38'),
+        PythonArtifact('manylinux2014', 'aarch64', 'cp39-cp39'),
+        PythonArtifact('linux_extra', 'armv7', 'cp36-cp36m'),
+        PythonArtifact('linux_extra', 'armv7', 'cp37-cp37m'),
+        PythonArtifact('linux_extra', 'armv7', 'cp38-cp38'),
+        PythonArtifact('linux_extra', 'armv7', 'cp39-cp39'),
         PythonArtifact('macos', 'x64', 'python2.7'),
         PythonArtifact('macos', 'x64', 'python3.5'),
         PythonArtifact('macos', 'x64', 'python3.6'),
diff --git a/grpc/tools/run_tests/artifacts/build_artifact_csharp.sh b/grpc/tools/run_tests/artifacts/build_artifact_csharp.sh
index bb8a91b..3ea389f 100755
--- a/grpc/tools/run_tests/artifacts/build_artifact_csharp.sh
+++ b/grpc/tools/run_tests/artifacts/build_artifact_csharp.sh
@@ -23,11 +23,26 @@
 cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \
       -DgRPC_BACKWARDS_COMPATIBILITY_MODE=ON \
       -DgRPC_BUILD_TESTS=OFF \
-      "${CMAKE_ARCH_OPTION}" \
       ../..
 
 make grpc_csharp_ext -j2
+
+if [ -f "libgrpc_csharp_ext.so" ]
+then
+    # in case we are in a crosscompilation environment
+    STRIP=${STRIP:-strip}
+    OBJCOPY=${OBJCOPY:-objcopy}
+    
+    # The .so file with all debug symbols is too large to
+    # package in the default nuget package.
+    # But we still want to keep the version with symbols
+    # to include it in a special "debug" package.
+    cp libgrpc_csharp_ext.so libgrpc_csharp_ext.dbginfo.so
+    ${STRIP} --strip-unneeded libgrpc_csharp_ext.so
+    ${OBJCOPY} --add-gnu-debuglink=libgrpc_csharp_ext.dbginfo.so libgrpc_csharp_ext.so
+fi
+
 cd ../..
 
 mkdir -p "${ARTIFACTS_OUT}"
-cp cmake/build/libgrpc_csharp_ext.so "${ARTIFACTS_OUT}" || cp cmake/build/libgrpc_csharp_ext.dylib "${ARTIFACTS_OUT}"
+cp cmake/build/libgrpc_csharp_ext.so cmake/build/libgrpc_csharp_ext.dbginfo.so "${ARTIFACTS_OUT}" || cp cmake/build/libgrpc_csharp_ext.dylib "${ARTIFACTS_OUT}"
diff --git a/grpc/tools/run_tests/artifacts/build_artifact_python.sh b/grpc/tools/run_tests/artifacts/build_artifact_python.sh
index 7a342ec..64f68cf 100755
--- a/grpc/tools/run_tests/artifacts/build_artifact_python.sh
+++ b/grpc/tools/run_tests/artifacts/build_artifact_python.sh
@@ -22,8 +22,17 @@
 export PIP=${PIP:-pip}
 export AUDITWHEEL=${AUDITWHEEL:-auditwheel}
 
-# Install Cython to avoid source wheel build failure.
-"${PIP}" install --upgrade cython
+if [ "$GRPC_SKIP_PIP_CYTHON_UPGRADE" == "" ]
+then
+  # Install Cython to avoid source wheel build failure.
+  # This only needs to be done when not running under docker (=on MacOS)
+  # since the docker images used for building python wheels
+  # already have a new-enough version of cython pre-installed.
+  # Any installation step is a potential source of breakages,
+  # so we are trying to perform as few download-and-install operations
+  # as possible.
+  "${PIP}" install --upgrade cython
+fi
 
 # Allow build_ext to build C/C++ files in parallel
 # by enabling a monkeypatch. It speeds up the build a lot.
@@ -33,6 +42,39 @@
 mkdir -p "${ARTIFACTS_OUT}"
 ARTIFACT_DIR="$PWD/${ARTIFACTS_OUT}"
 
+# check whether we are crosscompiling. AUDITWHEEL_ARCH is set by the dockcross docker image.
+if [ "$AUDITWHEEL_ARCH" == "aarch64" ]
+then
+  # when crosscompiling for aarch64, --plat-name needs to be set explicitly
+  # to end up with correctly named wheel file
+  # the value should be manylinuxABC_ARCH and dockcross docker image
+  # conveniently provides the value in the AUDITWHEEL_PLAT env
+  WHEEL_PLAT_NAME_FLAG="--plat-name=$AUDITWHEEL_PLAT"
+
+  # override the value of EXT_SUFFIX to make sure the crosscompiled .so files in the wheel have the correct filename suffix
+  GRPC_PYTHON_OVERRIDE_EXT_SUFFIX="$(${PYTHON} -c 'import sysconfig; print(sysconfig.get_config_var("EXT_SUFFIX").replace("-x86_64-linux-gnu.so", "-aarch64-linux-gnu.so"))')"
+  export GRPC_PYTHON_OVERRIDE_EXT_SUFFIX
+
+  # since we're crosscompiling, we need to explicitly choose the right platform for boringssl assembly optimizations
+  export GRPC_BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM="linux-aarch64"
+fi
+
+# check whether we are crosscompiling. AUDITWHEEL_ARCH is set by the dockcross docker image.
+if [ "$AUDITWHEEL_ARCH" == "armv7l" ]
+then
+  # when crosscompiling for arm, --plat-name needs to be set explicitly
+  # to end up with correctly named wheel file
+  # our dockcross-based docker image onveniently provides the value in the AUDITWHEEL_PLAT env
+  WHEEL_PLAT_NAME_FLAG="--plat-name=$AUDITWHEEL_PLAT"
+
+  # override the value of EXT_SUFFIX to make sure the crosscompiled .so files in the wheel have the correct filename suffix
+  GRPC_PYTHON_OVERRIDE_EXT_SUFFIX="$(${PYTHON} -c 'import sysconfig; print(sysconfig.get_config_var("EXT_SUFFIX").replace("-x86_64-linux-gnu.so", "-arm-linux-gnueabihf.so"))')"
+  export GRPC_PYTHON_OVERRIDE_EXT_SUFFIX
+
+  # since we're crosscompiling, we need to explicitly choose the right platform for boringssl assembly optimizations
+  export GRPC_BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM="linux-arm"
+fi
+
 # Build the source distribution first because MANIFEST.in cannot override
 # exclusion of built shared objects among package resources (for some
 # inexplicable reason).
@@ -40,7 +82,8 @@
 
 # Wheel has a bug where directories don't get excluded.
 # https://bitbucket.org/pypa/wheel/issues/99/cannot-exclude-directory
-${SETARCH_CMD} "${PYTHON}" setup.py bdist_wheel
+# shellcheck disable=SC2086
+${SETARCH_CMD} "${PYTHON}" setup.py bdist_wheel $WHEEL_PLAT_NAME_FLAG
 
 GRPCIO_STRIP_TEMPDIR=$(mktemp -d)
 GRPCIO_TAR_GZ_LIST=( dist/grpcio-*.tar.gz )
@@ -78,9 +121,10 @@
 ${SETARCH_CMD} "${PYTHON}" tools/distrib/python/grpcio_tools/setup.py sdist
 
 # Build gRPC tools package binary distribution
-${SETARCH_CMD} "${PYTHON}" tools/distrib/python/grpcio_tools/setup.py bdist_wheel
+# shellcheck disable=SC2086
+${SETARCH_CMD} "${PYTHON}" tools/distrib/python/grpcio_tools/setup.py bdist_wheel $WHEEL_PLAT_NAME_FLAG
 
-if [ "$GRPC_BUILD_MANYLINUX_WHEEL" != "" ]
+if [ "$GRPC_RUN_AUDITWHEEL_REPAIR" != "" ]
 then
   for wheel in dist/*.whl; do
     "${AUDITWHEEL}" show "$wheel" | tee /dev/stderr |  grep -E -w "$AUDITWHEEL_PLAT"
@@ -110,38 +154,60 @@
   "${PIP}" install grpcio --no-index --find-links "file://$ARTIFACT_DIR/"
   "${PIP}" install grpcio-tools --no-index --find-links "file://$ARTIFACT_DIR/"
 
+  # Note(lidiz) setuptools's "sdist" command creates a source tarball, which
+  # demands an extra step of building the wheel. The building step is merely ran
+  # through setup.py, but we can optimize it with "bdist_wheel" command, which
+  # skips the wheel building step.
+
   # Build grpcio_testing source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_testing/setup.py preprocess \
-      sdist
+      sdist bdist_wheel
   cp -r src/python/grpcio_testing/dist/* "$ARTIFACT_DIR"
 
   # Build grpcio_channelz source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_channelz/setup.py \
-      preprocess build_package_protos sdist
+      preprocess build_package_protos sdist bdist_wheel
   cp -r src/python/grpcio_channelz/dist/* "$ARTIFACT_DIR"
 
   # Build grpcio_health_checking source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_health_checking/setup.py \
-      preprocess build_package_protos sdist
+      preprocess build_package_protos sdist bdist_wheel
   cp -r src/python/grpcio_health_checking/dist/* "$ARTIFACT_DIR"
 
   # Build grpcio_reflection source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_reflection/setup.py \
-      preprocess build_package_protos sdist
+      preprocess build_package_protos sdist bdist_wheel
   cp -r src/python/grpcio_reflection/dist/* "$ARTIFACT_DIR"
 
   # Build grpcio_status source distribution
   ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_status/setup.py \
-      preprocess sdist
+      preprocess sdist bdist_wheel
   cp -r src/python/grpcio_status/dist/* "$ARTIFACT_DIR"
+
+  # Build grpcio_csds source distribution
+  ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_csds/setup.py \
+      sdist bdist_wheel
+  cp -r src/python/grpcio_csds/dist/* "$ARTIFACT_DIR"
+
+  # Build grpcio_admin source distribution and it needs the cutting-edge version
+  # of Channelz and CSDS to be installed.
+  "${PIP}" install --upgrade xds-protos==0.0.8
+  "${PIP}" install grpcio-channelz --no-index --find-links "file://$ARTIFACT_DIR/"
+  "${PIP}" install grpcio-csds --no-index --find-links "file://$ARTIFACT_DIR/"
+  ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_admin/setup.py \
+      sdist bdist_wheel
+  cp -r src/python/grpcio_admin/dist/* "$ARTIFACT_DIR"
 fi
 
-# Ensure the generated artifacts are valid.
-"${PYTHON}" -m pip install virtualenv
-"${PYTHON}" -m virtualenv venv || { "${PYTHON}" -m pip install virtualenv==16.7.9 && "${PYTHON}" -m virtualenv venv; }
-venv/bin/python -m pip install "twine<=2.0"
-venv/bin/python -m twine check dist/* tools/distrib/python/grpcio_tools/dist/*
-rm -rf venv/
+if [ "$GRPC_SKIP_TWINE_CHECK" == "" ]
+then
+  # Ensure the generated artifacts are valid.
+  "${PYTHON}" -m pip install virtualenv
+  "${PYTHON}" -m virtualenv venv || { "${PYTHON}" -m pip install virtualenv==16.7.9 && "${PYTHON}" -m virtualenv venv; }
+  venv/bin/python -m pip install "twine<=2.0"
+  venv/bin/python -m twine check dist/* tools/distrib/python/grpcio_tools/dist/*
+  rm -rf venv/
+fi
 
 cp -r dist/* "$ARTIFACT_DIR"
 cp -r tools/distrib/python/grpcio_tools/dist/* "$ARTIFACT_DIR"
diff --git a/grpc/tools/run_tests/artifacts/build_package_python.sh b/grpc/tools/run_tests/artifacts/build_package_python.sh
index 35c78e9..623eae7 100755
--- a/grpc/tools/run_tests/artifacts/build_package_python.sh
+++ b/grpc/tools/run_tests/artifacts/build_package_python.sh
@@ -23,21 +23,19 @@
 # and we only collect them here to deliver them to the distribtest phase.
 cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/python_*/* artifacts/ || true
 
-apt-get install -y python-pip
-python -m pip install -U pip
-python -m pip install -U wheel
+export PYTHON=${PYTHON:-python}
 
 strip_binary_wheel() {
     WHEEL_PATH="$1"
     TEMP_WHEEL_DIR=$(mktemp -d)
-    python -m wheel unpack "$WHEEL_PATH" -d "$TEMP_WHEEL_DIR"
+    ${PYTHON} -m wheel unpack "$WHEEL_PATH" -d "$TEMP_WHEEL_DIR"
     find "$TEMP_WHEEL_DIR" -name "_protoc_compiler*.so" -exec strip --strip-debug {} ";"
     find "$TEMP_WHEEL_DIR" -name "cygrpc*.so" -exec strip --strip-debug {} ";"
 
     WHEEL_FILE=$(basename "$WHEEL_PATH")
     DISTRIBUTION_NAME=$(basename "$WHEEL_PATH" | cut -d '-' -f 1)
     VERSION=$(basename "$WHEEL_PATH" | cut -d '-' -f 2)
-    python -m wheel pack "$TEMP_WHEEL_DIR/$DISTRIBUTION_NAME-$VERSION" -d "$TEMP_WHEEL_DIR"
+    ${PYTHON} -m wheel pack "$TEMP_WHEEL_DIR/$DISTRIBUTION_NAME-$VERSION" -d "$TEMP_WHEEL_DIR"
     mv "$TEMP_WHEEL_DIR/$WHEEL_FILE" "$WHEEL_PATH"
 }
 
diff --git a/grpc/tools/run_tests/artifacts/distribtest_targets.py b/grpc/tools/run_tests/artifacts/distribtest_targets.py
index fcd4e74..a2c8d6b 100644
--- a/grpc/tools/run_tests/artifacts/distribtest_targets.py
+++ b/grpc/tools/run_tests/artifacts/distribtest_targets.py
@@ -81,7 +81,10 @@
 class CSharpDistribTest(object):
     """Tests C# NuGet package"""
 
-    def __init__(self, platform, arch, docker_suffix=None,
+    def __init__(self,
+                 platform,
+                 arch,
+                 docker_suffix=None,
                  use_dotnet_cli=False):
         self.name = 'csharp_%s_%s' % (platform, arch)
         self.platform = platform
@@ -323,7 +326,8 @@
         CppDistribTest('linux', 'x64', 'stretch',
                        'cmake_module_install_pkgconfig'),
         CppDistribTest('linux', 'x64', 'stretch', 'cmake_pkgconfig'),
-        CppDistribTest('linux', 'x64', 'stretch', 'raspberry_pi'),
+        CppDistribTest('linux', 'x64', 'stretch_aarch64_cross',
+                       'cmake_aarch64_cross'),
         CppDistribTest('windows', 'x86', testcase='cmake'),
         CppDistribTest('windows', 'x86', testcase='cmake_as_externalproject'),
         # C#
@@ -349,6 +353,7 @@
         PythonDistribTest('linux', 'x64', 'arch'),
         PythonDistribTest('linux', 'x64', 'ubuntu1604'),
         PythonDistribTest('linux', 'x64', 'ubuntu1804'),
+        PythonDistribTest('linux', 'aarch64', 'python38_buster'),
         PythonDistribTest('linux', 'x64', 'alpine3.7', source=True),
         PythonDistribTest('linux', 'x64', 'jessie', source=True),
         PythonDistribTest('linux', 'x86', 'jessie', source=True),
@@ -358,7 +363,6 @@
         PythonDistribTest('linux', 'x64', 'ubuntu1604', source=True),
         PythonDistribTest('linux', 'x64', 'ubuntu1804', source=True),
         # Ruby
-        RubyDistribTest('linux', 'x64', 'jessie', ruby_version='ruby_2_3'),
         RubyDistribTest('linux', 'x64', 'jessie', ruby_version='ruby_2_4'),
         RubyDistribTest('linux', 'x64', 'jessie', ruby_version='ruby_2_5'),
         RubyDistribTest('linux', 'x64', 'jessie', ruby_version='ruby_2_6'),
@@ -367,7 +371,7 @@
         RubyDistribTest('linux',
                         'x64',
                         'jessie',
-                        ruby_version='ruby_2_3',
+                        ruby_version='ruby_2_4',
                         source=True),
         RubyDistribTest('linux', 'x64', 'centos7'),
         RubyDistribTest('linux', 'x64', 'fedora23'),
diff --git a/grpc/tools/run_tests/artifacts/package_targets.py b/grpc/tools/run_tests/artifacts/package_targets.py
index cc057ec..7123d18 100644
--- a/grpc/tools/run_tests/artifacts/package_targets.py
+++ b/grpc/tools/run_tests/artifacts/package_targets.py
@@ -113,7 +113,7 @@
 
     def build_jobspec(self):
         return create_docker_jobspec(
-            self.name, 'tools/dockerfile/grpc_artifact_linux_x64',
+            self.name, 'tools/dockerfile/grpc_artifact_centos6_x64',
             'tools/run_tests/artifacts/build_package_ruby.sh')
 
 
@@ -128,9 +128,14 @@
         return []
 
     def build_jobspec(self):
+        # since the python package build does very little, we can use virtually
+        # any image that has new-enough python, so reusing one of the images used
+        # for artifact building seems natural.
         return create_docker_jobspec(
-            self.name, 'tools/dockerfile/grpc_artifact_linux_x64',
-            'tools/run_tests/artifacts/build_package_python.sh')
+            self.name,
+            'tools/dockerfile/grpc_artifact_python_manylinux2014_x64',
+            'tools/run_tests/artifacts/build_package_python.sh',
+            environ={'PYTHON': '/opt/python/cp39-cp39/bin/python'})
 
 
 class PHPPackage:
@@ -145,7 +150,7 @@
 
     def build_jobspec(self):
         return create_docker_jobspec(
-            self.name, 'tools/dockerfile/grpc_artifact_linux_x64',
+            self.name, 'tools/dockerfile/grpc_artifact_centos6_x64',
             'tools/run_tests/artifacts/build_package_php.sh')
 
 
diff --git a/grpc/tools/run_tests/dockerize/build_and_run_docker.sh b/grpc/tools/run_tests/dockerize/build_and_run_docker.sh
index 7e9bc77..3f129ce 100755
--- a/grpc/tools/run_tests/dockerize/build_and_run_docker.sh
+++ b/grpc/tools/run_tests/dockerize/build_and_run_docker.sh
@@ -29,18 +29,11 @@
 # DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
 # OUTPUT_DIR - Directory that will be copied from inside docker after finishing.
 # DOCKERHUB_ORGANIZATION - If set, pull a prebuilt image from given dockerhub org.
-# DOCKER_BASE_IMAGE - If set, pull the latest base image.
 # $@ - Extra args to pass to docker run
 
 # Use image name based on Dockerfile location checksum
 DOCKER_IMAGE_NAME=$(basename "$DOCKERFILE_DIR"):$(sha1sum "$DOCKERFILE_DIR/Dockerfile" | cut -f1 -d\ )
 
-# Pull the base image to force an update
-if [ "$DOCKER_BASE_IMAGE" != "" ]
-then
-  time docker pull "$DOCKER_BASE_IMAGE"
-fi
-
 if [ "$DOCKERHUB_ORGANIZATION" != "" ]
 then
   DOCKER_IMAGE_NAME=$DOCKERHUB_ORGANIZATION/$DOCKER_IMAGE_NAME
@@ -65,7 +58,12 @@
   -e "KOKORO_BUILD_NUMBER=$KOKORO_BUILD_NUMBER" \
   -e "KOKORO_BUILD_URL=$KOKORO_BUILD_URL" \
   -e "KOKORO_JOB_NAME=$KOKORO_JOB_NAME" \
+  -e "KOKORO_ARTIFACTS_DIR=$KOKORO_ARTIFACTS_DIR" \
+  -e "GIT_ORIGIN_URL=$(git -C $git_root remote get-url origin)" \
+  -e "GIT_COMMIT_SHORT=$(git -C $git_root rev-parse --short HEAD)" \
+  -e "TESTGRID_EXCLUDE=$TESTGRID_EXCLUDE" \
   -v "$git_root:/var/local/jenkins/grpc:ro" \
+  -v "$KOKORO_ARTIFACTS_DIR:$KOKORO_ARTIFACTS_DIR" \
   -w /var/local/git/grpc \
   --name="$CONTAINER_NAME" \
   $EXTRA_DOCKER_ARGS \
diff --git a/grpc/tools/run_tests/helper_scripts/build_python.sh b/grpc/tools/run_tests/helper_scripts/build_python.sh
index 331f10e..7b928d1 100755
--- a/grpc/tools/run_tests/helper_scripts/build_python.sh
+++ b/grpc/tools/run_tests/helper_scripts/build_python.sh
@@ -153,7 +153,7 @@
 # See https://github.com/grpc/grpc/issues/14815 for more context. We cannot rely
 # on pip to upgrade itself because if pip is too old, it may not have the required
 # TLS version to run `pip install`.
-curl https://bootstrap.pypa.io/get-pip.py | $VENV_PYTHON
+curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | $VENV_PYTHON
 
 # pip-installs the directory specified. Used because on MSYS the vanilla Windows
 # Python gets confused when parsing paths.
@@ -220,6 +220,12 @@
 $VENV_PYTHON "$ROOT/src/python/grpcio_status/setup.py" build_package_protos
 pip_install_dir "$ROOT/src/python/grpcio_status"
 
+# Build/install csds
+pip_install_dir "$ROOT/src/python/grpcio_csds"
+
+# Build/install admin
+pip_install_dir "$ROOT/src/python/grpcio_admin"
+
 # Install testing
 pip_install_dir "$ROOT/src/python/grpcio_testing"
 
diff --git a/grpc/tools/run_tests/helper_scripts/prep_xds.sh b/grpc/tools/run_tests/helper_scripts/prep_xds.sh
index 5a65bc3..6187c88 100755
--- a/grpc/tools/run_tests/helper_scripts/prep_xds.sh
+++ b/grpc/tools/run_tests/helper_scripts/prep_xds.sh
@@ -20,7 +20,8 @@
 
 sudo apt-get install -y python3-pip
 sudo python3 -m pip install --upgrade pip
-sudo python3 -m pip install grpcio==1.31.0 grpcio-tools==1.31.0 google-api-python-client google-auth-httplib2 oauth2client
+sudo python3 -m pip install --upgrade setuptools
+sudo python3 -m pip install --upgrade grpcio==1.31.0 grpcio-tools==1.31.0 protobuf google-api-python-client google-auth-httplib2 oauth2client xds-protos
 
 # Prepare generated Python code.
 TOOLS_DIR=tools/run_tests
diff --git a/grpc/tools/run_tests/performance/README.md b/grpc/tools/run_tests/performance/README.md
index 1d09498..8e3ab27 100644
--- a/grpc/tools/run_tests/performance/README.md
+++ b/grpc/tools/run_tests/performance/README.md
@@ -1,38 +1,49 @@
 # Overview of performance test suite, with steps for manual runs:
 
-For design of the tests, see
-https://grpc.io/docs/guides/benchmarking.
+For design of the tests, see https://grpc.io/docs/guides/benchmarking.
+
+For scripts related to the GKE-based performance test suite (in development),
+see [gRPC OSS benchmarks](#grpc-oss-benchmarks).
 
 ## Pre-reqs for running these manually:
+
 In general the benchmark workers and driver build scripts expect
-[linux_performance_worker_init.sh](../../gce/linux_performance_worker_init.sh) to have been ran already.
+[linux_performance_worker_init.sh](../../gce/linux_performance_worker_init.sh)
+to have been ran already.
 
 ### To run benchmarks locally:
-* From the grpc repo root, start the
-[run_performance_tests.py](../run_performance_tests.py) runner script.
+
+- From the grpc repo root, start the
+  [run_performance_tests.py](../run_performance_tests.py) runner script.
 
 ### On remote machines, to start the driver and workers manually:
-The [run_performance_test.py](../run_performance_tests.py) top-level runner script can also
-be used with remote machines, but for e.g., profiling the server,
-it might be useful to run workers manually.
 
-1. You'll need a "driver" and separate "worker" machines.
-For example, you might use one GCE "driver" machine and 3 other
-GCE "worker" machines that are in the same zone.
+The [run_performance_test.py](../run_performance_tests.py) top-level runner
+script can also be used with remote machines, but for e.g., profiling the
+server, it might be useful to run workers manually.
 
-2. Connect to each worker machine and start up a benchmark worker with a "driver_port".
-  * For example, to start the grpc-go benchmark worker:
-  [grpc-go worker main.go](https://github.com/grpc/grpc-go/blob/master/benchmark/worker/main.go) --driver_port <driver_port>
+1. You'll need a "driver" and separate "worker" machines. For example, you might
+   use one GCE "driver" machine and 3 other GCE "worker" machines that are in
+   the same zone.
+
+2. Connect to each worker machine and start up a benchmark worker with a
+   "driver_port".
+
+- For example, to start the grpc-go benchmark worker:
+  [grpc-go worker main.go](https://github.com/grpc/grpc-go/blob/master/benchmark/worker/main.go)
+  --driver_port <driver_port>
 
 #### Commands to start workers in different languages:
- * Note that these commands are what the top-level
-   [run_performance_test.py](../run_performance_tests.py) script uses to
-   build and run different workers through the
-   [build_performance.sh](./build_performance.sh) script and "run worker"
-   scripts (such as the [run_worker_java.sh](./run_worker_java.sh)).
+
+- Note that these commands are what the top-level
+  [run_performance_test.py](../run_performance_tests.py) script uses to build
+  and run different workers through the
+  [build_performance.sh](./build_performance.sh) script and "run worker" scripts
+  (such as the [run_worker_java.sh](./run_worker_java.sh)).
 
 ##### Running benchmark workers for C-core wrapped languages (C++, Python, C#, Node, Ruby):
-   * These are more simple since they all live in the main grpc repo.
+
+- These are more simple since they all live in the main grpc repo.
 
 ```
 $ cd <grpc_repo_root>
@@ -40,11 +51,12 @@
 $ tools/run_tests/performance/run_worker_<language>.sh
 ```
 
-   * Note that there is one "run_worker" script per language, e.g.,
-     [run_worker_csharp.sh](./run_worker_csharp.sh) for c#.
+- Note that there is one "run_worker" script per language, e.g.,
+  [run_worker_csharp.sh](./run_worker_csharp.sh) for c#.
 
 ##### Running benchmark workers for gRPC-Java:
-   * You'll need the [grpc-java](https://github.com/grpc/grpc-java) repo.
+
+- You'll need the [grpc-java](https://github.com/grpc/grpc-java) repo.
 
 ```
 $ cd <grpc-java-repo>
@@ -53,7 +65,8 @@
 ```
 
 ##### Running benchmark workers for gRPC-Go:
-   * You'll need the [grpc-go repo](https://github.com/grpc/grpc-go)
+
+- You'll need the [grpc-go repo](https://github.com/grpc/grpc-go)
 
 ```
 $ cd <grpc-go-repo>/benchmark/worker && go install
@@ -62,27 +75,34 @@
 ```
 
 #### Build the driver:
-* Connect to the driver machine (if using a remote driver) and from the grpc repo root:
+
+- Connect to the driver machine (if using a remote driver) and from the grpc
+  repo root:
+
 ```
 $ tools/run_tests/performance/build_performance.sh
 ```
 
 #### Run the driver:
+
 1. Get the 'scenario_json' relevant for the scenario to run. Note that "scenario
-  json" configs are generated from [scenario_config.py](./scenario_config.py).
-  The [driver](../../../test/cpp/qps/qps_json_driver.cc) takes a list of these configs as a json string of the form: `{scenario: <json_list_of_scenarios> }`
-  in its `--scenarios_json` command argument.
-  One quick way to get a valid json string to pass to the driver is by running
-  the [run_performance_tests.py](./run_performance_tests.py) locally and copying the logged scenario json command arg.
+   json" configs are generated from [scenario_config.py](./scenario_config.py).
+   The [driver](../../../test/cpp/qps/qps_json_driver.cc) takes a list of these
+   configs as a json string of the form: `{scenario: <json_list_of_scenarios> }`
+   in its `--scenarios_json` command argument. One quick way to get a valid json
+   string to pass to the driver is by running the
+   [run_performance_tests.py](./run_performance_tests.py) locally and copying
+   the logged scenario json command arg.
 
 2. From the grpc repo root:
 
-* Set `QPS_WORKERS` environment variable to a comma separated list of worker
-machines. Note that the driver will start the "benchmark server" on the first
-entry in the list, and the rest will be told to run as clients against the
-benchmark server.
+- Set `QPS_WORKERS` environment variable to a comma separated list of worker
+  machines. Note that the driver will start the "benchmark server" on the first
+  entry in the list, and the rest will be told to run as clients against the
+  benchmark server.
 
 Example running and profiling of go benchmark server:
+
 ```
 $ export QPS_WORKERS=<host1>:<10000>,<host2>,10000,<host3>:10000
 $ bins/opt/qps_json_driver --scenario_json='<scenario_json_scenario_config_string>'
@@ -93,42 +113,269 @@
 While running the benchmark, a profiler can be attached to the server.
 
 Example to count syscalls in grpc-go server during a benchmark:
-* Connect to server machine and run:
+
+- Connect to server machine and run:
+
 ```
 $ netstat -tulpn | grep <driver_port> # to get pid of worker
 $ perf stat -p <worker_pid> -e syscalls:sys_enter_write # stop after test complete
 ```
 
 Example memory profile of grpc-go server, with `go tools pprof`:
-* After a run is done on the server, see its alloc profile with:
+
+- After a run is done on the server, see its alloc profile with:
+
 ```
 $ go tool pprof --text --alloc_space http://localhost:<pprof_port>/debug/heap
 ```
 
 ### Configuration environment variables:
 
-* QPS_WORKER_CHANNEL_CONNECT_TIMEOUT
+- QPS_WORKER_CHANNEL_CONNECT_TIMEOUT
 
   Consuming process: qps_worker
 
   Type: integer (number of seconds)
 
-  This can be used to configure the amount of time that benchmark
-  clients wait for channels to the benchmark server to become ready.
-  This is useful in certain benchmark environments in which the
-  server can take a long time to become ready. Note: if setting
-  this to a high value, then the scenario config under test should
-  probably also have a large "warmup_seconds".
+  This can be used to configure the amount of time that benchmark clients wait
+  for channels to the benchmark server to become ready. This is useful in
+  certain benchmark environments in which the server can take a long time to
+  become ready. Note: if setting this to a high value, then the scenario config
+  under test should probably also have a large "warmup_seconds".
 
-* QPS_WORKERS
+- QPS_WORKERS
 
   Consuming process: qps_json_driver
 
   Type: comma separated list of host:port
 
-  Set this to a comma separated list of QPS worker processes/machines.
-  Each scenario in a scenario config has specifies a certain number
-  of servers, `num_servers`, and the driver will start
-  "benchmark servers"'s on the first `num_server` `host:port` pairs in
-  the comma separated list. The rest will be told to run as clients
-  against the benchmark server.
+  Set this to a comma separated list of QPS worker processes/machines. Each
+  scenario in a scenario config has specifies a certain number of servers,
+  `num_servers`, and the driver will start "benchmark servers"'s on the first
+  `num_server` `host:port` pairs in the comma separated list. The rest will be
+  told to run as clients against the benchmark server.
+
+## gRPC OSS benchmarks
+
+The scripts in this section generate LoadTest configurations for the GKE-based
+gRPC OSS benchmarks framework. This framework is stored in a separate
+repository, [grpc/test-infra](https://github.com/grpc/test-infra).
+
+### Generating scenarios
+
+The benchmarks framework uses the same test scenarios as the legacy one. These
+script [scenario_config_exporter.py](./scenario_config_exporter.py) can be used
+to export these scenarios to files, and also to count and analyze existing
+scenarios.
+
+The language(s) and category of the scenarios are of particular importance to
+the tests. Continuous runs will typically run tests in the `scalable` category.
+
+The following example counts scenarios in the `scalable` category:
+
+```
+$ ./tools/run_tests/performance/scenario_config_exporter.py --count_scenarios --category=scalable
+Scenario count for all languages (category: scalable):
+Count  Language         Client   Server   Categories
+   77  c++                                scalable
+   19  python_asyncio                     scalable
+   16  java                               scalable
+   12  go                                 scalable
+   12  node                      node     scalable
+   12  node_purejs               node     scalable
+    9  csharp                             scalable
+    7  python                             scalable
+    5  ruby                               scalable
+    4  csharp                    c++      scalable
+    4  php7                      c++      scalable
+    4  php7_protobuf_c           c++      scalable
+    3  python_asyncio            c++      scalable
+    2  ruby                      c++      scalable
+    2  python                    c++      scalable
+    1  csharp           c++               scalable
+
+  189  total scenarios (category: scalable)
+```
+
+Client and server languages are only set for cross-language scenarios, where the
+client or server language do not match the scenario language.
+
+### Generating load test configurations
+
+The benchmarks framework uses LoadTest resources configured by YAML files. Each
+LoadTest resource specifies a driver, a server, and one or more clients to run
+the test. Each test runs one scenario. The scenario configuration is embedded in
+the LoadTest configuration. Example configurations for various languages can be
+found here:
+
+https://github.com/grpc/test-infra/tree/master/config/samples
+
+The script [loadtest_config.py](./loadtest_config.py) generates LoadTest
+configurations for tests running a set of scenarios. The configurations are
+written in multipart YAML format, either to a file or to stdout. Each
+configuration contains a single embedded scenario.
+
+The LoadTest configurations are generated from a template. Any configuration can
+be used as a template, as long as it contains the languages required by the set
+of scenarios we intend to run (for instance, if we are generating configurations
+to run go scenarios, the template must contain a go client and a go server; if
+we are generating configurations for cross-language scenarios that need a go
+client and a C++ server, the template must also contain a C++ server; and the
+same for all other languages).
+
+The LoadTests specified in the script output all have unique names and can be
+run by applying the test to a cluster running the LoadTest controller with
+`kubectl apply`:
+
+```
+$ kubectl apply -f loadtest_config.yaml
+```
+
+A basic template for generating tests in various languages can be found here:
+[loadtest_template_basic_all_languages.yaml](./templates/loadtest_template_basic_all_languages.yaml).
+The following example generates configurations for C# and Java tests using this
+template, including tests against C++ clients and servers, and running each test
+twice:
+
+```
+$ ./tools/run_tests/performance/loadtest_config.py -l go -l java \
+    -t ./tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml \
+    -s client_pool=workers-8core -s server_pool=workers-8core \
+    -s big_query_table=grpc-testing.e2e_benchmarks.experimental_results \
+    -s timeout_seconds=3600 --category=scalable \
+    -d --allow_client_language=c++ --allow_server_language=c++ \
+    --runs_per_test=2 -o ./loadtest.yaml
+```
+
+The script `loadtest_config.py` takes the following options:
+
+- `-l`, `--language`<br> Language to benchmark. May be repeated.
+- `-t`, `--template`<br> Template file. A template is a configuration file that
+  may contain multiple client and server configuration, and may also include
+  substitution keys.
+- `p`, `--prefix`<br> Test names consist of a prefix_joined with a uuid with a
+  dash. Test names are stored in `metadata.name`. The prefix is also added as
+  the `prefix` label in `metadata.labels`. The prefix defaults to the user name
+  if not set.
+- `-u`, `--uniquifier_element`<br> Uniquifier elements may be passed to the test
+  to make the test name unique. This option may be repeated to add multiple
+  elements. The uniquifier elements (plus a date string and a run index, if
+  applicable) are joined with a dash to form a _uniquifier_. The test name uuid
+  is derived from the scenario name and the uniquifier. The uniquifier is also
+  added as the `uniquifier` annotation in `metadata.annotations`.
+- `-d`<br> This option is a shorthand for the addition of a date string as a
+  uniquifier element.
+- `-a`, `--annotation`<br> Metadata annotation to be stored in
+  `metadata.annotations`, in the form key=value. May be repeated.
+- `-r`, `--regex`<br> Regex to select scenarios to run. Each scenario is
+  embedded in a LoadTest configuration containing a client and server of the
+  language(s) required for the test. Defaults to `.*`, i.e., select all
+  scenarios.
+- `--category`<br> Select scenarios of a specified _category_, or of all
+  categories. Defaults to `all`. Continuous runs typically run tests in the
+  `scalable` category.
+- `--allow_client_language`<br> Allows cross-language scenarios where the client
+  is of a specified language, different from the scenario language. This is
+  typically `c++`. This flag may be repeated.
+- `--allow_server_language`<br> Allows cross-language scenarios where the server
+  is of a specified language, different from the scenario language. This is
+  typically `node` or `c++`. This flag may be repeated.
+- `--runs_per_test`<br> This option specifies that each test should be repeated
+  `n` times, where `n` is the value of the flag. If `n` > 1, the index of each
+  test run is added as a uniquifier element for that run.
+- `-o`, `--output`<br> Output file name. The LoadTest configurations are added
+  to this file, in multipart YAML format. Output is streamed to `sys.stdout` if
+  not set.
+
+The script adds labels and annotations to the metadata of each LoadTest
+configuration:
+
+The following labels are added to `metadata.labels`:
+
+- `language`<br> The language of the LoadTest scenario.
+- `prefix`<br> The prefix used in `metadata.name`.
+
+The following annotations are added to `metadata.annotations`:
+
+- `scenario`<br> The name of the LoadTest scenario.
+- `uniquifier`<br> The uniquifier used to generate the LoadTest name, including
+  the run index if applicable.
+
+[Labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/)
+can be used in selectors in resource queries. Adding the prefix, in particular,
+allows the user (or an automation script) to select the resources started from a
+given run of the config generator.
+
+[Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/)
+contain additional information that is available to the user (or an automation
+script) but is not indexed and cannot be used to select objects. Scenario name
+and uniquifier are added to provide the elements of the LoadTest name uuid in
+human-readable form. Additional annotations may be added later for automation.
+
+### Concatenating load test configurations
+
+The LoadTest configuration generator can process multiple languages at a time,
+assuming that they are supported by the template. The convenience script
+[loadtest_concat_yaml.py](./loadtest_concat_yaml.py) is provided to concatenate
+several YAML files into one, so configurations generated by multiple generator
+invocations can be concatenated into one and run with a single command. The
+script can be invoked as follows:
+
+```
+$ loadtest_concat_yaml.py -i infile1.yaml infile2.yaml -o outfile.yaml
+```
+
+### Generating configuration templates
+
+The script [loadtest_template.py](./loadtest_template.py) generates a load test
+configuration template from a set of load test configurations. The source files
+may be load test configurations or load test configuration templates. The
+generated template supports all languages supported in any of the input
+configurations or templates.
+
+The example template in
+[loadtest_template_basic_template_all_languages.yaml](./templates/loadtest_template_basic_all_languages.yaml)
+was generated from the example configurations in
+[grpc/test-infra](https://github.com/grpc/test-infra) by the following command:
+
+```
+$ ./tools/run_tests/performance/loadtest_template.py \
+    -i ../test-infra/config/samples/*.yaml \
+    --inject_client_pool --inject_server_pool --inject_big_query_table \
+    --inject_timeout_seconds \
+    -o ./tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml \
+    --name basic_all_languages
+```
+
+The script `loadtest_template.py` takes the following options:
+
+- `-i`, `--inputs`<br> Space-separated list of the names of input files
+  containing LoadTest configurations. May be repeated.
+- `-o`, `--output`<br> Output file name. Outputs to `sys.stdout` if not set.
+- `--inject_client_pool`<br> If this option is set, the pool attribute of all
+  clients in `spec.clients` is set to `${client_pool}`, for later substitution.
+- `--inject_server_pool`<br> If this option is set, the pool attribute of all
+  servers in `spec.servers` is set to `${server_pool}`, for later substitution.
+- `--inject_big_query_table`<br> If this option is set,
+  spec.results.bigQueryTable is set to `${big_query_table}`.
+- `--inject_timeout_seconds`<br> If this option is set, `spec.timeoutSeconds` is
+  set to `${timeout_seconds}`.
+- `--inject_ttl_seconds`<br> If this option is set, `spec.ttlSeconds` is set to
+  `${ttl_seconds}`.
+- `-n`, `--name`<br> Name to be set in `metadata.name`.
+- `-a`, `--annotation`<br> Metadata annotation to be stored in
+  `metadata.annotations`, in the form key=value. May be repeated.
+
+The four options that inject substitution keys are the most useful for template
+reuse. When running tests on different node pools, it becomes necessary to set
+the pool, and usually also to store the data on a different table. When running
+as part of a larger collection of tests, it may also be necessary to adjust test
+timeout and time-to-live, to ensure that all tests have time to complete.
+
+The template name is replaced again by `loadtest_config.py`, and so is set only
+as a human-readable memo.
+
+Annotations, on the other hand, are passed on to the test configurations, and
+may be set to values or to substitution keys in themselves, allowing future
+automation scripts to process the tests generated from these configurations in
+different ways.
diff --git a/grpc/tools/run_tests/performance/loadtest_concat_yaml.py b/grpc/tools/run_tests/performance/loadtest_concat_yaml.py
new file mode 100755
index 0000000..bf64fdc
--- /dev/null
+++ b/grpc/tools/run_tests/performance/loadtest_concat_yaml.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# Copyright 2021 The 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.
+
+# Helper script to concatenate YAML files.
+#
+# This script concatenates multiple YAML files into a single multipart file.
+# Input files are not parsed but processed as strings. This is a convenience
+# script to concatenate output files generated by multiple runs of
+# loadtest_config.py.
+
+import argparse
+import sys
+
+from typing import Iterable
+
+
+def gen_content_strings(input_files: Iterable[str]) -> Iterable[str]:
+    if not input_files:
+        return
+
+    with open(input_files[0]) as f:
+        content = f.read()
+    yield content
+
+    for input_file in input_files[1:]:
+        with open(input_file) as f:
+            content = f.read()
+        yield '---\n'
+        yield content
+
+
+def main() -> None:
+    argp = argparse.ArgumentParser(description='Concatenates YAML files.')
+    argp.add_argument('-i',
+                      '--inputs',
+                      action='extend',
+                      nargs='+',
+                      type=str,
+                      required=True,
+                      help='Input files.')
+    argp.add_argument(
+        '-o',
+        '--output',
+        type=str,
+        help='Concatenated output file. Output to stdout if not set.')
+    args = argp.parse_args()
+
+    with open(args.output, 'w') if args.output else sys.stdout as f:
+        for content in gen_content_strings(args.inputs):
+            print(content, file=f, sep='', end='')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/grpc/tools/run_tests/performance/loadtest_config.py b/grpc/tools/run_tests/performance/loadtest_config.py
new file mode 100755
index 0000000..b91b2ca
--- /dev/null
+++ b/grpc/tools/run_tests/performance/loadtest_config.py
@@ -0,0 +1,383 @@
+#!/usr/bin/env python3
+# Copyright 2021 The 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.
+
+# Script to generate test configurations for the OSS benchmarks framework.
+#
+# This script filters test scenarios and generates uniquely named configurations
+# for each test. Configurations are dumped in multipart YAML format.
+#
+# See documentation below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md#grpc-oss-benchmarks
+
+import argparse
+import copy
+import datetime
+import itertools
+import os
+import string
+import sys
+import uuid
+
+from typing import Any, Dict, Iterable, Mapping, Optional, Type
+
+import json
+import yaml
+
+import scenario_config
+import scenario_config_exporter
+
+CONFIGURATION_FILE_HEADER_COMMENT = """
+# Load test configurations generated from a template by loadtest_config.py.
+# See documentation below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md#grpc-oss-benchmarks
+"""
+
+# TODO(paulosjca): Merge label_language and image_language into one function.
+# These functions are necessary because 'c++' is not allowed as a label value in
+# kubernetes, and because languages share images in the existing templates. Once
+# the templates are reorganized and most image mapping is removed, the two
+# functions can be merged into one.
+
+
+def label_language(language: str) -> str:
+    """Convert scenario language to place in a resource label."""
+    return {
+        'c++': 'cxx',
+    }.get(language, language)
+
+
+def image_language(language: str) -> str:
+    """Convert scenario languages to image languages."""
+    return {
+        'c++': 'cxx',
+        'node_purejs': 'node',
+        'php7': 'php',
+        'php7_protobuf_c': 'php',
+        'python_asyncio': 'python',
+    }.get(language, language)
+
+
+def default_prefix() -> str:
+    """Constructs and returns a default prefix for LoadTest names."""
+    return os.environ.get('USER', 'loadtest')
+
+
+def now_string() -> str:
+    """Returns the current date and time in string format."""
+    return datetime.datetime.now().strftime('%Y%m%d%H%M%S')
+
+
+def validate_loadtest_name(name: str) -> None:
+    """Validates that a LoadTest name is in the expected format."""
+    if len(name) > 63:
+        raise ValueError(
+            'LoadTest name must be less than 63 characters long: %s' % name)
+    if not all((s.isalnum() for s in name.split('-'))):
+        raise ValueError('Invalid elements in LoadTest name: %s' % name)
+
+
+def loadtest_base_name(scenario_name: str,
+                       uniquifier_elements: Iterable[str]) -> str:
+    """Constructs and returns the base name for a LoadTest resource."""
+    name_elements = scenario_name.split('_')
+    name_elements.extend(uniquifier_elements)
+    return '-'.join(name_elements)
+
+
+def loadtest_name(prefix: str, scenario_name: str,
+                  uniquifier_elements: Iterable[str]) -> str:
+    """Constructs and returns a valid name for a LoadTest resource."""
+    base_name = loadtest_base_name(scenario_name, uniquifier_elements)
+    name_elements = []
+    if prefix:
+        name_elements.append(prefix)
+    name_elements.append(str(uuid.uuid5(uuid.NAMESPACE_DNS, base_name)))
+    name = '-'.join(name_elements)
+    validate_loadtest_name(name)
+    return name
+
+
+def validate_annotations(annotations: Dict[str, str]) -> None:
+    """Validates that annotations do not contain reserved names.
+
+    These names are automatically added by the config generator.
+    """
+    names = set(('scenario', 'uniquifier')).intersection(annotations)
+    if names:
+        raise ValueError('Annotations contain reserved names: %s' % names)
+
+
+def gen_run_indices(runs_per_test: int) -> Iterable[str]:
+    """Generates run indices for multiple runs, as formatted strings."""
+    if runs_per_test < 2:
+        yield ''
+        return
+    prefix_length = len('{:d}'.format(runs_per_test - 1))
+    prefix_fmt = '{{:{:d}d}}'.format(prefix_length)
+    for i in range(runs_per_test):
+        yield prefix_fmt.format(i)
+
+
+def gen_loadtest_configs(
+        base_config: Mapping[str, Any],
+        base_config_clients: Iterable[Mapping[str, Any]],
+        base_config_servers: Iterable[Mapping[str, Any]],
+        scenario_name_regex: str,
+        language_config: scenario_config_exporter.LanguageConfig,
+        loadtest_name_prefix: str,
+        uniquifier_elements: Iterable[str],
+        annotations: Mapping[str, str],
+        runs_per_test: int = 1) -> Iterable[Dict[str, Any]]:
+    """Generates LoadTest configurations for a given language config.
+
+    The LoadTest configurations are generated as YAML objects.
+    """
+    validate_annotations(annotations)
+    prefix = loadtest_name_prefix or default_prefix()
+    cl = image_language(language_config.client_language or
+                        language_config.language)
+    sl = image_language(language_config.server_language or
+                        language_config.language)
+    scenario_filter = scenario_config_exporter.scenario_filter(
+        scenario_name_regex=scenario_name_regex,
+        category=language_config.category,
+        client_language=language_config.client_language,
+        server_language=language_config.server_language)
+    scenarios = scenario_config_exporter.gen_scenarios(language_config.language,
+                                                       scenario_filter)
+
+    for scenario in scenarios:
+        for run_index in gen_run_indices(runs_per_test):
+            uniq = (uniquifier_elements +
+                    [run_index] if run_index else uniquifier_elements)
+            name = loadtest_name(prefix, scenario['name'], uniq)
+            scenario_str = json.dumps({'scenarios': scenario},
+                                      indent='  ') + '\n'
+
+            config = copy.deepcopy(base_config)
+
+            metadata = config['metadata']
+            metadata['name'] = name
+            if 'labels' not in metadata:
+                metadata['labels'] = dict()
+            metadata['labels']['language'] = label_language(
+                language_config.language)
+            metadata['labels']['prefix'] = prefix
+            if 'annotations' not in metadata:
+                metadata['annotations'] = dict()
+            metadata['annotations'].update(annotations)
+            metadata['annotations'].update({
+                'scenario': scenario['name'],
+                'uniquifier': '-'.join(uniq),
+            })
+
+            spec = config['spec']
+
+            # Select clients with the required language.
+            spec['clients'] = [
+                client for client in base_config_clients
+                if client['language'] == cl
+            ]
+            if not spec['clients']:
+                raise IndexError('Client language not found in template: %s' %
+                                 cl)
+
+            # Select servers with the required language.
+            spec['servers'] = [
+                server for server in base_config_servers
+                if server['language'] == sl
+            ]
+            if not spec['servers']:
+                raise IndexError('Server language not found in template: %s' %
+                                 sl)
+
+            spec['scenariosJSON'] = scenario_str
+
+            yield config
+
+
+def parse_key_value_args(args: Optional[Iterable[str]]) -> Dict[str, str]:
+    """Parses arguments in the form key=value into a dictionary."""
+    d = dict()
+    if args is None:
+        return d
+    for arg in args:
+        key, equals, value = arg.partition('=')
+        if equals != '=':
+            raise ValueError('Expected key=value: ' + value)
+        d[key] = value
+    return d
+
+
+def config_dumper(header_comment: str) -> Type[yaml.SafeDumper]:
+    """Returns a custom dumper to dump configurations in the expected format."""
+
+    class ConfigDumper(yaml.SafeDumper):
+
+        def expect_stream_start(self):
+            super().expect_stream_start()
+            if isinstance(self.event, yaml.StreamStartEvent):
+                self.write_indent()
+                self.write_indicator(header_comment, need_whitespace=False)
+
+        def expect_block_sequence(self):
+            super().expect_block_sequence()
+            self.increase_indent()
+
+        def expect_block_sequence_item(self, first=False):
+            if isinstance(self.event, yaml.SequenceEndEvent):
+                self.indent = self.indents.pop()
+            super().expect_block_sequence_item(first)
+
+    def str_presenter(dumper, data):
+        if '\n' in data:
+            return dumper.represent_scalar('tag:yaml.org,2002:str',
+                                           data,
+                                           style='|')
+        return dumper.represent_scalar('tag:yaml.org,2002:str', data)
+
+    ConfigDumper.add_representer(str, str_presenter)
+
+    return ConfigDumper
+
+
+def main() -> None:
+    language_choices = sorted(scenario_config.LANGUAGES.keys())
+    argp = argparse.ArgumentParser(
+        description='Generates load test configs from a template.',
+        fromfile_prefix_chars='@')
+    argp.add_argument('-l',
+                      '--language',
+                      action='append',
+                      choices=language_choices,
+                      required=True,
+                      help='Language(s) to benchmark.',
+                      dest='languages')
+    argp.add_argument('-t',
+                      '--template',
+                      type=str,
+                      required=True,
+                      help='LoadTest configuration yaml file template.')
+    argp.add_argument('-s',
+                      '--substitution',
+                      action='append',
+                      default=[],
+                      help='Template substitution(s), in the form key=value.',
+                      dest='substitutions')
+    argp.add_argument('-p',
+                      '--prefix',
+                      default='',
+                      type=str,
+                      help='Test name prefix.')
+    argp.add_argument('-u',
+                      '--uniquifier_element',
+                      action='append',
+                      default=[],
+                      help='String element(s) to make the test name unique.',
+                      dest='uniquifier_elements')
+    argp.add_argument(
+        '-d',
+        action='store_true',
+        help='Use creation date and time as an additional uniquifier element.')
+    argp.add_argument('-a',
+                      '--annotation',
+                      action='append',
+                      default=[],
+                      help='metadata.annotation(s), in the form key=value.',
+                      dest='annotations')
+    argp.add_argument('-r',
+                      '--regex',
+                      default='.*',
+                      type=str,
+                      help='Regex to select scenarios to run.')
+    argp.add_argument(
+        '--category',
+        choices=['all', 'inproc', 'scalable', 'smoketest', 'sweep'],
+        default='all',
+        help='Select a category of tests to run.')
+    argp.add_argument(
+        '--allow_client_language',
+        action='append',
+        choices=language_choices,
+        default=[],
+        help='Allow cross-language scenarios with this client language.',
+        dest='allow_client_languages')
+    argp.add_argument(
+        '--allow_server_language',
+        action='append',
+        choices=language_choices,
+        default=[],
+        help='Allow cross-language scenarios with this server language.',
+        dest='allow_server_languages')
+    argp.add_argument('--runs_per_test',
+                      default=1,
+                      type=int,
+                      help='Number of copies to generate for each test.')
+    argp.add_argument('-o',
+                      '--output',
+                      type=str,
+                      help='Output file name. Output to stdout if not set.')
+    args = argp.parse_args()
+
+    substitutions = parse_key_value_args(args.substitutions)
+
+    uniquifier_elements = args.uniquifier_elements
+    if args.d:
+        uniquifier_elements.append(now_string())
+
+    annotations = parse_key_value_args(args.annotations)
+
+    with open(args.template) as f:
+        base_config = yaml.safe_load(
+            string.Template(f.read()).substitute(substitutions))
+
+    spec = base_config['spec']
+    base_config_clients = spec['clients']
+    del spec['clients']
+    base_config_servers = spec['servers']
+    del spec['servers']
+
+    client_languages = [''] + args.allow_client_languages
+    server_languages = [''] + args.allow_server_languages
+    config_generators = []
+    for l, cl, sl in itertools.product(args.languages, client_languages,
+                                       server_languages):
+        language_config = scenario_config_exporter.LanguageConfig(
+            category=args.category,
+            language=l,
+            client_language=cl,
+            server_language=sl)
+        config_generators.append(
+            gen_loadtest_configs(base_config,
+                                 base_config_clients,
+                                 base_config_servers,
+                                 args.regex,
+                                 language_config,
+                                 loadtest_name_prefix=args.prefix,
+                                 uniquifier_elements=uniquifier_elements,
+                                 annotations=annotations,
+                                 runs_per_test=args.runs_per_test))
+    configs = (config for config in itertools.chain(*config_generators))
+
+    with open(args.output, 'w') if args.output else sys.stdout as f:
+        yaml.dump_all(configs,
+                      stream=f,
+                      Dumper=config_dumper(
+                          CONFIGURATION_FILE_HEADER_COMMENT.strip()),
+                      default_flow_style=False)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/grpc/tools/run_tests/performance/loadtest_template.py b/grpc/tools/run_tests/performance/loadtest_template.py
new file mode 100755
index 0000000..9684bb9
--- /dev/null
+++ b/grpc/tools/run_tests/performance/loadtest_template.py
@@ -0,0 +1,216 @@
+#!/usr/bin/env python3
+# Copyright 2021 The 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.
+
+# This script generates a load test configuration template from a collection of
+# load test configurations.
+#
+# Configuration templates contain client and server configurations for multiple
+# languages, and may contain template substitution keys. These templates are
+# used to generate load test configurations by selecting clients and servers for
+# the required languages. The source files for template generation may be load
+# test configurations or load test configuration templates. Load test
+# configuration generation is performed by loadtest_config.py. See documentation
+# below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md
+
+import argparse
+import sys
+
+from typing import Any, Dict, Iterable, Mapping, Type
+
+import yaml
+
+import loadtest_config
+
+TEMPLATE_FILE_HEADER_COMMENT = """
+# Template generated from load test configurations by loadtest_template.py.
+#
+# Configuration templates contain client and server configurations for multiple
+# languages, and may contain template substitution keys. These templates are
+# used to generate load test configurations by selecting clients and servers for
+# the required languages. The source files for template generation may be load
+# test configurations or load test configuration templates. Load test
+# configuration generation is performed by loadtest_config.py. See documentation
+# below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md
+"""
+
+
+def loadtest_template(
+        input_file_names: Iterable[str],
+        metadata: Mapping[str, Any],
+        inject_client_pool: bool,
+        inject_server_pool: bool,
+        inject_big_query_table: bool,
+        inject_timeout_seconds: bool,
+        inject_ttl_seconds: bool) -> Dict[str, Any]:  # yapf: disable
+    """Generates the load test template."""
+    clients = list()
+    servers = list()
+    spec = dict()
+    client_languages = set()
+    server_languages = set()
+    template = {
+        'apiVersion': 'e2etest.grpc.io/v1',
+        'kind': 'LoadTest',
+        'metadata': metadata,
+    }
+    for input_file_name in input_file_names:
+        with open(input_file_name) as f:
+            input_config = yaml.safe_load(f.read())
+
+            if input_config.get('apiVersion') != template['apiVersion']:
+                raise ValueError('Unexpected api version in file {}: {}'.format(
+                    input_file_name, input_config.get('apiVersion')))
+            if input_config.get('kind') != template['kind']:
+                raise ValueError('Unexpected kind in file {}: {}'.format(
+                    input_file_name, input_config.get('kind')))
+
+            for client in input_config['spec']['clients']:
+                if client['language'] in client_languages:
+                    continue
+                if inject_client_pool:
+                    client['pool'] = '${client_pool}'
+                clients.append(client)
+                client_languages.add(client['language'])
+
+            for server in input_config['spec']['servers']:
+                if server['language'] in server_languages:
+                    continue
+                if inject_server_pool:
+                    server['pool'] = '${server_pool}'
+                servers.append(server)
+                server_languages.add(server['language'])
+
+            input_spec = input_config['spec']
+            del input_spec['clients']
+            del input_spec['servers']
+            del input_spec['scenariosJSON']
+            spec.update(input_config['spec'])
+
+    clients.sort(key=lambda x: x['language'])
+    servers.sort(key=lambda x: x['language'])
+
+    spec.update({
+        'clients': clients,
+        'servers': servers,
+    })
+
+    if inject_big_query_table:
+        if 'results' not in spec:
+            spec['results'] = dict()
+        spec['results']['bigQueryTable'] = '${big_query_table}'
+    if inject_timeout_seconds:
+        spec['timeoutSeconds'] = '${timeout_seconds}'
+    if inject_ttl_seconds:
+        spec['ttlSeconds'] = '${ttl_seconds}'
+
+    template['spec'] = spec
+
+    return template
+
+
+def template_dumper(header_comment: str) -> Type[yaml.SafeDumper]:
+    """Returns a custom dumper to dump templates in the expected format."""
+
+    class TemplateDumper(yaml.SafeDumper):
+
+        def expect_stream_start(self):
+            super().expect_stream_start()
+            if isinstance(self.event, yaml.StreamStartEvent):
+                self.write_indent()
+                self.write_indicator(header_comment, need_whitespace=False)
+
+        def expect_block_sequence(self):
+            super().expect_block_sequence()
+            self.increase_indent()
+
+        def expect_block_sequence_item(self, first=False):
+            if isinstance(self.event, yaml.SequenceEndEvent):
+                self.indent = self.indents.pop()
+            super().expect_block_sequence_item(first)
+
+    return TemplateDumper
+
+
+def main() -> None:
+    argp = argparse.ArgumentParser(
+        description='Creates a load test config generator template.',
+        fromfile_prefix_chars='@')
+    argp.add_argument('-i',
+                      '--inputs',
+                      action='extend',
+                      nargs='+',
+                      type=str,
+                      help='Input files.')
+    argp.add_argument('-o',
+                      '--output',
+                      type=str,
+                      help='Output file. Outputs to stdout if not set.')
+    argp.add_argument(
+        '--inject_client_pool',
+        action='store_true',
+        help='Set spec.client(s).pool values to \'${client_pool}\'.')
+    argp.add_argument(
+        '--inject_server_pool',
+        action='store_true',
+        help='Set spec.server(s).pool values to \'${server_pool}\'.')
+    argp.add_argument(
+        '--inject_big_query_table',
+        action='store_true',
+        help='Set spec.results.bigQueryTable to \'${big_query_table}\'.')
+    argp.add_argument('--inject_timeout_seconds',
+                      action='store_true',
+                      help='Set spec.timeoutSeconds to \'${timeout_seconds}\'.')
+    argp.add_argument('--inject_ttl_seconds',
+                      action='store_true',
+                      help='Set timeout ')
+    argp.add_argument('-n',
+                      '--name',
+                      default='',
+                      type=str,
+                      help='metadata.name.')
+    argp.add_argument('-a',
+                      '--annotation',
+                      action='append',
+                      type=str,
+                      help='metadata.annotation(s), in the form key=value.',
+                      dest='annotations')
+    args = argp.parse_args()
+
+    annotations = loadtest_config.parse_key_value_args(args.annotations)
+
+    metadata = {'name': args.name}
+    if annotations:
+        metadata['annotations'] = annotations
+
+    template = loadtest_template(
+        input_file_names=args.inputs,
+        metadata=metadata,
+        inject_client_pool=args.inject_client_pool,
+        inject_server_pool=args.inject_server_pool,
+        inject_big_query_table=args.inject_big_query_table,
+        inject_timeout_seconds=args.inject_timeout_seconds,
+        inject_ttl_seconds=args.inject_ttl_seconds)
+
+    with open(args.output, 'w') if args.output else sys.stdout as f:
+        yaml.dump(template,
+                  stream=f,
+                  Dumper=template_dumper(TEMPLATE_FILE_HEADER_COMMENT.strip()),
+                  default_flow_style=False)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/grpc/tools/run_tests/performance/remote_host_prepare.sh b/grpc/tools/run_tests/performance/remote_host_prepare.sh
index 685c435..2a7c5e7 100755
--- a/grpc/tools/run_tests/performance/remote_host_prepare.sh
+++ b/grpc/tools/run_tests/performance/remote_host_prepare.sh
@@ -18,7 +18,7 @@
 cd "$(dirname "$0")/../../.."
 
 # TODO(jtattermusch): To be sure there are no running processes that would
-# mess with the results, be rough and reboot the slave here
+# mess with the results, be rough and reboot the worker here
 # and wait for it to come back online.
 ssh "${USER_AT_HOST}" "killall -9 qps_worker dotnet mono node ruby worker || true"
 
@@ -29,7 +29,7 @@
 # cleanup after previous builds
 ssh "${USER_AT_HOST}" "rm -rf ~/performance_workspace && mkdir -p ~/performance_workspace"
 
-# push the current sources to the slave and unpack it.
+# push the current sources to the worker and unpack it.
 scp ../grpc.tar "${USER_AT_HOST}:~/performance_workspace"
 # Windows workaround: attempt to untar twice, first run is going to fail
 # with symlink creation error(s).
diff --git a/grpc/tools/run_tests/performance/scenario_config.py b/grpc/tools/run_tests/performance/scenario_config.py
index 9e710f1..52d63f3 100644
--- a/grpc/tools/run_tests/performance/scenario_config.py
+++ b/grpc/tools/run_tests/performance/scenario_config.py
@@ -53,8 +53,11 @@
 
 
 def remove_nonproto_fields(scenario):
-    """Remove special-purpose that contains some extra info about the scenario
-  but don't belong to the ScenarioConfig protobuf message"""
+    """Removes special-purpose fields that don't belong in the protobuf.
+
+    This function removes additional information about the scenario that is not
+    included in the ScenarioConfig protobuf message.
+    """
     scenario.pop('CATEGORIES', None)
     scenario.pop('CLIENT_LANGUAGE', None)
     scenario.pop('SERVER_LANGUAGE', None)
@@ -596,7 +599,8 @@
                                 1, 200000, math.sqrt(10)):
                             if synchronicity == 'sync' and outstanding > 1200:
                                 continue
-                            if outstanding < channels: continue
+                            if outstanding < channels:
+                                continue
                             yield _ping_pong_scenario(
                                 'cpp_protobuf_%s_%s_qps_unconstrained_%s_%d_channels_%d_outstanding'
                                 % (synchronicity, rpc_type, secstr, channels,
diff --git a/grpc/tools/run_tests/performance/scenario_config_exporter.py b/grpc/tools/run_tests/performance/scenario_config_exporter.py
index 23aad5c..d8837fd 100755
--- a/grpc/tools/run_tests/performance/scenario_config_exporter.py
+++ b/grpc/tools/run_tests/performance/scenario_config_exporter.py
@@ -14,48 +14,212 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Helper script to extract JSON scenario definitions from scenario_config.py
-# Useful to construct "ScenariosJSON" configuration accepted by the OSS benchmarks framework
+# Library to extract scenario definitions from scenario_config.py.
+#
+# Contains functions to filter, analyze and dump scenario definitions.
+#
+# This library is used in loadtest_config.py to generate the "scenariosJSON"
+# field in the format accepted by the OSS benchmarks framework.
 # See https://github.com/grpc/test-infra/blob/master/config/samples/cxx_example_loadtest.yaml
+#
+# It can also be used to dump scenarios to files, to count scenarios by
+# language, and to export scenario languages in a format that can be used for
+# automation.
+#
+# Example usage:
+#
+# scenario_config.py --export_scenarios -l cxx -f cxx_scenario_ -r '.*' \
+#     --category=scalable
+#
+# scenario_config.py --count_scenarios
+#
+# scenario_config.py --count_scenarios --category=scalable
+#
+# For usage of the language config output, see loadtest_config.py.
 
+import argparse
+import collections
 import json
 import re
-import scenario_config
 import sys
 
+from typing import Any, Callable, Dict, Iterable, NamedTuple
 
-def get_json_scenarios(language_name, scenario_name_regex='.*', category='all'):
-    """Returns list of scenarios that match given constraints."""
-    result = []
-    scenarios = scenario_config.LANGUAGES[language_name].scenarios()
-    for scenario_json in scenarios:
-        if re.search(scenario_name_regex, scenario_json['name']):
-            # if the 'CATEGORIES' key is missing, treat scenario as part of 'scalable' and 'smoketest'
-            # this matches the behavior of run_performance_tests.py
-            scenario_categories = scenario_json.get('CATEGORIES',
-                                                    ['scalable', 'smoketest'])
-            # TODO(jtattermusch): consider adding filtering for 'CLIENT_LANGUAGE' and 'SERVER_LANGUAGE'
-            # fields, before the get stripped away.
-            if category in scenario_categories or category == 'all':
-                scenario_json_stripped = scenario_config.remove_nonproto_fields(
-                    scenario_json)
-                result.append(scenario_json_stripped)
-    return result
+import scenario_config
+
+# Language parameters for load test config generation.
+LanguageConfig = NamedTuple('LanguageConfig', [('category', str),
+                                               ('language', str),
+                                               ('client_language', str),
+                                               ('server_language', str)])
 
 
-def dump_to_json_files(json_scenarios, filename_prefix='scenario_dump_'):
-    """Dump a list of json scenarios to json files"""
-    for scenario in json_scenarios:
-        filename = "%s%s.json" % (filename_prefix, scenario['name'])
-        print('Writing file %s' % filename, file=sys.stderr)
+def as_dict_no_empty_values(self):
+    """Returns the parameters as a dictionary, ignoring empty values."""
+    return dict((item for item in self._asdict().items() if item[1]))
+
+
+def category_string(categories: Iterable[str], category: str) -> str:
+    """Converts a list of categories into a single string for counting."""
+    if category != 'all':
+        return category if category in categories else ''
+
+    main_categories = ('scalable', 'smoketest')
+    s = set(categories)
+
+    c = [m for m in main_categories if m in s]
+    s.difference_update(main_categories)
+    c.extend(s)
+    return ' '.join(c)
+
+
+def gen_scenario_languages(category: str) -> Iterable[LanguageConfig]:
+    """Generates tuples containing the languages specified in each scenario."""
+    for language in scenario_config.LANGUAGES:
+        for scenario in scenario_config.LANGUAGES[language].scenarios():
+            client_language = scenario.get('CLIENT_LANGUAGE', '')
+            server_language = scenario.get('SERVER_LANGUAGE', '')
+            categories = scenario.get('CATEGORIES', [])
+            if category != 'all' and category not in categories:
+                continue
+            cat = category_string(categories, category)
+            yield LanguageConfig(category=cat,
+                                 language=language,
+                                 client_language=client_language,
+                                 server_language=server_language)
+
+
+def scenario_filter(
+    scenario_name_regex: str = '.*',
+    category: str = 'all',
+    client_language: str = '',
+    server_language: str = '',
+) -> Callable[[Dict[str, Any]], bool]:
+    """Returns a function to filter scenarios to process."""
+
+    def filter_scenario(scenario: Dict[str, Any]) -> bool:
+        """Filters scenarios that match specified criteria."""
+        if not re.search(scenario_name_regex, scenario["name"]):
+            return False
+        # if the 'CATEGORIES' key is missing, treat scenario as part of
+        # 'scalable' and 'smoketest'. This matches the behavior of
+        # run_performance_tests.py.
+        scenario_categories = scenario.get('CATEGORIES',
+                                           ['scalable', 'smoketest'])
+        if category not in scenario_categories and category != 'all':
+            return False
+
+        scenario_client_language = scenario.get('CLIENT_LANGUAGE', '')
+        if client_language != scenario_client_language:
+            return False
+
+        scenario_server_language = scenario.get('SERVER_LANGUAGE', '')
+        if server_language != scenario_server_language:
+            return False
+
+        return True
+
+    return filter_scenario
+
+
+def gen_scenarios(
+    language_name: str, scenario_filter_function: Callable[[Dict[str, Any]],
+                                                           bool]
+) -> Iterable[Dict[str, Any]]:
+    """Generates scenarios that match a given filter function."""
+    return map(
+        scenario_config.remove_nonproto_fields,
+        filter(scenario_filter_function,
+               scenario_config.LANGUAGES[language_name].scenarios()))
+
+
+def dump_to_json_files(scenarios: Iterable[Dict[str, Any]],
+                       filename_prefix: str) -> None:
+    """Dumps a list of scenarios to JSON files"""
+    count = 0
+    for scenario in scenarios:
+        filename = '{}{}.json'.format(filename_prefix, scenario['name'])
+        print('Writing file {}'.format(filename), file=sys.stderr)
         with open(filename, 'w') as outfile:
-            # the dump file should have {"scenarios" : []} as the top level element
+            # The dump file should have {"scenarios" : []} as the top level
+            # element, when embedded in a LoadTest configuration YAML file.
             json.dump({'scenarios': [scenario]}, outfile, indent=2)
+        count += 1
+    print('Wrote {} scenarios'.format(count), file=sys.stderr)
+
+
+def main() -> None:
+    language_choices = sorted(scenario_config.LANGUAGES.keys())
+    argp = argparse.ArgumentParser(description='Exports scenarios to files.')
+    argp.add_argument('--export_scenarios',
+                      action='store_true',
+                      help='Export scenarios to JSON files.')
+    argp.add_argument('--count_scenarios',
+                      action='store_true',
+                      help='Count scenarios for all test languages.')
+    argp.add_argument('-l',
+                      '--language',
+                      choices=language_choices,
+                      help='Language to export.')
+    argp.add_argument('-f',
+                      '--filename_prefix',
+                      default='scenario_dump_',
+                      type=str,
+                      help='Prefix for exported JSON file names.')
+    argp.add_argument('-r',
+                      '--regex',
+                      default='.*',
+                      type=str,
+                      help='Regex to select scenarios to run.')
+    argp.add_argument(
+        '--category',
+        default='all',
+        choices=['all', 'inproc', 'scalable', 'smoketest', 'sweep'],
+        help='Select scenarios for a category of tests.')
+    argp.add_argument(
+        '--client_language',
+        default='',
+        choices=language_choices,
+        help='Select only scenarios with a specified client language.')
+    argp.add_argument(
+        '--server_language',
+        default='',
+        choices=language_choices,
+        help='Select only scenarios with a specified server language.')
+    args = argp.parse_args()
+
+    if args.export_scenarios and not args.language:
+        print('Dumping scenarios requires a specified language.',
+              file=sys.stderr)
+        argp.print_usage(file=sys.stderr)
+        return
+
+    if args.export_scenarios:
+        s_filter = scenario_filter(scenario_name_regex=args.regex,
+                                   category=args.category,
+                                   client_language=args.client_language,
+                                   server_language=args.server_language)
+        scenarios = gen_scenarios(args.language, s_filter)
+        dump_to_json_files(scenarios, args.filename_prefix)
+
+    if args.count_scenarios:
+        print('Scenario count for all languages (category: {}):'.format(
+            args.category))
+        print('{:>5}  {:16} {:8} {:8} {}'.format('Count', 'Language', 'Client',
+                                                 'Server', 'Categories'))
+        c = collections.Counter(gen_scenario_languages(args.category))
+        total = 0
+        for ((cat, l, cl, sl), count) in c.most_common():
+            print('{count:5}  {l:16} {cl:8} {sl:8} {cat}'.format(l=l,
+                                                                 cl=cl,
+                                                                 sl=sl,
+                                                                 count=count,
+                                                                 cat=cat))
+            total += count
+
+        print('\n{:>5}  total scenarios (category: {})'.format(
+            total, args.category))
 
 
 if __name__ == "__main__":
-    # example usage: extract C# scenarios and dump them as .json files
-    scenarios = get_json_scenarios('csharp',
-                                   scenario_name_regex='.*',
-                                   category='scalable')
-    dump_to_json_files(scenarios, 'scenario_dump_')
+    main()
diff --git a/grpc/tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml b/grpc/tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml
new file mode 100644
index 0000000..fb1d633
--- /dev/null
+++ b/grpc/tools/run_tests/performance/templates/loadtest_template_basic_all_languages.yaml
@@ -0,0 +1,259 @@
+# Template generated from load test configurations by loadtest_template.py.
+#
+# Configuration templates contain client and server configurations for multiple
+# languages, and may contain template substitution keys. These templates are
+# used to generate load test configurations by selecting clients and servers for
+# the required languages. The source files for template generation may be load
+# test configurations or load test configuration templates. Load test
+# configuration generation is performed by loadtest_config.py. See documentation
+# below:
+# https://github.com/grpc/grpc/blob/master/tools/run_tests/performance/README.md
+apiVersion: e2etest.grpc.io/v1
+kind: LoadTest
+metadata:
+  name: basic_all_languages
+spec:
+  clients:
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: csharp
+      pool: ${client_pool}
+      run:
+        args:
+          - exec
+          - qps_worker/Grpc.IntegrationTesting.QpsWorker.dll
+        command:
+          - dotnet
+    - build:
+        args:
+          - build
+          - //test/cpp/qps:qps_worker
+        command:
+          - bazel
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: cxx
+      pool: ${client_pool}
+      run:
+        command:
+          - bazel-bin/test/cpp/qps/qps_worker
+    - build:
+        args:
+          - build
+          - -o
+          - /src/workspace/bin/worker
+          - ./benchmark/worker
+        command:
+          - go
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-go.git
+      language: go
+      pool: ${client_pool}
+      run:
+        command:
+          - /src/workspace/bin/worker
+    - build:
+        args:
+          - -PskipAndroid=true
+          - -PskipCodegen=true
+          - :grpc-benchmarks:installDist
+        command:
+          - gradle
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-java.git
+      language: java
+      pool: ${client_pool}
+      run:
+        command:
+          - benchmarks/build/install/grpc-benchmarks/bin/benchmark_worker
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-node.git
+      language: node
+      pool: ${client_pool}
+      run:
+        args:
+          - -r
+          - ./test/fixtures/native_native.js
+          - test/performance/worker.js
+          - --benchmark_impl=grpc
+        command:
+          - node
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: php
+      pool: ${client_pool}
+      run:
+        command:
+          - bash
+          - /run_scripts/run_worker.sh
+    - build:
+        args:
+          - build
+          - //src/python/grpcio_tests/tests/qps:qps_worker
+        command:
+          - bazel
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: python
+      pool: ${client_pool}
+      run:
+        command:
+          - bazel-bin/src/python/grpcio_tests/tests/qps/qps_worker
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc
+      language: ruby
+      pool: ${client_pool}
+      run:
+        args:
+          - src/ruby/qps/worker.rb
+        command:
+          - ruby
+  results:
+    bigQueryTable: ${big_query_table}
+  servers:
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: csharp
+      pool: ${server_pool}
+      run:
+        args:
+          - exec
+          - qps_worker/Grpc.IntegrationTesting.QpsWorker.dll
+        command:
+          - dotnet
+    - build:
+        args:
+          - build
+          - //test/cpp/qps:qps_worker
+        command:
+          - bazel
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: cxx
+      pool: ${server_pool}
+      run:
+        args:
+          - --server_port=10010
+        command:
+          - bazel-bin/test/cpp/qps/qps_worker
+    - build:
+        args:
+          - build
+          - -o
+          - /src/workspace/bin/worker
+          - ./benchmark/worker
+        command:
+          - go
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-go.git
+      language: go
+      pool: ${server_pool}
+      run:
+        command:
+          - /src/workspace/bin/worker
+    - build:
+        args:
+          - -PskipAndroid=true
+          - -PskipCodegen=true
+          - :grpc-benchmarks:installDist
+        command:
+          - gradle
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-java.git
+      language: java
+      pool: ${server_pool}
+      run:
+        command:
+          - benchmarks/build/install/grpc-benchmarks/bin/benchmark_worker
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc-node.git
+      language: node
+      pool: ${server_pool}
+      run:
+        args:
+          - -r
+          - ./test/fixtures/native_native.js
+          - test/performance/worker.js
+          - --benchmark_impl=grpc
+        command:
+          - node
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: php
+      pool: ${server_pool}
+      run:
+        command:
+          - bash
+          - /run_scripts/run_worker.sh
+    - build:
+        args:
+          - build
+          - //src/python/grpcio_tests/tests/qps:qps_worker
+        command:
+          - bazel
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc.git
+      language: python
+      pool: ${server_pool}
+      run:
+        command:
+          - bazel-bin/src/python/grpcio_tests/tests/qps/qps_worker
+    - build:
+        command:
+          - bash
+          - /build_scripts/build_qps_worker.sh
+      clone:
+        gitRef: master
+        repo: https://github.com/grpc/grpc
+      language: ruby
+      pool: ${server_pool}
+      run:
+        args:
+          - src/ruby/qps/worker.rb
+        command:
+          - ruby
+  timeoutSeconds: ${timeout_seconds}
+  ttlSeconds: 86400
diff --git a/grpc/tools/run_tests/python_utils/check_on_pr.py b/grpc/tools/run_tests/python_utils/check_on_pr.py
index 6516e9d..7dd0b25 100644
--- a/grpc/tools/run_tests/python_utils/check_on_pr.py
+++ b/grpc/tools/run_tests/python_utils/check_on_pr.py
@@ -55,7 +55,7 @@
                 url='https://api.github.com/app/installations/%s/access_tokens'
                 % _INSTALLATION_ID,
                 headers={
-                    'Authorization': 'Bearer %s' % _jwt_token().decode('ASCII'),
+                    'Authorization': 'Bearer %s' % _jwt_token(),
                     'Accept': 'application/vnd.github.machine-man-preview+json',
                 })
 
@@ -65,8 +65,8 @@
                     'exp': time.time() + 60
                 }
                 break
-            except (KeyError, ValueError) as e:
-                traceback.print_exc(e)
+            except (KeyError, ValueError):
+                traceback.print_exc()
                 print('HTTP Status %d %s' % (resp.status_code, resp.reason))
                 print("Fetch access token from Github API failed:")
                 print(resp.text)
diff --git a/grpc/tools/run_tests/python_utils/filter_pull_request_tests.py b/grpc/tools/run_tests/python_utils/filter_pull_request_tests.py
index 5072df1..c8574ad 100644
--- a/grpc/tools/run_tests/python_utils/filter_pull_request_tests.py
+++ b/grpc/tools/run_tests/python_utils/filter_pull_request_tests.py
@@ -18,7 +18,7 @@
 
 import re
 import six
-from subprocess import check_output
+import subprocess
 
 
 class TestSuite:
@@ -61,12 +61,12 @@
     _LINUX_TEST_SUITE, _WINDOWS_TEST_SUITE, _MACOS_TEST_SUITE
 ]
 
-# Dictionary of whitelistable files where the key is a regex matching changed files
+# Dictionary of allowlistable files where the key is a regex matching changed files
 # and the value is a list of tests that should be run. An empty list means that
 # the changed files should not trigger any tests. Any changed file that does not
 # match any of these regexes will trigger all tests
 # DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU ARE DOING (be careful even if you do)
-_WHITELIST_DICT = {
+_ALLOWLIST_DICT = {
     '^doc/': [],
     '^examples/': [],
     '^include/grpc\+\+/': [_CPP_TEST_SUITE],
@@ -86,6 +86,8 @@
     '^test/distrib/php/': [_PHP_TEST_SUITE],
     '^test/distrib/python/': [_PYTHON_TEST_SUITE],
     '^test/distrib/ruby/': [_RUBY_TEST_SUITE],
+    '^tools/run_tests/xds_k8s_test_driver/': [],
+    '^tools/internal_ci/linux/grpc_xds_k8s.*': [],
     '^vsprojects/': [_WINDOWS_TEST_SUITE],
     'composer\.json$': [_PHP_TEST_SUITE],
     'config\.m4$': [_PHP_TEST_SUITE],
@@ -110,11 +112,11 @@
     'setup\.py$': [_PYTHON_TEST_SUITE]
 }
 
-# Regex that combines all keys in _WHITELIST_DICT
-_ALL_TRIGGERS = "(" + ")|(".join(_WHITELIST_DICT.keys()) + ")"
+# Regex that combines all keys in _ALLOWLIST_DICT
+_ALL_TRIGGERS = "(" + ")|(".join(_ALLOWLIST_DICT.keys()) + ")"
 
 # Add all triggers to their respective test suites
-for trigger, test_suites in six.iteritems(_WHITELIST_DICT):
+for trigger, test_suites in six.iteritems(_ALLOWLIST_DICT):
     for test_suite in test_suites:
         test_suite.add_trigger(trigger)
 
@@ -125,10 +127,11 @@
   """
     # Get file changes between branch and merge-base of specified branch
     # Not combined to be Windows friendly
-    base_commit = check_output(["git", "merge-base", base_branch,
-                                "HEAD"]).rstrip()
-    return check_output(["git", "diff", base_commit, "--name-only",
-                         "HEAD"]).splitlines()
+    base_commit = subprocess.check_output(
+        ["git", "merge-base", base_branch, "HEAD"]).decode("UTF-8").rstrip()
+    return subprocess.check_output(
+        ["git", "diff", base_commit, "--name-only",
+         "HEAD"]).decode("UTF-8").splitlines()
 
 
 def _can_skip_tests(file_names, triggers):
@@ -165,7 +168,7 @@
   :return: boolean indicating whether C/C++ changes are made in pull request
   """
     changed_files = _get_changed_files(base_branch)
-    # Run all tests if any changed file is not in the whitelist dictionary
+    # Run all tests if any changed file is not in the allowlist dictionary
     for changed_file in changed_files:
         if not re.match(_ALL_TRIGGERS, changed_file):
             return True
@@ -187,7 +190,7 @@
         print('  %s' % changed_file)
     print('')
 
-    # Run all tests if any changed file is not in the whitelist dictionary
+    # Run all tests if any changed file is not in the allowlist dictionary
     for changed_file in changed_files:
         if not re.match(_ALL_TRIGGERS, changed_file):
             return (tests)
diff --git a/grpc/tools/run_tests/python_utils/jobset.py b/grpc/tools/run_tests/python_utils/jobset.py
index d9ae062..552d16c 100755
--- a/grpc/tools/run_tests/python_utils/jobset.py
+++ b/grpc/tools/run_tests/python_utils/jobset.py
@@ -130,15 +130,15 @@
         try:
             if platform_string() == 'windows' or not sys.stdout.isatty():
                 if explanatory_text:
-                    logging.info(explanatory_text)
+                    logging.info(explanatory_text.decode('utf8'))
                 logging.info('%s: %s', tag, msg)
             else:
                 sys.stdout.write(
                     '%s%s%s\x1b[%d;%dm%s\x1b[0m: %s%s' %
                     (_BEGINNING_OF_LINE, _CLEAR_LINE, '\n%s' %
-                     explanatory_text if explanatory_text is not None else '',
-                     _COLORS[_TAG_COLOR[tag]][1], _COLORS[_TAG_COLOR[tag]][0],
-                     tag, msg, '\n'
+                     explanatory_text.decode('utf8') if explanatory_text
+                     is not None else '', _COLORS[_TAG_COLOR[tag]][1],
+                     _COLORS[_TAG_COLOR[tag]][0], tag, msg, '\n'
                      if do_newline or explanatory_text is not None else ''))
             sys.stdout.flush()
             return
@@ -212,6 +212,9 @@
     def __cmp__(self, other):
         return self.identity() == other.identity()
 
+    def __lt__(self, other):
+        return self.identity() < other.identity()
+
     def __repr__(self):
         return 'JobSpec(shortname=%s, cmdline=%s)' % (self.shortname,
                                                       self.cmdline)
@@ -274,7 +277,10 @@
                 os.makedirs(logfile_dir)
             self._logfile = open(self._spec.logfilename, 'w+')
         else:
-            self._logfile = tempfile.TemporaryFile()
+            # macOS: a series of quick os.unlink invocation might cause OS
+            # error during the creation of temporary file. By using
+            # NamedTemporaryFile, we defer the removal of file and directory.
+            self._logfile = tempfile.NamedTemporaryFile()
         env = dict(os.environ)
         env.update(self._spec.environ)
         env.update(self._add_env)
@@ -456,14 +462,17 @@
                 message('SKIPPED', spec.shortname, do_newline=True)
                 self.resultset[spec.shortname] = [skipped_job_result]
                 return True
-            if self.cancelled(): return False
+            if self.cancelled():
+                return False
             current_cpu_cost = self.cpu_cost()
-            if current_cpu_cost == 0: break
+            if current_cpu_cost == 0:
+                break
             if current_cpu_cost + spec.cpu_cost <= self._maxjobs:
                 if len(self._running) < self._maxjobs_cpu_agnostic:
                     break
             self.reap(spec.shortname, spec.cpu_cost)
-        if self.cancelled(): return False
+        if self.cancelled():
+            return False
         job = Job(spec, self._newline_on_success, self._travis, self._add_env,
                   self._quiet_success)
         self._running.add(job)
@@ -477,7 +486,8 @@
             dead = set()
             for job in self._running:
                 st = eintr_be_gone(lambda: job.state())
-                if st == _RUNNING: continue
+                if st == _RUNNING:
+                    continue
                 if st == _FAILURE or st == _KILLED:
                     self._failures += 1
                     if self._stop_on_failure:
@@ -491,7 +501,8 @@
                 if not self._quiet_success or job.result.state != 'PASSED':
                     self.resultset[job.GetSpec().shortname].append(job.result)
                 self._running.remove(job)
-            if dead: return
+            if dead:
+                return
             if not self._travis and platform_string() != 'windows':
                 rstr = '' if self._remaining is None else '%d queued, ' % self._remaining
                 if self._remaining is not None and self._completed > 0:
@@ -518,8 +529,10 @@
 
     def cancelled(self):
         """Poll for cancellation."""
-        if self._cancelled: return True
-        if not self._check_cancelled(): return False
+        if self._cancelled:
+            return True
+        if not self._check_cancelled():
+            return False
         for job in self._running:
             job.kill()
         self._cancelled = True
@@ -527,7 +540,8 @@
 
     def finish(self):
         while self._running:
-            if self.cancelled(): pass  # poll cancellation
+            if self.cancelled():
+                pass  # poll cancellation
             self.reap()
         if platform_string() != 'windows':
             signal.alarm(0)
diff --git a/grpc/tools/run_tests/python_utils/port_server.py b/grpc/tools/run_tests/python_utils/port_server.py
index 64d6c90..c934f83 100755
--- a/grpc/tools/run_tests/python_utils/port_server.py
+++ b/grpc/tools/run_tests/python_utils/port_server.py
@@ -71,7 +71,8 @@
 def can_connect(port):
     # this test is only really useful on unices where SO_REUSE_PORT is available
     # so on Windows, where this test is expensive, skip it
-    if platform.system() == 'Windows': return False
+    if platform.system() == 'Windows':
+        return False
     s = socket.socket()
     try:
         s.connect(('localhost', port))
@@ -102,7 +103,8 @@
     ]
     random.shuffle(chk)
     for i in chk:
-        if len(pool) > 100: break
+        if len(pool) > 100:
+            break
         if i in in_use:
             age = time.time() - in_use[i]
             if age < max_timeout:
diff --git a/grpc/tools/run_tests/python_utils/start_port_server.py b/grpc/tools/run_tests/python_utils/start_port_server.py
index 165e733..5915f44 100644
--- a/grpc/tools/run_tests/python_utils/start_port_server.py
+++ b/grpc/tools/run_tests/python_utils/start_port_server.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
 # Copyright 2015 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/grpc/tools/run_tests/python_utils/watch_dirs.py b/grpc/tools/run_tests/python_utils/watch_dirs.py
index f2f1c00..7befcca 100755
--- a/grpc/tools/run_tests/python_utils/watch_dirs.py
+++ b/grpc/tools/run_tests/python_utils/watch_dirs.py
@@ -39,7 +39,8 @@
                 continue
             for root, _, files in os.walk(path):
                 for f in files:
-                    if f and f[0] == '.': continue
+                    if f and f[0] == '.':
+                        continue
                     try:
                         st = os.stat(os.path.join(root, f))
                     except OSError as e:
diff --git a/grpc/tools/run_tests/run_microbenchmark.py b/grpc/tools/run_tests/run_microbenchmark.py
index a275e16..7cd4b96 100755
--- a/grpc/tools/run_tests/run_microbenchmark.py
+++ b/grpc/tools/run_tests/run_microbenchmark.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,12 +13,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import cgi
+import argparse
+import html
 import multiprocessing
 import os
 import subprocess
 import sys
-import argparse
 
 import python_utils.jobset as jobset
 import python_utils.start_port_server as start_port_server
@@ -41,7 +41,8 @@
     out = ''
     for c in s:
         if c in '<>, /':
-            if len(out) and out[-1] == '_': continue
+            if len(out) and out[-1] == '_':
+                continue
             out += '_'
         else:
             out += c
@@ -65,13 +66,13 @@
 
 def link(txt, tgt):
     global index_html
-    index_html += "<p><a href=\"%s\">%s</a></p>\n" % (cgi.escape(
-        tgt, quote=True), cgi.escape(txt))
+    index_html += "<p><a href=\"%s\">%s</a></p>\n" % (html.escape(
+        tgt, quote=True), html.escape(txt))
 
 
 def text(txt):
     global index_html
-    index_html += "<p><pre>%s</pre></p>\n" % cgi.escape(txt)
+    index_html += "<p><pre>%s</pre></p>\n" % html.escape(txt)
 
 
 def _bazel_build_benchmark(bm_name, cfg):
@@ -94,7 +95,7 @@
     for line in subprocess.check_output([
             'bazel-bin/test/cpp/microbenchmarks/%s' % bm_name,
             '--benchmark_list_tests'
-    ]).splitlines():
+    ]).decode('UTF-8').splitlines():
         link(line, '%s.txt' % fnize(line))
         benchmarks.append(
             jobset.JobSpec([
@@ -148,7 +149,7 @@
     for line in subprocess.check_output([
             'bazel-bin/test/cpp/microbenchmarks/%s' % bm_name,
             '--benchmark_list_tests'
-    ]).splitlines():
+    ]).decode('UTF-8').splitlines():
         link(line, '%s.svg' % fnize(line))
         benchmarks.append(
             jobset.JobSpec([
@@ -198,7 +199,7 @@
     ]
     if args.summary_time is not None:
         cmd += ['--benchmark_min_time=%d' % args.summary_time]
-    return subprocess.check_output(cmd)
+    return subprocess.check_output(cmd).decode('UTF-8')
 
 
 def collect_summary(bm_name, args):
@@ -213,7 +214,7 @@
                     'tools/profiling/microbenchmarks/bm2bq.py',
                     '%s.counters.json' % bm_name,
                     '%s.opt.json' % bm_name
-                ]))
+                ]).decode('UTF-8'))
         subprocess.check_call([
             'bq', 'load', 'microbenchmarks.microbenchmarks',
             '%s.csv' % bm_name
diff --git a/grpc/tools/run_tests/run_tests.py b/grpc/tools/run_tests/run_tests.py
index d87a2f2..5176331 100755
--- a/grpc/tools/run_tests/run_tests.py
+++ b/grpc/tools/run_tests/run_tests.py
@@ -355,9 +355,10 @@
                             tests = subprocess.check_output(
                                 [binary, '--benchmark_list_tests'],
                                 stderr=fnull)
-                        for line in tests.split('\n'):
+                        for line in tests.decode().split('\n'):
                             test = line.strip()
-                            if not test: continue
+                            if not test:
+                                continue
                             cmdline = [binary,
                                        '--benchmark_filter=%s$' % test
                                       ] + target['args']
@@ -380,10 +381,12 @@
                             tests = subprocess.check_output(
                                 [binary, '--gtest_list_tests'], stderr=fnull)
                         base = None
-                        for line in tests.split('\n'):
+                        for line in tests.decode().split('\n'):
                             i = line.find('#')
-                            if i >= 0: line = line[:i]
-                            if not line: continue
+                            if i >= 0:
+                                line = line[:i]
+                            if not line:
+                                continue
                             if line[0] != ' ':
                                 base = line.strip()
                             else:
@@ -484,14 +487,14 @@
             return ('buster', [])
         elif compiler == 'gcc_musl':
             return ('alpine', [])
-        elif compiler == 'clang3.6':
+        elif compiler == 'clang4.0':
             return ('ubuntu1604',
                     self._clang_cmake_configure_extra_args(
-                        version_suffix='-3.6'))
-        elif compiler == 'clang3.7':
+                        version_suffix='-4.0'))
+        elif compiler == 'clang5.0':
             return ('ubuntu1604',
                     self._clang_cmake_configure_extra_args(
-                        version_suffix='-3.7'))
+                        version_suffix='-5.0'))
         else:
             raise Exception('Compiler %s not supported.' % compiler)
 
@@ -1324,7 +1327,8 @@
         return 0
     try:
         n = int(arg_str)
-        if n <= 0: raise ValueError
+        if n <= 0:
+            raise ValueError
         return n
     except:
         msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
@@ -1421,8 +1425,8 @@
         'gcc7.4',
         'gcc8.3',
         'gcc_musl',
-        'clang3.6',
-        'clang3.7',
+        'clang4.0',
+        'clang5.0',
         'python2.7',
         'python3.5',
         'python3.6',
diff --git a/grpc/tools/run_tests/run_tests_matrix.py b/grpc/tools/run_tests/run_tests_matrix.py
index 2147e80..951229d 100755
--- a/grpc/tools/run_tests/run_tests_matrix.py
+++ b/grpc/tools/run_tests/run_tests_matrix.py
@@ -266,8 +266,8 @@
 
     # portability C and C++ on x64
     for compiler in [
-            'gcc4.9', 'gcc5.3', 'gcc7.4', 'gcc8.3', 'gcc_musl', 'clang3.6',
-            'clang3.7'
+            'gcc4.9', 'gcc5.3', 'gcc7.4', 'gcc8.3', 'gcc_musl', 'clang4.0',
+            'clang5.0'
     ]:
         test_jobs += _generate_jobs(languages=['c', 'c++'],
                                     configs=['dbg'],
@@ -369,7 +369,8 @@
     """Auxiliary function to parse the "runs_per_test" flag."""
     try:
         n = int(arg_str)
-        if n <= 0: raise ValueError
+        if n <= 0:
+            raise ValueError
         return n
     except:
         msg = '\'{}\' is not a positive integer'.format(arg_str)
diff --git a/grpc/tools/run_tests/run_xds_tests.py b/grpc/tools/run_tests/run_xds_tests.py
index 6b397d4..7743df1 100755
--- a/grpc/tools/run_tests/run_xds_tests.py
+++ b/grpc/tools/run_tests/run_xds_tests.py
@@ -15,6 +15,7 @@
 """Run xDS integration tests on GCP using Traffic Director."""
 
 import argparse
+import datetime
 import googleapiclient.discovery
 import grpc
 import json
@@ -27,8 +28,10 @@
 import sys
 import tempfile
 import time
+import uuid
 
 from oauth2client.client import GoogleCredentials
+from google.protobuf import json_format
 
 import python_utils.jobset as jobset
 import python_utils.report_utils as report_utils
@@ -39,6 +42,20 @@
 from src.proto.grpc.testing import messages_pb2
 from src.proto.grpc.testing import test_pb2_grpc
 
+# Envoy protos provided by PyPI package xds-protos
+# Needs to import the generated Python file to load descriptors
+try:
+    from envoy.service.status.v3 import csds_pb2
+    from envoy.service.status.v3 import csds_pb2_grpc
+    from envoy.extensions.filters.network.http_connection_manager.v3 import http_connection_manager_pb2
+    from envoy.extensions.filters.common.fault.v3 import fault_pb2
+    from envoy.extensions.filters.http.fault.v3 import fault_pb2
+    from envoy.extensions.filters.http.router.v3 import router_pb2
+except ImportError:
+    # These protos are required by CSDS test. We should not fail the entire
+    # script for one test case.
+    pass
+
 logger = logging.getLogger()
 console_handler = logging.StreamHandler()
 formatter = logging.Formatter(fmt='%(asctime)s: %(levelname)-8s %(message)s')
@@ -47,27 +64,49 @@
 logger.addHandler(console_handler)
 logger.setLevel(logging.WARNING)
 
+# Suppress excessive logs for gRPC Python
+original_grpc_trace = os.environ.pop('GRPC_TRACE', None)
+original_grpc_verbosity = os.environ.pop('GRPC_VERBOSITY', None)
+# Suppress not-essential logs for GCP clients
+logging.getLogger('google_auth_httplib2').setLevel(logging.WARNING)
+logging.getLogger('googleapiclient.discovery').setLevel(logging.WARNING)
+
 _TEST_CASES = [
     'backends_restart',
     'change_backend_service',
     'gentle_failover',
+    'load_report_based_failover',
     'ping_pong',
     'remove_instance_group',
     'round_robin',
     'secondary_locality_gets_no_requests_on_partial_primary_failure',
     'secondary_locality_gets_requests_on_primary_failure',
     'traffic_splitting',
+    'path_matching',
+    'header_matching',
+    'forwarding_rule_port_match',
+    'forwarding_rule_default_port',
+    'metadata_filter',
 ]
+
 # Valid test cases, but not in all. So the tests can only run manually, and
 # aren't enabled automatically for all languages.
 #
 # TODO: Move them into _TEST_CASES when support is ready in all languages.
 _ADDITIONAL_TEST_CASES = [
-    'path_matching',
-    'header_matching',
     'circuit_breaking',
+    'timeout',
+    'fault_injection',
+    'csds',
+    'api_listener',  # TODO(b/187352987) Relieve quota pressure
 ]
 
+# Test cases that require the V3 API.  Skipped in older runs.
+_V3_TEST_CASES = frozenset(['timeout', 'fault_injection', 'csds'])
+
+# Test cases that require the alpha API.  Skipped for stable API runs.
+_ALPHA_TEST_CASES = frozenset(['timeout'])
+
 
 def parse_test_cases(arg):
     if arg == '':
@@ -96,7 +135,11 @@
 
 
 argp = argparse.ArgumentParser(description='Run xDS interop tests on GCP')
-argp.add_argument('--project_id', help='GCP project id')
+# TODO(zdapeng): remove default value of project_id and project_num
+argp.add_argument('--project_id', default='grpc-testing', help='GCP project id')
+argp.add_argument('--project_num',
+                  default='830293263384',
+                  help='GCP project number')
 argp.add_argument(
     '--gcp_suffix',
     default='',
@@ -175,8 +218,9 @@
 argp.add_argument('--network',
                   default='global/networks/default',
                   help='GCP network to use')
+_DEFAULT_PORT_RANGE = '8080:8280'
 argp.add_argument('--service_port_range',
-                  default='8080:8110',
+                  default=_DEFAULT_PORT_RANGE,
                   type=parse_port_range,
                   help='Listening port for created gRPC backends. Specified as '
                   'either a single int or as a range in the format min:max, in '
@@ -235,14 +279,23 @@
 if args.client_hosts:
     CLIENT_HOSTS = args.client_hosts.split(',')
 
+# Each of the config propagation in the control plane should finish within 600s.
+# Otherwise, it indicates a bug in the control plane. The config propagation
+# includes all kinds of traffic config update, like updating urlMap, creating
+# the resources for the first time, updating BackendService, and changing the
+# status of endpoints in BackendService.
+_WAIT_FOR_URL_MAP_PATCH_SEC = 600
+# In general, fetching load balancing stats only takes ~10s. However, slow
+# config update could lead to empty EDS or similar symptoms causing the
+# connection to hang for a long period of time. So, we want to extend the stats
+# wait time to be the same as urlMap patch time.
+_WAIT_FOR_STATS_SEC = _WAIT_FOR_URL_MAP_PATCH_SEC
+
 _DEFAULT_SERVICE_PORT = 80
 _WAIT_FOR_BACKEND_SEC = args.wait_for_backend_sec
 _WAIT_FOR_OPERATION_SEC = 1200
 _INSTANCE_GROUP_SIZE = args.instance_group_size
 _NUM_TEST_RPCS = 10 * args.qps
-_WAIT_FOR_STATS_SEC = 360
-_WAIT_FOR_VALID_CONFIG_SEC = 60
-_WAIT_FOR_URL_MAP_PATCH_SEC = 300
 _CONNECTION_TIMEOUT_SEC = 60
 _GCP_API_RETRIES = 5
 _BOOTSTRAP_TEMPLATE = """
@@ -250,7 +303,8 @@
   "node": {{
     "id": "{node_id}",
     "metadata": {{
-      "TRAFFICDIRECTOR_NETWORK_NAME": "%s"
+      "TRAFFICDIRECTOR_NETWORK_NAME": "%s",
+      "com.googleapis.trafficdirector.config_time_trace": "TRUE"
     }},
     "locality": {{
       "zone": "%s"
@@ -279,6 +333,9 @@
 _TEST_METADATA_KEY = 'xds_md'
 _TEST_METADATA_VALUE_UNARY = 'unary_yranu'
 _TEST_METADATA_VALUE_EMPTY = 'empty_ytpme'
+# Extra RPC metadata whose value is a number, sent with UnaryCall only.
+_TEST_METADATA_NUMERIC_KEY = 'xds_md_numeric'
+_TEST_METADATA_NUMERIC_VALUE = '159'
 _PATH_MATCHER_NAME = 'path-matcher'
 _BASE_TEMPLATE_NAME = 'test-template'
 _BASE_INSTANCE_GROUP_NAME = 'test-ig'
@@ -313,7 +370,8 @@
             response = stub.GetClientStats(request,
                                            wait_for_ready=True,
                                            timeout=rpc_timeout)
-            logger.debug('Invoked GetClientStats RPC to %s: %s', host, response)
+            logger.debug('Invoked GetClientStats RPC to %s: %s', host,
+                         json_format.MessageToJson(response))
             return response
 
 
@@ -336,7 +394,33 @@
             return response
 
 
-def configure_client(rpc_types, metadata):
+def get_client_xds_config_dump():
+    if CLIENT_HOSTS:
+        hosts = CLIENT_HOSTS
+    else:
+        hosts = ['localhost']
+    for host in hosts:
+        server_address = '%s:%d' % (host, args.stats_port)
+        with grpc.insecure_channel(server_address) as channel:
+            stub = csds_pb2_grpc.ClientStatusDiscoveryServiceStub(channel)
+            logger.debug('Fetching xDS config dump from %s', server_address)
+            response = stub.FetchClientStatus(csds_pb2.ClientStatusRequest(),
+                                              wait_for_ready=True,
+                                              timeout=_CONNECTION_TIMEOUT_SEC)
+            logger.debug('Fetched xDS config dump from %s', server_address)
+            if len(response.config) != 1:
+                logger.error('Unexpected number of ClientConfigs %d: %s',
+                             len(response.config), response)
+                return None
+            else:
+                # Converting the ClientStatusResponse into JSON, because many
+                # fields are packed in google.protobuf.Any. It will require many
+                # duplicated code to unpack proto message and inspect values.
+                return json_format.MessageToDict(
+                    response.config[0], preserving_proto_field_name=True)
+
+
+def configure_client(rpc_types, metadata=[], timeout_sec=None):
     if CLIENT_HOSTS:
         hosts = CLIENT_HOSTS
     else:
@@ -352,6 +436,8 @@
                 md.type = rpc_type
                 md.key = md_key
                 md.value = md_value
+            if timeout_sec:
+                request.timeout_sec = timeout_sec
             logger.debug(
                 'Invoking XdsUpdateClientConfigureService RPC to %s:%d: %s',
                 host, args.stats_port, request)
@@ -407,6 +493,21 @@
                                    allow_failures=False)
 
 
+def wait_until_no_rpcs_go_to_given_backends(backends, timeout_sec):
+    start_time = time.time()
+    while time.time() - start_time <= timeout_sec:
+        stats = get_client_stats(_NUM_TEST_RPCS, timeout_sec)
+        error_msg = None
+        rpcs_by_peer = stats.rpcs_by_peer
+        for backend in backends:
+            if backend in rpcs_by_peer:
+                error_msg = 'Unexpected backend %s receives load' % backend
+                break
+        if not error_msg:
+            return
+    raise Exception('Unexpected RPCs going to given backends')
+
+
 def wait_until_rpcs_in_flight(rpc_type, timeout_sec, num_rpcs, threshold):
     '''Block until the test client reaches the state with the given number
     of RPCs being outstanding stably.
@@ -619,6 +720,56 @@
                                                  _WAIT_FOR_BACKEND_SEC)
 
 
+def test_load_report_based_failover(gcp, backend_service,
+                                    primary_instance_group,
+                                    secondary_instance_group):
+    logger.info('Running test_load_report_based_failover')
+    try:
+        patch_backend_service(
+            gcp, backend_service,
+            [primary_instance_group, secondary_instance_group])
+        primary_instance_names = get_instance_names(gcp, primary_instance_group)
+        secondary_instance_names = get_instance_names(gcp,
+                                                      secondary_instance_group)
+        wait_for_healthy_backends(gcp, backend_service, primary_instance_group)
+        wait_for_healthy_backends(gcp, backend_service,
+                                  secondary_instance_group)
+        wait_until_all_rpcs_go_to_given_backends(primary_instance_names,
+                                                 _WAIT_FOR_STATS_SEC)
+        # Set primary locality's balance mode to RATE, and RPS to 20% of the
+        # client's QPS. The secondary locality will be used.
+        max_rate = int(args.qps * 1 / 5)
+        logger.info('Patching backend service to RATE with %d max_rate',
+                    max_rate)
+        patch_backend_service(
+            gcp,
+            backend_service, [primary_instance_group, secondary_instance_group],
+            balancing_mode='RATE',
+            max_rate=max_rate)
+        wait_until_all_rpcs_go_to_given_backends(
+            primary_instance_names + secondary_instance_names,
+            _WAIT_FOR_BACKEND_SEC)
+
+        # Set primary locality's balance mode to RATE, and RPS to 120% of the
+        # client's QPS. Only the primary locality will be used.
+        max_rate = int(args.qps * 6 / 5)
+        logger.info('Patching backend service to RATE with %d max_rate',
+                    max_rate)
+        patch_backend_service(
+            gcp,
+            backend_service, [primary_instance_group, secondary_instance_group],
+            balancing_mode='RATE',
+            max_rate=max_rate)
+        wait_until_all_rpcs_go_to_given_backends(primary_instance_names,
+                                                 _WAIT_FOR_BACKEND_SEC)
+        logger.info("success")
+    finally:
+        patch_backend_service(gcp, backend_service, [primary_instance_group])
+        instance_names = get_instance_names(gcp, primary_instance_group)
+        wait_until_all_rpcs_go_to_given_backends(instance_names,
+                                                 _WAIT_FOR_BACKEND_SEC)
+
+
 def test_ping_pong(gcp, backend_service, instance_group):
     logger.info('Running test_ping_pong')
     wait_for_healthy_backends(gcp, backend_service, instance_group)
@@ -829,6 +980,303 @@
     return original_backend_instances, alternate_backend_instances
 
 
+def test_metadata_filter(gcp, original_backend_service, instance_group,
+                         alternate_backend_service, same_zone_instance_group):
+    logger.info("Running test_metadata_filter")
+    wait_for_healthy_backends(gcp, original_backend_service, instance_group)
+    original_backend_instances = get_instance_names(gcp, instance_group)
+    alternate_backend_instances = get_instance_names(gcp,
+                                                     same_zone_instance_group)
+    patch_backend_service(gcp, alternate_backend_service,
+                          [same_zone_instance_group])
+    wait_for_healthy_backends(gcp, alternate_backend_service,
+                              same_zone_instance_group)
+    try:
+        with open(bootstrap_path) as f:
+            md = json.load(f)['node']['metadata']
+            match_labels = []
+            for k, v in md.items():
+                match_labels.append({'name': k, 'value': v})
+
+        not_match_labels = [{'name': 'fake', 'value': 'fail'}]
+        test_route_rules = [
+            # test MATCH_ALL
+            [
+                {
+                    'priority': 0,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ALL',
+                            'filterLabels': not_match_labels
+                        }]
+                    }],
+                    'service': original_backend_service.url
+                },
+                {
+                    'priority': 1,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ALL',
+                            'filterLabels': match_labels
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                },
+            ],
+            # test mixing MATCH_ALL and MATCH_ANY
+            # test MATCH_ALL: super set labels won't match
+            [
+                {
+                    'priority': 0,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ALL',
+                            'filterLabels': not_match_labels + match_labels
+                        }]
+                    }],
+                    'service': original_backend_service.url
+                },
+                {
+                    'priority': 1,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ANY',
+                            'filterLabels': not_match_labels + match_labels
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                },
+            ],
+            # test MATCH_ANY
+            [
+                {
+                    'priority': 0,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ANY',
+                            'filterLabels': not_match_labels
+                        }]
+                    }],
+                    'service': original_backend_service.url
+                },
+                {
+                    'priority': 1,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ANY',
+                            'filterLabels': not_match_labels + match_labels
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                },
+            ],
+            # test match multiple route rules
+            [
+                {
+                    'priority': 0,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ANY',
+                            'filterLabels': match_labels
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                },
+                {
+                    'priority': 1,
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'metadataFilters': [{
+                            'filterMatchCriteria': 'MATCH_ALL',
+                            'filterLabels': match_labels
+                        }]
+                    }],
+                    'service': original_backend_service.url
+                },
+            ]
+        ]
+
+        for route_rules in test_route_rules:
+            wait_until_all_rpcs_go_to_given_backends(original_backend_instances,
+                                                     _WAIT_FOR_STATS_SEC)
+            patch_url_map_backend_service(gcp,
+                                          original_backend_service,
+                                          route_rules=route_rules)
+            wait_until_no_rpcs_go_to_given_backends(original_backend_instances,
+                                                    _WAIT_FOR_STATS_SEC)
+            wait_until_all_rpcs_go_to_given_backends(
+                alternate_backend_instances, _WAIT_FOR_STATS_SEC)
+            patch_url_map_backend_service(gcp, original_backend_service)
+    finally:
+        patch_backend_service(gcp, alternate_backend_service, [])
+
+
+def test_api_listener(gcp, backend_service, instance_group,
+                      alternate_backend_service):
+    logger.info("Running api_listener")
+    try:
+        wait_for_healthy_backends(gcp, backend_service, instance_group)
+        backend_instances = get_instance_names(gcp, instance_group)
+        wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                 _WAIT_FOR_STATS_SEC)
+        # create a second suite of map+tp+fr with the same host name in host rule
+        # and we have to disable proxyless validation because it needs `0.0.0.0`
+        # ip address in fr for proxyless and also we violate ip:port uniqueness
+        # for test purpose. See https://github.com/grpc/grpc-java/issues/8009
+        new_config_suffix = '2'
+        create_url_map(gcp, url_map_name + new_config_suffix, backend_service,
+                       service_host_name)
+        create_target_proxy(gcp, target_proxy_name + new_config_suffix, False)
+        if not gcp.service_port:
+            raise Exception(
+                'Faied to find a valid port for the forwarding rule')
+        potential_ip_addresses = []
+        max_attempts = 10
+        for i in range(max_attempts):
+            potential_ip_addresses.append('10.10.10.%d' %
+                                          (random.randint(0, 255)))
+        create_global_forwarding_rule(gcp,
+                                      forwarding_rule_name + new_config_suffix,
+                                      [gcp.service_port],
+                                      potential_ip_addresses)
+        if gcp.service_port != _DEFAULT_SERVICE_PORT:
+            patch_url_map_host_rule_with_port(gcp,
+                                              url_map_name + new_config_suffix,
+                                              backend_service,
+                                              service_host_name)
+        wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                 _WAIT_FOR_STATS_SEC)
+
+        delete_global_forwarding_rule(gcp, forwarding_rule_name)
+        delete_target_proxy(gcp, target_proxy_name)
+        delete_url_map(gcp, url_map_name)
+        verify_attempts = int(_WAIT_FOR_URL_MAP_PATCH_SEC / _NUM_TEST_RPCS *
+                              args.qps)
+        for i in range(verify_attempts):
+            wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                     _WAIT_FOR_STATS_SEC)
+        # delete host rule for the original host name
+        patch_url_map_backend_service(gcp, alternate_backend_service)
+        wait_until_no_rpcs_go_to_given_backends(backend_instances,
+                                                _WAIT_FOR_STATS_SEC)
+
+    finally:
+        delete_global_forwarding_rule(gcp,
+                                      forwarding_rule_name + new_config_suffix)
+        delete_target_proxy(gcp, target_proxy_name + new_config_suffix)
+        delete_url_map(gcp, url_map_name + new_config_suffix)
+        create_url_map(gcp, url_map_name, backend_service, service_host_name)
+        create_target_proxy(gcp, target_proxy_name)
+        create_global_forwarding_rule(gcp, forwarding_rule_name,
+                                      potential_service_ports)
+        if gcp.service_port != _DEFAULT_SERVICE_PORT:
+            patch_url_map_host_rule_with_port(gcp, url_map_name,
+                                              backend_service,
+                                              service_host_name)
+            server_uri = service_host_name + ':' + str(gcp.service_port)
+        else:
+            server_uri = service_host_name
+        return server_uri
+
+
+def test_forwarding_rule_port_match(gcp, backend_service, instance_group):
+    logger.info("Running test_forwarding_rule_port_match")
+    try:
+        wait_for_healthy_backends(gcp, backend_service, instance_group)
+        backend_instances = get_instance_names(gcp, instance_group)
+        wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                 _WAIT_FOR_STATS_SEC)
+        delete_global_forwarding_rule(gcp)
+        create_global_forwarding_rule(gcp, forwarding_rule_name, [
+            x for x in parse_port_range(_DEFAULT_PORT_RANGE)
+            if x != gcp.service_port
+        ])
+        wait_until_no_rpcs_go_to_given_backends(backend_instances,
+                                                _WAIT_FOR_STATS_SEC)
+    finally:
+        delete_global_forwarding_rule(gcp)
+        create_global_forwarding_rule(gcp, forwarding_rule_name,
+                                      potential_service_ports)
+        if gcp.service_port != _DEFAULT_SERVICE_PORT:
+            patch_url_map_host_rule_with_port(gcp, url_map_name,
+                                              backend_service,
+                                              service_host_name)
+            server_uri = service_host_name + ':' + str(gcp.service_port)
+        else:
+            server_uri = service_host_name
+        return server_uri
+
+
+def test_forwarding_rule_default_port(gcp, backend_service, instance_group):
+    logger.info("Running test_forwarding_rule_default_port")
+    try:
+        wait_for_healthy_backends(gcp, backend_service, instance_group)
+        backend_instances = get_instance_names(gcp, instance_group)
+        if gcp.service_port == _DEFAULT_SERVICE_PORT:
+            wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                     _WAIT_FOR_STATS_SEC)
+            delete_global_forwarding_rule(gcp)
+            create_global_forwarding_rule(gcp, forwarding_rule_name,
+                                          parse_port_range(_DEFAULT_PORT_RANGE))
+            patch_url_map_host_rule_with_port(gcp, url_map_name,
+                                              backend_service,
+                                              service_host_name)
+        wait_until_no_rpcs_go_to_given_backends(backend_instances,
+                                                _WAIT_FOR_STATS_SEC)
+        # expect success when no port in client request service uri, and no port in url-map
+        delete_global_forwarding_rule(gcp)
+        delete_target_proxy(gcp)
+        delete_url_map(gcp)
+        create_url_map(gcp, url_map_name, backend_service, service_host_name)
+        create_target_proxy(gcp, gcp.target_proxy.name, False)
+        potential_ip_addresses = []
+        max_attempts = 10
+        for i in range(max_attempts):
+            potential_ip_addresses.append('10.10.10.%d' %
+                                          (random.randint(0, 255)))
+        create_global_forwarding_rule(gcp, forwarding_rule_name, [80],
+                                      potential_ip_addresses)
+        wait_until_all_rpcs_go_to_given_backends(backend_instances,
+                                                 _WAIT_FOR_STATS_SEC)
+
+        # expect failure when no port in client request uri, but specify port in url-map
+        patch_url_map_host_rule_with_port(gcp, url_map_name, backend_service,
+                                          service_host_name)
+        wait_until_no_rpcs_go_to_given_backends(backend_instances,
+                                                _WAIT_FOR_STATS_SEC)
+    finally:
+        delete_global_forwarding_rule(gcp)
+        delete_target_proxy(gcp)
+        delete_url_map(gcp)
+        create_url_map(gcp, url_map_name, backend_service, service_host_name)
+        create_target_proxy(gcp, target_proxy_name)
+        create_global_forwarding_rule(gcp, forwarding_rule_name,
+                                      potential_service_ports)
+        if gcp.service_port != _DEFAULT_SERVICE_PORT:
+            patch_url_map_host_rule_with_port(gcp, url_map_name,
+                                              backend_service,
+                                              service_host_name)
+            server_uri = service_host_name + ':' + str(gcp.service_port)
+        else:
+            server_uri = service_host_name
+        return server_uri
+
+
 def test_traffic_splitting(gcp, original_backend_service, instance_group,
                            alternate_backend_service, same_zone_instance_group):
     # This test start with all traffic going to original_backend_service. Then
@@ -974,7 +1422,36 @@
                 {
                     "UnaryCall": original_backend_instances,
                     "EmptyCall": alternate_backend_instances
-                })
+                }),
+            (
+                [{
+                    'priority': 0,
+                    # Regex UnaryCall -> alternate_backend_service.
+                    'matchRules': [{
+                        'regexMatch':
+                            '^\/.*\/UnaryCall$'  # Unary methods with any services.
+                    }],
+                    'service': alternate_backend_service.url
+                }],
+                {
+                    "UnaryCall": alternate_backend_instances,
+                    "EmptyCall": original_backend_instances
+                }),
+            (
+                [{
+                    'priority': 0,
+                    # ignoreCase EmptyCall -> alternate_backend_service.
+                    'matchRules': [{
+                        # Case insensitive matching.
+                        'fullPathMatch': '/gRpC.tEsTinG.tEstseRvice/empTycaLl',
+                        'ignoreCase': True,
+                    }],
+                    'service': alternate_backend_service.url
+                }],
+                {
+                    "UnaryCall": original_backend_instances,
+                    "EmptyCall": alternate_backend_instances
+                }),
         ]
 
         for (route_rules, expected_instances) in test_cases:
@@ -991,8 +1468,8 @@
                 original_backend_instances + alternate_backend_instances,
                 _WAIT_FOR_STATS_SEC)
 
-            retry_count = 20
-            # Each attempt takes about 10 seconds, 20 retries is equivalent to 200
+            retry_count = 80
+            # Each attempt takes about 5 seconds, 80 retries is equivalent to 400
             # seconds timeout.
             for i in range(retry_count):
                 stats = get_client_stats(_NUM_TEST_RPCS, _WAIT_FOR_STATS_SEC)
@@ -1004,6 +1481,10 @@
                 if compare_expected_instances(stats, expected_instances):
                     logger.info("success")
                     break
+                elif i == retry_count - 1:
+                    raise Exception(
+                        'timeout waiting for RPCs to the expected instances: %s'
+                        % expected_instances)
     finally:
         patch_url_map_backend_service(gcp, original_backend_service)
         patch_backend_service(gcp, alternate_backend_service, [])
@@ -1087,15 +1568,14 @@
             (
                 [{
                     'priority': 0,
-                    # Header invert ExactMatch -> alternate_backend_service.
-                    # EmptyCall is sent with the metadata, so will be sent to original.
+                    # Header 'xds_md_numeric' present -> alternate_backend_service.
+                    # UnaryCall is sent with the metadata, so will be sent to alternative.
                     'matchRules': [{
                         'prefixMatch':
                             '/',
                         'headerMatches': [{
-                            'headerName': _TEST_METADATA_KEY,
-                            'exactMatch': _TEST_METADATA_VALUE_EMPTY,
-                            'invertMatch': True
+                            'headerName': _TEST_METADATA_NUMERIC_KEY,
+                            'presentMatch': True
                         }]
                     }],
                     'service': alternate_backend_service.url
@@ -1104,6 +1584,71 @@
                     "EmptyCall": original_backend_instances,
                     "UnaryCall": alternate_backend_instances
                 }),
+            (
+                [{
+                    'priority': 0,
+                    # Header invert ExactMatch -> alternate_backend_service.
+                    # UnaryCall is sent with the metadata, so will be sent to
+                    # original. EmptyCall will be sent to alternative.
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'headerMatches': [{
+                            'headerName': _TEST_METADATA_KEY,
+                            'exactMatch': _TEST_METADATA_VALUE_UNARY,
+                            'invertMatch': True
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                }],
+                {
+                    "EmptyCall": alternate_backend_instances,
+                    "UnaryCall": original_backend_instances
+                }),
+            (
+                [{
+                    'priority': 0,
+                    # Header 'xds_md_numeric' range [100,200] -> alternate_backend_service.
+                    # UnaryCall is sent with the metadata in range.
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'headerMatches': [{
+                            'headerName': _TEST_METADATA_NUMERIC_KEY,
+                            'rangeMatch': {
+                                'rangeStart': '100',
+                                'rangeEnd': '200'
+                            }
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                }],
+                {
+                    "EmptyCall": original_backend_instances,
+                    "UnaryCall": alternate_backend_instances
+                }),
+            (
+                [{
+                    'priority': 0,
+                    # Header RegexMatch -> alternate_backend_service.
+                    # EmptyCall is sent with the metadata.
+                    'matchRules': [{
+                        'prefixMatch':
+                            '/',
+                        'headerMatches': [{
+                            'headerName':
+                                _TEST_METADATA_KEY,
+                            'regexMatch':
+                                "^%s.*%s$" % (_TEST_METADATA_VALUE_EMPTY[:2],
+                                              _TEST_METADATA_VALUE_EMPTY[-2:])
+                        }]
+                    }],
+                    'service': alternate_backend_service.url
+                }],
+                {
+                    "EmptyCall": alternate_backend_instances,
+                    "UnaryCall": original_backend_instances
+                }),
         ]
 
         for (route_rules, expected_instances) in test_cases:
@@ -1121,8 +1666,8 @@
                 original_backend_instances + alternate_backend_instances,
                 _WAIT_FOR_STATS_SEC)
 
-            retry_count = 20
-            # Each attempt takes about 10 seconds, 10 retries is equivalent to 100
+            retry_count = 80
+            # Each attempt takes about 5 seconds, 80 retries is equivalent to 400
             # seconds timeout.
             for i in range(retry_count):
                 stats = get_client_stats(_NUM_TEST_RPCS, _WAIT_FOR_STATS_SEC)
@@ -1134,6 +1679,10 @@
                 if compare_expected_instances(stats, expected_instances):
                     logger.info("success")
                     break
+                elif i == retry_count - 1:
+                    raise Exception(
+                        'timeout waiting for RPCs to the expected instances: %s'
+                        % expected_instances)
     finally:
         patch_url_map_backend_service(gcp, original_backend_service)
         patch_backend_service(gcp, alternate_backend_service, [])
@@ -1235,7 +1784,7 @@
         configure_client([
             messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
             messages_pb2.ClientConfigureRequest.RpcType.EMPTY_CALL
-        ], [])
+        ])
         logger.info('Patching url map with %s', route_rules)
         patch_url_map_backend_service(gcp,
                                       extra_backend_service,
@@ -1285,7 +1834,7 @@
         # Avoid new RPCs being outstanding (some test clients create threads
         # for sending RPCs) after restoring backend services.
         configure_client(
-            [messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL], [])
+            [messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL])
     finally:
         patch_url_map_backend_service(gcp, original_backend_service)
         patch_backend_service(gcp, original_backend_service, [instance_group])
@@ -1294,6 +1843,426 @@
         set_validate_for_proxyless(gcp, True)
 
 
+def test_timeout(gcp, original_backend_service, instance_group):
+    logger.info('Running test_timeout')
+
+    logger.info('waiting for original backends to become healthy')
+    wait_for_healthy_backends(gcp, original_backend_service, instance_group)
+
+    # UnaryCall -> maxStreamDuration:3s
+    route_rules = [{
+        'priority': 0,
+        'matchRules': [{
+            'fullPathMatch': '/grpc.testing.TestService/UnaryCall'
+        }],
+        'service': original_backend_service.url,
+        'routeAction': {
+            'maxStreamDuration': {
+                'seconds': 3,
+            },
+        },
+    }]
+    patch_url_map_backend_service(gcp,
+                                  original_backend_service,
+                                  route_rules=route_rules)
+    # A list of tuples (testcase_name, {client_config}, {expected_results})
+    test_cases = [
+        (
+            'timeout_exceeded (UNARY_CALL), timeout_different_route (EMPTY_CALL)',
+            # UnaryCall and EmptyCall both sleep-4.
+            # UnaryCall timeouts, EmptyCall succeeds.
+            {
+                'rpc_types': [
+                    messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+                    messages_pb2.ClientConfigureRequest.RpcType.EMPTY_CALL,
+                ],
+                'metadata': [
+                    (messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+                     'rpc-behavior', 'sleep-4'),
+                    (messages_pb2.ClientConfigureRequest.RpcType.EMPTY_CALL,
+                     'rpc-behavior', 'sleep-4'),
+                ],
+            },
+            {
+                'UNARY_CALL': 4,  # DEADLINE_EXCEEDED
+                'EMPTY_CALL': 0,
+            },
+        ),
+        (
+            'app_timeout_exceeded',
+            # UnaryCall only with sleep-2; timeout=1s; calls timeout.
+            {
+                'rpc_types': [
+                    messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+                ],
+                'metadata': [
+                    (messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+                     'rpc-behavior', 'sleep-2'),
+                ],
+                'timeout_sec': 1,
+            },
+            {
+                'UNARY_CALL': 4,  # DEADLINE_EXCEEDED
+            },
+        ),
+        (
+            'timeout_not_exceeded',
+            # UnaryCall only with no sleep; calls succeed.
+            {
+                'rpc_types': [
+                    messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+                ],
+            },
+            {
+                'UNARY_CALL': 0,
+            },
+        )
+    ]
+
+    try:
+        first_case = True
+        for (testcase_name, client_config, expected_results) in test_cases:
+            logger.info('starting case %s', testcase_name)
+            configure_client(**client_config)
+            # wait a second to help ensure the client stops sending RPCs with
+            # the old config.  We will make multiple attempts if it is failing,
+            # but this improves confidence that the test is valid if the
+            # previous client_config would lead to the same results.
+            time.sleep(1)
+            # Each attempt takes 10 seconds; 20 attempts is equivalent to 200
+            # second timeout.
+            attempt_count = 20
+            if first_case:
+                attempt_count = 120
+                first_case = False
+            before_stats = get_client_accumulated_stats()
+            if not before_stats.stats_per_method:
+                raise ValueError(
+                    'stats.stats_per_method is None, the interop client stats service does not support this test case'
+                )
+            for i in range(attempt_count):
+                logger.info('%s: attempt %d', testcase_name, i)
+
+                test_runtime_secs = 10
+                time.sleep(test_runtime_secs)
+                after_stats = get_client_accumulated_stats()
+
+                success = True
+                for rpc, status in expected_results.items():
+                    qty = (after_stats.stats_per_method[rpc].result[status] -
+                           before_stats.stats_per_method[rpc].result[status])
+                    want = test_runtime_secs * args.qps
+                    # Allow 10% deviation from expectation to reduce flakiness
+                    if qty < (want * .9) or qty > (want * 1.1):
+                        logger.info('%s: failed due to %s[%s]: got %d want ~%d',
+                                    testcase_name, rpc, status, qty, want)
+                        success = False
+                if success:
+                    logger.info('success')
+                    break
+                logger.info('%s attempt %d failed', testcase_name, i)
+                before_stats = after_stats
+            else:
+                raise Exception(
+                    '%s: timeout waiting for expected results: %s; got %s' %
+                    (testcase_name, expected_results,
+                     after_stats.stats_per_method))
+    finally:
+        patch_url_map_backend_service(gcp, original_backend_service)
+
+
+def test_fault_injection(gcp, original_backend_service, instance_group):
+    logger.info('Running test_fault_injection')
+
+    logger.info('waiting for original backends to become healthy')
+    wait_for_healthy_backends(gcp, original_backend_service, instance_group)
+
+    testcase_header = 'fi_testcase'
+
+    def _route(pri, name, fi_policy):
+        return {
+            'priority': pri,
+            'matchRules': [{
+                'prefixMatch':
+                    '/',
+                'headerMatches': [{
+                    'headerName': testcase_header,
+                    'exactMatch': name,
+                }],
+            }],
+            'service': original_backend_service.url,
+            'routeAction': {
+                'faultInjectionPolicy': fi_policy
+            },
+        }
+
+    def _abort(pct):
+        return {
+            'abort': {
+                'httpStatus': 401,
+                'percentage': pct,
+            }
+        }
+
+    def _delay(pct):
+        return {
+            'delay': {
+                'fixedDelay': {
+                    'seconds': '20'
+                },
+                'percentage': pct,
+            }
+        }
+
+    zero_route = _abort(0)
+    zero_route.update(_delay(0))
+    route_rules = [
+        _route(0, 'zero_percent_fault_injection', zero_route),
+        _route(1, 'always_delay', _delay(100)),
+        _route(2, 'always_abort', _abort(100)),
+        _route(3, 'delay_half', _delay(50)),
+        _route(4, 'abort_half', _abort(50)),
+        {
+            'priority': 5,
+            'matchRules': [{
+                'prefixMatch': '/'
+            }],
+            'service': original_backend_service.url,
+        },
+    ]
+    set_validate_for_proxyless(gcp, False)
+    patch_url_map_backend_service(gcp,
+                                  original_backend_service,
+                                  route_rules=route_rules)
+    # A list of tuples (testcase_name, {client_config}, {code: percent}).  Each
+    # test case will set the testcase_header with the testcase_name for routing
+    # to the appropriate config for the case, defined above.
+    test_cases = [
+        (
+            'zero_percent_fault_injection',
+            {},
+            {
+                0: 1
+            },  # OK
+        ),
+        (
+            'non_matching_fault_injection',  # Not in route_rules, above.
+            {},
+            {
+                0: 1
+            },  # OK
+        ),
+        (
+            'always_delay',
+            {
+                'timeout_sec': 2
+            },
+            {
+                4: 1
+            },  # DEADLINE_EXCEEDED
+        ),
+        (
+            'always_abort',
+            {},
+            {
+                16: 1
+            },  # UNAUTHENTICATED
+        ),
+        (
+            'delay_half',
+            {
+                'timeout_sec': 2
+            },
+            {
+                4: .5,
+                0: .5
+            },  # DEADLINE_EXCEEDED / OK: 50% / 50%
+        ),
+        (
+            'abort_half',
+            {},
+            {
+                16: .5,
+                0: .5
+            },  # UNAUTHENTICATED / OK: 50% / 50%
+        )
+    ]
+
+    try:
+        first_case = True
+        for (testcase_name, client_config, expected_results) in test_cases:
+            logger.info('starting case %s', testcase_name)
+
+            client_config['metadata'] = [
+                (messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+                 testcase_header, testcase_name)
+            ]
+            client_config['rpc_types'] = [
+                messages_pb2.ClientConfigureRequest.RpcType.UNARY_CALL,
+            ]
+            configure_client(**client_config)
+            # wait a second to help ensure the client stops sending RPCs with
+            # the old config.  We will make multiple attempts if it is failing,
+            # but this improves confidence that the test is valid if the
+            # previous client_config would lead to the same results.
+            time.sleep(1)
+            # Each attempt takes 10 seconds; 20 attempts is equivalent to 200
+            # second timeout.
+            attempt_count = 20
+            if first_case:
+                attempt_count = 120
+                first_case = False
+            before_stats = get_client_accumulated_stats()
+            if not before_stats.stats_per_method:
+                raise ValueError(
+                    'stats.stats_per_method is None, the interop client stats service does not support this test case'
+                )
+            for i in range(attempt_count):
+                logger.info('%s: attempt %d', testcase_name, i)
+
+                test_runtime_secs = 10
+                time.sleep(test_runtime_secs)
+                after_stats = get_client_accumulated_stats()
+
+                success = True
+                for status, pct in expected_results.items():
+                    rpc = 'UNARY_CALL'
+                    qty = (after_stats.stats_per_method[rpc].result[status] -
+                           before_stats.stats_per_method[rpc].result[status])
+                    want = pct * args.qps * test_runtime_secs
+                    # Allow 10% deviation from expectation to reduce flakiness
+                    VARIANCE_ALLOWED = 0.1
+                    if abs(qty - want) > want * VARIANCE_ALLOWED:
+                        logger.info('%s: failed due to %s[%s]: got %d want ~%d',
+                                    testcase_name, rpc, status, qty, want)
+                        success = False
+                if success:
+                    logger.info('success')
+                    break
+                logger.info('%s attempt %d failed', testcase_name, i)
+                before_stats = after_stats
+            else:
+                raise Exception(
+                    '%s: timeout waiting for expected results: %s; got %s' %
+                    (testcase_name, expected_results,
+                     after_stats.stats_per_method))
+    finally:
+        patch_url_map_backend_service(gcp, original_backend_service)
+        set_validate_for_proxyless(gcp, True)
+
+
+def test_csds(gcp, original_backend_service, instance_group, server_uri):
+    test_csds_timeout_s = datetime.timedelta(minutes=5).total_seconds()
+    sleep_interval_between_attempts_s = datetime.timedelta(
+        seconds=2).total_seconds()
+    logger.info('Running test_csds')
+
+    logger.info('waiting for original backends to become healthy')
+    wait_for_healthy_backends(gcp, original_backend_service, instance_group)
+
+    # Test case timeout: 5 minutes
+    deadline = time.time() + test_csds_timeout_s
+    cnt = 0
+    while time.time() <= deadline:
+        client_config = get_client_xds_config_dump()
+        logger.info('test_csds attempt %d: received xDS config %s', cnt,
+                    json.dumps(client_config, indent=2))
+        if client_config is not None:
+            # Got the xDS config dump, now validate it
+            ok = True
+            try:
+                if client_config['node']['locality']['zone'] != args.zone:
+                    logger.info('Invalid zone %s != %s',
+                                client_config['node']['locality']['zone'],
+                                args.zone)
+                    ok = False
+                seen = set()
+                for xds_config in client_config['xds_config']:
+                    if 'listener_config' in xds_config:
+                        listener_name = xds_config['listener_config'][
+                            'dynamic_listeners'][0]['active_state']['listener'][
+                                'name']
+                        if listener_name != server_uri:
+                            logger.info('Invalid Listener name %s != %s',
+                                        listener_name, server_uri)
+                            ok = False
+                        else:
+                            seen.add('lds')
+                    elif 'route_config' in xds_config:
+                        num_vh = len(
+                            xds_config['route_config']['dynamic_route_configs']
+                            [0]['route_config']['virtual_hosts'])
+                        if num_vh <= 0:
+                            logger.info('Invalid number of VirtualHosts %s',
+                                        num_vh)
+                            ok = False
+                        else:
+                            seen.add('rds')
+                    elif 'cluster_config' in xds_config:
+                        cluster_type = xds_config['cluster_config'][
+                            'dynamic_active_clusters'][0]['cluster']['type']
+                        if cluster_type != 'EDS':
+                            logger.info('Invalid cluster type %s != EDS',
+                                        cluster_type)
+                            ok = False
+                        else:
+                            seen.add('cds')
+                    elif 'endpoint_config' in xds_config:
+                        sub_zone = xds_config["endpoint_config"][
+                            "dynamic_endpoint_configs"][0]["endpoint_config"][
+                                "endpoints"][0]["locality"]["sub_zone"]
+                        if args.zone not in sub_zone:
+                            logger.info('Invalid endpoint sub_zone %s',
+                                        sub_zone)
+                            ok = False
+                        else:
+                            seen.add('eds')
+                want = {'lds', 'rds', 'cds', 'eds'}
+                if seen != want:
+                    logger.info('Incomplete xDS config dump, seen=%s', seen)
+                    ok = False
+            except:
+                logger.exception('Error in xDS config dump:')
+                ok = False
+            finally:
+                if ok:
+                    # Successfully fetched xDS config, and they looks good.
+                    logger.info('success')
+                    return
+        logger.info('test_csds attempt %d failed', cnt)
+        # Give the client some time to fetch xDS resources
+        time.sleep(sleep_interval_between_attempts_s)
+        cnt += 1
+
+    raise RuntimeError('failed to receive a valid xDS config in %s seconds' %
+                       test_csds_timeout_s)
+
+
+def maybe_write_sponge_properties():
+    """Writing test infos to enable more advanced testgrid searches."""
+    if 'KOKORO_ARTIFACTS_DIR' not in os.environ:
+        return
+    if 'GIT_ORIGIN_URL' not in os.environ:
+        return
+    if 'GIT_COMMIT_SHORT' not in os.environ:
+        return
+    properties = [
+        # Technically, 'TESTS_FORMAT_VERSION' is not required for run_xds_tests.
+        # We keep it here so one day we may merge the process of writing sponge
+        # properties.
+        'TESTS_FORMAT_VERSION,2',
+        'TESTGRID_EXCLUDE,%s' % os.environ.get('TESTGRID_EXCLUDE', 0),
+        'GIT_ORIGIN_URL,%s' % os.environ['GIT_ORIGIN_URL'],
+        'GIT_COMMIT_SHORT,%s' % os.environ['GIT_COMMIT_SHORT'],
+    ]
+    logger.info('Writing Sponge configs: %s', properties)
+    with open(
+            os.path.join(os.environ['KOKORO_ARTIFACTS_DIR'],
+                         "custom_sponge_config.csv"), 'w') as f:
+        f.write("\n".join(properties))
+        f.write("\n")
+
+
 def set_validate_for_proxyless(gcp, validate_for_proxyless):
     if not gcp.alpha_compute:
         logger.debug(
@@ -1350,7 +2319,7 @@
 
 def get_startup_script(path_to_server_binary, service_port):
     if path_to_server_binary:
-        return "nohup %s --port=%d 1>/dev/null &" % (path_to_server_binary,
+        return 'nohup %s --port=%d 1>/dev/null &' % (path_to_server_binary,
                                                      service_port)
     else:
         return """#!/bin/bash
@@ -1561,34 +2530,39 @@
     gcp.target_proxy = GcpResource(config['name'], result['targetLink'])
 
 
-def create_global_forwarding_rule(gcp, name, potential_ports):
+def create_global_forwarding_rule(gcp,
+                                  name,
+                                  potential_ports,
+                                  potential_ip_addresses=['0.0.0.0']):
     if gcp.alpha_compute:
         compute_to_use = gcp.alpha_compute
     else:
         compute_to_use = gcp.compute
     for port in potential_ports:
-        try:
-            config = {
-                'name': name,
-                'loadBalancingScheme': 'INTERNAL_SELF_MANAGED',
-                'portRange': str(port),
-                'IPAddress': '0.0.0.0',
-                'network': args.network,
-                'target': gcp.target_proxy.url,
-            }
-            logger.debug('Sending GCP request with body=%s', config)
-            result = compute_to_use.globalForwardingRules().insert(
-                project=gcp.project,
-                body=config).execute(num_retries=_GCP_API_RETRIES)
-            wait_for_global_operation(gcp, result['name'])
-            gcp.global_forwarding_rule = GcpResource(config['name'],
-                                                     result['targetLink'])
-            gcp.service_port = port
-            return
-        except googleapiclient.errors.HttpError as http_error:
-            logger.warning(
-                'Got error %s when attempting to create forwarding rule to '
-                '0.0.0.0:%d. Retrying with another port.' % (http_error, port))
+        for ip_address in potential_ip_addresses:
+            try:
+                config = {
+                    'name': name,
+                    'loadBalancingScheme': 'INTERNAL_SELF_MANAGED',
+                    'portRange': str(port),
+                    'IPAddress': ip_address,
+                    'network': args.network,
+                    'target': gcp.target_proxy.url,
+                }
+                logger.debug('Sending GCP request with body=%s', config)
+                result = compute_to_use.globalForwardingRules().insert(
+                    project=gcp.project,
+                    body=config).execute(num_retries=_GCP_API_RETRIES)
+                wait_for_global_operation(gcp, result['name'])
+                gcp.global_forwarding_rule = GcpResource(
+                    config['name'], result['targetLink'])
+                gcp.service_port = port
+                return
+            except googleapiclient.errors.HttpError as http_error:
+                logger.warning(
+                    'Got error %s when attempting to create forwarding rule to '
+                    '%s:%d. Retrying with another port.' %
+                    (http_error, ip_address, port))
 
 
 def get_health_check(gcp, health_check_name):
@@ -1652,39 +2626,49 @@
     return instance_group
 
 
-def delete_global_forwarding_rule(gcp):
+def delete_global_forwarding_rule(gcp, name=None):
+    if name:
+        forwarding_rule_to_delete = name
+    else:
+        forwarding_rule_to_delete = gcp.global_forwarding_rule.name
     try:
         result = gcp.compute.globalForwardingRules().delete(
             project=gcp.project,
-            forwardingRule=gcp.global_forwarding_rule.name).execute(
+            forwardingRule=forwarding_rule_to_delete).execute(
                 num_retries=_GCP_API_RETRIES)
         wait_for_global_operation(gcp, result['name'])
     except googleapiclient.errors.HttpError as http_error:
         logger.info('Delete failed: %s', http_error)
 
 
-def delete_target_proxy(gcp):
+def delete_target_proxy(gcp, name=None):
+    if name:
+        proxy_to_delete = name
+    else:
+        proxy_to_delete = gcp.target_proxy.name
     try:
         if gcp.alpha_compute:
             result = gcp.alpha_compute.targetGrpcProxies().delete(
-                project=gcp.project,
-                targetGrpcProxy=gcp.target_proxy.name).execute(
+                project=gcp.project, targetGrpcProxy=proxy_to_delete).execute(
                     num_retries=_GCP_API_RETRIES)
         else:
             result = gcp.compute.targetHttpProxies().delete(
-                project=gcp.project,
-                targetHttpProxy=gcp.target_proxy.name).execute(
+                project=gcp.project, targetHttpProxy=proxy_to_delete).execute(
                     num_retries=_GCP_API_RETRIES)
         wait_for_global_operation(gcp, result['name'])
     except googleapiclient.errors.HttpError as http_error:
         logger.info('Delete failed: %s', http_error)
 
 
-def delete_url_map(gcp):
+def delete_url_map(gcp, name=None):
+    if name:
+        url_map_to_delete = name
+    else:
+        url_map_to_delete = gcp.url_map.name
     try:
         result = gcp.compute.urlMaps().delete(
             project=gcp.project,
-            urlMap=gcp.url_map.name).execute(num_retries=_GCP_API_RETRIES)
+            urlMap=url_map_to_delete).execute(num_retries=_GCP_API_RETRIES)
         wait_for_global_operation(gcp, result['name'])
     except googleapiclient.errors.HttpError as http_error:
         logger.info('Delete failed: %s', http_error)
@@ -1757,6 +2741,7 @@
                           backend_service,
                           instance_groups,
                           balancing_mode='UTILIZATION',
+                          max_rate=1,
                           circuit_breakers=None):
     if gcp.alpha_compute:
         compute_to_use = gcp.alpha_compute
@@ -1766,7 +2751,7 @@
         'backends': [{
             'group': instance_group.url,
             'balancingMode': balancing_mode,
-            'maxRate': 1 if balancing_mode == 'RATE' else None
+            'maxRate': max_rate if balancing_mode == 'RATE' else None
         } for instance_group in instance_groups],
         'circuitBreakers': circuit_breakers,
     }
@@ -1804,6 +2789,11 @@
 
     Only one of backend_service and service_with_weights can be not None.
     '''
+    if gcp.alpha_compute:
+        compute_to_use = gcp.alpha_compute
+    else:
+        compute_to_use = gcp.compute
+
     if backend_service and services_with_weights:
         raise ValueError(
             'both backend_service and service_with_weights are not None.')
@@ -1825,7 +2815,7 @@
         }]
     }
     logger.debug('Sending GCP request with body=%s', config)
-    result = gcp.compute.urlMaps().patch(
+    result = compute_to_use.urlMaps().patch(
         project=gcp.project, urlMap=gcp.url_map.name,
         body=config).execute(num_retries=_GCP_API_RETRIES)
     wait_for_global_operation(gcp, result['name'])
@@ -1973,10 +2963,11 @@
 
 class GcpState(object):
 
-    def __init__(self, compute, alpha_compute, project):
+    def __init__(self, compute, alpha_compute, project, project_num):
         self.compute = compute
         self.alpha_compute = alpha_compute
         self.project = project
+        self.project_num = project_num
         self.health_check = None
         self.health_check_firewall_rule = None
         self.backend_services = []
@@ -1988,6 +2979,7 @@
         self.instance_groups = []
 
 
+maybe_write_sponge_properties()
 alpha_compute = None
 if args.compute_discovery_document:
     with open(args.compute_discovery_document, 'r') as discovery_doc:
@@ -2003,7 +2995,7 @@
         alpha_compute = googleapiclient.discovery.build('compute', 'alpha')
 
 try:
-    gcp = GcpState(compute, alpha_compute, args.project_id)
+    gcp = GcpState(compute, alpha_compute, args.project_id, args.project_num)
     gcp_suffix = args.gcp_suffix
     health_check_name = _BASE_HEALTH_CHECK_NAME + gcp_suffix
     if not args.use_existing_gcp_resources:
@@ -2095,7 +3087,12 @@
 
     if args.test_case:
         client_env = dict(os.environ)
+        if original_grpc_trace:
+            client_env['GRPC_TRACE'] = original_grpc_trace
+        if original_grpc_verbosity:
+            client_env['GRPC_VERBOSITY'] = original_grpc_verbosity
         bootstrap_server_features = []
+
         if gcp.service_port == _DEFAULT_SERVICE_PORT:
             server_uri = service_host_name
         else:
@@ -2109,15 +3106,38 @@
             with tempfile.NamedTemporaryFile(delete=False) as bootstrap_file:
                 bootstrap_file.write(
                     _BOOTSTRAP_TEMPLATE.format(
-                        node_id=socket.gethostname(),
+                        node_id='projects/%s/networks/%s/nodes/%s' %
+                        (gcp.project_num, args.network.split('/')[-1],
+                         uuid.uuid1()),
                         server_features=json.dumps(
                             bootstrap_server_features)).encode('utf-8'))
                 bootstrap_path = bootstrap_file.name
         client_env['GRPC_XDS_BOOTSTRAP'] = bootstrap_path
         client_env['GRPC_XDS_EXPERIMENTAL_CIRCUIT_BREAKING'] = 'true'
+        client_env['GRPC_XDS_EXPERIMENTAL_ENABLE_TIMEOUT'] = 'true'
+        client_env['GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION'] = 'true'
         test_results = {}
         failed_tests = []
         for test_case in args.test_case:
+            if test_case in _V3_TEST_CASES and not args.xds_v3_support:
+                logger.info('skipping test %s due to missing v3 support',
+                            test_case)
+                continue
+            if test_case in _ALPHA_TEST_CASES and not gcp.alpha_compute:
+                logger.info('skipping test %s due to missing alpha support',
+                            test_case)
+                continue
+            if test_case in [
+                    'api_listener', 'forwarding_rule_port_match',
+                    'forwarding_rule_default_port'
+            ] and CLIENT_HOSTS:
+                logger.info(
+                    'skipping test %s because test configuration is'
+                    'not compatible with client processes on existing'
+                    'client hosts', test_case)
+                continue
+            if test_case == 'forwarding_rule_default_port':
+                server_uri = service_host_name
             result = jobset.JobResult()
             log_dir = os.path.join(_TEST_LOG_BASE_DIR, test_case)
             if not os.path.exists(log_dir):
@@ -2132,11 +3152,13 @@
                 rpcs_to_send = '--rpc="UnaryCall"'
 
             if test_case in _TESTS_TO_SEND_METADATA:
-                metadata_to_send = '--metadata="EmptyCall:{keyE}:{valueE},UnaryCall:{keyU}:{valueU}"'.format(
+                metadata_to_send = '--metadata="EmptyCall:{keyE}:{valueE},UnaryCall:{keyU}:{valueU},UnaryCall:{keyNU}:{valueNU}"'.format(
                     keyE=_TEST_METADATA_KEY,
                     valueE=_TEST_METADATA_VALUE_EMPTY,
                     keyU=_TEST_METADATA_KEY,
-                    valueU=_TEST_METADATA_VALUE_UNARY)
+                    valueU=_TEST_METADATA_VALUE_UNARY,
+                    keyNU=_TEST_METADATA_NUMERIC_KEY,
+                    valueNU=_TEST_METADATA_NUMERIC_VALUE)
             else:
                 # Setting the arg explicitly to empty with '--metadata=""'
                 # makes C# client fail
@@ -2185,6 +3207,10 @@
                 elif test_case == 'gentle_failover':
                     test_gentle_failover(gcp, backend_service, instance_group,
                                          secondary_zone_instance_group)
+                elif test_case == 'load_report_based_failover':
+                    test_load_report_based_failover(
+                        gcp, backend_service, instance_group,
+                        secondary_zone_instance_group)
                 elif test_case == 'ping_pong':
                     test_ping_pong(gcp, backend_service, instance_group)
                 elif test_case == 'remove_instance_group':
@@ -2216,6 +3242,26 @@
                 elif test_case == 'circuit_breaking':
                     test_circuit_breaking(gcp, backend_service, instance_group,
                                           same_zone_instance_group)
+                elif test_case == 'timeout':
+                    test_timeout(gcp, backend_service, instance_group)
+                elif test_case == 'fault_injection':
+                    test_fault_injection(gcp, backend_service, instance_group)
+                elif test_case == 'api_listener':
+                    server_uri = test_api_listener(gcp, backend_service,
+                                                   instance_group,
+                                                   alternate_backend_service)
+                elif test_case == 'forwarding_rule_port_match':
+                    server_uri = test_forwarding_rule_port_match(
+                        gcp, backend_service, instance_group)
+                elif test_case == 'forwarding_rule_default_port':
+                    server_uri = test_forwarding_rule_default_port(
+                        gcp, backend_service, instance_group)
+                elif test_case == 'metadata_filter':
+                    test_metadata_filter(gcp, backend_service, instance_group,
+                                         alternate_backend_service,
+                                         same_zone_instance_group)
+                elif test_case == 'csds':
+                    test_csds(gcp, backend_service, instance_group, server_uri)
                 else:
                     logger.error('Unknown test case: %s', test_case)
                     sys.exit(1)
diff --git a/grpc/tools/run_tests/sanity/check_bazel_workspace.py b/grpc/tools/run_tests/sanity/check_bazel_workspace.py
index 4070e63..c87892a 100755
--- a/grpc/tools/run_tests/sanity/check_bazel_workspace.py
+++ b/grpc/tools/run_tests/sanity/check_bazel_workspace.py
@@ -41,30 +41,16 @@
 _TWISTED_CONSTANTLY_DEP_NAME = 'com_github_twisted_constantly'
 
 _GRPC_DEP_NAMES = [
-    'upb',
-    'boringssl',
-    'zlib',
-    'com_google_protobuf',
-    'com_google_googletest',
-    'rules_cc',
-    'com_github_google_benchmark',
-    'com_github_cares_cares',
-    'com_google_absl',
-    'io_opencensus_cpp',
-    'envoy_api',
-    _BAZEL_SKYLIB_DEP_NAME,
-    _BAZEL_TOOLCHAINS_DEP_NAME,
-    _BAZEL_COMPDB_DEP_NAME,
-    _TWISTED_TWISTED_DEP_NAME,
-    _YAML_PYYAML_DEP_NAME,
-    _TWISTED_INCREMENTAL_DEP_NAME,
-    _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME,
-    _TWISTED_CONSTANTLY_DEP_NAME,
-    'io_bazel_rules_go',
-    'build_bazel_rules_apple',
-    'build_bazel_apple_support',
-    'libuv',
-    'com_github_google_re2',
+    'upb', 'boringssl', 'zlib', 'com_google_protobuf', 'com_google_googletest',
+    'rules_cc', 'com_github_google_benchmark', 'com_github_cares_cares',
+    'com_google_absl', 'io_opencensus_cpp', 'envoy_api', _BAZEL_SKYLIB_DEP_NAME,
+    _BAZEL_TOOLCHAINS_DEP_NAME, _BAZEL_COMPDB_DEP_NAME,
+    _TWISTED_TWISTED_DEP_NAME, _YAML_PYYAML_DEP_NAME,
+    _TWISTED_INCREMENTAL_DEP_NAME, _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME,
+    _TWISTED_CONSTANTLY_DEP_NAME, 'io_bazel_rules_go',
+    'build_bazel_rules_apple', 'build_bazel_apple_support', 'libuv',
+    'com_googlesource_code_re2', 'bazel_gazelle', 'opencensus_proto',
+    'com_envoyproxy_protoc_gen_validate', 'com_google_googleapis'
 ]
 
 _GRPC_BAZEL_ONLY_DEPS = [
@@ -83,6 +69,11 @@
     'io_bazel_rules_go',
     'build_bazel_rules_apple',
     'build_bazel_apple_support',
+    'com_googlesource_code_re2',
+    'bazel_gazelle',
+    'opencensus_proto',
+    'com_envoyproxy_protoc_gen_validate',
+    'com_google_googleapis',
 ]
 
 
diff --git a/grpc/tools/run_tests/sanity/check_illegal_terms.sh b/grpc/tools/run_tests/sanity/check_illegal_terms.sh
new file mode 100755
index 0000000..f0d06a9
--- /dev/null
+++ b/grpc/tools/run_tests/sanity/check_illegal_terms.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Copyright 2021 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.
+
+set -e
+
+cd "$(dirname "$0")/../../.."
+
+#
+# Disallow the usage of certain terms.
+#
+
+grep -PIirn \
+    '((\b|_)(black[\ -]?hat|black[\ -]?list|black[\ -]?listed|black[\ -]?listing|dummy|grand[\ -]?father\ clause|grand[\ -]?fathered|hang|hung|man[\ -]?power|man[\ -]?hours|master(?!/)|slave|white[\ -]?hat|white[\ -]?list|white[\ -]?listed|white[\ -]?listing)(\b|_))' \
+    examples \
+    include \
+    src/abseil-cpp \
+    src/compiler \
+    src/core \
+    src/cpp \
+    test | \
+    diff - /dev/null
diff --git a/grpc/tools/run_tests/sanity/check_port_platform.py b/grpc/tools/run_tests/sanity/check_port_platform.py
index 4b7c92f..a3e8e03 100755
--- a/grpc/tools/run_tests/sanity/check_port_platform.py
+++ b/grpc/tools/run_tests/sanity/check_port_platform.py
@@ -25,7 +25,8 @@
     for root, dirs, files in os.walk(directory_root):
         for filename in files:
             path = os.path.join(root, filename)
-            if os.path.splitext(path)[1] not in ['.c', '.cc', '.h']: continue
+            if os.path.splitext(path)[1] not in ['.c', '.cc', '.h']:
+                continue
             if path in [
                     os.path.join('include', 'grpc', 'support',
                                  'port_platform.h'),
diff --git a/grpc/tools/run_tests/sanity/check_submodules.sh b/grpc/tools/run_tests/sanity/check_submodules.sh
index 363e6f1..530c5bf 100755
--- a/grpc/tools/run_tests/sanity/check_submodules.sh
+++ b/grpc/tools/run_tests/sanity/check_submodules.sh
@@ -24,22 +24,23 @@
 submodules=$(mktemp /tmp/submXXXXXX)
 want_submodules=$(mktemp /tmp/submXXXXXX)
 
-git submodule | awk '{ print $1 }' | sort > "$submodules"
-cat << EOF | awk '{ print $1 }' | sort > "$want_submodules"
- 0f3bb466b868b523cf1dc9b2aaaed65c77b28862 third_party/abseil-cpp (heads/master)
- 090faecb454fbd6e6e17a75ef8146acb037118d4 third_party/benchmark (v1.5.0)
- 73594cde8c9a52a102c4341c244c833aa61b9c06 third_party/bloaty (remotes/origin/wide-14-g73594cd)
- 29c6e0e27268f5a43e039cd2ed4e849d6b736fc1 third_party/boringssl-with-bazel (remotes/origin/master-with-bazel)
- e982924acee7f7313b4baa4ee5ec000c5e373c30 third_party/cares/cares (cares-1_15_0)
- 9997e1137cdb59e622af13e57ca915a2f3c9f84f third_party/envoy-api (heads/master)
- 80ed4d0bbf65d57cc267dfc63bd2584557f11f9b third_party/googleapis (common-protos-1_3_1-915-g80ed4d0bb)
- c9ccac7cb7345901884aabf5d1a786cfa6e2f397 third_party/googletest (6e2f397)
- 15ae750151ac9341e5945eb38f8982d59fb99201 third_party/libuv (v1.34.0)
- 19fb89416f3fdc2d6668f3738f444885575285bc third_party/protobuf (v3.7.0-rc.2-1277-gfde7cf735)
- e020f3aef8ae6cb59f384bfbaaed72e71e88ccd6 third_party/protoc-gen-validate (v0.4.1)
- aecba11114cf1fac5497aeb844b6966106de3eb6 third_party/re2 (heads/master)
- 1f710aca26a95876e64973a6d2a927a9f4b20ca4 third_party/udpa (heads/master)
- cacf7f1d4e3d44d871b605da3b647f07d718623f third_party/zlib (v1.2.11)
+git submodule | awk '{ print $2 " " $1 }' | sort > "$submodules"
+cat << EOF | sort > "$want_submodules"
+third_party/abseil-cpp 997aaf3a28308eba1b9156aa35ab7bca9688e9f6
+third_party/benchmark 73d4d5e8d6d449fc8663765a42aa8aeeee844489
+third_party/bloaty 73594cde8c9a52a102c4341c244c833aa61b9c06
+third_party/boringssl-with-bazel 688fc5cf5428868679d2ae1072cad81055752068
+third_party/cares/cares e982924acee7f7313b4baa4ee5ec000c5e373c30
+third_party/envoy-api 18b54850c9b7ba29a4ab67cbd7ed7eab7b0bbdb2
+third_party/googleapis 82944da21578a53b74e547774cf62ed31a05b841
+third_party/googletest c9ccac7cb7345901884aabf5d1a786cfa6e2f397
+third_party/libuv 15ae750151ac9341e5945eb38f8982d59fb99201
+third_party/opencensus-proto 4aa53e15cbf1a47bc9087e6cfdca214c1eea4e89
+third_party/protobuf 436bd7880e458532901c58f4d9d1ea23fa7edd52
+third_party/protoc-gen-validate 872b28c457822ed9c2a5405da3c33f386ac0e86f
+third_party/re2 aecba11114cf1fac5497aeb844b6966106de3eb6
+third_party/udpa cc1b757b3eddccaaaf0743cbb107742bb7e3ee4f
+third_party/zlib cacf7f1d4e3d44d871b605da3b647f07d718623f
 EOF
 
 diff -u "$submodules" "$want_submodules"
diff --git a/grpc/tools/run_tests/sanity/check_test_filtering.py b/grpc/tools/run_tests/sanity/check_test_filtering.py
index ea9039f..f287864 100755
--- a/grpc/tools/run_tests/sanity/check_test_filtering.py
+++ b/grpc/tools/run_tests/sanity/check_test_filtering.py
@@ -146,13 +146,13 @@
             if label not in filter_pull_request_tests._WINDOWS_TEST_SUITE.labels
         ])
 
-    def test_whitelist(self):
-        whitelist = filter_pull_request_tests._WHITELIST_DICT
+    def test_allowlist(self):
+        allowlist = filter_pull_request_tests._ALLOWLIST_DICT
         files_that_should_trigger_all_tests = [
             'src/core/foo.bar', 'some_file_not_on_the_white_list', 'BUILD',
             'etc/roots.pem', 'Makefile', 'tools/foo'
         ]
-        for key in list(whitelist.keys()):
+        for key in list(allowlist.keys()):
             for file_name in files_that_should_trigger_all_tests:
                 self.assertFalse(re.match(key, file_name))
 
diff --git a/grpc/tools/run_tests/sanity/check_tracer_sanity.py b/grpc/tools/run_tests/sanity/check_tracer_sanity.py
index 019e44f..8d5635b 100755
--- a/grpc/tools/run_tests/sanity/check_tracer_sanity.py
+++ b/grpc/tools/run_tests/sanity/check_tracer_sanity.py
@@ -26,7 +26,8 @@
 for root, dirs, files in os.walk('src/core'):
     for filename in files:
         path = os.path.join(root, filename)
-        if os.path.splitext(path)[1] != '.c': continue
+        if os.path.splitext(path)[1] != '.c':
+            continue
         with open(path) as f:
             text = f.read()
         for o in pattern.findall(text):
diff --git a/grpc/tools/run_tests/sanity/core_banned_functions.py b/grpc/tools/run_tests/sanity/core_banned_functions.py
index 200ff39..aa18806 100755
--- a/grpc/tools/run_tests/sanity/core_banned_functions.py
+++ b/grpc/tools/run_tests/sanity/core_banned_functions.py
@@ -13,13 +13,16 @@
 # 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.
+"""Explicitly ban select functions from being used in src/core/**.
+
+Most of these functions have internal versions that should be used instead."""
 
 import os
 import sys
 
 os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
 
-# map of banned function signature to whitelist
+# map of banned function signature to allowlist
 BANNED_EXCEPT = {
     'grpc_slice_from_static_buffer(': ['src/core/lib/slice/slice.cc'],
     'grpc_resource_quota_ref(': ['src/core/lib/iomgr/resource_quota.cc'],
@@ -52,15 +55,18 @@
 errors = 0
 num_files = 0
 for root, dirs, files in os.walk('src/core'):
-    if root.startswith('src/core/tsi'): continue
+    if root.startswith('src/core/tsi'):
+        continue
     for filename in files:
         num_files += 1
         path = os.path.join(root, filename)
-        if os.path.splitext(path)[1] != '.cc': continue
+        if os.path.splitext(path)[1] != '.cc':
+            continue
         with open(path) as f:
             text = f.read()
         for banned, exceptions in BANNED_EXCEPT.items():
-            if path in exceptions: continue
+            if path in exceptions:
+                continue
             if banned in text:
                 print('Illegal use of "%s" in %s' % (banned, path))
                 errors += 1
diff --git a/grpc/tools/run_tests/sanity/sanity_tests.yaml b/grpc/tools/run_tests/sanity/sanity_tests.yaml
index 9b6d300..f6954c4 100644
--- a/grpc/tools/run_tests/sanity/sanity_tests.yaml
+++ b/grpc/tools/run_tests/sanity/sanity_tests.yaml
@@ -4,6 +4,7 @@
 - script: tools/run_tests/sanity/check_buildifier.sh
 - script: tools/run_tests/sanity/check_cache_mk.sh
 - script: tools/run_tests/sanity/check_deprecated_grpc++.py
+- script: tools/run_tests/sanity/check_illegal_terms.sh
 - script: tools/run_tests/sanity/check_owners.sh
 - script: tools/run_tests/sanity/check_port_platform.py
 - script: tools/run_tests/sanity/check_qps_scenario_changes.py
diff --git a/grpc/tools/run_tests/start_port_server.py b/grpc/tools/run_tests/start_port_server.py
index cca9859..c3e4789 100755
--- a/grpc/tools/run_tests/start_port_server.py
+++ b/grpc/tools/run_tests/start_port_server.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-
+#!/usr/bin/env python3
 # Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/grpc/tools/run_tests/task_runner.py b/grpc/tools/run_tests/task_runner.py
index ab18004..d54a5c5 100755
--- a/grpc/tools/run_tests/task_runner.py
+++ b/grpc/tools/run_tests/task_runner.py
@@ -73,6 +73,11 @@
                   default=False,
                   action='store_const',
                   const=True)
+argp.add_argument('-x',
+                  '--xml_report',
+                  default='report_taskrunner_sponge_log.xml',
+                  type=str,
+                  help='Filename for the JUnit-compatible XML report')
 
 args = argp.parse_args()
 
@@ -109,7 +114,7 @@
                                      newline_on_success=True,
                                      maxjobs=args.jobs)
 report_utils.render_junit_xml_report(resultset,
-                                     'report_taskrunner_sponge_log.xml',
+                                     args.xml_report,
                                      suite_name='tasks')
 if num_failures == 0:
     jobset.message('SUCCESS',
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/README.md b/grpc/tools/run_tests/xds_k8s_test_driver/README.md
index 640582b..ebacd4b 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/README.md
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/README.md
@@ -3,7 +3,7 @@
 Proxyless Security Mesh Interop Tests executed on Kubernetes.
 
 ### Experimental
-Work in progress. Internal APIs may and will change. Please refrain from making 
+Work in progress. Internal APIs may and will change. Please refrain from making
 changes to this codebase at the moment.
 
 ### Stabilization roadmap 
@@ -11,10 +11,11 @@
 - [ ] Generate namespace for each test to prevent resource name conflicts and
       allow running tests in parallel
 - [ ] Security: run server and client in separate namespaces
-- [ ] Make framework.infrastructure.gcp resources [first-class citizen](https://en.wikipedia.org/wiki/First-class_citizen),
-      support simpler CRUD
-- [ ] Security: manage `roles/iam.workloadIdentityUser` role grant lifecycle
-      for dynamically-named namespaces 
+- [ ] Make framework.infrastructure.gcp resources [first-class
+      citizen](https://en.wikipedia.org/wiki/First-class_citizen), support
+      simpler CRUD
+- [ ] Security: manage `roles/iam.workloadIdentityUser` role grant lifecycle for
+      dynamically-named namespaces 
 - [ ] Restructure `framework.test_app` and `framework.xds_k8s*` into a module
       containing xDS-interop-specific logic
 - [ ] Address inline TODOs in code
@@ -25,6 +26,12 @@
 #### Requirements
 1. Python v3.6+
 2. [Google Cloud SDK](https://cloud.google.com/sdk/docs/install)
+3. A GKE cluster (must enable "Enable VPC-native traffic routing" to use it with
+   the Traffic Director)
+    * Otherwise, you will see error logs when you inspect Kubernetes virtual
+      service
+    * (In `grpc-testing`, you will need a metadata tag
+      `--tags=allow-health-checks` to allow UHC to reach your resources.)
 
 #### Configure GKE cluster access
 
@@ -63,34 +70,77 @@
 
 ### xDS Baseline Tests
 
-Test suite meant to confirm that basic xDS features work as expected.
-Executing it before other test suites will help to identify whether test failure
-related to specific features under test, or caused by unrelated infrastructure
+Test suite meant to confirm that basic xDS features work as expected. Executing
+it before other test suites will help to identify whether test failure related
+to specific features under test, or caused by unrelated infrastructure
 disturbances.
 
+The client and server images are created based on Git commit hashes, but not
+every single one of them. It is triggered nightly and per-release. For example,
+the commit we are using below (`d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf`) comes
+from branch `v1.37.x` in `grpc-java` repo.
+
 ```sh
 # Help
 python -m tests.baseline_test --help
-python -m tests.baseline_test --helpfull
+python -m tests.baseline_test --helpful
 
 # Run on grpc-testing cluster
 python -m tests.baseline_test \
   --flagfile="config/grpc-testing.cfg" \
   --kube_context="${KUBE_CONTEXT}" \
-  --server_image="gcr.io/grpc-testing/xds-k8s-test-server-java:latest" \
-  --client_image="gcr.io/grpc-testing/xds-k8s-test-client-java:latest" \
+  --server_image="gcr.io/grpc-testing/xds-interop/java-server:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf" \
+  --client_image="gcr.io/grpc-testing/xds-interop/java-client:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf"
 ```
 
 ### xDS Security Tests
 ```sh
 # Help
 python -m tests.security_test --help
-python -m tests.security_test --helpfull
+python -m tests.security_test --helpful
 
 # Run on grpc-testing cluster
 python -m tests.security_test \
   --flagfile="config/grpc-testing.cfg" \
   --kube_context="${KUBE_CONTEXT}" \
-  --server_image="gcr.io/grpc-testing/xds-k8s-test-server-java:latest" \
-  --client_image="gcr.io/grpc-testing/xds-k8s-test-client-java:latest" \
+  --server_image="gcr.io/grpc-testing/xds-interop/java-server:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf" \
+  --client_image="gcr.io/grpc-testing/xds-interop/java-client:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf"
+```
+
+### Test namespace
+
+It's possible to run multiple xDS interop test workloads in the same project.
+But we need to ensure the name of the global resources won't conflict. This can
+be solved by supplying `--namespace` and `--server_xds_port`. The xDS port needs
+to be unique across the entire project (default port range is [8080, 8280],
+avoid if possible). Here is an example:
+
+```shell
+python3 -m tests.baseline_test \
+  --flagfile="config/grpc-testing.cfg" \
+  --kube_context="${KUBE_CONTEXT}" \
+  --server_image="gcr.io/grpc-testing/xds-interop/java-server:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf" \
+  --client_image="gcr.io/grpc-testing/xds-interop/java-client:d22f93e1ade22a1e026b57210f6fc21f7a3ca0cf" \
+  --namespace="box-$(date +"%F-%R")" \
+  --server_xds_port="$(($RANDOM%1000 + 34567))"
+```
+
+### Setup test configuration
+
+There are many arguments to be passed into the test run. You can save the
+arguments to a config file for your development environment. Please take a look
+at
+https://github.com/grpc/grpc/blob/master/tools/run_tests/xds_k8s_test_driver/config/local-dev.cfg.example.
+You can create your own config by:
+
+```shell
+cp config/local-dev.cfg.example config/local-dev.cfg
+```
+
+### Clean-up resources
+
+```shell
+python -m bin.run_td_setup --cmd=cleanup --flagfile=config/local-dev.cfg && \
+python -m bin.run_test_client --cmd=cleanup --flagfile=config/local-dev.cfg && \
+python -m bin.run_test_server --cmd=cleanup --cleanup_namespace --flagfile=config/local-dev.cfg
 ```
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_channelz.py b/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_channelz.py
index a3ccb3a..a3a341a 100755
--- a/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_channelz.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_channelz.py
@@ -26,7 +26,7 @@
     python -m bin.run_channelz --flagfile=config/local-dev.cfg --security=mtls_error
 
     # More information and usage options
-    python -m bin.run_channelz --helpfull
+    python -m bin.run_channelz --helpful
 """
 import hashlib
 import logging
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_td_setup.py b/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_td_setup.py
index a3b57d4..049493a 100755
--- a/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_td_setup.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_td_setup.py
@@ -28,7 +28,7 @@
     python -m bin.run_td_setup --flagfile=config/local-dev.cfg --security=mtls
 
     # More information and usage options
-    python -m bin.run_td_setup --helpfull
+    python -m bin.run_td_setup --helpful
 """
 import logging
 import uuid
@@ -41,6 +41,7 @@
 from framework.infrastructure import gcp
 from framework.infrastructure import k8s
 from framework.infrastructure import traffic_director
+from framework.test_app import server_app
 
 logger = logging.getLogger(__name__)
 # Flags
@@ -61,6 +62,9 @@
 flags.adopt_module_key_flags(xds_flags)
 flags.adopt_module_key_flags(xds_k8s_flags)
 
+_DEFAULT_SECURE_MODE_MAINTENANCE_PORT = \
+    server_app.KubernetesServerRunner.DEFAULT_SECURE_MODE_MAINTENANCE_PORT
+
 
 def main(argv):
     if len(argv) > 1:
@@ -76,6 +80,7 @@
     # Test server
     server_name = xds_flags.SERVER_NAME.value
     server_port = xds_flags.SERVER_PORT.value
+    server_maintenance_port = xds_flags.SERVER_MAINTENANCE_PORT.value
     server_xds_host = xds_flags.SERVER_XDS_HOST.value
     server_xds_port = xds_flags.SERVER_XDS_PORT.value
 
@@ -92,17 +97,23 @@
             project=project,
             resource_prefix=namespace,
             network=network)
+        if server_maintenance_port is None:
+            server_maintenance_port = _DEFAULT_SECURE_MODE_MAINTENANCE_PORT
 
     try:
         if command in ('create', 'cycle'):
             logger.info('Create mode')
             if security_mode is None:
                 logger.info('No security')
-                td.setup_for_grpc(server_xds_host, server_xds_port)
+                td.setup_for_grpc(server_xds_host,
+                                  server_xds_port,
+                                  health_check_port=server_maintenance_port)
 
             elif security_mode == 'mtls':
                 logger.info('Setting up mtls')
-                td.setup_for_grpc(server_xds_host, server_xds_port)
+                td.setup_for_grpc(server_xds_host,
+                                  server_xds_port,
+                                  health_check_port=server_maintenance_port)
                 td.setup_server_security(server_namespace=namespace,
                                          server_name=server_name,
                                          server_port=server_port,
@@ -115,7 +126,9 @@
 
             elif security_mode == 'tls':
                 logger.info('Setting up tls')
-                td.setup_for_grpc(server_xds_host, server_xds_port)
+                td.setup_for_grpc(server_xds_host,
+                                  server_xds_port,
+                                  health_check_port=server_maintenance_port)
                 td.setup_server_security(server_namespace=namespace,
                                          server_name=server_name,
                                          server_port=server_port,
@@ -128,7 +141,9 @@
 
             elif security_mode == 'plaintext':
                 logger.info('Setting up plaintext')
-                td.setup_for_grpc(server_xds_host, server_xds_port)
+                td.setup_for_grpc(server_xds_host,
+                                  server_xds_port,
+                                  health_check_port=server_maintenance_port)
                 td.setup_server_security(server_namespace=namespace,
                                          server_name=server_name,
                                          server_port=server_port,
@@ -143,7 +158,9 @@
                 # Error case: server expects client mTLS cert,
                 # but client configured only for TLS
                 logger.info('Setting up mtls_error')
-                td.setup_for_grpc(server_xds_host, server_xds_port)
+                td.setup_for_grpc(server_xds_host,
+                                  server_xds_port,
+                                  health_check_port=server_maintenance_port)
                 td.setup_server_security(server_namespace=namespace,
                                          server_name=server_name,
                                          server_port=server_port,
@@ -158,7 +175,9 @@
                 # Error case: client does not authorize server
                 # because of mismatched SAN name.
                 logger.info('Setting up mtls_error')
-                td.setup_for_grpc(server_xds_host, server_xds_port)
+                td.setup_for_grpc(server_xds_host,
+                                  server_xds_port,
+                                  health_check_port=server_maintenance_port)
                 # Regular TLS setup, but with client policy configured using
                 # intentionality incorrect server_namespace.
                 td.setup_server_security(server_namespace=namespace,
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_test_client.py b/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_test_client.py
index 2d1bc06..18faa87 100755
--- a/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_test_client.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_test_client.py
@@ -57,8 +57,9 @@
         deployment_name=xds_flags.CLIENT_NAME.value,
         image_name=xds_k8s_flags.CLIENT_IMAGE.value,
         gcp_service_account=xds_k8s_flags.GCP_SERVICE_ACCOUNT.value,
-        network=xds_flags.NETWORK.value,
         td_bootstrap_image=xds_k8s_flags.TD_BOOTSTRAP_IMAGE.value,
+        xds_server_uri=xds_flags.XDS_SERVER_URI.value,
+        network=xds_flags.NETWORK.value,
         stats_port=xds_flags.CLIENT_PORT.value,
         reuse_namespace=_REUSE_NAMESPACE.value)
 
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_test_server.py b/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_test_server.py
index fe78799..a1e45b3 100755
--- a/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_test_server.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/bin/run_test_server.py
@@ -59,6 +59,7 @@
     if _SECURE.value:
         runner_kwargs.update(
             td_bootstrap_image=xds_k8s_flags.TD_BOOTSTRAP_IMAGE.value,
+            xds_server_uri=xds_flags.XDS_SERVER_URI.value,
             deployment_template='server-secure.deployment.yaml')
 
     k8s_api_manager = k8s.KubernetesApiManager(xds_k8s_flags.KUBE_CONTEXT.value)
@@ -68,8 +69,10 @@
 
     if _CMD.value == 'run':
         logger.info('Run server, secure_mode=%s', _SECURE.value)
-        server_runner.run(test_port=xds_flags.SERVER_PORT.value,
-                          secure_mode=_SECURE.value)
+        server_runner.run(
+            test_port=xds_flags.SERVER_PORT.value,
+            maintenance_port=xds_flags.SERVER_MAINTENANCE_PORT.value,
+            secure_mode=_SECURE.value)
 
     elif _CMD.value == 'cleanup':
         logger.info('Cleanup server')
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/config/common.cfg b/grpc/tools/run_tests/xds_k8s_test_driver/config/common.cfg
index 9e253aa..e4c8090 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/config/common.cfg
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/config/common.cfg
@@ -1,4 +1,4 @@
 --namespace=interop-psm-security
---td_bootstrap_image=gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.10.0
+--td_bootstrap_image=gcr.io/grpc-testing/td-grpc-bootstrap:2558ec79df06984ed0d37e9e69f34688ffe301bb
 --logger_levels=__main__:DEBUG,framework:INFO
 --verbosity=0
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/config/local-dev.cfg.example b/grpc/tools/run_tests/xds_k8s_test_driver/config/local-dev.cfg.example
index b32517a..2b31024 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/config/local-dev.cfg.example
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/config/local-dev.cfg.example
@@ -1,10 +1,26 @@
 # Copy to local-dev.cfg
-# Local dev settings
---flagfile=config/grpc-testing.cfg
---kube_context=gke_grpc-testing_us-central1-a_interop-test-psm-sec1-us-central1
---namespace=your-namespace
-# Test images
---server_image=gcr.io/grpc-testing/xds-k8s-test-server-java:latest
---client_image=gcr.io/grpc-testing/xds-k8s-test-client-java:latest
+# Usage: python -m tests.baseline_test --flagfile=config/local-dev.cfg
+
+# Import common settings
+--flagfile=config/common.cfg
+
+# Project settings
+--project=your_project_id
+--gcp_service_account=project_number-compute@developer.gserviceaccount.com
+--private_api_key_secret_name=projects/project_number/secrets/xds-interop-tests-private-api-access-key
+
+# The name of kube context to use. See `gcloud container clusters get-credentials` and `kubectl config`
+--kube_context=context_name
+
+# Test images, f.e. java v1.35.x:
+--server_image=gcr.io/grpc-testing/xds-interop/java-server:3b8b3c8f297617848fd6471a76985430dc6bd4c5
+--client_image=gcr.io/grpc-testing/xds-interop/java-client:3b8b3c8f297617848fd6471a76985430dc6bd4c5
+
+# Uncomment for verbose output
+#--logger_levels=__main__:DEBUG,framework:DEBUG
+#--verbosity=1
+
 # Enable port forwarding in local dev
 --debug_use_port_forwarding
+# (convenience) Allow to set always known flags
+--undefok=private_api_key_secret_name
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/helpers/retryers.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/helpers/retryers.py
index d76a406..4ea4e90 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/helpers/retryers.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/helpers/retryers.py
@@ -21,16 +21,24 @@
 > - https://tenacity.readthedocs.io/en/latest/index.html
 """
 import datetime
+import logging
 from typing import Any, List, Optional
 
 import tenacity
 
+retryers_logger = logging.getLogger(__name__)
 # Type aliases
 timedelta = datetime.timedelta
 Retrying = tenacity.Retrying
+RetryError = tenacity.RetryError
+_after_log = tenacity.after_log
+_before_sleep_log = tenacity.before_sleep_log
 _retry_if_exception_type = tenacity.retry_if_exception_type
+_stop_after_attempt = tenacity.stop_after_attempt
 _stop_after_delay = tenacity.stop_after_delay
+_stop_any = tenacity.stop_any
 _wait_exponential = tenacity.wait_exponential
+_wait_fixed = tenacity.wait_fixed
 
 
 def _retry_on_exceptions(retry_on_exceptions: Optional[List[Any]] = None):
@@ -45,9 +53,40 @@
         wait_min: timedelta,
         wait_max: timedelta,
         timeout: timedelta,
-        retry_on_exceptions: Optional[List[Any]] = None) -> Retrying:
+        retry_on_exceptions: Optional[List[Any]] = None,
+        logger: Optional[logging.Logger] = None,
+        log_level: Optional[int] = logging.DEBUG) -> Retrying:
+    if logger is None:
+        logger = retryers_logger
+    if log_level is None:
+        log_level = logging.DEBUG
     return Retrying(retry=_retry_on_exceptions(retry_on_exceptions),
                     wait=_wait_exponential(min=wait_min.total_seconds(),
                                            max=wait_max.total_seconds()),
                     stop=_stop_after_delay(timeout.total_seconds()),
-                    reraise=True)
+                    before_sleep=_before_sleep_log(logger, log_level))
+
+
+def constant_retryer(*,
+                     wait_fixed: timedelta,
+                     attempts: int = 0,
+                     timeout: timedelta = None,
+                     retry_on_exceptions: Optional[List[Any]] = None,
+                     logger: Optional[logging.Logger] = None,
+                     log_level: Optional[int] = logging.DEBUG) -> Retrying:
+    if logger is None:
+        logger = retryers_logger
+    if log_level is None:
+        log_level = logging.DEBUG
+    if attempts < 1 and timeout is None:
+        raise ValueError('The number of attempts or the timeout must be set')
+    stops = []
+    if attempts > 0:
+        stops.append(_stop_after_attempt(attempts))
+    if timeout is not None:
+        stops.append(_stop_after_delay.total_seconds())
+
+    return Retrying(retry=_retry_on_exceptions(retry_on_exceptions),
+                    wait=_wait_fixed(wait_fixed.total_seconds()),
+                    stop=_stop_any(*stops),
+                    before_sleep=_before_sleep_log(logger, log_level))
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py
index b326f54..25458bc 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py
@@ -15,7 +15,7 @@
 import contextlib
 import functools
 import logging
-from typing import Optional
+from typing import Optional, List
 
 # Workaround: `grpc` must be imported before `google.protobuf.json_format`,
 # to prevent "Segmentation fault". Ref https://github.com/grpc/grpc/issues/24897
@@ -112,9 +112,11 @@
     def networksecurity(self, version):
         api_name = 'networksecurity'
         if version == 'v1alpha1':
-            return self._build_from_discovery_v2(api_name,
-                                                 version,
-                                                 api_key=self.private_api_key)
+            return self._build_from_discovery_v2(
+                api_name,
+                version,
+                api_key=self.private_api_key,
+                visibility_labels=['NETWORKSECURITY_ALPHA'])
 
         raise NotImplementedError(f'Network Security {version} not supported')
 
@@ -122,9 +124,11 @@
     def networkservices(self, version):
         api_name = 'networkservices'
         if version == 'v1alpha1':
-            return self._build_from_discovery_v2(api_name,
-                                                 version,
-                                                 api_key=self.private_api_key)
+            return self._build_from_discovery_v2(
+                api_name,
+                version,
+                api_key=self.private_api_key,
+                visibility_labels=['NETWORKSERVICES_ALPHA'])
 
         raise NotImplementedError(f'Network Services {version} not supported')
 
@@ -133,7 +137,7 @@
         if version == 'v1':
             return secretmanager_v1.SecretManagerServiceClient()
 
-        raise NotImplementedError(f'Secrets Manager {version} not supported')
+        raise NotImplementedError(f'Secret Manager {version} not supported')
 
     def _build_from_discovery_v1(self, api_name, version):
         api = discovery.build(api_name,
@@ -143,13 +147,28 @@
         self._exit_stack.enter_context(api)
         return api
 
-    def _build_from_discovery_v2(self, api_name, version, *, api_key=None):
-        key_arg = f'&key={api_key}' if api_key else ''
+    def _build_from_discovery_v2(self,
+                                 api_name,
+                                 version,
+                                 *,
+                                 api_key: Optional[str] = None,
+                                 visibility_labels: Optional[List] = None):
+        params = {}
+        if api_key:
+            params['key'] = api_key
+        if visibility_labels:
+            # Dash-separated list of labels.
+            params['labels'] = '_'.join(visibility_labels)
+
+        params_str = ''
+        if params:
+            params_str = '&' + ('&'.join(f'{k}={v}' for k, v in params.items()))
+
         api = discovery.build(
             api_name,
             version,
             cache_discovery=False,
-            discoveryServiceUrl=f'{self.v2_discovery_uri}{key_arg}')
+            discoveryServiceUrl=f'{self.v2_discovery_uri}{params_str}')
         self._exit_stack.enter_context(api)
         return api
 
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/compute.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/compute.py
index a001346..838aed0 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/compute.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/compute.py
@@ -28,7 +28,7 @@
 
 class ComputeV1(gcp.api.GcpProjectApiResource):
     # TODO(sergiitk): move someplace better
-    _WAIT_FOR_BACKEND_SEC = 60 * 5
+    _WAIT_FOR_BACKEND_SEC = 60 * 10
     _WAIT_FOR_OPERATION_SEC = 60 * 5
 
     @dataclasses.dataclass(frozen=True)
@@ -45,22 +45,37 @@
 
     class HealthCheckProtocol(enum.Enum):
         TCP = enum.auto()
+        GRPC = enum.auto()
 
     class BackendServiceProtocol(enum.Enum):
         HTTP2 = enum.auto()
         GRPC = enum.auto()
 
-    def create_health_check_tcp(self, name,
-                                use_serving_port=False) -> GcpResource:
-        health_check_settings = {}
-        if use_serving_port:
-            health_check_settings['portSpecification'] = 'USE_SERVING_PORT'
+    def create_health_check(self,
+                            name: str,
+                            protocol: HealthCheckProtocol,
+                            *,
+                            port: Optional[int] = None) -> GcpResource:
+        if protocol is self.HealthCheckProtocol.TCP:
+            health_check_field = 'tcpHealthCheck'
+        elif protocol is self.HealthCheckProtocol.GRPC:
+            health_check_field = 'grpcHealthCheck'
+        else:
+            raise TypeError(f'Unexpected Health Check protocol: {protocol}')
 
-        return self._insert_resource(self.api.healthChecks(), {
-            'name': name,
-            'type': 'TCP',
-            'tcpHealthCheck': health_check_settings,
-        })
+        health_check_settings = {}
+        if port is None:
+            health_check_settings['portSpecification'] = 'USE_SERVING_PORT'
+        else:
+            health_check_settings['portSpecification'] = 'USE_FIXED_PORT'
+            health_check_settings['port'] = port
+
+        return self._insert_resource(
+            self.api.healthChecks(), {
+                'name': name,
+                'type': protocol.name,
+                health_check_field: health_check_settings,
+            })
 
     def delete_health_check(self, name):
         self._delete_resource(self.api.healthChecks(), 'healthCheck', name)
@@ -113,12 +128,12 @@
                               name)
 
     def create_url_map(
-            self,
-            name: str,
-            matcher_name: str,
-            src_hosts,
-            dst_default_backend_service: GcpResource,
-            dst_host_rule_match_backend_service: Optional[GcpResource] = None,
+        self,
+        name: str,
+        matcher_name: str,
+        src_hosts,
+        dst_default_backend_service: GcpResource,
+        dst_host_rule_match_backend_service: Optional[GcpResource] = None,
     ) -> GcpResource:
         if dst_host_rule_match_backend_service is None:
             dst_host_rule_match_backend_service = dst_default_backend_service
@@ -142,9 +157,9 @@
         self._delete_resource(self.api.urlMaps(), 'urlMap', name)
 
     def create_target_grpc_proxy(
-            self,
-            name: str,
-            url_map: GcpResource,
+        self,
+        name: str,
+        url_map: GcpResource,
     ) -> GcpResource:
         return self._insert_resource(self.api.targetGrpcProxies(), {
             'name': name,
@@ -157,9 +172,9 @@
                               name)
 
     def create_target_http_proxy(
-            self,
-            name: str,
-            url_map: GcpResource,
+        self,
+        name: str,
+        url_map: GcpResource,
     ) -> GcpResource:
         return self._insert_resource(self.api.targetHttpProxies(), {
             'name': name,
@@ -171,11 +186,11 @@
                               name)
 
     def create_forwarding_rule(
-            self,
-            name: str,
-            src_port: int,
-            target_proxy: GcpResource,
-            network_url: str,
+        self,
+        name: str,
+        src_port: int,
+        target_proxy: GcpResource,
+        network_url: str,
     ) -> GcpResource:
         return self._insert_resource(
             self.api.globalForwardingRules(),
@@ -229,11 +244,11 @@
         return neg
 
     def wait_for_backends_healthy_status(
-            self,
-            backend_service,
-            backends,
-            timeout_sec=_WAIT_FOR_BACKEND_SEC,
-            wait_sec=4,
+        self,
+        backend_service,
+        backends,
+        timeout_sec=_WAIT_FOR_BACKEND_SEC,
+        wait_sec=4,
     ):
         pending = set(backends)
 
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/k8s.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/k8s.py
index ca446bc..557c424 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/k8s.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/k8s.py
@@ -82,6 +82,12 @@
     NEG_STATUS_META = 'cloud.google.com/neg-status'
     PORT_FORWARD_LOCAL_ADDRESS: str = '127.0.0.1'
     DELETE_GRACE_PERIOD_SEC: int = 5
+    WAIT_SHORT_TIMEOUT_SEC: int = 60
+    WAIT_SHORT_SLEEP_SEC: int = 1
+    WAIT_MEDIUM_TIMEOUT_SEC: int = 5 * 60
+    WAIT_MEDIUM_SLEEP_SEC: int = 10
+    WAIT_LONG_TIMEOUT_SEC: int = 10 * 60
+    WAIT_LONG_SLEEP_SEC: int = 30
 
     def __init__(self, api: KubernetesApiManager, name: str):
         self.name = name
@@ -100,7 +106,8 @@
     def get_service_account(self, name) -> V1Service:
         return self.api.core.read_namespaced_service_account(name, self.name)
 
-    def delete_service(self, name,
+    def delete_service(self,
+                       name,
                        grace_period_seconds=DELETE_GRACE_PERIOD_SEC):
         self.api.core.delete_namespaced_service(
             name=name,
@@ -130,7 +137,10 @@
                 propagation_policy='Foreground',
                 grace_period_seconds=grace_period_seconds))
 
-    def wait_for_service_deleted(self, name: str, timeout_sec=60, wait_sec=1):
+    def wait_for_service_deleted(self,
+                                 name: str,
+                                 timeout_sec=WAIT_SHORT_TIMEOUT_SEC,
+                                 wait_sec=WAIT_SHORT_SLEEP_SEC):
 
         @retrying.retry(retry_on_result=lambda r: r is not None,
                         stop_max_delay=timeout_sec * 1000,
@@ -146,8 +156,8 @@
 
     def wait_for_service_account_deleted(self,
                                          name: str,
-                                         timeout_sec=60,
-                                         wait_sec=1):
+                                         timeout_sec=WAIT_SHORT_TIMEOUT_SEC,
+                                         wait_sec=WAIT_SHORT_SLEEP_SEC):
 
         @retrying.retry(retry_on_result=lambda r: r is not None,
                         stop_max_delay=timeout_sec * 1000,
@@ -161,7 +171,9 @@
 
         _wait_for_deleted_service_account_with_retry()
 
-    def wait_for_namespace_deleted(self, timeout_sec=240, wait_sec=5):
+    def wait_for_namespace_deleted(self,
+                                   timeout_sec=WAIT_LONG_TIMEOUT_SEC,
+                                   wait_sec=WAIT_LONG_SLEEP_SEC):
 
         @retrying.retry(retry_on_result=lambda r: r is not None,
                         stop_max_delay=timeout_sec * 1000,
@@ -175,7 +187,10 @@
 
         _wait_for_deleted_namespace_with_retry()
 
-    def wait_for_service_neg(self, name: str, timeout_sec=60, wait_sec=1):
+    def wait_for_service_neg(self,
+                             name: str,
+                             timeout_sec=WAIT_SHORT_TIMEOUT_SEC,
+                             wait_sec=WAIT_SHORT_SLEEP_SEC):
 
         @retrying.retry(retry_on_result=lambda r: not r,
                         stop_max_delay=timeout_sec * 1000,
@@ -217,11 +232,12 @@
         # V1LabelSelector.match_expressions not supported at the moment
         return self.list_pods_with_labels(deployment.spec.selector.match_labels)
 
-    def wait_for_deployment_available_replicas(self,
-                                               name,
-                                               count=1,
-                                               timeout_sec=60,
-                                               wait_sec=3):
+    def wait_for_deployment_available_replicas(
+            self,
+            name,
+            count=1,
+            timeout_sec=WAIT_MEDIUM_TIMEOUT_SEC,
+            wait_sec=WAIT_MEDIUM_SLEEP_SEC):
 
         @retrying.retry(
             retry_on_result=lambda r: not self._replicas_available(r, count),
@@ -239,8 +255,8 @@
 
     def wait_for_deployment_deleted(self,
                                     deployment_name: str,
-                                    timeout_sec=60,
-                                    wait_sec=1):
+                                    timeout_sec=WAIT_MEDIUM_TIMEOUT_SEC,
+                                    wait_sec=WAIT_MEDIUM_SLEEP_SEC):
 
         @retrying.retry(retry_on_result=lambda r: r is not None,
                         stop_max_delay=timeout_sec * 1000,
@@ -264,7 +280,10 @@
     def get_pod(self, name) -> client.V1Pod:
         return self.api.core.read_namespaced_pod(name, self.name)
 
-    def wait_for_pod_started(self, pod_name, timeout_sec=60, wait_sec=1):
+    def wait_for_pod_started(self,
+                             pod_name,
+                             timeout_sec=WAIT_SHORT_TIMEOUT_SEC,
+                             wait_sec=WAIT_SHORT_SLEEP_SEC):
 
         @retrying.retry(retry_on_result=lambda r: not self._pod_started(r),
                         stop_max_delay=timeout_sec * 1000,
@@ -278,11 +297,11 @@
         _wait_for_pod_started()
 
     def port_forward_pod(
-            self,
-            pod: V1Pod,
-            remote_port: int,
-            local_port: Optional[int] = None,
-            local_address: Optional[str] = None,
+        self,
+        pod: V1Pod,
+        remote_port: int,
+        local_port: Optional[int] = None,
+        local_address: Optional[str] = None,
     ) -> subprocess.Popen:
         """Experimental"""
         local_address = local_address or self.PORT_FORWARD_LOCAL_ADDRESS
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/traffic_director.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/traffic_director.py
index 895651f..531c0c2 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/traffic_director.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/traffic_director.py
@@ -26,6 +26,7 @@
 ZonalGcpResource = _ComputeV1.ZonalGcpResource
 BackendServiceProtocol = _ComputeV1.BackendServiceProtocol
 _BackendGRPC = BackendServiceProtocol.GRPC
+_HealthCheckGRPC = HealthCheckProtocol.GRPC
 
 # Network Security
 _NetworkSecurityV1Alpha1 = gcp.network_security.NetworkSecurityV1Alpha1
@@ -47,12 +48,12 @@
     FORWARDING_RULE_NAME = "forwarding-rule"
 
     def __init__(
-            self,
-            gcp_api_manager: gcp.api.GcpApiManager,
-            project: str,
-            *,
-            resource_prefix: str,
-            network: str = 'default',
+        self,
+        gcp_api_manager: gcp.api.GcpApiManager,
+        project: str,
+        *,
+        resource_prefix: str,
+        network: str = 'default',
     ):
         # API
         self.compute = _ComputeV1(gcp_api_manager, project)
@@ -83,13 +84,18 @@
             service_host,
             service_port,
             *,
-            backend_protocol: Optional[BackendServiceProtocol] = _BackendGRPC):
-        self.setup_backend_for_grpc(protocol=backend_protocol)
+            backend_protocol: Optional[BackendServiceProtocol] = _BackendGRPC,
+            health_check_port: Optional[int] = None):
+        self.setup_backend_for_grpc(protocol=backend_protocol,
+                                    health_check_port=health_check_port)
         self.setup_routing_rule_map_for_grpc(service_host, service_port)
 
     def setup_backend_for_grpc(
-            self, *, protocol: Optional[BackendServiceProtocol] = _BackendGRPC):
-        self.create_health_check()
+            self,
+            *,
+            protocol: Optional[BackendServiceProtocol] = _BackendGRPC,
+            health_check_port: Optional[int] = None):
+        self.create_health_check(port=health_check_port)
         self.create_backend_service(protocol)
 
     def setup_routing_rule_map_for_grpc(self, service_host, service_port):
@@ -111,17 +117,20 @@
     def _ns_name(self, name):
         return f'{self.resource_prefix}-{name}'
 
-    def create_health_check(self, protocol=HealthCheckProtocol.TCP):
+    def create_health_check(
+            self,
+            *,
+            protocol: Optional[HealthCheckProtocol] = _HealthCheckGRPC,
+            port: Optional[int] = None):
         if self.health_check:
             raise ValueError(f'Health check {self.health_check.name} '
                              'already created, delete it first')
+        if protocol is None:
+            protocol = _HealthCheckGRPC
+
         name = self._ns_name(self.HEALTH_CHECK_NAME)
         logger.info('Creating %s Health Check "%s"', protocol.name, name)
-        if protocol is HealthCheckProtocol.TCP:
-            resource = self.compute.create_health_check_tcp(
-                name, use_serving_port=True)
-        else:
-            raise ValueError('Unexpected protocol')
+        resource = self.compute.create_health_check(name, protocol, port=port)
         self.health_check = resource
 
     def delete_health_check(self, force=False):
@@ -191,9 +200,9 @@
                                                       self.backends)
 
     def create_url_map(
-            self,
-            src_host: str,
-            src_port: int,
+        self,
+        src_host: str,
+        src_port: int,
     ) -> GcpResource:
         src_address = f'{src_host}:{src_port}'
         name = self._ns_name(self.URL_MAP_NAME)
@@ -290,12 +299,12 @@
     CERTIFICATE_PROVIDER_INSTANCE = "google_cloud_private_spiffe"
 
     def __init__(
-            self,
-            gcp_api_manager: gcp.api.GcpApiManager,
-            project: str,
-            *,
-            resource_prefix: str,
-            network: str = 'default',
+        self,
+        gcp_api_manager: gcp.api.GcpApiManager,
+        project: str,
+        *,
+        resource_prefix: str,
+        network: str = 'default',
     ):
         super().__init__(gcp_api_manager,
                          project,
@@ -387,7 +396,7 @@
             "metadataLabels": endpoint_matcher_labels
         }
         config = {
-            "type": "SIDECAR_PROXY",
+            "type": "GRPC_SERVER",
             "httpFilters": {},
             "trafficPortSelector": port_selector,
             "endpointMatcher": {
@@ -448,9 +457,9 @@
         self.client_tls_policy = None
 
     def backend_service_apply_client_mtls_policy(
-            self,
-            server_namespace,
-            server_name,
+        self,
+        server_namespace,
+        server_name,
     ):
         if not self.client_tls_policy:
             logger.warning(
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc.py
index 79ab84a..3e15553 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc.py
@@ -29,8 +29,7 @@
 
 class GrpcClientHelper:
     channel: grpc.Channel
-    DEFAULT_CONNECTION_TIMEOUT_SEC = 60
-    DEFAULT_WAIT_FOR_READY_SEC = 60
+    DEFAULT_RPC_DEADLINE_SEC = 90
 
     def __init__(self, channel: grpc.Channel, stub_class: ClassVar):
         self.channel = channel
@@ -44,20 +43,16 @@
             *,
             rpc: str,
             req: Message,
-            wait_for_ready_sec: Optional[int] = DEFAULT_WAIT_FOR_READY_SEC,
-            connection_timeout_sec: Optional[
-                int] = DEFAULT_CONNECTION_TIMEOUT_SEC,
+            deadline_sec: Optional[int] = DEFAULT_RPC_DEADLINE_SEC,
             log_level: Optional[int] = logging.DEBUG) -> Message:
-        if wait_for_ready_sec is None:
-            wait_for_ready_sec = self.DEFAULT_WAIT_FOR_READY_SEC
-        if connection_timeout_sec is None:
-            connection_timeout_sec = self.DEFAULT_CONNECTION_TIMEOUT_SEC
+        if deadline_sec is None:
+            deadline_sec = self.DEFAULT_RPC_DEADLINE_SEC
 
-        timeout_sec = wait_for_ready_sec + connection_timeout_sec
-        rpc_callable: grpc.UnaryUnaryMultiCallable = getattr(self.stub, rpc)
-
-        call_kwargs = dict(wait_for_ready=True, timeout=timeout_sec)
+        call_kwargs = dict(wait_for_ready=True, timeout=deadline_sec)
         self._log_rpc_request(rpc, req, call_kwargs, log_level)
+
+        # Call RPC, e.g. RpcStub(channel).RpcMethod(req, ...options)
+        rpc_callable: grpc.UnaryUnaryMultiCallable = getattr(self.stub, rpc)
         return rpc_callable(req, **call_kwargs)
 
     def _log_rpc_request(self, rpc, req, call_kwargs, log_level=logging.DEBUG):
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_channelz.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_channelz.py
index 3bf4b26..b4e6b18 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_channelz.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_channelz.py
@@ -95,22 +95,25 @@
                 return server_socket
         return None
 
-    def find_channels_for_target(self, target: str) -> Iterator[Channel]:
-        return (channel for channel in self.list_channels()
+    def find_channels_for_target(self, target: str,
+                                 **kwargs) -> Iterator[Channel]:
+        return (channel for channel in self.list_channels(**kwargs)
                 if channel.data.target == target)
 
-    def find_server_listening_on_port(self, port: int) -> Optional[Server]:
-        for server in self.list_servers():
+    def find_server_listening_on_port(self, port: int,
+                                      **kwargs) -> Optional[Server]:
+        for server in self.list_servers(**kwargs):
             listen_socket_ref: SocketRef
             for listen_socket_ref in server.listen_socket:
-                listen_socket = self.get_socket(listen_socket_ref.socket_id)
+                listen_socket = self.get_socket(listen_socket_ref.socket_id,
+                                                **kwargs)
                 listen_address: Address = listen_socket.local
                 if (self.is_sock_tcpip_address(listen_address) and
                         listen_address.tcpip_address.port == port):
                     return server
         return None
 
-    def list_channels(self) -> Iterator[Channel]:
+    def list_channels(self, **kwargs) -> Iterator[Channel]:
         """
         Iterate over all pages of all root channels.
 
@@ -125,12 +128,13 @@
             start += 1
             response = self.call_unary_with_deadline(
                 rpc='GetTopChannels',
-                req=_GetTopChannelsRequest(start_channel_id=start))
+                req=_GetTopChannelsRequest(start_channel_id=start),
+                **kwargs)
             for channel in response.channel:
                 start = max(start, channel.ref.channel_id)
                 yield channel
 
-    def list_servers(self) -> Iterator[Server]:
+    def list_servers(self, **kwargs) -> Iterator[Server]:
         """Iterate over all pages of all servers that exist in the process."""
         start: int = -1
         response: Optional[_GetServersResponse] = None
@@ -139,12 +143,14 @@
             # value by adding 1 to the highest seen result ID.
             start += 1
             response = self.call_unary_with_deadline(
-                rpc='GetServers', req=_GetServersRequest(start_server_id=start))
+                rpc='GetServers',
+                req=_GetServersRequest(start_server_id=start),
+                **kwargs)
             for server in response.server:
                 start = max(start, server.ref.server_id)
                 yield server
 
-    def list_server_sockets(self, server: Server) -> Iterator[Socket]:
+    def list_server_sockets(self, server: Server, **kwargs) -> Iterator[Socket]:
         """List all server sockets that exist in server process.
 
         Iterating over the results will resolve additional pages automatically.
@@ -158,39 +164,44 @@
             response = self.call_unary_with_deadline(
                 rpc='GetServerSockets',
                 req=_GetServerSocketsRequest(server_id=server.ref.server_id,
-                                             start_socket_id=start))
+                                             start_socket_id=start),
+                **kwargs)
             socket_ref: SocketRef
             for socket_ref in response.socket_ref:
                 start = max(start, socket_ref.socket_id)
                 # Yield actual socket
-                yield self.get_socket(socket_ref.socket_id)
+                yield self.get_socket(socket_ref.socket_id, **kwargs)
 
-    def list_channel_sockets(self, channel: Channel) -> Iterator[Socket]:
+    def list_channel_sockets(self, channel: Channel,
+                             **kwargs) -> Iterator[Socket]:
         """List all sockets of all subchannels of a given channel."""
-        for subchannel in self.list_channel_subchannels(channel):
-            yield from self.list_subchannels_sockets(subchannel)
+        for subchannel in self.list_channel_subchannels(channel, **kwargs):
+            yield from self.list_subchannels_sockets(subchannel, **kwargs)
 
-    def list_channel_subchannels(self,
-                                 channel: Channel) -> Iterator[Subchannel]:
+    def list_channel_subchannels(self, channel: Channel,
+                                 **kwargs) -> Iterator[Subchannel]:
         """List all subchannels of a given channel."""
         for subchannel_ref in channel.subchannel_ref:
-            yield self.get_subchannel(subchannel_ref.subchannel_id)
+            yield self.get_subchannel(subchannel_ref.subchannel_id, **kwargs)
 
-    def list_subchannels_sockets(self,
-                                 subchannel: Subchannel) -> Iterator[Socket]:
+    def list_subchannels_sockets(self, subchannel: Subchannel,
+                                 **kwargs) -> Iterator[Socket]:
         """List all sockets of a given subchannel."""
         for socket_ref in subchannel.socket_ref:
-            yield self.get_socket(socket_ref.socket_id)
+            yield self.get_socket(socket_ref.socket_id, **kwargs)
 
-    def get_subchannel(self, subchannel_id) -> Subchannel:
+    def get_subchannel(self, subchannel_id, **kwargs) -> Subchannel:
         """Return a single Subchannel, otherwise raises RpcError."""
         response: _GetSubchannelResponse = self.call_unary_with_deadline(
             rpc='GetSubchannel',
-            req=_GetSubchannelRequest(subchannel_id=subchannel_id))
+            req=_GetSubchannelRequest(subchannel_id=subchannel_id),
+            **kwargs)
         return response.subchannel
 
-    def get_socket(self, socket_id) -> Socket:
+    def get_socket(self, socket_id, **kwargs) -> Socket:
         """Return a single Socket, otherwise raises RpcError."""
         response: _GetSocketResponse = self.call_unary_with_deadline(
-            rpc='GetSocket', req=_GetSocketRequest(socket_id=socket_id))
+            rpc='GetSocket',
+            req=_GetSocketRequest(socket_id=socket_id),
+            **kwargs)
         return response.socket
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_testing.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_testing.py
index 58fff64..31485f9 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_testing.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_testing.py
@@ -37,10 +37,10 @@
         super().__init__(channel, test_pb2_grpc.LoadBalancerStatsServiceStub)
 
     def get_client_stats(
-            self,
-            *,
-            num_rpcs: int,
-            timeout_sec: Optional[int] = STATS_PARTIAL_RESULTS_TIMEOUT_SEC,
+        self,
+        *,
+        num_rpcs: int,
+        timeout_sec: Optional[int] = STATS_PARTIAL_RESULTS_TIMEOUT_SEC,
     ) -> LoadBalancerStatsResponse:
         if timeout_sec is None:
             timeout_sec = self.STATS_PARTIAL_RESULTS_TIMEOUT_SEC
@@ -49,5 +49,5 @@
                                              req=_LoadBalancerStatsRequest(
                                                  num_rpcs=num_rpcs,
                                                  timeout_sec=timeout_sec),
-                                             wait_for_ready_sec=timeout_sec,
+                                             deadline_sec=timeout_sec,
                                              log_level=logging.INFO)
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/test_app/client_app.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/test_app/client_app.py
index 31ec666..23dddf9 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/test_app/client_app.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/test_app/client_app.py
@@ -72,10 +72,10 @@
         return _ChannelzServiceClient(self._make_channel(self.maintenance_port))
 
     def get_load_balancer_stats(
-            self,
-            *,
-            num_rpcs: int,
-            timeout_sec: Optional[int] = None,
+        self,
+        *,
+        num_rpcs: int,
+        timeout_sec: Optional[int] = None,
     ) -> grpc_testing.LoadBalancerStatsResponse:
         """
         Shortcut to LoadBalancerStatsServiceClient.get_client_stats()
@@ -83,9 +83,6 @@
         return self.load_balancer_stats.get_client_stats(
             num_rpcs=num_rpcs, timeout_sec=timeout_sec)
 
-    def get_server_channels(self) -> Iterator[_ChannelzChannel]:
-        return self.channelz.find_channels_for_target(self.server_target)
-
     def wait_for_active_server_channel(self) -> _ChannelzChannel:
         """Wait for the channel to the server to transition to READY.
 
@@ -94,16 +91,9 @@
         """
         return self.wait_for_server_channel_state(_ChannelzChannelState.READY)
 
-    def get_active_server_channel(self) -> _ChannelzChannel:
-        """Return a READY channel to the server.
-
-        Raises:
-            GrpcApp.NotFound: If there's no READY channel to the server.
-        """
-        return self.find_server_channel_with_state(_ChannelzChannelState.READY)
-
     def get_active_server_channel_socket(self) -> _ChannelzSocket:
-        channel = self.get_active_server_channel()
+        channel = self.find_server_channel_with_state(
+            _ChannelzChannelState.READY)
         # Get the first subchannel of the active channel to the server.
         logger.debug(
             'Retrieving client -> server socket, '
@@ -121,32 +111,45 @@
         logger.debug('Found client -> server socket: %s', socket.ref.name)
         return socket
 
-    def wait_for_server_channel_state(self,
-                                      state: _ChannelzChannelState,
-                                      *,
-                                      timeout: Optional[_timedelta] = None
-                                     ) -> _ChannelzChannel:
+    def wait_for_server_channel_state(
+            self,
+            state: _ChannelzChannelState,
+            *,
+            timeout: Optional[_timedelta] = None,
+            rpc_deadline: Optional[_timedelta] = None) -> _ChannelzChannel:
+        # When polling for a state, prefer smaller wait times to avoid
+        # exhausting all allowed time on a single long RPC.
+        if rpc_deadline is None:
+            rpc_deadline = _timedelta(seconds=30)
+
         # Fine-tuned to wait for the channel to the server.
         retryer = retryers.exponential_retryer_with_timeout(
             wait_min=_timedelta(seconds=10),
             wait_max=_timedelta(seconds=25),
-            timeout=_timedelta(minutes=3) if timeout is None else timeout)
+            timeout=_timedelta(minutes=5) if timeout is None else timeout)
 
         logger.info('Waiting for client %s to report a %s channel to %s',
                     self.ip, _ChannelzChannelState.Name(state),
                     self.server_target)
-        channel = retryer(self.find_server_channel_with_state, state)
+        channel = retryer(self.find_server_channel_with_state,
+                          state,
+                          rpc_deadline=rpc_deadline)
         logger.info('Client %s channel to %s transitioned to state %s:\n%s',
                     self.ip, self.server_target,
                     _ChannelzChannelState.Name(state), channel)
         return channel
 
-    def find_server_channel_with_state(self,
-                                       state: _ChannelzChannelState,
-                                       *,
-                                       check_subchannel=True
-                                      ) -> _ChannelzChannel:
-        for channel in self.get_server_channels():
+    def find_server_channel_with_state(
+            self,
+            state: _ChannelzChannelState,
+            *,
+            rpc_deadline: Optional[_timedelta] = None,
+            check_subchannel=True) -> _ChannelzChannel:
+        rpc_params = {}
+        if rpc_deadline is not None:
+            rpc_params['deadline_sec'] = rpc_deadline.total_seconds()
+
+        for channel in self.get_server_channels(**rpc_params):
             channel_state: _ChannelzChannelState = channel.data.state.state
             logger.info('Server channel: %s, state: %s', channel.ref.name,
                         _ChannelzChannelState.Name(channel_state))
@@ -156,8 +159,9 @@
                     # one subchannel in the requested state.
                     try:
                         subchannel = self.find_subchannel_with_state(
-                            channel, state)
-                        logger.info('Found subchannel in state %s: %s', state,
+                            channel, state, **rpc_params)
+                        logger.info('Found subchannel in state %s: %s',
+                                    _ChannelzChannelState.Name(state),
                                     subchannel)
                     except self.NotFound as e:
                         # Otherwise, keep searching.
@@ -169,10 +173,15 @@
             f'Client has no {_ChannelzChannelState.Name(state)} channel with '
             'the server')
 
+    def get_server_channels(self, **kwargs) -> Iterator[_ChannelzChannel]:
+        return self.channelz.find_channels_for_target(self.server_target,
+                                                      **kwargs)
+
     def find_subchannel_with_state(self, channel: _ChannelzChannel,
-                                   state: _ChannelzChannelState
-                                  ) -> _ChannelzSubchannel:
-        for subchannel in self.channelz.list_channel_subchannels(channel):
+                                   state: _ChannelzChannelState,
+                                   **kwargs) -> _ChannelzSubchannel:
+        subchannels = self.channelz.list_channel_subchannels(channel, **kwargs)
+        for subchannel in subchannels:
             if subchannel.data.state.state is state:
                 return subchannel
 
@@ -190,9 +199,10 @@
                  image_name,
                  gcp_service_account,
                  td_bootstrap_image,
+                 xds_server_uri=None,
+                 network='default',
                  service_account_name=None,
                  stats_port=8079,
-                 network='default',
                  deployment_template='client.deployment.yaml',
                  service_account_template='service-account.yaml',
                  reuse_namespace=False,
@@ -208,6 +218,7 @@
         self.stats_port = stats_port
         # xDS bootstrap generator
         self.td_bootstrap_image = td_bootstrap_image
+        self.xds_server_uri = xds_server_uri
         self.network = network
         self.deployment_template = deployment_template
         self.service_account_template = service_account_template
@@ -243,7 +254,8 @@
             namespace_name=self.k8s_namespace.name,
             service_account_name=self.service_account_name,
             td_bootstrap_image=self.td_bootstrap_image,
-            network_name=self.network,
+            xds_server_uri=self.xds_server_uri,
+            network=self.network,
             stats_port=self.stats_port,
             server_target=server_target,
             rpc=rpc,
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/test_app/server_app.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/test_app/server_app.py
index 0f41df7..2b258af 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/test_app/server_app.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/test_app/server_app.py
@@ -126,6 +126,9 @@
 
 
 class KubernetesServerRunner(base_runner.KubernetesBaseRunner):
+    DEFAULT_TEST_PORT = 8080
+    DEFAULT_MAINTENANCE_PORT = 8080
+    DEFAULT_SECURE_MODE_MAINTENANCE_PORT = 8081
 
     def __init__(self,
                  k8s_namespace,
@@ -137,6 +140,7 @@
                  service_name=None,
                  neg_name=None,
                  td_bootstrap_image=None,
+                 xds_server_uri=None,
                  network='default',
                  deployment_template='server.deployment.yaml',
                  service_account_template='service-account.yaml',
@@ -155,6 +159,7 @@
         self.service_name = service_name or deployment_name
         # xDS bootstrap generator
         self.td_bootstrap_image = td_bootstrap_image
+        self.xds_server_uri = xds_server_uri
         # This only works in k8s >= 1.18.10-gke.600
         # https://cloud.google.com/kubernetes-engine/docs/how-to/standalone-neg#naming_negs
         self.neg_name = neg_name or (f'{self.k8s_namespace.name}-'
@@ -174,7 +179,7 @@
 
     def run(self,
             *,
-            test_port=8080,
+            test_port=DEFAULT_TEST_PORT,
             maintenance_port=None,
             secure_mode=False,
             server_id=None,
@@ -188,7 +193,11 @@
         # maintenance services can be reached independently from the security
         # configuration under test.
         if maintenance_port is None:
-            maintenance_port = test_port if not secure_mode else test_port + 1
+            if not secure_mode:
+                maintenance_port = self.DEFAULT_MAINTENANCE_PORT
+            else:
+                maintenance_port = self.DEFAULT_SECURE_MODE_MAINTENANCE_PORT
+
         if secure_mode and maintenance_port == test_port:
             raise ValueError('port and maintenance_port must be different '
                              'when running test server in secure mode')
@@ -229,7 +238,8 @@
             namespace_name=self.k8s_namespace.name,
             service_account_name=self.service_account_name,
             td_bootstrap_image=self.td_bootstrap_image,
-            network_name=self.network,
+            xds_server_uri=self.xds_server_uri,
+            network=self.network,
             replica_count=replica_count,
             test_port=test_port,
             maintenance_port=maintenance_port,
@@ -237,8 +247,7 @@
             secure_mode=secure_mode)
 
         self._wait_deployment_with_available_replicas(self.deployment_name,
-                                                      replica_count,
-                                                      timeout_sec=120)
+                                                      replica_count)
 
         # Wait for pods running
         pods = self.k8s_namespace.list_deployment_pods(self.deployment)
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_flags.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_flags.py
index dc118ad..65ebc84 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_flags.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_flags.py
@@ -25,6 +25,11 @@
 NETWORK = flags.DEFINE_string("network",
                               default="default",
                               help="GCP Network ID")
+# Mirrors --xds-server-uri argument of Traffic Director gRPC Bootstrap
+XDS_SERVER_URI = flags.DEFINE_string(
+    "xds_server_uri",
+    default=None,
+    help="Override Traffic Director server uri, for testing")
 
 # Test server
 SERVER_NAME = flags.DEFINE_string("server_name",
@@ -32,7 +37,16 @@
                                   help="Server deployment and service name")
 SERVER_PORT = flags.DEFINE_integer("server_port",
                                    default=8080,
+                                   lower_bound=0,
+                                   upper_bound=65535,
                                    help="Server test port")
+SERVER_MAINTENANCE_PORT = flags.DEFINE_integer(
+    "server_maintenance_port",
+    lower_bound=0,
+    upper_bound=65535,
+    default=None,
+    help="Server port running maintenance services: health check, channelz, etc"
+)
 SERVER_XDS_HOST = flags.DEFINE_string("server_xds_host",
                                       default='xds-test-server',
                                       help="Test server xDS hostname")
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py b/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py
index eaa3c24..0606ba9 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py
@@ -23,6 +23,7 @@
 
 from framework import xds_flags
 from framework import xds_k8s_flags
+from framework.helpers import retryers
 from framework.infrastructure import gcp
 from framework.infrastructure import k8s
 from framework.infrastructure import traffic_director
@@ -36,6 +37,12 @@
     "force_cleanup",
     default=False,
     help="Force resource cleanup, even if not created by this test run")
+# TODO(yashkt): We will no longer need this flag once Core exposes local certs
+# from channelz
+_CHECK_LOCAL_CERTS = flags.DEFINE_bool(
+    "check_local_certs",
+    default=True,
+    help="Security Tests also check the value of local certs")
 flags.adopt_module_key_flags(xds_flags)
 flags.adopt_module_key_flags(xds_k8s_flags)
 
@@ -45,6 +52,8 @@
 LoadBalancerStatsResponse = grpc_testing.LoadBalancerStatsResponse
 _ChannelState = grpc_channelz.ChannelState
 _timedelta = datetime.timedelta
+_DEFAULT_SECURE_MODE_MAINTENANCE_PORT = \
+    server_app.KubernetesServerRunner.DEFAULT_SECURE_MODE_MAINTENANCE_PORT
 
 
 class XdsKubernetesTestCase(absltest.TestCase):
@@ -58,6 +67,7 @@
         cls.network: str = xds_flags.NETWORK.value
         cls.gcp_service_account: str = xds_k8s_flags.GCP_SERVICE_ACCOUNT.value
         cls.td_bootstrap_image = xds_k8s_flags.TD_BOOTSTRAP_IMAGE.value
+        cls.xds_server_uri = xds_flags.XDS_SERVER_URI.value
 
         # Base namespace
         # TODO(sergiitk): generate for each test
@@ -67,6 +77,7 @@
         cls.server_image = xds_k8s_flags.SERVER_IMAGE.value
         cls.server_name = xds_flags.SERVER_NAME.value
         cls.server_port = xds_flags.SERVER_PORT.value
+        cls.server_maintenance_port = xds_flags.SERVER_MAINTENANCE_PORT.value
         cls.server_xds_host = xds_flags.SERVER_NAME.value
         cls.server_xds_port = xds_flags.SERVER_XDS_PORT.value
 
@@ -79,6 +90,7 @@
         cls.force_cleanup = _FORCE_CLEANUP.value
         cls.debug_use_port_forwarding = \
             xds_k8s_flags.DEBUG_USE_PORT_FORWARDING.value
+        cls.check_local_certs = _CHECK_LOCAL_CERTS.value
 
         # Resource managers
         cls.k8s_api_manager = k8s.KubernetesApiManager(
@@ -103,13 +115,24 @@
 
     def tearDown(self):
         logger.info('----- TestMethod %s teardown -----', self.id())
+        retryer = retryers.constant_retryer(wait_fixed=_timedelta(seconds=10),
+                                            attempts=3,
+                                            log_level=logging.INFO)
+        try:
+            retryer(self._cleanup)
+        except retryers.RetryError:
+            logger.exception('Got error during teardown')
+
+    def _cleanup(self):
         self.td.cleanup(force=self.force_cleanup)
         self.client_runner.cleanup(force=self.force_cleanup)
         self.server_runner.cleanup(force=self.force_cleanup,
                                    force_namespace=self.force_cleanup)
 
     def setupTrafficDirectorGrpc(self):
-        self.td.setup_for_grpc(self.server_xds_host, self.server_xds_port)
+        self.td.setup_for_grpc(self.server_xds_host,
+                               self.server_xds_port,
+                               health_check_port=self.server_maintenance_port)
 
     def setupServerBackends(self, *, wait_for_healthy_status=True):
         # Load Backends
@@ -179,8 +202,9 @@
             deployment_name=self.server_name,
             image_name=self.server_image,
             gcp_service_account=self.gcp_service_account,
-            network=self.network,
-            td_bootstrap_image=self.td_bootstrap_image)
+            td_bootstrap_image=self.td_bootstrap_image,
+            xds_server_uri=self.xds_server_uri,
+            network=self.network)
 
         # Test Client Runner
         self.client_runner = client_app.KubernetesClientRunner(
@@ -189,16 +213,19 @@
             deployment_name=self.client_name,
             image_name=self.client_image,
             gcp_service_account=self.gcp_service_account,
-            network=self.network,
             td_bootstrap_image=self.td_bootstrap_image,
+            xds_server_uri=self.xds_server_uri,
+            network=self.network,
             debug_use_port_forwarding=self.debug_use_port_forwarding,
             stats_port=self.client_port,
             reuse_namespace=self.server_namespace == self.client_namespace)
 
     def startTestServer(self, replica_count=1, **kwargs) -> XdsTestServer:
-        test_server = self.server_runner.run(replica_count=replica_count,
-                                             test_port=self.server_port,
-                                             **kwargs)
+        test_server = self.server_runner.run(
+            replica_count=replica_count,
+            test_port=self.server_port,
+            maintenance_port=self.server_maintenance_port,
+            **kwargs)
         test_server.set_xds_address(self.server_xds_host, self.server_xds_port)
         return test_server
 
@@ -217,6 +244,17 @@
         TLS = enum.auto()
         PLAINTEXT = enum.auto()
 
+    @classmethod
+    def setUpClass(cls):
+        super().setUpClass()
+        if cls.server_maintenance_port is None:
+            # In secure mode, the maintenance port is different from
+            # the test port to keep it insecure, and make
+            # Health Checks and Channelz tests available.
+            # When not provided, use explicit numeric port value, so
+            # Backend Health Checks are created on a fixed port.
+            cls.server_maintenance_port = _DEFAULT_SECURE_MODE_MAINTENANCE_PORT
+
     def setUp(self):
         super().setUp()
 
@@ -236,6 +274,7 @@
             gcp_service_account=self.gcp_service_account,
             network=self.network,
             td_bootstrap_image=self.td_bootstrap_image,
+            xds_server_uri=self.xds_server_uri,
             deployment_template='server-secure.deployment.yaml',
             debug_use_port_forwarding=self.debug_use_port_forwarding)
 
@@ -246,19 +285,21 @@
             deployment_name=self.client_name,
             image_name=self.client_image,
             gcp_service_account=self.gcp_service_account,
-            network=self.network,
             td_bootstrap_image=self.td_bootstrap_image,
+            xds_server_uri=self.xds_server_uri,
+            network=self.network,
             deployment_template='client-secure.deployment.yaml',
             stats_port=self.client_port,
             reuse_namespace=self.server_namespace == self.client_namespace,
             debug_use_port_forwarding=self.debug_use_port_forwarding)
 
     def startSecureTestServer(self, replica_count=1, **kwargs) -> XdsTestServer:
-        test_server = self.server_runner.run(replica_count=replica_count,
-                                             test_port=self.server_port,
-                                             maintenance_port=8081,
-                                             secure_mode=True,
-                                             **kwargs)
+        test_server = self.server_runner.run(
+            replica_count=replica_count,
+            test_port=self.server_port,
+            maintenance_port=self.server_maintenance_port,
+            secure_mode=True,
+            **kwargs)
         test_server.set_xds_address(self.server_xds_host, self.server_xds_port)
         return test_server
 
@@ -316,26 +357,30 @@
         server_tls, client_tls = server_security.tls, client_security.tls
 
         # Confirm regular TLS: server local cert == client remote cert
-        self.assertNotEmpty(server_tls.local_certificate,
-                            msg="(mTLS) Server local certificate is missing")
         self.assertNotEmpty(client_tls.remote_certificate,
                             msg="(mTLS) Client remote certificate is missing")
-        self.assertEqual(
-            server_tls.local_certificate,
-            client_tls.remote_certificate,
-            msg="(mTLS) Server local certificate must match client's "
-            "remote certificate")
+        if self.check_local_certs:
+            self.assertNotEmpty(
+                server_tls.local_certificate,
+                msg="(mTLS) Server local certificate is missing")
+            self.assertEqual(
+                server_tls.local_certificate,
+                client_tls.remote_certificate,
+                msg="(mTLS) Server local certificate must match client's "
+                "remote certificate")
 
         # mTLS: server remote cert == client local cert
         self.assertNotEmpty(server_tls.remote_certificate,
                             msg="(mTLS) Server remote certificate is missing")
-        self.assertNotEmpty(client_tls.local_certificate,
-                            msg="(mTLS) Client local certificate is missing")
-        self.assertEqual(
-            server_tls.remote_certificate,
-            client_tls.local_certificate,
-            msg="(mTLS) Server remote certificate must match client's "
-            "local certificate")
+        if self.check_local_certs:
+            self.assertNotEmpty(
+                client_tls.local_certificate,
+                msg="(mTLS) Client local certificate is missing")
+            self.assertEqual(
+                server_tls.remote_certificate,
+                client_tls.local_certificate,
+                msg="(mTLS) Server remote certificate must match client's "
+                "local certificate")
 
     def assertSecurityTls(self, client_security: grpc_channelz.Security,
                           server_security: grpc_channelz.Security):
@@ -348,14 +393,16 @@
         server_tls, client_tls = server_security.tls, client_security.tls
 
         # Regular TLS: server local cert == client remote cert
-        self.assertNotEmpty(server_tls.local_certificate,
-                            msg="(TLS) Server local certificate is missing")
         self.assertNotEmpty(client_tls.remote_certificate,
                             msg="(TLS) Client remote certificate is missing")
-        self.assertEqual(server_tls.local_certificate,
-                         client_tls.remote_certificate,
-                         msg="(TLS) Server local certificate must match client "
-                         "remote certificate")
+        if self.check_local_certs:
+            self.assertNotEmpty(server_tls.local_certificate,
+                                msg="(TLS) Server local certificate is missing")
+            self.assertEqual(
+                server_tls.local_certificate,
+                client_tls.remote_certificate,
+                msg="(TLS) Server local certificate must match client "
+                "remote certificate")
 
         # mTLS must not be used
         self.assertEmpty(
@@ -433,13 +480,10 @@
                        1,
                        msg="Client channel must have exactly one subchannel "
                        "in state TRANSIENT_FAILURE.")
-        sockets = list(
-            test_client.channelz.list_subchannels_sockets(subchannels[0]))
-        self.assertEmpty(sockets, msg="Client subchannel must have no sockets")
 
     @staticmethod
     def getConnectedSockets(
-            test_client: XdsTestClient, test_server: XdsTestServer
+        test_client: XdsTestClient, test_server: XdsTestServer
     ) -> Tuple[grpc_channelz.Socket, grpc_channelz.Socket]:
         client_sock = test_client.get_active_server_channel_socket()
         server_sock = test_server.get_server_socket_matching_client(client_sock)
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/client-secure.deployment.yaml b/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/client-secure.deployment.yaml
index 18630ad..6db4192 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/client-secure.deployment.yaml
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/client-secure.deployment.yaml
@@ -17,6 +17,8 @@
       labels:
         app: ${deployment_name}
         owner: xds-k8s-interop-test
+      annotations:
+        security.cloud.google.com/use-workload-certificates: ""
     spec:
       serviceAccountName: ${service_account_name}
       containers:
@@ -43,9 +45,6 @@
           - mountPath: /tmp/grpc-xds/
             name: grpc-td-conf
             readOnly: true
-          - mountPath: /var/run/gke-spiffe/certs
-            name: gke-spiffe-certs-volume
-            readOnly: true
         resources:
           limits:
             cpu: 800m
@@ -59,7 +58,10 @@
           imagePullPolicy: Always
           args:
             - "--output=/tmp/bootstrap/td-grpc-bootstrap.json"
-            - "--vpc-network-name=${network_name}"
+            - "--vpc-network-name=${network}"
+            % if xds_server_uri:
+            - "--xds-server-uri=${xds_server_uri}"
+            % endif
             - "--include-v3-features-experimental"
             - "--include-psm-security-experimental"
           resources:
@@ -76,7 +78,4 @@
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
-        - name: gke-spiffe-certs-volume
-          csi:
-            driver: certs.spiffe.gke.io
 ...
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/client.deployment.yaml b/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/client.deployment.yaml
index 793bef6..9449e51 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/client.deployment.yaml
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/client.deployment.yaml
@@ -51,7 +51,10 @@
           imagePullPolicy: Always
           args:
             - "--output=/tmp/bootstrap/td-grpc-bootstrap.json"
-            - "--vpc-network-name=${network_name}"
+            - "--vpc-network-name=${network}"
+            % if xds_server_uri:
+            - "--xds-server-uri=${xds_server_uri}"
+            % endif
           resources:
             limits:
               cpu: 100m
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/server-secure.deployment.yaml b/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/server-secure.deployment.yaml
index 0687aa0..151aede 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/server-secure.deployment.yaml
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/kubernetes-manifests/server-secure.deployment.yaml
@@ -14,6 +14,8 @@
       app: ${deployment_name}
   template:
     metadata:
+      annotations:
+        security.cloud.google.com/use-workload-certificates: ""
       labels:
         app: ${deployment_name}
         owner: xds-k8s-interop-test
@@ -37,13 +39,13 @@
             value: "true"
           - name: GRPC_XDS_EXPERIMENTAL_V3_SUPPORT
             value: "true"
+          # TODO(sergiitk): this should be conditional for if version < v1.37.x
+          - name: GRPC_XDS_EXPERIMENTAL_NEW_SERVER_API
+            value: "true"
         volumeMounts:
           - mountPath: /tmp/grpc-xds/
             name: grpc-td-conf
             readOnly: true
-          - mountPath: /var/run/gke-spiffe/certs
-            name: gke-spiffe-certs-volume
-            readOnly: true
         resources:
           limits:
             cpu: 800m
@@ -57,7 +59,10 @@
           imagePullPolicy: Always
           args:
             - "--output=/tmp/bootstrap/td-grpc-bootstrap.json"
-            - "--vpc-network-name=${network_name}"
+            - "--vpc-network-name=${network}"
+            % if xds_server_uri:
+            - "--xds-server-uri=${xds_server_uri}"
+            % endif
             - "--include-v3-features-experimental"
             - "--include-psm-security-experimental"
             - "--node-metadata-experimental=app=${namespace_name}-${deployment_name}"
@@ -75,7 +80,4 @@
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
-        - name: gke-spiffe-certs-volume
-          csi:
-            driver: certs.spiffe.gke.io
 ...
diff --git a/grpc/tools/run_tests/xds_k8s_test_driver/tests/security_test.py b/grpc/tools/run_tests/xds_k8s_test_driver/tests/security_test.py
index 58604b7..2c19d33 100644
--- a/grpc/tools/run_tests/xds_k8s_test_driver/tests/security_test.py
+++ b/grpc/tools/run_tests/xds_k8s_test_driver/tests/security_test.py
@@ -109,7 +109,8 @@
         been received as confirmed by the TD team.
         """
         # Create backend service
-        self.td.setup_backend_for_grpc()
+        self.td.setup_backend_for_grpc(
+            health_check_port=self.server_maintenance_port)
 
         # Start server and attach its NEGs to the backend service, but
         # until they become healthy.
@@ -145,7 +146,8 @@
         The order of operations is the same as in `test_mtls_error`.
         """
         # Create backend service
-        self.td.setup_backend_for_grpc()
+        self.td.setup_backend_for_grpc(
+            health_check_port=self.server_maintenance_port)
 
         # Start server and attach its NEGs to the backend service, but
         # until they become healthy.
diff --git a/patches/Android.bp.patch b/patches/Android.bp.patch
index 2ec02dd..e7d7f1c 100644
--- a/patches/Android.bp.patch
+++ b/patches/Android.bp.patch
@@ -14,7 +14,7 @@
      edition: "2018",
      features: [
          "bindgen",
-@@ -50,50 +53,58 @@ rust_library {
+@@ -50,51 +53,58 @@ rust_library {
          "liblibc",
          "liblibz_sys",
      ],
@@ -48,6 +48,7 @@
 -        "libabsl_throw_delegate",
 -        "libabsl_time",
 -        "libabsl_time_zone",
+-        "libabsl_wyhash",
 -        "libaddress_sorting",
 -        "libcares",
 -        "libcrypto",