diff --git a/BUILD b/BUILD
index 97ddc56b41956639801085d4e62178c021c00c03..8690052bc4444c5d2a9af6204008cb4190b334ba 100644
--- a/BUILD
+++ b/BUILD
@@ -252,6 +252,7 @@ cc_library(
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.h",
     "src/core/lib/transport/method_config.h",
+    "src/core/lib/transport/pid_controller.h",
     "src/core/lib/transport/static_metadata.h",
     "src/core/lib/transport/timeout_encoding.h",
     "src/core/lib/transport/transport.h",
@@ -436,6 +437,7 @@ cc_library(
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.c",
     "src/core/lib/transport/method_config.c",
+    "src/core/lib/transport/pid_controller.c",
     "src/core/lib/transport/static_metadata.c",
     "src/core/lib/transport/timeout_encoding.c",
     "src/core/lib/transport/transport.c",
@@ -676,6 +678,7 @@ cc_library(
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.h",
     "src/core/lib/transport/method_config.h",
+    "src/core/lib/transport/pid_controller.h",
     "src/core/lib/transport/static_metadata.h",
     "src/core/lib/transport/timeout_encoding.h",
     "src/core/lib/transport/transport.h",
@@ -845,6 +848,7 @@ cc_library(
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.c",
     "src/core/lib/transport/method_config.c",
+    "src/core/lib/transport/pid_controller.c",
     "src/core/lib/transport/static_metadata.c",
     "src/core/lib/transport/timeout_encoding.c",
     "src/core/lib/transport/transport.c",
@@ -1055,6 +1059,7 @@ cc_library(
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.h",
     "src/core/lib/transport/method_config.h",
+    "src/core/lib/transport/pid_controller.h",
     "src/core/lib/transport/static_metadata.h",
     "src/core/lib/transport/timeout_encoding.h",
     "src/core/lib/transport/transport.h",
@@ -1216,6 +1221,7 @@ cc_library(
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.c",
     "src/core/lib/transport/method_config.c",
+    "src/core/lib/transport/pid_controller.c",
     "src/core/lib/transport/static_metadata.c",
     "src/core/lib/transport/timeout_encoding.c",
     "src/core/lib/transport/transport.c",
@@ -1364,6 +1370,7 @@ cc_library(
     "src/cpp/common/core_codegen.cc",
     "src/cpp/common/resource_quota_cc.cc",
     "src/cpp/common/rpc_method.cc",
+    "src/cpp/common/version_cc.cc",
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
     "src/cpp/server/dynamic_thread_pool.cc",
@@ -1507,6 +1514,7 @@ cc_library(
     "src/cpp/common/core_codegen.cc",
     "src/cpp/common/resource_quota_cc.cc",
     "src/cpp/common/rpc_method.cc",
+    "src/cpp/common/version_cc.cc",
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
     "src/cpp/server/dynamic_thread_pool.cc",
@@ -1671,6 +1679,7 @@ cc_library(
     "src/cpp/common/core_codegen.cc",
     "src/cpp/common/resource_quota_cc.cc",
     "src/cpp/common/rpc_method.cc",
+    "src/cpp/common/version_cc.cc",
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
     "src/cpp/server/dynamic_thread_pool.cc",
@@ -2073,6 +2082,7 @@ objc_library(
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.c",
     "src/core/lib/transport/method_config.c",
+    "src/core/lib/transport/pid_controller.c",
     "src/core/lib/transport/static_metadata.c",
     "src/core/lib/transport/timeout_encoding.c",
     "src/core/lib/transport/transport.c",
@@ -2292,6 +2302,7 @@ objc_library(
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.h",
     "src/core/lib/transport/method_config.h",
+    "src/core/lib/transport/pid_controller.h",
     "src/core/lib/transport/static_metadata.h",
     "src/core/lib/transport/timeout_encoding.h",
     "src/core/lib/transport/transport.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b073b0d684d9f5d245e472257f88b5ec0400f10..b551ce341161c59c51c8e9846c841b452a320110 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -393,6 +393,7 @@ add_library(grpc
   src/core/lib/transport/metadata.c
   src/core/lib/transport/metadata_batch.c
   src/core/lib/transport/method_config.c
+  src/core/lib/transport/pid_controller.c
   src/core/lib/transport/static_metadata.c
   src/core/lib/transport/timeout_encoding.c
   src/core/lib/transport/transport.c
@@ -665,6 +666,7 @@ add_library(grpc_cronet
   src/core/lib/transport/metadata.c
   src/core/lib/transport/metadata_batch.c
   src/core/lib/transport/method_config.c
+  src/core/lib/transport/pid_controller.c
   src/core/lib/transport/static_metadata.c
   src/core/lib/transport/timeout_encoding.c
   src/core/lib/transport/transport.c
@@ -909,6 +911,7 @@ add_library(grpc_unsecure
   src/core/lib/transport/metadata.c
   src/core/lib/transport/metadata_batch.c
   src/core/lib/transport/method_config.c
+  src/core/lib/transport/pid_controller.c
   src/core/lib/transport/static_metadata.c
   src/core/lib/transport/timeout_encoding.c
   src/core/lib/transport/transport.c
@@ -1066,6 +1069,7 @@ add_library(grpc++
   src/cpp/common/core_codegen.cc
   src/cpp/common/resource_quota_cc.cc
   src/cpp/common/rpc_method.cc
+  src/cpp/common/version_cc.cc
   src/cpp/server/async_generic_service.cc
   src/cpp/server/create_default_thread_pool.cc
   src/cpp/server/dynamic_thread_pool.cc
@@ -1223,6 +1227,7 @@ add_library(grpc++_cronet
   src/cpp/common/core_codegen.cc
   src/cpp/common/resource_quota_cc.cc
   src/cpp/common/rpc_method.cc
+  src/cpp/common/version_cc.cc
   src/cpp/server/async_generic_service.cc
   src/cpp/server/create_default_thread_pool.cc
   src/cpp/server/dynamic_thread_pool.cc
@@ -1418,6 +1423,7 @@ add_library(grpc++_unsecure
   src/cpp/common/core_codegen.cc
   src/cpp/common/resource_quota_cc.cc
   src/cpp/common/rpc_method.cc
+  src/cpp/common/version_cc.cc
   src/cpp/server/async_generic_service.cc
   src/cpp/server/create_default_thread_pool.cc
   src/cpp/server/dynamic_thread_pool.cc
diff --git a/Makefile b/Makefile
index 1fd1380cc243d5ae4d5eac61fd5ca3cdc0566195..09520d0b68eedc5b9487550083ee6e71454c2acf 100644
--- a/Makefile
+++ b/Makefile
@@ -434,7 +434,9 @@ E = @echo
 Q = @
 endif
 
-VERSION = 1.1.0-dev
+CORE_VERSION = 2.0.0-dev
+CPP_VERSION = 1.1.0-dev
+CSHARP_VERSION = 1.1.0-dev
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -470,20 +472,36 @@ ifeq ($(HAS_PKG_CONFIG), true)
 CACHE_MK += HAS_PKG_CONFIG = true,
 endif
 
-PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
+CORE_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CORE_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
+
+CPP_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CPP_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
+
+CSHARP_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CSHARP_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
 
 ifeq ($(SYSTEM),MINGW32)
-SHARED_EXT = dll
+SHARED_EXT_CORE = dll
+SHARED_EXT_CPP = dll
+SHARED_EXT_CSHARP = dll
 SHARED_PREFIX =
-SHARED_VERSION = -1
+SHARED_VERSION_CORE = -2
+SHARED_VERSION_CPP = -1
+SHARED_VERSION_CSHARP = -1
 else ifeq ($(SYSTEM),Darwin)
-SHARED_EXT = dylib
+SHARED_EXT_CORE = dylib
+SHARED_EXT_CPP = dylib
+SHARED_EXT_CSHARP = dylib
 SHARED_PREFIX = lib
-SHARED_VERSION =
+SHARED_VERSION_CORE =
+SHARED_VERSION_CPP =
+SHARED_VERSION_CSHARP =
 else
-SHARED_EXT = so.$(VERSION)
+SHARED_EXT_CORE = so.$(CORE_VERSION)
+SHARED_EXT_CPP = so.$(CPP_VERSION)
+SHARED_EXT_CSHARP = so.$(CSHARP_VERSION)
 SHARED_PREFIX = lib
-SHARED_VERSION =
+SHARED_VERSION_CORE =
+SHARED_VERSION_CPP =
+SHARED_VERSION_CSHARP =
 endif
 
 ifeq ($(wildcard .git),)
@@ -718,7 +736,7 @@ PC_CFLAGS =
 PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
 PC_LIBS_PRIVATE = $(PC_LIBS_GRPC) $(PC_LIBS_SECURE)
 PC_LIB = -lgrpc
-GRPC_PC_FILE := $(PC_TEMPLATE)
+GRPC_PC_FILE := $(CORE_PC_TEMPLATE)
 
 # grpc_unsecure .pc file
 PC_NAME = gRPC unsecure
@@ -727,7 +745,7 @@ PC_CFLAGS =
 PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC)
 PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
 PC_LIB = -lgrpc
-GRPC_UNSECURE_PC_FILE := $(PC_TEMPLATE)
+GRPC_UNSECURE_PC_FILE := $(CORE_PC_TEMPLATE)
 
 PROTOBUF_PKG_CONFIG = false
 
@@ -789,7 +807,7 @@ PC_CFLAGS =
 PC_REQUIRES_PRIVATE = grpc $(PC_REQUIRES_GRPCXX)
 PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
 PC_LIB = -lgrpc++
-GRPCXX_PC_FILE := $(PC_TEMPLATE)
+GRPCXX_PC_FILE := $(CPP_PC_TEMPLATE)
 
 # grpc++_unsecure .pc file
 PC_NAME = gRPC++ unsecure
@@ -798,7 +816,7 @@ PC_CFLAGS =
 PC_REQUIRES_PRIVATE = grpc_unsecure $(PC_REQUIRES_GRPCXX)
 PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
 PC_LIB = -lgrpc++
-GRPCXX_UNSECURE_PC_FILE := $(PC_TEMPLATE)
+GRPCXX_UNSECURE_PC_FILE := $(CPP_PC_TEMPLATE)
 
 ifeq ($(MAKECMDGOALS),clean)
 NO_DEPS = true
@@ -1028,6 +1046,7 @@ timer_heap_test: $(BINDIR)/$(CONFIG)/timer_heap_test
 timer_list_test: $(BINDIR)/$(CONFIG)/timer_list_test
 transport_connectivity_state_test: $(BINDIR)/$(CONFIG)/transport_connectivity_state_test
 transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test
+transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
 transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test
 udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
 uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test
@@ -1216,10 +1235,10 @@ static_cxx: pc_cxx pc_cxx_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(L
 
 shared: shared_c shared_cxx
 
-shared_c: pc_c pc_c_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)
-shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
+shared_c: pc_c pc_c_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
+shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 
-shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)
+shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)
 grpc_csharp_ext: shared_csharp
 
 plugins: $(PROTOC_PLUGINS)
@@ -1352,6 +1371,7 @@ buildtests_c: privatelibs_c \
   $(BINDIR)/$(CONFIG)/timer_list_test \
   $(BINDIR)/$(CONFIG)/transport_connectivity_state_test \
   $(BINDIR)/$(CONFIG)/transport_metadata_test \
+  $(BINDIR)/$(CONFIG)/transport_pid_controller_test \
   $(BINDIR)/$(CONFIG)/transport_security_test \
   $(BINDIR)/$(CONFIG)/udp_server_test \
   $(BINDIR)/$(CONFIG)/uri_parser_test \
@@ -1762,6 +1782,8 @@ test_c: buildtests_c
 	$(Q) $(BINDIR)/$(CONFIG)/transport_connectivity_state_test || ( echo test transport_connectivity_state_test failed ; exit 1 )
 	$(E) "[RUN]     Testing transport_metadata_test"
 	$(Q) $(BINDIR)/$(CONFIG)/transport_metadata_test || ( echo test transport_metadata_test failed ; exit 1 )
+	$(E) "[RUN]     Testing transport_pid_controller_test"
+	$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
 	$(E) "[RUN]     Testing transport_security_test"
 	$(Q) $(BINDIR)/$(CONFIG)/transport_security_test || ( echo test transport_security_test failed ; exit 1 )
 	$(E) "[RUN]     Testing udp_server_test"
@@ -1936,32 +1958,32 @@ endif
 
 strip-shared_c: shared_c
 ifeq ($(CONFIG),opt)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 endif
 
 strip-shared_cxx: shared_cxx
 ifeq ($(CONFIG),opt)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 endif
 
 strip-shared_csharp: shared_csharp
 ifeq ($(CONFIG),opt)
-	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)
 endif
 
 cache.mk::
@@ -2286,41 +2308,41 @@ install-static_cxx: static_cxx strip-static_cxx install-pkg-config_cxx
 
 
 install-shared_c: shared_c strip-shared_c install-pkg-config_c
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT_CORE)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr-imp.a $(prefix)/lib/libgpr-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgpr.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgpr.so
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so
 endif
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT_CORE)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc-imp.a $(prefix)/lib/libgrpc-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc.so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so
 endif
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT_CORE)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_cronet-imp.a $(prefix)/lib/libgrpc_cronet-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_cronet.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_cronet.so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so
 endif
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT_CORE)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure-imp.a $(prefix)/lib/libgrpc_unsecure-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so
 endif
 ifneq ($(SYSTEM),MINGW32)
 ifneq ($(SYSTEM),Darwin)
@@ -2330,41 +2352,41 @@ endif
 
 
 install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c install-pkg-config_cxx
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++-imp.a $(prefix)/lib/libgrpc++-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++.so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so
 endif
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet-imp.a $(prefix)/lib/libgrpc++_cronet-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_cronet.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_cronet.so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so
 endif
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection-imp.a $(prefix)/lib/libgrpc++_reflection-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_reflection.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_reflection.so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so
 endif
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure-imp.a $(prefix)/lib/libgrpc++_unsecure-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so
 endif
 ifneq ($(SYSTEM),MINGW32)
 ifneq ($(SYSTEM),Darwin)
@@ -2374,14 +2396,14 @@ endif
 
 
 install-shared_csharp: shared_csharp strip-shared_csharp
-	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT_CSHARP)
 ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext-imp.a $(prefix)/lib/libgrpc_csharp_ext-imp.a
 else ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so
 endif
 ifneq ($(SYSTEM),MINGW32)
 ifneq ($(SYSTEM),Darwin)
@@ -2541,20 +2563,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION).$(SHARED_EXT): $(LIBGPR_OBJS)  $(ZLIB_DEP)
+$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared gpr.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared gpr.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).$(SHARED_EXT): $(LIBGPR_OBJS)  $(ZLIB_DEP)
+$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.1 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).so
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.2 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.2
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so
 endif
 endif
 
@@ -2693,6 +2715,7 @@ LIBGRPC_SRC = \
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.c \
     src/core/lib/transport/method_config.c \
+    src/core/lib/transport/pid_controller.c \
     src/core/lib/transport/static_metadata.c \
     src/core/lib/transport/timeout_encoding.c \
     src/core/lib/transport/transport.c \
@@ -2835,7 +2858,7 @@ ifeq ($(NO_SECURE),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc.a: openssl_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): openssl_dep_error
 
 else
 
@@ -2852,20 +2875,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).so
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so
 endif
 endif
 
@@ -2983,6 +3006,7 @@ LIBGRPC_CRONET_SRC = \
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.c \
     src/core/lib/transport/method_config.c \
+    src/core/lib/transport/pid_controller.c \
     src/core/lib/transport/static_metadata.c \
     src/core/lib/transport/timeout_encoding.c \
     src/core/lib/transport/transport.c \
@@ -3097,7 +3121,7 @@ ifeq ($(NO_SECURE),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a: openssl_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): openssl_dep_error
 
 else
 
@@ -3114,20 +3138,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc_cronet.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc_cronet.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION).so
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so
 endif
 endif
 
@@ -3264,6 +3288,7 @@ LIBGRPC_TEST_UTIL_SRC = \
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.c \
     src/core/lib/transport/method_config.c \
+    src/core/lib/transport/pid_controller.c \
     src/core/lib/transport/static_metadata.c \
     src/core/lib/transport/timeout_encoding.c \
     src/core/lib/transport/transport.c \
@@ -3474,6 +3499,7 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.c \
     src/core/lib/transport/method_config.c \
+    src/core/lib/transport/pid_controller.c \
     src/core/lib/transport/static_metadata.c \
     src/core/lib/transport/timeout_encoding.c \
     src/core/lib/transport/transport.c \
@@ -3592,20 +3618,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
+$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
+$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).so
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so
 endif
 endif
 
@@ -3714,6 +3740,7 @@ LIBGRPC++_SRC = \
     src/cpp/common/core_codegen.cc \
     src/cpp/common/resource_quota_cc.cc \
     src/cpp/common/rpc_method.cc \
+    src/cpp/common/version_cc.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
     src/cpp/server/dynamic_thread_pool.cc \
@@ -3828,7 +3855,7 @@ ifeq ($(NO_SECURE),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc++.a: openssl_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): openssl_dep_error
 
 else
 
@@ -3838,7 +3865,7 @@ ifeq ($(NO_PROTOBUF),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc++.a: protobuf_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): protobuf_dep_error
 
 else
 
@@ -3854,20 +3881,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).so
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so
 endif
 endif
 
@@ -3900,6 +3927,7 @@ LIBGRPC++_CRONET_SRC = \
     src/cpp/common/core_codegen.cc \
     src/cpp/common/resource_quota_cc.cc \
     src/cpp/common/rpc_method.cc \
+    src/cpp/common/version_cc.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
     src/cpp/server/dynamic_thread_pool.cc \
@@ -4014,7 +4042,7 @@ ifeq ($(NO_SECURE),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a: openssl_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): openssl_dep_error
 
 else
 
@@ -4024,7 +4052,7 @@ ifeq ($(NO_PROTOBUF),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a: protobuf_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): protobuf_dep_error
 
 else
 
@@ -4040,20 +4068,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc_cronet.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_cronet.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_cronet.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_cronet-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_cronet.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_cronet-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_cronet
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_cronet
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_cronet.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_cronet
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION).so
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_cronet.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_cronet
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so
 endif
 endif
 
@@ -4137,7 +4165,7 @@ ifeq ($(NO_SECURE),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a: openssl_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): openssl_dep_error
 
 else
 
@@ -4147,7 +4175,7 @@ ifeq ($(NO_PROTOBUF),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a: protobuf_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): protobuf_dep_error
 
 else
 
@@ -4163,20 +4191,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT_CPP) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_reflection.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_reflection.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT_CPP) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_reflection.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION).so
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_reflection.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so
 endif
 endif
 
@@ -4422,6 +4450,7 @@ LIBGRPC++_UNSECURE_SRC = \
     src/cpp/common/core_codegen.cc \
     src/cpp/common/resource_quota_cc.cc \
     src/cpp/common/rpc_method.cc \
+    src/cpp/common/version_cc.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
     src/cpp/server/dynamic_thread_pool.cc \
@@ -4536,7 +4565,7 @@ ifeq ($(NO_PROTOBUF),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a: protobuf_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): protobuf_dep_error
 
 else
 
@@ -4552,20 +4581,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT_CORE)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_unsecure-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_unsecure-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT_CORE)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).so
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so
 endif
 endif
 
@@ -5025,7 +5054,7 @@ ifeq ($(NO_SECURE),true)
 
 $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a: openssl_dep_error
 
-$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): openssl_dep_error
 
 else
 
@@ -5042,20 +5071,20 @@ endif
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared grpc_csharp_ext.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared grpc_csharp_ext.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT_CSHARP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).so
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so
 endif
 endif
 
@@ -6744,6 +6773,19 @@ endif
 
 
 LIBGOOGLE_BENCHMARK_SRC = \
+    third_party/google_benchmark/src/benchmark.cc \
+    third_party/google_benchmark/src/benchmark_register.cc \
+    third_party/google_benchmark/src/colorprint.cc \
+    third_party/google_benchmark/src/commandlineflags.cc \
+    third_party/google_benchmark/src/complexity.cc \
+    third_party/google_benchmark/src/console_reporter.cc \
+    third_party/google_benchmark/src/csv_reporter.cc \
+    third_party/google_benchmark/src/json_reporter.cc \
+    third_party/google_benchmark/src/reporter.cc \
+    third_party/google_benchmark/src/sleep.cc \
+    third_party/google_benchmark/src/string_util.cc \
+    third_party/google_benchmark/src/sysinfo.cc \
+    third_party/google_benchmark/src/timers.cc \
 
 PUBLIC_HEADERS_CXX += \
 
@@ -6899,6 +6941,7 @@ endif
 
 LIBEND2END_TESTS_SRC = \
     test/core/end2end/end2end_tests.c \
+    test/core/end2end/end2end_test_utils.c \
     test/core/end2end/tests/bad_hostname.c \
     test/core/end2end/tests/binary_metadata.c \
     test/core/end2end/tests/call_creds.c \
@@ -6983,6 +7026,7 @@ endif
 
 LIBEND2END_NOSEC_TESTS_SRC = \
     test/core/end2end/end2end_nosec_tests.c \
+    test/core/end2end/end2end_test_utils.c \
     test/core/end2end/tests/bad_hostname.c \
     test/core/end2end/tests/binary_metadata.c \
     test/core/end2end/tests/cancel_after_accept.c \
@@ -11054,6 +11098,38 @@ endif
 endif
 
 
+TRANSPORT_PID_CONTROLLER_TEST_SRC = \
+    test/core/transport/pid_controller_test.c \
+
+TRANSPORT_PID_CONTROLLER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_PID_CONTROLLER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/transport_pid_controller_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/transport_pid_controller_test: $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/transport_pid_controller_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/transport/pid_controller_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_transport_pid_controller_test: $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 TRANSPORT_SECURITY_TEST_SRC = \
     test/core/tsi/transport_security_test.c \
 
diff --git a/binding.gyp b/binding.gyp
index 9f3b75aaf3d1223b783bd5649b6a3aa8f2de46c2..bb215c4889ef2d4daf259869e11db702bc93774e 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -671,6 +671,7 @@
         'src/core/lib/transport/metadata.c',
         'src/core/lib/transport/metadata_batch.c',
         'src/core/lib/transport/method_config.c',
+        'src/core/lib/transport/pid_controller.c',
         'src/core/lib/transport/static_metadata.c',
         'src/core/lib/transport/timeout_encoding.c',
         'src/core/lib/transport/transport.c',
diff --git a/build.yaml b/build.yaml
index 75aee47c922fe46b8fb43e36aec2451c22daa1ad..c62e9e6bb8a26138c372fe8efdd29e58d23b7dd7 100644
--- a/build.yaml
+++ b/build.yaml
@@ -12,6 +12,7 @@ settings:
   '#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: 2.0.0-dev
   g_stands_for: good
   version: 1.1.0-dev
 filegroups:
@@ -256,6 +257,7 @@ filegroups:
   - src/core/lib/transport/metadata.h
   - src/core/lib/transport/metadata_batch.h
   - src/core/lib/transport/method_config.h
+  - src/core/lib/transport/pid_controller.h
   - src/core/lib/transport/static_metadata.h
   - src/core/lib/transport/timeout_encoding.h
   - src/core/lib/transport/transport.h
@@ -364,6 +366,7 @@ filegroups:
   - src/core/lib/transport/metadata.c
   - src/core/lib/transport/metadata_batch.c
   - src/core/lib/transport/method_config.c
+  - src/core/lib/transport/pid_controller.c
   - src/core/lib/transport/static_metadata.c
   - src/core/lib/transport/timeout_encoding.c
   - src/core/lib/transport/transport.c
@@ -749,6 +752,7 @@ filegroups:
   - src/cpp/common/core_codegen.cc
   - src/cpp/common/resource_quota_cc.cc
   - src/cpp/common/rpc_method.cc
+  - src/cpp/common/version_cc.cc
   - src/cpp/server/async_generic_service.cc
   - src/cpp/server/create_default_thread_pool.cc
   - src/cpp/server/dynamic_thread_pool.cc
@@ -2668,6 +2672,16 @@ targets:
   - grpc
   - gpr_test_util
   - gpr
+- name: transport_pid_controller_test
+  build: test
+  language: c
+  src:
+  - test/core/transport/pid_controller_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: transport_security_test
   build: test
   language: c
diff --git a/config.m4 b/config.m4
index 8f26e42678968c0485547917c0218d6d31a71a00..09aaac635db818690c30d0efc327f36c57594d51 100644
--- a/config.m4
+++ b/config.m4
@@ -187,6 +187,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.c \
     src/core/lib/transport/method_config.c \
+    src/core/lib/transport/pid_controller.c \
     src/core/lib/transport/static_metadata.c \
     src/core/lib/transport/timeout_encoding.c \
     src/core/lib/transport/transport.c \
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 43aedecd06f82adfc943825baec958cbb039170d..706d7afee0a52e486b21606e68519212b287bc1b 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -339,6 +339,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/transport/metadata.h',
                       'src/core/lib/transport/metadata_batch.h',
                       'src/core/lib/transport/method_config.h',
+                      'src/core/lib/transport/pid_controller.h',
                       'src/core/lib/transport/static_metadata.h',
                       'src/core/lib/transport/timeout_encoding.h',
                       'src/core/lib/transport/transport.h',
@@ -527,6 +528,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/transport/metadata.c',
                       'src/core/lib/transport/metadata_batch.c',
                       'src/core/lib/transport/method_config.c',
+                      'src/core/lib/transport/pid_controller.c',
                       'src/core/lib/transport/static_metadata.c',
                       'src/core/lib/transport/timeout_encoding.c',
                       'src/core/lib/transport/transport.c',
@@ -735,6 +737,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/transport/metadata.h',
                               'src/core/lib/transport/metadata_batch.h',
                               'src/core/lib/transport/method_config.h',
+                              'src/core/lib/transport/pid_controller.h',
                               'src/core/lib/transport/static_metadata.h',
                               'src/core/lib/transport/timeout_encoding.h',
                               'src/core/lib/transport/transport.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 615a962cdb6d1a8f9ee971064c0dc6d5528b8228..f4919bfb25d7c12c54ff0fe35bd842a3f60d74ec 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -259,6 +259,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/transport/metadata.h )
   s.files += %w( src/core/lib/transport/metadata_batch.h )
   s.files += %w( src/core/lib/transport/method_config.h )
+  s.files += %w( src/core/lib/transport/pid_controller.h )
   s.files += %w( src/core/lib/transport/static_metadata.h )
   s.files += %w( src/core/lib/transport/timeout_encoding.h )
   s.files += %w( src/core/lib/transport/transport.h )
@@ -447,6 +448,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/transport/metadata.c )
   s.files += %w( src/core/lib/transport/metadata_batch.c )
   s.files += %w( src/core/lib/transport/method_config.c )
+  s.files += %w( src/core/lib/transport/pid_controller.c )
   s.files += %w( src/core/lib/transport/static_metadata.c )
   s.files += %w( src/core/lib/transport/timeout_encoding.c )
   s.files += %w( src/core/lib/transport/transport.c )
diff --git a/include/grpc++/grpc++.h b/include/grpc++/grpc++.h
index afb1c555bb6b820fd3da393a562660624cdb03bf..36d65d6ee1eb691098d8019feecde9bc11768cba 100644
--- a/include/grpc++/grpc++.h
+++ b/include/grpc++/grpc++.h
@@ -67,4 +67,8 @@
 #include <grpc++/server_posix.h>
 // IWYU pragma: end_exports
 
+namespace grpc {
+grpc::string Version();
+}  // namespace grpc
+
 #endif  // GRPCXX_GRPCXX_H
diff --git a/package.xml b/package.xml
index a60eac68205b1afb76a0ed223ccecd0ccf17ba0f..169553efb3fb422d510b60b8879d5227ddbaa461 100644
--- a/package.xml
+++ b/package.xml
@@ -266,6 +266,7 @@
     <file baseinstalldir="/" name="src/core/lib/transport/metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/method_config.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/pid_controller.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
@@ -454,6 +455,7 @@
     <file baseinstalldir="/" name="src/core/lib/transport/metadata.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/method_config.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/pid_controller.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport.c" role="src" />
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index 30e412e3580d18e0458322f6bb6556033239894e..6249f8b80fba9fca4eab718da78af702cebccf05 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -756,6 +756,18 @@ static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
   glb_policy->pending_picks = NULL;
   pending_ping *pping = glb_policy->pending_pings;
   glb_policy->pending_pings = NULL;
+  if (glb_policy->rr_policy) {
+    GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown");
+  }
+  if (glb_policy->started_picking) {
+    if (glb_policy->lb_call != NULL) {
+      grpc_call_cancel(glb_policy->lb_call, NULL);
+      /* lb_on_server_status_received will pick up the cancel and clean up */
+    }
+  }
+  grpc_connectivity_state_set(
+      exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+      GRPC_ERROR_CREATE("Channel Shutdown"), "glb_shutdown");
   gpr_mu_unlock(&glb_policy->mu);
 
   while (pp != NULL) {
@@ -772,22 +784,6 @@ static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
                         GRPC_ERROR_NONE, NULL);
     pping = next;
   }
-
-  if (glb_policy->rr_policy) {
-    GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown");
-  }
-
-  if (glb_policy->started_picking) {
-    if (glb_policy->lb_call != NULL) {
-      grpc_call_cancel(glb_policy->lb_call, NULL);
-      /* lb_on_server_status_received will pick up the cancellation and clean up
-       */
-    }
-  }
-
-  grpc_connectivity_state_set(
-      exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN,
-      GRPC_ERROR_CREATE("Channel Shutdown"), "glb_shutdown");
 }
 
 static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
@@ -994,7 +990,7 @@ static void lb_call_init(glb_lb_policy *glb_policy) {
                    BACKOFF_MAX_SECONDS * 1000);
 }
 
-static void lb_call_destroy(glb_lb_policy *glb_policy) {
+static void lb_call_destroy_locked(glb_lb_policy *glb_policy) {
   GPR_ASSERT(glb_policy->lb_call != NULL);
   grpc_call_destroy(glb_policy->lb_call);
   glb_policy->lb_call = NULL;
@@ -1199,7 +1195,7 @@ static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg,
   }
 
   /* We need to performe cleanups no matter what. */
-  lb_call_destroy(glb_policy);
+  lb_call_destroy_locked(glb_policy);
 
   if (!glb_policy->shutting_down) {
     /* if we aren't shutting down, restart the LB client call after some time */
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index 427999aa6b8244440b2f7981e9061332bbe114c0..0fd3abe0992a1b0e6aab712cbbf1530336ab1f36 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -609,6 +609,7 @@ static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
         grpc_subchannel_get_connected_subchannel(selected->subchannel),
         "picked");
     grpc_connected_subchannel_ping(exec_ctx, target, closure);
+    GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "picked");
   } else {
     gpr_mu_unlock(&p->mu);
     grpc_exec_ctx_sched(exec_ctx, closure,
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 0981d59f637c7de9f0bfa7365576a90a286d0eb0..23b7dfb8fd7a7fcbd99f9cb31ddd45c4381f968e 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -111,9 +111,13 @@ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
   return md;
 }
 
-static int skip_compression(grpc_call_element *elem) {
+static int skip_compression(grpc_call_element *elem, uint32_t flags) {
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
+
+  if (flags & (GRPC_WRITE_NO_COMPRESS | GRPC_WRITE_INTERNAL_COMPRESS)) {
+    return 1;
+  }
   if (calld->has_compression_algorithm) {
     if (calld->compression_algorithm == GRPC_COMPRESS_NONE) {
       return 1;
@@ -241,8 +245,8 @@ static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
   if (op->send_initial_metadata) {
     process_send_initial_metadata(elem, op->send_initial_metadata);
   }
-  if (op->send_message != NULL && !skip_compression(elem) &&
-      0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) {
+  if (op->send_message != NULL &&
+      !skip_compression(elem, op->send_message->flags)) {
     calld->send_op = op;
     calld->send_length = op->send_message->length;
     calld->send_flags = op->send_message->flags;
diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c
index 8a06443d58fc5940b1b11d2e24abd2a8d71ffbb6..1770d722682b28bde08fba1ba86ef7fb1ba45a6c 100644
--- a/src/core/lib/iomgr/resource_quota.c
+++ b/src/core/lib/iomgr/resource_quota.c
@@ -44,6 +44,81 @@
 
 int grpc_resource_quota_trace = 0;
 
+/* Internal linked list pointers for a resource user */
+typedef struct {
+  grpc_resource_user *next;
+  grpc_resource_user *prev;
+} grpc_resource_user_link;
+
+/* Resource users are kept in (potentially) several intrusive linked lists
+   at once. These are the list names. */
+typedef enum {
+  /* Resource users that are waiting for an allocation */
+  GRPC_RULIST_AWAITING_ALLOCATION,
+  /* Resource users that have free memory available for internal reclamation */
+  GRPC_RULIST_NON_EMPTY_FREE_POOL,
+  /* Resource users that have published a benign reclamation is available */
+  GRPC_RULIST_RECLAIMER_BENIGN,
+  /* Resource users that have published a destructive reclamation is
+     available */
+  GRPC_RULIST_RECLAIMER_DESTRUCTIVE,
+  /* Number of lists: must be last */
+  GRPC_RULIST_COUNT
+} grpc_rulist;
+
+struct grpc_resource_user {
+  /* The quota this resource user consumes from */
+  grpc_resource_quota *resource_quota;
+
+  /* Closure to schedule an allocation under the resource quota combiner lock */
+  grpc_closure allocate_closure;
+  /* Closure to publish a non empty free pool under the resource quota combiner
+     lock */
+  grpc_closure add_to_free_pool_closure;
+
+  /* one ref for each ref call (released by grpc_resource_user_unref), and one
+     ref for each byte allocated (released by grpc_resource_user_free) */
+  gpr_atm refs;
+  /* is this resource user unlocked? starts at 0, increases for each shutdown
+     call */
+  gpr_atm shutdown;
+
+  gpr_mu mu;
+  /* The amount of memory (in bytes) this user has cached for its own use: to
+     avoid quota contention, each resource user can keep some memory in
+     addition to what it is immediately using (e.g., for caching), and the quota
+     can pull it back under memory pressure.
+     This value can become negative if more memory has been requested than
+     existed in the free pool, at which point the quota is consulted to bring
+     this value non-negative (asynchronously). */
+  int64_t free_pool;
+  /* A list of closures to call once free_pool becomes non-negative - ie when
+     all outstanding allocations have been granted. */
+  grpc_closure_list on_allocated;
+  /* True if we are currently trying to allocate from the quota, false if not */
+  bool allocating;
+  /* True if we are currently trying to add ourselves to the non-free quota
+     list, false otherwise */
+  bool added_to_free_pool;
+
+  /* Reclaimers: index 0 is the benign reclaimer, 1 is the destructive reclaimer
+   */
+  grpc_closure *reclaimers[2];
+  /* Trampoline closures to finish reclamation and re-enter the quota combiner
+     lock */
+  grpc_closure post_reclaimer_closure[2];
+
+  /* Closure to execute under the quota combiner to de-register and shutdown the
+     resource user */
+  grpc_closure destroy_closure;
+
+  /* Links in the various grpc_rulist lists */
+  grpc_resource_user_link links[GRPC_RULIST_COUNT];
+
+  /* The name of this resource user, for debugging/tracing */
+  char *name;
+};
+
 struct grpc_resource_quota {
   /* refcount */
   gpr_refcount refs;
@@ -373,9 +448,19 @@ static void ru_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
   rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
 }
 
+static void ru_shutdown(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
+  grpc_resource_user *resource_user = ru;
+  grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[0],
+                      GRPC_ERROR_CANCELLED, NULL);
+  grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1],
+                      GRPC_ERROR_CANCELLED, NULL);
+  resource_user->reclaimers[0] = NULL;
+  resource_user->reclaimers[1] = NULL;
+}
+
 static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
   grpc_resource_user *resource_user = ru;
-  GPR_ASSERT(resource_user->allocated == 0);
+  GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->refs) == 0);
   for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
     rulist_remove(resource_user, (grpc_rulist)i);
   }
@@ -383,13 +468,14 @@ static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
                       GRPC_ERROR_CANCELLED, NULL);
   grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1],
                       GRPC_ERROR_CANCELLED, NULL);
-  grpc_exec_ctx_sched(exec_ctx, (grpc_closure *)gpr_atm_no_barrier_load(
-                                    &resource_user->on_done_destroy_closure),
-                      GRPC_ERROR_NONE, NULL);
   if (resource_user->free_pool != 0) {
     resource_user->resource_quota->free_pool += resource_user->free_pool;
     rq_step_sched(exec_ctx, resource_user->resource_quota);
   }
+  grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota);
+  gpr_mu_destroy(&resource_user->mu);
+  gpr_free(resource_user->name);
+  gpr_free(resource_user);
 }
 
 static void ru_allocated_slices(grpc_exec_ctx *exec_ctx, void *arg,
@@ -539,9 +625,9 @@ const grpc_arg_pointer_vtable *grpc_resource_quota_arg_vtable(void) {
  * grpc_resource_user api
  */
 
-void grpc_resource_user_init(grpc_resource_user *resource_user,
-                             grpc_resource_quota *resource_quota,
-                             const char *name) {
+grpc_resource_user *grpc_resource_user_create(
+    grpc_resource_quota *resource_quota, const char *name) {
+  grpc_resource_user *resource_user = gpr_malloc(sizeof(*resource_user));
   resource_user->resource_quota =
       grpc_resource_quota_internal_ref(resource_quota);
   grpc_closure_init(&resource_user->allocate_closure, &ru_allocate,
@@ -555,12 +641,12 @@ void grpc_resource_user_init(grpc_resource_user *resource_user,
   grpc_closure_init(&resource_user->destroy_closure, &ru_destroy,
                     resource_user);
   gpr_mu_init(&resource_user->mu);
-  resource_user->allocated = 0;
+  gpr_atm_rel_store(&resource_user->refs, 1);
+  gpr_atm_rel_store(&resource_user->shutdown, 0);
   resource_user->free_pool = 0;
   grpc_closure_list_init(&resource_user->on_allocated);
   resource_user->allocating = false;
   resource_user->added_to_free_pool = false;
-  gpr_atm_no_barrier_store(&resource_user->on_done_destroy_closure, 0);
   resource_user->reclaimers[0] = NULL;
   resource_user->reclaimers[1] = NULL;
   for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
@@ -572,56 +658,54 @@ void grpc_resource_user_init(grpc_resource_user *resource_user,
     gpr_asprintf(&resource_user->name, "anonymous_resource_user_%" PRIxPTR,
                  (intptr_t)resource_user);
   }
+  return resource_user;
 }
 
-void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
-                                 grpc_resource_user *resource_user,
-                                 grpc_closure *on_done) {
-  gpr_mu_lock(&resource_user->mu);
-  GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->on_done_destroy_closure) ==
-             0);
-  gpr_atm_no_barrier_store(&resource_user->on_done_destroy_closure,
-                           (gpr_atm)on_done);
-  if (resource_user->allocated == 0) {
+static void ru_ref_by(grpc_resource_user *resource_user, gpr_atm amount) {
+  GPR_ASSERT(amount > 0);
+  GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&resource_user->refs, amount) != 0);
+}
+
+static void ru_unref_by(grpc_exec_ctx *exec_ctx,
+                        grpc_resource_user *resource_user, gpr_atm amount) {
+  GPR_ASSERT(amount > 0);
+  gpr_atm old = gpr_atm_full_fetch_add(&resource_user->refs, -amount);
+  GPR_ASSERT(old >= amount);
+  if (old == amount) {
     grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
                           &resource_user->destroy_closure, GRPC_ERROR_NONE,
                           false);
   }
-  gpr_mu_unlock(&resource_user->mu);
 }
 
-void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
-                                grpc_resource_user *resource_user) {
-  grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota);
-  gpr_mu_destroy(&resource_user->mu);
-  gpr_free(resource_user->name);
+void grpc_resource_user_ref(grpc_resource_user *resource_user) {
+  ru_ref_by(resource_user, 1);
+}
+
+void grpc_resource_user_unref(grpc_exec_ctx *exec_ctx,
+                              grpc_resource_user *resource_user) {
+  ru_unref_by(exec_ctx, resource_user, 1);
+}
+
+void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
+                                 grpc_resource_user *resource_user) {
+  if (gpr_atm_full_fetch_add(&resource_user->shutdown, 1) == 0) {
+    grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+                          grpc_closure_create(ru_shutdown, resource_user),
+                          GRPC_ERROR_NONE, false);
+  }
 }
 
 void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx,
                               grpc_resource_user *resource_user, size_t size,
                               grpc_closure *optional_on_done) {
   gpr_mu_lock(&resource_user->mu);
-  grpc_closure *on_done_destroy = (grpc_closure *)gpr_atm_no_barrier_load(
-      &resource_user->on_done_destroy_closure);
-  if (on_done_destroy != NULL) {
-    /* already shutdown */
-    if (grpc_resource_quota_trace) {
-      gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR " after shutdown",
-              resource_user->resource_quota->name, resource_user->name, size);
-    }
-    grpc_exec_ctx_sched(
-        exec_ctx, optional_on_done,
-        GRPC_ERROR_CREATE("Buffer pool user is already shutdown"), NULL);
-    gpr_mu_unlock(&resource_user->mu);
-    return;
-  }
-  resource_user->allocated += (int64_t)size;
+  ru_ref_by(resource_user, (gpr_atm)size);
   resource_user->free_pool -= (int64_t)size;
   if (grpc_resource_quota_trace) {
-    gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; allocated -> %" PRId64
-                       ", free_pool -> %" PRId64,
+    gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64,
             resource_user->resource_quota->name, resource_user->name, size,
-            resource_user->allocated, resource_user->free_pool);
+            resource_user->free_pool);
   }
   if (resource_user->free_pool < 0) {
     grpc_closure_list_append(&resource_user->on_allocated, optional_on_done,
@@ -641,15 +725,12 @@ void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx,
 void grpc_resource_user_free(grpc_exec_ctx *exec_ctx,
                              grpc_resource_user *resource_user, size_t size) {
   gpr_mu_lock(&resource_user->mu);
-  GPR_ASSERT(resource_user->allocated >= (int64_t)size);
   bool was_zero_or_negative = resource_user->free_pool <= 0;
   resource_user->free_pool += (int64_t)size;
-  resource_user->allocated -= (int64_t)size;
   if (grpc_resource_quota_trace) {
-    gpr_log(GPR_DEBUG, "RQ %s %s: free %" PRIdPTR "; allocated -> %" PRId64
-                       ", free_pool -> %" PRId64,
+    gpr_log(GPR_DEBUG, "RQ %s %s: free %" PRIdPTR "; free_pool -> %" PRId64,
             resource_user->resource_quota->name, resource_user->name, size,
-            resource_user->allocated, resource_user->free_pool);
+            resource_user->free_pool);
   }
   bool is_bigger_than_zero = resource_user->free_pool > 0;
   if (is_bigger_than_zero && was_zero_or_negative &&
@@ -659,29 +740,23 @@ void grpc_resource_user_free(grpc_exec_ctx *exec_ctx,
                           &resource_user->add_to_free_pool_closure,
                           GRPC_ERROR_NONE, false);
   }
-  grpc_closure *on_done_destroy = (grpc_closure *)gpr_atm_no_barrier_load(
-      &resource_user->on_done_destroy_closure);
-  if (on_done_destroy != NULL && resource_user->allocated == 0) {
-    grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
-                          &resource_user->destroy_closure, GRPC_ERROR_NONE,
-                          false);
-  }
   gpr_mu_unlock(&resource_user->mu);
+  ru_unref_by(exec_ctx, resource_user, (gpr_atm)size);
 }
 
 void grpc_resource_user_post_reclaimer(grpc_exec_ctx *exec_ctx,
                                        grpc_resource_user *resource_user,
                                        bool destructive,
                                        grpc_closure *closure) {
-  if (gpr_atm_acq_load(&resource_user->on_done_destroy_closure) == 0) {
-    GPR_ASSERT(resource_user->reclaimers[destructive] == NULL);
-    resource_user->reclaimers[destructive] = closure;
-    grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
-                          &resource_user->post_reclaimer_closure[destructive],
-                          GRPC_ERROR_NONE, false);
-  } else {
+  GPR_ASSERT(resource_user->reclaimers[destructive] == NULL);
+  if (gpr_atm_acq_load(&resource_user->shutdown) > 0) {
     grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CANCELLED, NULL);
+    return;
   }
+  resource_user->reclaimers[destructive] = closure;
+  grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+                        &resource_user->post_reclaimer_closure[destructive],
+                        GRPC_ERROR_NONE, false);
 }
 
 void grpc_resource_user_finish_reclamation(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index da68f21a2c7143cdf29d54a383a4b55f69b5e924..bbe0af1a1413ce9ea1fb5313c63ed017b14545b7 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -84,91 +84,15 @@ void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx,
 grpc_resource_quota *grpc_resource_quota_from_channel_args(
     const grpc_channel_args *channel_args);
 
-/* Resource users are kept in (potentially) several intrusive linked lists
-   at once. These are the list names. */
-typedef enum {
-  /* Resource users that are waiting for an allocation */
-  GRPC_RULIST_AWAITING_ALLOCATION,
-  /* Resource users that have free memory available for internal reclamation */
-  GRPC_RULIST_NON_EMPTY_FREE_POOL,
-  /* Resource users that have published a benign reclamation is available */
-  GRPC_RULIST_RECLAIMER_BENIGN,
-  /* Resource users that have published a destructive reclamation is
-     available */
-  GRPC_RULIST_RECLAIMER_DESTRUCTIVE,
-  /* Number of lists: must be last */
-  GRPC_RULIST_COUNT
-} grpc_rulist;
-
 typedef struct grpc_resource_user grpc_resource_user;
 
-/* Internal linked list pointers for a resource user */
-typedef struct {
-  grpc_resource_user *next;
-  grpc_resource_user *prev;
-} grpc_resource_user_link;
-
-struct grpc_resource_user {
-  /* The quota this resource user consumes from */
-  grpc_resource_quota *resource_quota;
-
-  /* Closure to schedule an allocation under the resource quota combiner lock */
-  grpc_closure allocate_closure;
-  /* Closure to publish a non empty free pool under the resource quota combiner
-     lock */
-  grpc_closure add_to_free_pool_closure;
-
-  gpr_mu mu;
-  /* Total allocated memory outstanding by this resource user in bytes;
-     always positive */
-  int64_t allocated;
-  /* The amount of memory (in bytes) this user has cached for its own use: to
-     avoid quota contention, each resource user can keep some memory in
-     addition to what it is immediately using (e.g., for caching), and the quota
-     can pull it back under memory pressure.
-     This value can become negative if more memory has been requested than
-     existed in the free pool, at which point the quota is consulted to bring
-     this value non-negative (asynchronously). */
-  int64_t free_pool;
-  /* A list of closures to call once free_pool becomes non-negative - ie when
-     all outstanding allocations have been granted. */
-  grpc_closure_list on_allocated;
-  /* True if we are currently trying to allocate from the quota, false if not */
-  bool allocating;
-  /* True if we are currently trying to add ourselves to the non-free quota
-     list, false otherwise */
-  bool added_to_free_pool;
-
-  /* Reclaimers: index 0 is the benign reclaimer, 1 is the destructive reclaimer
-   */
-  grpc_closure *reclaimers[2];
-  /* Trampoline closures to finish reclamation and re-enter the quota combiner
-     lock */
-  grpc_closure post_reclaimer_closure[2];
-
-  /* Closure to execute under the quota combiner to de-register and shutdown the
-     resource user */
-  grpc_closure destroy_closure;
-  /* User supplied closure to call once the user has finished shutting down AND
-     all outstanding allocations have been freed. Real type is grpc_closure*,
-     but it's stored as an atomic to avoid a mutex on some fast paths. */
-  gpr_atm on_done_destroy_closure;
-
-  /* Links in the various grpc_rulist lists */
-  grpc_resource_user_link links[GRPC_RULIST_COUNT];
-
-  /* The name of this resource user, for debugging/tracing */
-  char *name;
-};
-
-void grpc_resource_user_init(grpc_resource_user *resource_user,
-                             grpc_resource_quota *resource_quota,
-                             const char *name);
+grpc_resource_user *grpc_resource_user_create(
+    grpc_resource_quota *resource_quota, const char *name);
+void grpc_resource_user_ref(grpc_resource_user *resource_user);
+void grpc_resource_user_unref(grpc_exec_ctx *exec_ctx,
+                              grpc_resource_user *resource_user);
 void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
-                                 grpc_resource_user *resource_user,
-                                 grpc_closure *on_done);
-void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
-                                grpc_resource_user *resource_user);
+                                 grpc_resource_user *resource_user);
 
 /* Allocate from the resource user (and its quota).
    If optional_on_done is NULL, then allocate immediately. This may push the
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 880af93ee1ae9b628408c36354b6c3f987b6c0cb..70416c6eef4d4117c44a0c9ea397726815ab34ed 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -102,7 +102,7 @@ typedef struct {
 
   char *peer_string;
 
-  grpc_resource_user resource_user;
+  grpc_resource_user *resource_user;
   grpc_resource_user_slice_allocator slice_allocator;
 } grpc_tcp;
 
@@ -110,28 +110,18 @@ static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
                             grpc_error *error);
 static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
                              grpc_error *error);
-static void tcp_unref_closure(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                              grpc_error *error);
-
-static void tcp_maybe_shutdown_resource_user(grpc_exec_ctx *exec_ctx,
-                                             grpc_tcp *tcp) {
-  if (gpr_atm_full_fetch_add(&tcp->shutdown_count, 1) == 0) {
-    grpc_resource_user_shutdown(exec_ctx, &tcp->resource_user,
-                                grpc_closure_create(tcp_unref_closure, tcp));
-  }
-}
 
 static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
   grpc_tcp *tcp = (grpc_tcp *)ep;
-  tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
   grpc_fd_shutdown(exec_ctx, tcp->em_fd);
+  grpc_resource_user_shutdown(exec_ctx, tcp->resource_user);
 }
 
 static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
   grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
                  "tcp_unref_orphan");
   gpr_slice_buffer_destroy(&tcp->last_read_buffer);
-  grpc_resource_user_destroy(exec_ctx, &tcp->resource_user);
+  grpc_resource_user_unref(exec_ctx, tcp->resource_user);
   gpr_free(tcp->peer_string);
   gpr_free(tcp);
 }
@@ -168,15 +158,9 @@ static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
 static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
 #endif
 
-static void tcp_unref_closure(grpc_exec_ctx *exec_ctx, void *arg,
-                              grpc_error *error) {
-  TCP_UNREF(exec_ctx, arg, "resource_user");
-}
-
 static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
   grpc_network_status_unregister_endpoint(ep);
   grpc_tcp *tcp = (grpc_tcp *)ep;
-  tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
   gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
   TCP_UNREF(exec_ctx, tcp, "destroy");
 }
@@ -515,7 +499,7 @@ static grpc_workqueue *tcp_get_workqueue(grpc_endpoint *ep) {
 
 static grpc_resource_user *tcp_get_resource_user(grpc_endpoint *ep) {
   grpc_tcp *tcp = (grpc_tcp *)ep;
-  return &tcp->resource_user;
+  return tcp->resource_user;
 }
 
 static const grpc_endpoint_vtable vtable = {tcp_read,
@@ -543,9 +527,8 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
   tcp->slice_size = slice_size;
   tcp->iov_size = 1;
   tcp->finished_edge = true;
-  /* paired with unref in grpc_tcp_destroy, and with the shutdown for our
-   * resource_user */
-  gpr_ref_init(&tcp->refcount, 2);
+  /* paired with unref in grpc_tcp_destroy */
+  gpr_ref_init(&tcp->refcount, 1);
   gpr_atm_no_barrier_store(&tcp->shutdown_count, 0);
   tcp->em_fd = em_fd;
   tcp->read_closure.cb = tcp_handle_read;
@@ -553,10 +536,9 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
   tcp->write_closure.cb = tcp_handle_write;
   tcp->write_closure.cb_arg = tcp;
   gpr_slice_buffer_init(&tcp->last_read_buffer);
-  grpc_resource_user_init(&tcp->resource_user, resource_quota, peer_string);
-  grpc_resource_user_slice_allocator_init(&tcp->slice_allocator,
-                                          &tcp->resource_user,
-                                          tcp_read_allocation_done, tcp);
+  tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
+  grpc_resource_user_slice_allocator_init(
+      &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
   /* Tell network status tracker about new endpoint */
   grpc_network_status_register_endpoint(&tcp->base);
 
@@ -576,7 +558,6 @@ void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
   GPR_ASSERT(ep->vtable == &vtable);
   tcp->release_fd = fd;
   tcp->release_fd_cb = done;
-  tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
   gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
   TCP_UNREF(exec_ctx, tcp, "destroy");
 }
diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c
index 46f0491d10aef8d8791d07664872fb4a092c7297..e7abf2971f35995d2fc83f75a347af1f30358879 100644
--- a/src/core/lib/iomgr/tcp_windows.c
+++ b/src/core/lib/iomgr/tcp_windows.c
@@ -109,46 +109,35 @@ typedef struct grpc_tcp {
   gpr_slice_buffer *write_slices;
   gpr_slice_buffer *read_slices;
 
-  grpc_resource_user resource_user;
+  grpc_resource_user *resource_user;
 
   /* The IO Completion Port runs from another thread. We need some mechanism
      to protect ourselves when requesting a shutdown. */
   gpr_mu mu;
   int shutting_down;
 
-  gpr_atm resource_user_shutdown_count;
-
   char *peer_string;
 } grpc_tcp;
 
-static void win_unref_closure(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                              grpc_error *error);
-
-static void win_maybe_shutdown_resource_user(grpc_exec_ctx *exec_ctx,
-                                             grpc_tcp *tcp) {
-  if (gpr_atm_full_fetch_add(&tcp->resource_user_shutdown_count, 1) == 0) {
-    grpc_resource_user_shutdown(exec_ctx, &tcp->resource_user,
-                                grpc_closure_create(win_unref_closure, tcp));
-  }
-}
-
-static void tcp_free(grpc_tcp *tcp) {
+static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
   grpc_winsocket_destroy(tcp->socket);
   gpr_mu_destroy(&tcp->mu);
   gpr_free(tcp->peer_string);
+  grpc_resource_user_unref(exec_ctx, tcp->resource_user);
   gpr_free(tcp);
 }
 
 /*#define GRPC_TCP_REFCOUNT_DEBUG*/
 #ifdef GRPC_TCP_REFCOUNT_DEBUG
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
+#define TCP_UNREF(exec_ctx, tcp, reason) \
+  tcp_unref((exec_ctx), (tcp), (reason), __FILE__, __LINE__)
 #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
-static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
-                      int line) {
+static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
+                      const char *reason, const char *file, int line) {
   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
           reason, tcp->refcount.count, tcp->refcount.count - 1);
   if (gpr_unref(&tcp->refcount)) {
-    tcp_free(tcp);
+    tcp_free(exec_ctx, tcp);
   }
 }
 
@@ -159,22 +148,17 @@ static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
   gpr_ref(&tcp->refcount);
 }
 #else
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
+#define TCP_UNREF(exec_ctx, tcp, reason) tcp_unref((exec_ctx), (tcp))
 #define TCP_REF(tcp, reason) tcp_ref((tcp))
-static void tcp_unref(grpc_tcp *tcp) {
+static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
   if (gpr_unref(&tcp->refcount)) {
-    tcp_free(tcp);
+    tcp_free(exec_ctx, tcp);
   }
 }
 
 static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
 #endif
 
-static void win_unref_closure(grpc_exec_ctx *exec_ctx, void *arg,
-                              grpc_error *error) {
-  TCP_UNREF(arg, "resource_user");
-}
-
 /* Asynchronous callback from the IOCP, or the background thread. */
 static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
   grpc_tcp *tcp = tcpp;
@@ -203,7 +187,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
   }
 
   tcp->read_cb = NULL;
-  TCP_UNREF(tcp, "read");
+  TCP_UNREF(exec_ctx, tcp, "read");
   grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
 }
 
@@ -287,7 +271,7 @@ static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
     }
   }
 
-  TCP_UNREF(tcp, "write");
+  TCP_UNREF(exec_ctx, tcp, "write");
   grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
 }
 
@@ -355,7 +339,7 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
   if (status != 0) {
     int wsa_error = WSAGetLastError();
     if (wsa_error != WSA_IO_PENDING) {
-      TCP_UNREF(tcp, "write");
+      TCP_UNREF(exec_ctx, tcp, "write");
       grpc_exec_ctx_sched(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend"),
                           NULL);
       return;
@@ -396,15 +380,14 @@ static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
      callback. See the comments in on_read and on_write. */
   tcp->shutting_down = 1;
   grpc_winsocket_shutdown(tcp->socket);
-  win_maybe_shutdown_resource_user(exec_ctx, tcp);
   gpr_mu_unlock(&tcp->mu);
+  grpc_resource_user_shutdown(exec_ctx, tcp->resource_user);
 }
 
 static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
   grpc_network_status_unregister_endpoint(ep);
   grpc_tcp *tcp = (grpc_tcp *)ep;
-  win_maybe_shutdown_resource_user(exec_ctx, tcp);
-  TCP_UNREF(tcp, "destroy");
+  TCP_UNREF(exec_ctx, tcp, "destroy");
 }
 
 static char *win_get_peer(grpc_endpoint *ep) {
@@ -416,7 +399,7 @@ static grpc_workqueue *win_get_workqueue(grpc_endpoint *ep) { return NULL; }
 
 static grpc_resource_user *win_get_resource_user(grpc_endpoint *ep) {
   grpc_tcp *tcp = (grpc_tcp *)ep;
-  return &tcp->resource_user;
+  return tcp->resource_user;
 }
 
 static grpc_endpoint_vtable vtable = {win_read,
@@ -441,7 +424,7 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
   grpc_closure_init(&tcp->on_read, on_read, tcp);
   grpc_closure_init(&tcp->on_write, on_write, tcp);
   tcp->peer_string = gpr_strdup(peer_string);
-  grpc_resource_user_init(&tcp->resource_user, resource_quota, peer_string);
+  tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
   /* Tell network status tracking code about the new endpoint */
   grpc_network_status_register_endpoint(&tcp->base);
 
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 6c25952c0a986073d7108781e55dc2f7a924fd1e..e3b088f663ad8c9c448d645b859094b063dc0195 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -1461,6 +1461,12 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
         grpc_slice_buffer_stream_init(
             &call->sending_stream,
             &op->data.send_message->data.raw.slice_buffer, op->flags);
+        /* If the outgoing buffer is already compressed, mark it as so in the
+           flags. These will be picked up by the compression filter and further
+           (wasteful) attempts at compression skipped. */
+        if (op->data.send_message->data.raw.compression > GRPC_COMPRESS_NONE) {
+          call->sending_stream.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+        }
         stream_op->send_message = &call->sending_stream.base;
         break;
       case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index 41242684da5d559b2d6d9ccd9b74ae43c181d3a8..0db8b41aa926f76d15fd42748c28218fc153e5ce 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,6 +36,6 @@
 
 #include <grpc/grpc.h>
 
-const char *grpc_version_string(void) { return "1.1.0-dev"; }
+const char *grpc_version_string(void) { return "2.0.0-dev"; }
 
 const char *grpc_g_stands_for(void) { return "good"; }
diff --git a/src/core/lib/transport/pid_controller.c b/src/core/lib/transport/pid_controller.c
new file mode 100644
index 0000000000000000000000000000000000000000..3cef225d4bad049e9eb6dda3f77ce4adc5d524fb
--- /dev/null
+++ b/src/core/lib/transport/pid_controller.c
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+#include "src/core/lib/transport/pid_controller.h"
+
+void grpc_pid_controller_init(grpc_pid_controller *pid_controller,
+                              double gain_p, double gain_i, double gain_d) {
+  pid_controller->gain_p = gain_p;
+  pid_controller->gain_i = gain_i;
+  pid_controller->gain_d = gain_d;
+  grpc_pid_controller_reset(pid_controller);
+}
+
+void grpc_pid_controller_reset(grpc_pid_controller *pid_controller) {
+  pid_controller->last_error = 0.0;
+  pid_controller->error_integral = 0.0;
+}
+
+double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
+                                  double error, double dt) {
+  pid_controller->error_integral += error * dt;
+  double diff_error = (error - pid_controller->last_error) / dt;
+  pid_controller->last_error = error;
+  return dt * (pid_controller->gain_p * error +
+               pid_controller->gain_i * pid_controller->error_integral +
+               pid_controller->gain_d * diff_error);
+}
diff --git a/src/core/lib/transport/pid_controller.h b/src/core/lib/transport/pid_controller.h
new file mode 100644
index 0000000000000000000000000000000000000000..059b5b08346a48b1f9d13e9fb07584799e3a63f3
--- /dev/null
+++ b/src/core/lib/transport/pid_controller.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
+#define GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
+
+/* \file Simple PID controller.
+   Implements a proportional-integral-derivative controller.
+   Used when we want to iteratively control a variable to converge some other
+   observed value to a 'set-point'.
+   Gains can be set to adjust sensitivity to current error (p), the integral
+   of error (i), and the derivative of error (d). */
+
+typedef struct {
+  double gain_p;
+  double gain_i;
+  double gain_d;
+  double last_error;
+  double error_integral;
+} grpc_pid_controller;
+
+/** Initialize the controller */
+void grpc_pid_controller_init(grpc_pid_controller *pid_controller,
+                              double gain_p, double gain_i, double gain_d);
+
+/** Reset the controller: useful when things have changed significantly */
+void grpc_pid_controller_reset(grpc_pid_controller *pid_controller);
+
+/** Update the controller: given a current error estimate, and the time since
+    the last update, returns a delta to the control value */
+double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
+                                  double error, double dt);
+
+#endif
diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc
index c6cad8eeaeece5b897891c38a1f9758d53bb8a0d..d86ba9dd4e8c4760a80d7f299787ff3e61943830 100644
--- a/src/cpp/common/channel_arguments.cc
+++ b/src/cpp/common/channel_arguments.cc
@@ -34,6 +34,7 @@
 
 #include <sstream>
 
+#include <grpc++/grpc++.h>
 #include <grpc++/resource_quota.h>
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/log.h>
@@ -42,10 +43,8 @@
 namespace grpc {
 
 ChannelArguments::ChannelArguments() {
-  std::ostringstream user_agent_prefix;
-  user_agent_prefix << "grpc-c++/" << grpc_version_string();
   // This will be ignored if used on the server side.
-  SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, user_agent_prefix.str());
+  SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, "grpc-c++/" + Version());
 }
 
 ChannelArguments::ChannelArguments(const ChannelArguments& other)
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7be338417f65ad9b337b111a2c1095aee24d65f4
--- /dev/null
+++ b/src/cpp/common/version_cc.cc
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+/* This file is autogenerated from:
+   templates/src/core/surface/version.c.template */
+
+#include <grpc++/grpc++.h>
+
+namespace grpc {
+grpc::string Version() { return "1.1.0-dev"; }
+}
diff --git a/src/google_benchmark/gen_build_yaml.py b/src/google_benchmark/gen_build_yaml.py
index f3b3f4613228339f0a328766275efe74d5bd88f7..302e08737aff92192d2b9f3e32d52d8d23b29ec4 100755
--- a/src/google_benchmark/gen_build_yaml.py
+++ b/src/google_benchmark/gen_build_yaml.py
@@ -44,8 +44,10 @@ out['libs'] = [{
     'language': 'c++',
     'secure': 'no',
     'defaults': 'google_benchmark',
-    'src': glob.glob('third_party/google_benchmark/src/*.cc'),
-    'headers': glob.glob('third_party/google_benchmark/src/*.h') + glob.glob('third_party/google_benchmark/include/benchmark/*.h'),
+    'src': sorted(glob.glob('third_party/google_benchmark/src/*.cc')),
+    'headers': sorted(
+        glob.glob('third_party/google_benchmark/src/*.h') +
+        glob.glob('third_party/google_benchmark/include/benchmark/*.h')),
 }]
 
 print yaml.dump(out)
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index e24be3fc7638fd8bcfee215042df7d5f80e69c55..c4d56790f7568e1d5c2355d2260e24a152f8a017 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -35,7 +35,7 @@
 namespace Grpc;
 
 /**
- * Class AbstractCall
+ * Class AbstractCall.
  * @package Grpc
  */
 abstract class AbstractCall
@@ -121,13 +121,14 @@ abstract class AbstractCall
     }
 
     /**
-     * Serialize a message to the protobuf binary format
+     * Serialize a message to the protobuf binary format.
      *
      * @param mixed $data The Protobuf message
      *
      * @return string The protobuf binary format
      */
-    protected function serializeMessage($data) {
+    protected function serializeMessage($data)
+    {
         // Proto3 implementation
         if (method_exists($data, 'encode')) {
             return $data->encode();
@@ -155,6 +156,7 @@ abstract class AbstractCall
             list($className, $deserializeFunc) = $this->deserialize;
             $obj = new $className();
             $obj->$deserializeFunc($value);
+
             return $obj;
         }
 
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 36d94cae2c90ce1d2a9b6ce52eee0423d128a17e..d0baeae955bb4a07a807861e8db1df054fe0be5e 100644
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -252,7 +252,7 @@ class BaseStub
      *
      * @param string   $method      The name of the method to call
      * @param array    $arguments   An array or Traversable of arguments to stream to the
-     *     server
+     *                              server
      * @param callable $deserialize A function that deserializes the response
      * @param array    $metadata    A metadata map to send to the server
      *
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 3d62e86ab04341c78e6acafbb09f27760499c389..d201915d668e2f05560561836b1fd7915d45b0e0 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -477,10 +477,10 @@ function statusCodeAndMessage($stub)
     list($result, $status) = $call->wait();
 
     hardAssert($status->code === 2,
-               'Received unexpected UnaryCall status code: ' .
+               'Received unexpected UnaryCall status code: '.
                $status->code);
     hardAssert($status->details === 'test status message',
-               'Received unexpected UnaryCall status details: ' .
+               'Received unexpected UnaryCall status details: '.
                $status->details);
 
     $streaming_call = $stub->FullDuplexCall();
@@ -493,10 +493,10 @@ function statusCodeAndMessage($stub)
 
     $status = $streaming_call->getStatus();
     hardAssert($status->code === 2,
-               'Received unexpected FullDuplexCall status code: ' .
+               'Received unexpected FullDuplexCall status code: '.
                $status->code);
     hardAssert($status->details === 'test status message',
-               'Received unexpected FullDuplexCall status details: ' .
+               'Received unexpected FullDuplexCall status details: '.
                $status->details);
 }
 
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index 1205f0cd8eb7b7fca3b9ad8b891dd23b84d7b025..f60eb96730fb9073f794c9effbf6883034dd37f0 100644
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -94,7 +94,7 @@ class CallTest extends PHPUnit_Framework_TestCase
         $batch = [
             Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'],
                                               'key2' => ['value2',
-                                                         'value3'], ],
+                                                         'value3', ], ],
         ];
         $result = $this->call->startBatch($batch);
         $this->assertTrue($result->send_metadata);
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 1ad423909f5f38ce0fb8db5291c881f9b5351306..8f4b3bc9b27eb1550e0e5fdd39e020371af03770 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -181,6 +181,7 @@ CORE_SOURCE_FILES = [
   'src/core/lib/transport/metadata.c',
   'src/core/lib/transport/metadata_batch.c',
   'src/core/lib/transport/method_config.c',
+  'src/core/lib/transport/pid_controller.c',
   'src/core/lib/transport/static_metadata.c',
   'src/core/lib/transport/timeout_encoding.c',
   'src/core/lib/transport/transport.c',
diff --git a/src/python/grpcio_tests/tests/unit/_rpc_test.py b/src/python/grpcio_tests/tests/unit/_rpc_test.py
index ab6546bf87fc62cd099647420892a10cd2577d84..eb00156da514857a44342b1acb69b16c803d47bd 100644
--- a/src/python/grpcio_tests/tests/unit/_rpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_rpc_test.py
@@ -191,6 +191,10 @@ class RPCTest(unittest.TestCase):
 
     self._channel = grpc.insecure_channel('localhost:%d' % port)
 
+  def tearDown(self):
+    self._server.stop(None)
+    self._server_pool.shutdown(wait=True)
+
   def testUnrecognizedMethod(self):
     request = b'abc'
 
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index 2b6c0b1a367935e51718aeef40437c332be3c13f..c3c636c6af7db733bd1ec7e298735553ce7b8b38 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -60,7 +60,7 @@
   cmake_minimum_required(VERSION 2.8)
 
   set(PACKAGE_NAME      "grpc")
-  set(PACKAGE_VERSION   "${settings.core_version}")
+  set(PACKAGE_VERSION   "${settings.cpp_version}")
   set(PACKAGE_STRING    "<%text>${PACKAGE_NAME} ${PACKAGE_VERSION}</%text>")
   set(PACKAGE_TARNAME   "<%text>${PACKAGE_NAME}-${PACKAGE_VERSION}</%text>")
   set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 3b76ded95db24b744fe4bfa28ed849c65e197ae9..109de33c31eca42d9929373a64537e4320d2e519 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -62,6 +62,12 @@
         return warning[3:]
       else:
         return 'no-' + warning
+
+    lang_to_var = {
+      'c': 'CORE',
+      'c++': 'CPP',
+      'csharp': 'CSHARP'
+    }
   %>
 
 
@@ -311,7 +317,9 @@
   Q = @
   endif
 
-  VERSION = ${settings.core_version}
+  CORE_VERSION = ${settings.core_version}
+  CPP_VERSION = ${settings.cpp_version}
+  CSHARP_VERSION = ${settings.csharp_version}
 
   CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
   CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -344,31 +352,69 @@
   CACHE_MK += HAS_PKG_CONFIG = true,
   endif
 
-  PC_TEMPLATE = prefix=$(prefix),\
+  CORE_PC_TEMPLATE = prefix=$(prefix),\
+  exec_prefix=${'\$${prefix}'},\
+  includedir=${'\$${prefix}'}/include,\
+  libdir=${'\$${exec_prefix}'}/lib,\
+  ,\
+  Name: $(PC_NAME),\
+  Description: $(PC_DESCRIPTION),\
+  Version: $(CORE_VERSION),\
+  Cflags: -I${'\$${includedir}'} $(PC_CFLAGS),\
+  Requires.private: $(PC_REQUIRES_PRIVATE),\
+  Libs: -L${'\$${libdir}'} $(PC_LIB),\
+  Libs.private: $(PC_LIBS_PRIVATE)
+
+  CPP_PC_TEMPLATE = prefix=$(prefix),\
+  exec_prefix=${'\$${prefix}'},\
+  includedir=${'\$${prefix}'}/include,\
+  libdir=${'\$${exec_prefix}'}/lib,\
+  ,\
+  Name: $(PC_NAME),\
+  Description: $(PC_DESCRIPTION),\
+  Version: $(CPP_VERSION),\
+  Cflags: -I${'\$${includedir}'} $(PC_CFLAGS),\
+  Requires.private: $(PC_REQUIRES_PRIVATE),\
+  Libs: -L${'\$${libdir}'} $(PC_LIB),\
+  Libs.private: $(PC_LIBS_PRIVATE)
+
+  CSHARP_PC_TEMPLATE = prefix=$(prefix),\
   exec_prefix=${'\$${prefix}'},\
   includedir=${'\$${prefix}'}/include,\
   libdir=${'\$${exec_prefix}'}/lib,\
   ,\
   Name: $(PC_NAME),\
   Description: $(PC_DESCRIPTION),\
-  Version: $(VERSION),\
+  Version: $(CSHARP_VERSION),\
   Cflags: -I${'\$${includedir}'} $(PC_CFLAGS),\
   Requires.private: $(PC_REQUIRES_PRIVATE),\
   Libs: -L${'\$${libdir}'} $(PC_LIB),\
   Libs.private: $(PC_LIBS_PRIVATE)
 
   ifeq ($(SYSTEM),MINGW32)
-  SHARED_EXT = dll
+  SHARED_EXT_CORE = dll
+  SHARED_EXT_CPP = dll
+  SHARED_EXT_CSHARP = dll
   SHARED_PREFIX =
-  SHARED_VERSION = -${settings.core_version.major}
+  SHARED_VERSION_CORE = -${settings.core_version.major}
+  SHARED_VERSION_CPP = -${settings.cpp_version.major}
+  SHARED_VERSION_CSHARP = -${settings.csharp_version.major}
   else ifeq ($(SYSTEM),Darwin)
-  SHARED_EXT = dylib
+  SHARED_EXT_CORE = dylib
+  SHARED_EXT_CPP = dylib
+  SHARED_EXT_CSHARP = dylib
   SHARED_PREFIX = lib
-  SHARED_VERSION =
+  SHARED_VERSION_CORE =
+  SHARED_VERSION_CPP =
+  SHARED_VERSION_CSHARP =
   else
-  SHARED_EXT = so.$(VERSION)
+  SHARED_EXT_CORE = so.$(CORE_VERSION)
+  SHARED_EXT_CPP = so.$(CPP_VERSION)
+  SHARED_EXT_CSHARP = so.$(CSHARP_VERSION)
   SHARED_PREFIX = lib
-  SHARED_VERSION =
+  SHARED_VERSION_CORE =
+  SHARED_VERSION_CPP =
+  SHARED_VERSION_CSHARP =
   endif
 
   ifeq ($(wildcard .git),)
@@ -603,7 +649,7 @@
   PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC) $(PC_REQUIRES_SECURE)
   PC_LIBS_PRIVATE = $(PC_LIBS_GRPC) $(PC_LIBS_SECURE)
   PC_LIB = -lgrpc
-  GRPC_PC_FILE := $(PC_TEMPLATE)
+  GRPC_PC_FILE := $(CORE_PC_TEMPLATE)
 
   # grpc_unsecure .pc file
   PC_NAME = gRPC unsecure
@@ -612,7 +658,7 @@
   PC_REQUIRES_PRIVATE = $(PC_REQUIRES_GRPC)
   PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
   PC_LIB = -lgrpc
-  GRPC_UNSECURE_PC_FILE := $(PC_TEMPLATE)
+  GRPC_UNSECURE_PC_FILE := $(CORE_PC_TEMPLATE)
 
   PROTOBUF_PKG_CONFIG = false
 
@@ -680,7 +726,7 @@
   PC_REQUIRES_PRIVATE = grpc $(PC_REQUIRES_GRPCXX)
   PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
   PC_LIB = -lgrpc++
-  GRPCXX_PC_FILE := $(PC_TEMPLATE)
+  GRPCXX_PC_FILE := $(CPP_PC_TEMPLATE)
 
   # grpc++_unsecure .pc file
   PC_NAME = gRPC++ unsecure
@@ -689,7 +735,7 @@
   PC_REQUIRES_PRIVATE = grpc_unsecure $(PC_REQUIRES_GRPCXX)
   PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
   PC_LIB = -lgrpc++
-  GRPCXX_UNSECURE_PC_FILE := $(PC_TEMPLATE)
+  GRPCXX_UNSECURE_PC_FILE := $(CPP_PC_TEMPLATE)
 
   ifeq ($(MAKECMDGOALS),clean)
   NO_DEPS = true
@@ -855,7 +901,7 @@
   % for lib in libs:
   % if 'Makefile' in lib.get('build_system', ['Makefile']):
   % if lib.build == 'all' and lib.language == 'c' and not lib.get('external_deps', None):
-   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)\
+   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)\
   % endif
   % endif
   % endfor
@@ -864,7 +910,7 @@
   % for lib in libs:
   % if 'Makefile' in lib.get('build_system', ['Makefile']):
   % if lib.build == 'all' and lib.language == 'c++':
-   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)\
+   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)\
   % endif
   % endif
   % endfor
@@ -874,7 +920,7 @@
   % for lib in libs:
   % if 'Makefile' in lib.get('build_system', ['Makefile']):
   % if lib.build == 'all' and lib.language == 'csharp':
-   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)\
+   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)\
   % endif
   % endif
   % endfor
@@ -1076,8 +1122,8 @@
   % if lib.language == "c":
   % if lib.build == "all":
   % if not lib.get('external_deps', None):
-  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
-  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
+  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
+  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
   % endif
   % endif
   % endif
@@ -1091,8 +1137,8 @@
   % if 'Makefile' in lib.get('build_system', ['Makefile']):
   % if lib.language == "c++":
   % if lib.build == "all":
-  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
-  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
+  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
+  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
   % endif
   % endif
   % endif
@@ -1105,8 +1151,8 @@
   % if 'Makefile' in lib.get('build_system', ['Makefile']):
   % if lib.language == "csharp":
   % if lib.build == "all":
-  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
-  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
+  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)"
+  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)
   % endif
   % endif
   % endif
@@ -1245,14 +1291,14 @@
   % if lib.language == lang_filter:
   % if lib.build == "all":
   % if not lib.get('external_deps', None):
-  	$(E) "[INSTALL] Installing $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
+  	$(E) "[INSTALL] Installing $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]})"
   	$(Q) $(INSTALL) -d $(prefix)/lib
-  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
+  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT_${lang_to_var[lib.language]})
   ifeq ($(SYSTEM),MINGW32)
   	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a
   else ifneq ($(SYSTEM),Darwin)
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.core_version.major}
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/lib${lib.name}.so.${settings.core_version.major}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/lib${lib.name}.so
   endif
   % endif
   % endif
@@ -1364,7 +1410,7 @@
   $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: openssl_dep_error
 
   % if lib.build == "all":
-  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
+  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}): openssl_dep_error
   % endif
 
   else
@@ -1377,7 +1423,7 @@
   $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: protobuf_dep_error
 
   % if lib.build == "all":
-  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
+  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}): protobuf_dep_error
   % endif
 
   else
@@ -1394,7 +1440,7 @@
   $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: protobuf_dep_error
 
   % if lib.build == "all":
-  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
+  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}): protobuf_dep_error
   % endif
 
   else
@@ -1440,12 +1486,12 @@
     else:
       ld = '$(LD)'
 
-    out_mingbase = '$(LIBDIR)/$(CONFIG)/' + lib.name + '$(SHARED_VERSION)'
-    out_libbase = '$(LIBDIR)/$(CONFIG)/lib' + lib.name + '$(SHARED_VERSION)'
+    out_mingbase = '$(LIBDIR)/$(CONFIG)/' + lib.name + '$(SHARED_VERSION_' + lang_to_var[lib.language] + ')'
+    out_libbase = '$(LIBDIR)/$(CONFIG)/lib' + lib.name + '$(SHARED_VERSION_' + lang_to_var[lib.language] + ')'
 
     common = '$(LIB' + lib.name.upper() + '_OBJS) $(LDLIBS)'
 
-    libs = ''
+    link_libs = ''
     lib_deps = ' $(ZLIB_DEP)'
     mingw_libs = ''
     mingw_lib_deps = ' $(ZLIB_DEP)'
@@ -1460,10 +1506,15 @@
         mingw_lib_deps = mingw_lib_deps + ' ' + lib_archive
     else:
       for dep in lib.get('deps', []):
-        libs = libs + ' -l' + dep
-        lib_deps = lib_deps + ' $(LIBDIR)/$(CONFIG)/lib' + dep + '.$(SHARED_EXT)'
+        dep_lib = None
+        for dl in libs:
+          if dl.name == dep:
+            dep_lib = dl
+        assert dep_lib, 'lib %s not found (in %s)' % (dep, lib.name)
+        link_libs = link_libs + ' -l' + dep
+        lib_deps = lib_deps + ' $(LIBDIR)/$(CONFIG)/lib' + dep + '.$(SHARED_EXT_' + lang_to_var[dep_lib.language] + ')'
         mingw_libs = mingw_libs + ' -l' + dep + '-imp'
-        mingw_lib_deps = mingw_lib_deps + ' $(LIBDIR)/$(CONFIG)/' + dep + '.$(SHARED_EXT)'
+        mingw_lib_deps = mingw_lib_deps + ' $(LIBDIR)/$(CONFIG)/' + dep + '.$(SHARED_EXT_' + lang_to_var[dep_lib.language] + ')'
 
     security = lib.get('secure', 'check')
     if security == True:
@@ -1492,20 +1543,20 @@
 
   % if lib.build == "all":
   ifeq ($(SYSTEM),MINGW32)
-  ${out_mingbase}.$(SHARED_EXT): $(LIB${lib.name.upper()}_OBJS) ${mingw_lib_deps}
+  ${out_mingbase}.$(SHARED_EXT_${lang_to_var[lib.language]}): $(LIB${lib.name.upper()}_OBJS) ${mingw_lib_deps}
   	$(E) "[LD]      Linking $@"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared ${lib.name}.def -Wl,--output-def=${out_mingbase}.def -Wl,--out-implib=${out_libbase}-dll.a -o ${out_mingbase}.$(SHARED_EXT) ${common}${mingw_libs}
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared ${lib.name}.def -Wl,--output-def=${out_mingbase}.def -Wl,--out-implib=${out_libbase}-dll.a -o ${out_mingbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${mingw_libs}
   else
-  ${out_libbase}.$(SHARED_EXT): $(LIB${lib.name.upper()}_OBJS) ${lib_deps}
+  ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}): $(LIB${lib.name.upper()}_OBJS) ${lib_deps}
   	$(E) "[LD]      Linking $@"
   	$(Q) mkdir -p `dirname $@`
   ifeq ($(SYSTEM),Darwin)
-  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT_${lang_to_var[lib.language]}) -dynamiclib -o ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${link_libs}
   else
-  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.core_version.major} -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) ${out_libbase}.so.${settings.core_version.major}
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) ${out_libbase}.so
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.core_version.major} -o ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${link_libs}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT_${lang_to_var[lib.language]}) ${out_libbase}.so.${settings.get(lang_to_var[lib.language].lower() + '_version').major}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT_${lang_to_var[lib.language]}) ${out_libbase}.so
   endif
   endif
   % endif
diff --git a/templates/src/cpp/common/version_cc.cc.template b/templates/src/cpp/common/version_cc.cc.template
new file mode 100644
index 0000000000000000000000000000000000000000..d14e974f5673180beb077f2b969aaa8ba421b1a3
--- /dev/null
+++ b/templates/src/cpp/common/version_cc.cc.template
@@ -0,0 +1,43 @@
+%YAML 1.2
+--- |
+  /*
+   *
+   * Copyright 2016, Google Inc.
+   * All rights reserved.
+   *
+   * 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.
+   *     * Neither the name of Google Inc. nor the names of its
+   * contributors may be used to endorse or promote products derived from
+   * this software without specific prior written permission.
+   *
+   * 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.
+   *
+   */
+
+  /* This file is autogenerated from:
+     templates/src/core/surface/version.c.template */
+
+  #include <grpc++/grpc++.h>
+
+  namespace grpc {
+  grpc::string Version() { return "${settings.cpp_version}"; }
+  }
diff --git a/test/core/end2end/end2end_test_utils.c b/test/core/end2end/end2end_test_utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..46fb4ec1aff7917c80979fa4b01fe8f05d6e118b
--- /dev/null
+++ b/test/core/end2end/end2end_test_utils.c
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+
+const char *get_host_override_string(const char *str,
+                                     grpc_end2end_test_config config) {
+  return (config.feature_mask & FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER ? str
+                                                                       : NULL);
+}
+
+void validate_host_override_string(const char *pattern, const char *str,
+                                   grpc_end2end_test_config config) {
+  if (config.feature_mask & FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER) {
+    GPR_ASSERT(0 == strcmp(str, pattern));
+  }
+}
diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h
index b56b595cc5170da10470987bd146fb710caad210..f25e90b5f61e8c4992cf157c869a680e1d4cdf07 100644
--- a/test/core/end2end/end2end_tests.h
+++ b/test/core/end2end/end2end_tests.h
@@ -44,6 +44,7 @@ typedef struct grpc_end2end_test_config grpc_end2end_test_config;
 #define FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS 4
 #define FEATURE_MASK_SUPPORTS_REQUEST_PROXYING 8
 #define FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL 16
+#define FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER 32
 
 #define FAIL_AUTH_CHECK_SERVER_ARG_NAME "fail_auth_check"
 
@@ -69,4 +70,10 @@ struct grpc_end2end_test_config {
 void grpc_end2end_tests_pre_init(void);
 void grpc_end2end_tests(int argc, char **argv, grpc_end2end_test_config config);
 
+const char *get_host_override_string(const char *str,
+                                     grpc_end2end_test_config config);
+
+void validate_host_override_string(const char *pattern, const char *str,
+                                   grpc_end2end_test_config config);
+
 #endif /* GRPC_TEST_CORE_END2END_END2END_TESTS_H */
diff --git a/test/core/end2end/fixtures/h2_census.c b/test/core/end2end/fixtures/h2_census.c
index c8d1a90a9744372e43090efe95c9fa2e1ff31f8b..c52d7660f59850776dc54b390aede107b1c76d9d 100644
--- a/test/core/end2end/fixtures/h2_census.c
+++ b/test/core/end2end/fixtures/h2_census.c
@@ -112,7 +112,8 @@ void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack+census", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-                                    FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+                                    FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                                    FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
      chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
 };
diff --git a/test/core/end2end/fixtures/h2_compress.c b/test/core/end2end/fixtures/h2_compress.c
index b4a2b0ddd52d9749db2dae1e46786aa066690d2d..fedd2ebc467d2bcaf04c0b33efde67a9ca7014a6 100644
--- a/test/core/end2end/fixtures/h2_compress.c
+++ b/test/core/end2end/fixtures/h2_compress.c
@@ -114,7 +114,8 @@ void chttp2_tear_down_fullstack_compression(grpc_end2end_test_fixture *f) {
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack_compression", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-                                         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+                                         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                                         FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_fullstack_compression,
      chttp2_init_client_fullstack_compression,
      chttp2_init_server_fullstack_compression,
diff --git a/test/core/end2end/fixtures/h2_fakesec.c b/test/core/end2end/fixtures/h2_fakesec.c
index 9a8739a1dec2c77510964cd613bbc004e5ee36a3..c9747913c2f4ea0e65aa18ef150f8034c747339e 100644
--- a/test/core/end2end/fixtures/h2_fakesec.c
+++ b/test/core/end2end/fixtures/h2_fakesec.c
@@ -141,7 +141,8 @@ static grpc_end2end_test_config configs[] = {
     {"chttp2/fake_secure_fullstack",
      FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
          FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
-         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+         FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_secure_fullstack,
      chttp2_init_client_fake_secure_fullstack,
      chttp2_init_server_fake_secure_fullstack,
diff --git a/test/core/end2end/fixtures/h2_fd.c b/test/core/end2end/fixtures/h2_fd.c
index e9fd6668ed0cbaf7fa36a32cac327fd0c1259563..223fadc386dbfc0568370cab0a0fdf0ae7439952 100644
--- a/test/core/end2end/fixtures/h2_fd.c
+++ b/test/core/end2end/fixtures/h2_fd.c
@@ -111,9 +111,9 @@ static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
 
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
-    {"chttp2/fd", 0, chttp2_create_fixture_socketpair,
-     chttp2_init_client_socketpair, chttp2_init_server_socketpair,
-     chttp2_tear_down_socketpair},
+    {"chttp2/fd", FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
+     chttp2_create_fixture_socketpair, chttp2_init_client_socketpair,
+     chttp2_init_server_socketpair, chttp2_tear_down_socketpair},
 };
 
 int main(int argc, char **argv) {
diff --git a/test/core/end2end/fixtures/h2_full+pipe.c b/test/core/end2end/fixtures/h2_full+pipe.c
index 74ed021ce8ca81544789973fae894159b2e32b95..c6013f3040048eac4c2a389d75bc3c08a7c8e3ac 100644
--- a/test/core/end2end/fixtures/h2_full+pipe.c
+++ b/test/core/end2end/fixtures/h2_full+pipe.c
@@ -103,7 +103,8 @@ void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                             FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
      chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
 };
diff --git a/test/core/end2end/fixtures/h2_full+trace.c b/test/core/end2end/fixtures/h2_full+trace.c
index b2fd490df285816c3a98b46476df042aea1c3df2..11a102a5765028fb9baadf32ac7a9608bf6ea52d 100644
--- a/test/core/end2end/fixtures/h2_full+trace.c
+++ b/test/core/end2end/fixtures/h2_full+trace.c
@@ -103,7 +103,8 @@ void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                             FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
      chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
 };
diff --git a/test/core/end2end/fixtures/h2_full.c b/test/core/end2end/fixtures/h2_full.c
index e87382edae0d7242c38e4c5b9c7495117322c8a1..3399f1981e44600105779a5d36cb374dc1d9d068 100644
--- a/test/core/end2end/fixtures/h2_full.c
+++ b/test/core/end2end/fixtures/h2_full.c
@@ -97,7 +97,8 @@ void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                             FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
      chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
 };
diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c
index f0720c4f51294025a6d909c5dcf81cf6f3409549..44b223664ab42be3449f09b5d95db566a7db0c0e 100644
--- a/test/core/end2end/fixtures/h2_http_proxy.c
+++ b/test/core/end2end/fixtures/h2_http_proxy.c
@@ -108,7 +108,8 @@ void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                             FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
      chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
 };
diff --git a/test/core/end2end/fixtures/h2_load_reporting.c b/test/core/end2end/fixtures/h2_load_reporting.c
index 3b3a1449bc3c01837d28d771854ad6bf8530761e..7a76489b440a8903740582c53fc971dcf87cce91 100644
--- a/test/core/end2end/fixtures/h2_load_reporting.c
+++ b/test/core/end2end/fixtures/h2_load_reporting.c
@@ -104,7 +104,8 @@ void chttp2_tear_down_load_reporting(grpc_end2end_test_fixture *f) {
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack+load_reporting",
      FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+         FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_load_reporting, chttp2_init_client_load_reporting,
      chttp2_init_server_load_reporting, chttp2_tear_down_load_reporting},
 };
diff --git a/test/core/end2end/fixtures/h2_oauth2.c b/test/core/end2end/fixtures/h2_oauth2.c
index eca866f93b111a7e532563fe085c4f2f063b6df4..6122f4f2f93c4e51806a48fc61f60b4ed869812a 100644
--- a/test/core/end2end/fixtures/h2_oauth2.c
+++ b/test/core/end2end/fixtures/h2_oauth2.c
@@ -217,7 +217,8 @@ static grpc_end2end_test_config configs[] = {
     {"chttp2/simple_ssl_with_oauth2_fullstack",
      FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
          FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
-         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+         FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_secure_fullstack,
      chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack,
      chttp2_init_server_simple_ssl_secure_fullstack,
diff --git a/test/core/end2end/fixtures/h2_proxy.c b/test/core/end2end/fixtures/h2_proxy.c
index 65469b73c58f813d4e2663976086d3caeb32569d..9e37ed4db34382bb891cd57b31779dcbc6e1225f 100644
--- a/test/core/end2end/fixtures/h2_proxy.c
+++ b/test/core/end2end/fixtures/h2_proxy.c
@@ -115,7 +115,8 @@ void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack+proxy", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
                                    FEATURE_MASK_SUPPORTS_REQUEST_PROXYING |
-                                   FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+                                   FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                                   FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
      chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
 };
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c
index 164828cb57d397ceda53ab7ec96e59706d31bb7d..726ed8735c6e08eb3ea3660e0e6d0b0d478a2f4b 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -141,9 +141,9 @@ static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
 
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
-    {"chttp2/socketpair", 0, chttp2_create_fixture_socketpair,
-     chttp2_init_client_socketpair, chttp2_init_server_socketpair,
-     chttp2_tear_down_socketpair},
+    {"chttp2/socketpair", FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
+     chttp2_create_fixture_socketpair, chttp2_init_client_socketpair,
+     chttp2_init_server_socketpair, chttp2_tear_down_socketpair},
 };
 
 int main(int argc, char **argv) {
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index 182583ce05b5505f6a0c0560c6b9a79757dba3ae..94b2623b3ea00b179b597fcebf3e643bec71327e 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -135,9 +135,9 @@ static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
 
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
-    {"chttp2/socketpair", 0, chttp2_create_fixture_socketpair,
-     chttp2_init_client_socketpair, chttp2_init_server_socketpair,
-     chttp2_tear_down_socketpair},
+    {"chttp2/socketpair", FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
+     chttp2_create_fixture_socketpair, chttp2_init_client_socketpair,
+     chttp2_init_server_socketpair, chttp2_tear_down_socketpair},
 };
 
 int main(int argc, char **argv) {
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 218d5f2cb4765e0ef6a7d047f4e3602fea4f1bb5..0a45f76395378b2dbeceafacf5026b6b3db3cbe2 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -135,9 +135,10 @@ static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
 
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
-    {"chttp2/socketpair_one_byte_at_a_time", 0,
-     chttp2_create_fixture_socketpair, chttp2_init_client_socketpair,
-     chttp2_init_server_socketpair, chttp2_tear_down_socketpair},
+    {"chttp2/socketpair_one_byte_at_a_time",
+     FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER, chttp2_create_fixture_socketpair,
+     chttp2_init_client_socketpair, chttp2_init_server_socketpair,
+     chttp2_tear_down_socketpair},
 };
 
 int main(int argc, char **argv) {
diff --git a/test/core/end2end/fixtures/h2_ssl.c b/test/core/end2end/fixtures/h2_ssl.c
index 23b6f9f73a1aa9e89dd8de34bc91f434afde864e..bbd522cf309719b4f8a38c886c0aceb4b61785bb 100644
--- a/test/core/end2end/fixtures/h2_ssl.c
+++ b/test/core/end2end/fixtures/h2_ssl.c
@@ -152,7 +152,8 @@ static grpc_end2end_test_config configs[] = {
     {"chttp2/simple_ssl_fullstack",
      FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
          FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
-         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+         FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_secure_fullstack,
      chttp2_init_client_simple_ssl_secure_fullstack,
      chttp2_init_server_simple_ssl_secure_fullstack,
diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.c b/test/core/end2end/fixtures/h2_ssl_proxy.c
index a7490d13ec62547b44e5214054153d18e12268bb..27cf3ebf326e326c9fd904c22bb23952d20c1649 100644
--- a/test/core/end2end/fixtures/h2_ssl_proxy.c
+++ b/test/core/end2end/fixtures/h2_ssl_proxy.c
@@ -186,7 +186,8 @@ static grpc_end2end_test_config configs[] = {
      FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
          FEATURE_MASK_SUPPORTS_REQUEST_PROXYING |
          FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
-         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+         FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_secure_fullstack,
      chttp2_init_client_simple_ssl_secure_fullstack,
      chttp2_init_server_simple_ssl_secure_fullstack,
diff --git a/test/core/end2end/fixtures/h2_uds.c b/test/core/end2end/fixtures/h2_uds.c
index 0a17ff5860a2c708dc38b094530ce18ac9c6754a..bc973ea8e3c9da818d59f8611e4660d6a8244280 100644
--- a/test/core/end2end/fixtures/h2_uds.c
+++ b/test/core/end2end/fixtures/h2_uds.c
@@ -102,7 +102,8 @@ void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
 /* All test configurations */
 static grpc_end2end_test_config configs[] = {
     {"chttp2/fullstack_uds", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-                                 FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL,
+                                 FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                                 FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
      chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
      chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
 };
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 7f33e07a003284c0ef803ccf4410fca05ffc1b7a..26eee934398c6a9077d1b0242adea20c2a4b6870 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -190,7 +190,8 @@ def main():
               'build': 'private',
               'language': 'c',
               'secure': True,
-              'src': ['test/core/end2end/end2end_tests.c'] + [
+              'src': ['test/core/end2end/end2end_tests.c',
+                      'test/core/end2end/end2end_test_utils.c'] + [
                   'test/core/end2end/tests/%s.c' % t
                   for t in sorted(END2END_TESTS.keys())],
               'headers': ['test/core/end2end/tests/cancel_test_helpers.h',
@@ -204,7 +205,8 @@ def main():
               'build': 'private',
               'language': 'c',
               'secure': False,
-              'src': ['test/core/end2end/end2end_nosec_tests.c'] + [
+              'src': ['test/core/end2end/end2end_nosec_tests.c',
+                      'test/core/end2end/end2end_test_utils.c'] + [
                   'test/core/end2end/tests/%s.c' % t
                   for t in sorted(END2END_TESTS.keys())
                   if not END2END_TESTS[t].secure],
diff --git a/test/core/end2end/tests/binary_metadata.c b/test/core/end2end/tests/binary_metadata.c
index 6b105def33c2325c284ea3841e271e036f5908f8..f1ebbbb66f447e2efbdf8afd8c8d4c6457d7af57 100644
--- a/test/core/end2end/tests/binary_metadata.c
+++ b/test/core/end2end/tests/binary_metadata.c
@@ -146,8 +146,10 @@ static void test_request_response_with_metadata_and_payload(
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -248,7 +250,8 @@ static void test_request_response_with_metadata_and_payload(
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 0);
   GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world"));
   GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, "hello you"));
diff --git a/test/core/end2end/tests/call_creds.c b/test/core/end2end/tests/call_creds.c
index 981c0fcc8c5a13d535ef0e56b2909bda6bd992c9..8bde79c40012d2e49bed1f7241bef2faf25fce9c 100644
--- a/test/core/end2end/tests/call_creds.c
+++ b/test/core/end2end/tests/call_creds.c
@@ -164,8 +164,10 @@ static void request_response_with_payload_and_call_creds(
   f = begin_test(config, test_name, 0);
   cqv = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
   creds = grpc_google_iam_credentials_create(iam_token, iam_selector, NULL);
   GPR_ASSERT(creds != NULL);
@@ -294,7 +296,8 @@ static void request_response_with_payload_and_call_creds(
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 0);
   GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world"));
   GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, "hello you"));
@@ -397,8 +400,10 @@ static void test_request_with_server_rejecting_client_creds(
   f = begin_test(config, "test_request_with_server_rejecting_client_creds", 1);
   cqv = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   creds = grpc_google_iam_credentials_create(iam_token, iam_selector, NULL);
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index 768416a108c87c513a75fb1b2e388725a50decf3..fd03432ff54d05f7d87e5e926c415c9f098655a1 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -151,9 +151,10 @@ static void test_cancel_after_accept(grpc_end2end_test_config config,
       begin_test(config, "cancel_after_accept", args, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/service/method", "foo.test.google.fr",
-                               deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/service/method",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/cancel_after_client_done.c b/test/core/end2end/tests/cancel_after_client_done.c
index 5adc71e255208e7dd9852ce692dfa212386a6bbf..26de66eba797b4a23d93011eb1d0f784071467e8 100644
--- a/test/core/end2end/tests/cancel_after_client_done.c
+++ b/test/core/end2end/tests/cancel_after_client_done.c
@@ -125,8 +125,10 @@ static void test_cancel_after_accept_and_writes_closed(
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
index 85d8799f36db59557e3b2343a805ab21a8cebfba..afbfb02a39e81d7c81b7f9b0084930dffdd57fb5 100644
--- a/test/core/end2end/tests/cancel_after_invoke.c
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -120,8 +120,10 @@ static void test_cancel_after_invoke(grpc_end2end_test_config config,
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c
index c57091476e4a4fd2f229594a1a20d0541390e005..d0eeed8ab88152f83e9637cc671fe429b46d3847 100644
--- a/test/core/end2end/tests/cancel_before_invoke.c
+++ b/test/core/end2end/tests/cancel_before_invoke.c
@@ -118,8 +118,10 @@ static void test_cancel_before_invoke(grpc_end2end_test_config config,
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_cancel(c, NULL));
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c
index 3b03616b3bbe1f9a012d2f2109cb5870039e509f..5be850b6ea9b3842c095ab480cbee7c053c54675 100644
--- a/test/core/end2end/tests/cancel_in_a_vacuum.c
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.c
@@ -105,8 +105,10 @@ static void test_cancel_in_a_vacuum(grpc_end2end_test_config config,
   gpr_timespec deadline = five_seconds_time();
   cq_verifier *v_client = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, NULL));
diff --git a/test/core/end2end/tests/cancel_with_status.c b/test/core/end2end/tests/cancel_with_status.c
index e65390ac4a5a729c0c031dcb1221f449d1c03b54..3aecaf71598b47c4c3a941ebe64c57d44946c4fb 100644
--- a/test/core/end2end/tests/cancel_with_status.c
+++ b/test/core/end2end/tests/cancel_with_status.c
@@ -97,7 +97,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f, size_t num_ops) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f, size_t num_ops) {
   grpc_call *c;
   gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -112,9 +113,10 @@ static void simple_request_body(grpc_end2end_test_fixture f, size_t num_ops) {
 
   gpr_log(GPR_DEBUG, "test with %" PRIuPTR " ops", num_ops);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -170,7 +172,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config,
   grpc_end2end_test_fixture f;
 
   f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
-  simple_request_body(f, num_ops);
+  simple_request_body(config, f, num_ops);
   end_test(&f);
   config.tear_down_data(&f);
 }
diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c
index 1724da4d0cfdbffbfd99ee9e75d6388f061d895b..166e8efe3788bbc02b8e0e665b5635d9ed39eff2 100644
--- a/test/core/end2end/tests/compressed_payload.c
+++ b/test/core/end2end/tests/compressed_payload.c
@@ -146,8 +146,10 @@ static void request_for_disabled_algorithm(
   f = begin_test(config, test_name, client_args, server_args);
   cqv = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -242,7 +244,8 @@ static void request_for_disabled_algorithm(
   GPR_ASSERT(0 == strcmp(details, expected_details));
   gpr_free(expected_details);
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
@@ -318,8 +321,10 @@ static void request_with_payload_template(
   f = begin_test(config, test_name, client_args, server_args);
   cqv = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -491,7 +496,8 @@ static void request_with_payload_template(
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 0);
 
   gpr_free(details);
diff --git a/test/core/end2end/tests/disappearing_server.c b/test/core/end2end/tests/disappearing_server.c
index a0059b9ad59700bf3bb2e06dee6706b1597570d5..8ebf7e643e025c699276c6b74d03cd3298f417f9 100644
--- a/test/core/end2end/tests/disappearing_server.c
+++ b/test/core/end2end/tests/disappearing_server.c
@@ -79,7 +79,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void do_request_and_shutdown_server(grpc_end2end_test_fixture *f,
+static void do_request_and_shutdown_server(grpc_end2end_test_config config,
+                                           grpc_end2end_test_fixture *f,
                                            cq_verifier *cqv) {
   grpc_call *c;
   grpc_call *s;
@@ -96,9 +97,10 @@ static void do_request_and_shutdown_server(grpc_end2end_test_fixture *f,
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -174,7 +176,8 @@ static void do_request_and_shutdown_server(grpc_end2end_test_fixture *f,
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
@@ -196,12 +199,12 @@ static void disappearing_server_test(grpc_end2end_test_config config) {
   config.init_client(&f, NULL);
   config.init_server(&f, NULL);
 
-  do_request_and_shutdown_server(&f, cqv);
+  do_request_and_shutdown_server(config, &f, cqv);
 
   /* now destroy and recreate the server */
   config.init_server(&f, NULL);
 
-  do_request_and_shutdown_server(&f, cqv);
+  do_request_and_shutdown_server(config, &f, cqv);
 
   cq_verifier_destroy(cqv);
 
diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c
index ac53e1839be4274bf9c3e65b21337567b75e3a3e..dc8e52a60f0e7543d0980a29a0ec46026884b8b2 100644
--- a/test/core/end2end/tests/empty_batch.c
+++ b/test/core/end2end/tests/empty_batch.c
@@ -97,15 +97,18 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void empty_batch_body(grpc_end2end_test_fixture f) {
+static void empty_batch_body(grpc_end2end_test_config config,
+                             grpc_end2end_test_fixture f) {
   grpc_call *c;
   gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_call_error error;
   grpc_op *op = NULL;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   error = grpc_call_start_batch(c, op, 0, tag(1), NULL);
@@ -122,7 +125,7 @@ static void test_invoke_empty_body(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f;
 
   f = begin_test(config, "test_invoke_empty_body", NULL, NULL);
-  empty_batch_body(f);
+  empty_batch_body(config, f);
   end_test(&f);
   config.tear_down_data(&f);
 }
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index a70f50af988674bec50998185f294faa430705cd..84d95b20b8a04db7ffd5c65021d895dff6233fc7 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -127,8 +127,10 @@ static void test_request(grpc_end2end_test_config config) {
   char *details = NULL;
   size_t details_capacity = 0;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index f14bb323f27bd5b892f61531b72f79b2e368f948..51e56d74a3430f5db41deddc5535012e7078282e 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -123,8 +123,10 @@ static void test_request(grpc_end2end_test_config config) {
   char *details = NULL;
   size_t details_capacity = 0;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/graceful_server_shutdown.c b/test/core/end2end/tests/graceful_server_shutdown.c
index 29347a068ae1888d0dd171bf6b8e999db6d25b47..5fecadbe441c0ddaf16b28db0a2f5e48cac16a5e 100644
--- a/test/core/end2end/tests/graceful_server_shutdown.c
+++ b/test/core/end2end/tests/graceful_server_shutdown.c
@@ -111,8 +111,10 @@ static void test_early_server_shutdown_finishes_inflight_calls(
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -190,7 +192,8 @@ static void test_early_server_shutdown_finishes_inflight_calls(
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
diff --git a/test/core/end2end/tests/high_initial_seqno.c b/test/core/end2end/tests/high_initial_seqno.c
index dab527005cfcb329802d36b444abb41e79fa9d8d..01a4909ccdb3a67fa6d2f3551e25ec4b629aa7b9 100644
--- a/test/core/end2end/tests/high_initial_seqno.c
+++ b/test/core/end2end/tests/high_initial_seqno.c
@@ -99,7 +99,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -116,9 +117,10 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -189,7 +191,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
@@ -229,7 +232,7 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config,
                initial_sequence_number);
   f = begin_test(config, name, &client_args, NULL);
   for (i = 0; i < 10; i++) {
-    simple_request_body(f);
+    simple_request_body(config, f);
     gpr_log(GPR_INFO, "Passed simple request %d", i);
   }
   end_test(&f);
diff --git a/test/core/end2end/tests/hpack_size.c b/test/core/end2end/tests/hpack_size.c
index fb00ae4eaaa9252b224e75bd9c59752ce5a35a94..cec8b2faae1b6131a2020d4d4703d3e1c2fcc44d 100644
--- a/test/core/end2end/tests/hpack_size.c
+++ b/test/core/end2end/tests/hpack_size.c
@@ -239,7 +239,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f, size_t index) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f, size_t index) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -268,9 +269,10 @@ static void simple_request_body(grpc_end2end_test_fixture f, size_t index) {
   extra_metadata[2].value = dragons[index % GPR_ARRAY_SIZE(dragons)];
   extra_metadata[2].value_length = strlen(extra_metadata[2].value);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -342,7 +344,8 @@ static void simple_request_body(grpc_end2end_test_fixture f, size_t index) {
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
@@ -383,7 +386,7 @@ static void test_size(grpc_end2end_test_config config, int encode_size,
   f = begin_test(config, name, encode_size != 4096 ? &client_args : NULL,
                  decode_size != 4096 ? &server_args : NULL);
   for (i = 0; i < 4 * GPR_ARRAY_SIZE(hobbits); i++) {
-    simple_request_body(f, i);
+    simple_request_body(config, f, i);
   }
   end_test(&f);
   config.tear_down_data(&f);
diff --git a/test/core/end2end/tests/idempotent_request.c b/test/core/end2end/tests/idempotent_request.c
index 65f6dd08c5a7b6cbf2471ece078e14979e205ada..4f6d3bb808c11a38b42cd38d41006c746e72544a 100644
--- a/test/core/end2end/tests/idempotent_request.c
+++ b/test/core/end2end/tests/idempotent_request.c
@@ -97,7 +97,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -115,9 +116,10 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   int was_cancelled = 2;
   char *peer;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   peer = grpc_call_get_peer(c);
@@ -202,7 +204,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST == call_details.flags);
   GPR_ASSERT(was_cancelled == 1);
 
@@ -222,7 +225,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f;
 
   f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
-  simple_request_body(f);
+  simple_request_body(config, f);
   end_test(&f);
   config.tear_down_data(&f);
 }
@@ -232,7 +235,7 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_10_simple_requests", NULL, NULL);
   for (i = 0; i < 10; i++) {
-    simple_request_body(f);
+    simple_request_body(config, f);
     gpr_log(GPR_INFO, "Passed simple request %d", i);
   }
   end_test(&f);
diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c
index 1df237cb6c4e64aec4b4583bfbf12cd969f32e83..edb655fea5b6aed9552cbcf227aa0db5b4276ef8 100644
--- a/test/core/end2end/tests/invoke_large_request.c
+++ b/test/core/end2end/tests/invoke_large_request.c
@@ -144,8 +144,10 @@ static void test_invoke_large_request(grpc_end2end_test_config config,
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -244,7 +246,8 @@ static void test_invoke_large_request(grpc_end2end_test_config config,
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
diff --git a/test/core/end2end/tests/large_metadata.c b/test/core/end2end/tests/large_metadata.c
index eb174a2dbb7e80132b1c76ed9a0658d9ba7b5ba3..499c56413ba7f578757380ca58b4e6912bcf197e 100644
--- a/test/core/end2end/tests/large_metadata.c
+++ b/test/core/end2end/tests/large_metadata.c
@@ -125,8 +125,10 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config) {
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   meta.key = "key";
@@ -227,7 +229,8 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config) {
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 0);
   GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world"));
   GPR_ASSERT(contains_metadata(&request_metadata_recv, "key", meta.value));
diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c
index 7f95dfd949b721752da931f8dcd4ca41eeace719..ca4e2709a92e88abd3d8fb6125076fb172d5d9b0 100644
--- a/test/core/end2end/tests/load_reporting_hook.c
+++ b/test/core/end2end/tests/load_reporting_hook.c
@@ -121,12 +121,10 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void request_response_with_payload(grpc_end2end_test_fixture f,
-                                          const char *method_name,
-                                          const char *request_msg,
-                                          const char *response_msg,
-                                          grpc_metadata *initial_lr_metadata,
-                                          grpc_metadata *trailing_lr_metadata) {
+static void request_response_with_payload(
+    grpc_end2end_test_config config, grpc_end2end_test_fixture f,
+    const char *method_name, const char *request_msg, const char *response_msg,
+    grpc_metadata *initial_lr_metadata, grpc_metadata *trailing_lr_metadata) {
   gpr_slice request_payload_slice = gpr_slice_from_static_string(request_msg);
   gpr_slice response_payload_slice = gpr_slice_from_static_string(response_msg);
   grpc_call *c;
@@ -151,9 +149,10 @@ static void request_response_with_payload(grpc_end2end_test_fixture f,
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               method_name, "foo.test.google.fr", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, method_name,
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -307,8 +306,9 @@ static void test_load_reporting_hook(grpc_end2end_test_config config) {
   memset(&trailing_lr_metadata.internal_data, 0,
          sizeof(trailing_lr_metadata.internal_data));
 
-  request_response_with_payload(f, method_name, request_msg, response_msg,
-                                &initial_lr_metadata, &trailing_lr_metadata);
+  request_response_with_payload(config, f, method_name, request_msg,
+                                response_msg, &initial_lr_metadata,
+                                &trailing_lr_metadata);
   end_test(&f);
   grpc_channel_args_destroy(lr_server_args);
   config.tear_down_data(&f);
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
index 65fa94683870a57c9fedeb15d92dd6ba9269be67..9338bc5f0d76824ad21ad2ee407d9c8ff39427da 100644
--- a/test/core/end2end/tests/max_concurrent_streams.c
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -95,7 +95,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -112,9 +113,10 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -185,7 +187,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
@@ -250,20 +253,22 @@ static void test_max_concurrent_streams(grpc_end2end_test_config config) {
 
   /* perform a ping-pong to ensure that settings have had a chance to round
      trip */
-  simple_request_body(f);
+  simple_request_body(config, f);
   /* perform another one to make sure that the one stream case still works */
-  simple_request_body(f);
+  simple_request_body(config, f);
 
   /* start two requests - ensuring that the second is not accepted until
      the first completes */
   deadline = n_seconds_time(1000);
-  c1 = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                                "/alpha", "foo.test.google.fr:1234", deadline,
-                                NULL);
+  c1 = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/alpha",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c1);
-  c2 = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                                "/beta", "foo.test.google.fr:1234", deadline,
-                                NULL);
+  c2 = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/beta",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c2);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index 3a927ddcbc6be512d603abaede5be9c0fb5a98bd..b416627bfd7c3f568880ec9c22676c8c847a1e3d 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -172,9 +172,10 @@ static void test_max_message_length_on_request(grpc_end2end_test_config config,
 
   cqv = cq_verifier_create(f.cq);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/service/method", "foo.test.google.fr:1234",
-                               gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/service/method",
+      get_host_override_string("foo.test.google.fr:1234", config),
+      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -247,7 +248,8 @@ static void test_max_message_length_on_request(grpc_end2end_test_config config,
   cq_verify(cqv);
 
   GPR_ASSERT(0 == strcmp(call_details.method, "/service/method"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
 done:
diff --git a/test/core/end2end/tests/negative_deadline.c b/test/core/end2end/tests/negative_deadline.c
index c999ac116aa4b499ec68f50fbe16535dcc4af845..929777d39ef92ea9943fd45cda79fb9eb5f94b04 100644
--- a/test/core/end2end/tests/negative_deadline.c
+++ b/test/core/end2end/tests/negative_deadline.c
@@ -97,7 +97,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f, size_t num_ops) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f, size_t num_ops) {
   grpc_call *c;
   gpr_timespec deadline = gpr_inf_past(GPR_CLOCK_REALTIME);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -112,9 +113,10 @@ static void simple_request_body(grpc_end2end_test_fixture f, size_t num_ops) {
 
   gpr_log(GPR_DEBUG, "test with %" PRIuPTR " ops", num_ops);
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -167,7 +169,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config,
   grpc_end2end_test_fixture f;
 
   f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
-  simple_request_body(f, num_ops);
+  simple_request_body(config, f, num_ops);
   end_test(&f);
   config.tear_down_data(&f);
 }
diff --git a/test/core/end2end/tests/network_status_change.c b/test/core/end2end/tests/network_status_change.c
index fe9c45f273d08b1719c90dff7a1894dafd773d47..96e909e4635be3c94b244fab37ed9b79342c18c2 100644
--- a/test/core/end2end/tests/network_status_change.c
+++ b/test/core/end2end/tests/network_status_change.c
@@ -122,8 +122,10 @@ static void test_invoke_network_status_change(grpc_end2end_test_config config) {
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -212,7 +214,8 @@ static void test_invoke_network_status_change(grpc_end2end_test_config config) {
   // Expected behavior of a RPC when network is lost.
   GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/no_logging.c b/test/core/end2end/tests/no_logging.c
index 1d3cfda6e504db20c7fd16e20a8b4ad46718c14f..54614cb029152a2202daffc7c01cd264aef1945c 100644
--- a/test/core/end2end/tests/no_logging.c
+++ b/test/core/end2end/tests/no_logging.c
@@ -125,7 +125,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -143,9 +144,10 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   int was_cancelled = 2;
   char *peer;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   peer = grpc_call_get_peer(c);
@@ -227,7 +229,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(0 == call_details.flags);
   GPR_ASSERT(was_cancelled == 1);
 
@@ -248,7 +251,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) {
 
   f = begin_test(config, "test_invoke_simple_request_with_no_error_logging",
                  NULL, NULL);
-  simple_request_body(f);
+  simple_request_body(config, f);
   end_test(&f);
   config.tear_down_data(&f);
 }
@@ -259,10 +262,10 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
       begin_test(config, "test_invoke_10_simple_requests_with_no_error_logging",
                  NULL, NULL);
   for (i = 0; i < 10; i++) {
-    simple_request_body(f);
+    simple_request_body(config, f);
     gpr_log(GPR_INFO, "Passed simple request %d", i);
   }
-  simple_request_body(f);
+  simple_request_body(config, f);
   end_test(&f);
   config.tear_down_data(&f);
 }
@@ -283,10 +286,10 @@ static void test_no_logging_in_one_request(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f =
       begin_test(config, "test_no_logging_in_last_request", NULL, NULL);
   for (i = 0; i < 10; i++) {
-    simple_request_body(f);
+    simple_request_body(config, f);
   }
   gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)test_no_log);
-  simple_request_body(f);
+  simple_request_body(config, f);
   gpr_atm_no_barrier_store(&g_log_func, (gpr_atm)gpr_default_log);
   end_test(&f);
   config.tear_down_data(&f);
diff --git a/test/core/end2end/tests/payload.c b/test/core/end2end/tests/payload.c
index 40696d088f106605498f2d46b99e4dcbc47bca31..17cea48f03783c02ee59c6c687d340d504f6678f 100644
--- a/test/core/end2end/tests/payload.c
+++ b/test/core/end2end/tests/payload.c
@@ -111,7 +111,8 @@ static gpr_slice generate_random_slice() {
   return out;
 }
 
-static void request_response_with_payload(grpc_end2end_test_fixture f) {
+static void request_response_with_payload(grpc_end2end_test_config config,
+                                          grpc_end2end_test_fixture f) {
   /* Create large request and response bodies. These are big enough to require
    * multiple round trips to deliver to the peer, and their exact contents of
    * will be verified on completion. */
@@ -140,8 +141,10 @@ static void request_response_with_payload(grpc_end2end_test_fixture f) {
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -240,7 +243,8 @@ static void request_response_with_payload(grpc_end2end_test_fixture f) {
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 0);
   GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
   GPR_ASSERT(
@@ -269,7 +273,7 @@ static void test_invoke_request_response_with_payload(
     grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f = begin_test(
       config, "test_invoke_request_response_with_payload", NULL, NULL);
-  request_response_with_payload(f);
+  request_response_with_payload(config, f);
   end_test(&f);
   config.tear_down_data(&f);
 }
@@ -280,7 +284,7 @@ static void test_invoke_10_request_response_with_payload(
   grpc_end2end_test_fixture f = begin_test(
       config, "test_invoke_10_request_response_with_payload", NULL, NULL);
   for (i = 0; i < 10; i++) {
-    request_response_with_payload(f);
+    request_response_with_payload(config, f);
   }
   end_test(&f);
   config.tear_down_data(&f);
diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c
index 7e360c415b172eaf1a034f73ae6249322cd6c398..52f0d70a443c12a13f700d4c8e1b9533e37c08d8 100644
--- a/test/core/end2end/tests/ping_pong_streaming.c
+++ b/test/core/end2end/tests/ping_pong_streaming.c
@@ -123,9 +123,10 @@ static void test_pingpong_streaming(grpc_end2end_test_config config,
   gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
   gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c
index 9b2b42b5583ab55cd643cdca54b017f566190f02..6594b420b9d51a77951d48d1baa4ae937f2abe86 100644
--- a/test/core/end2end/tests/registered_call.c
+++ b/test/core/end2end/tests/registered_call.c
@@ -97,7 +97,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f, void *rc) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f, void *rc) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -186,7 +187,8 @@ static void simple_request_body(grpc_end2end_test_fixture f, void *rc) {
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
@@ -204,10 +206,11 @@ static void simple_request_body(grpc_end2end_test_fixture f, void *rc) {
 static void test_invoke_simple_request(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_simple_request", NULL, NULL);
-  void *rc = grpc_channel_register_call(f.client, "/foo",
-                                        "foo.test.google.fr:1234", NULL);
+  void *rc = grpc_channel_register_call(
+      f.client, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), NULL);
 
-  simple_request_body(f, rc);
+  simple_request_body(config, f, rc);
   end_test(&f);
   config.tear_down_data(&f);
 }
@@ -216,11 +219,12 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
   int i;
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_10_simple_requests", NULL, NULL);
-  void *rc = grpc_channel_register_call(f.client, "/foo",
-                                        "foo.test.google.fr:1234", NULL);
+  void *rc = grpc_channel_register_call(
+      f.client, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), NULL);
 
   for (i = 0; i < 10; i++) {
-    simple_request_body(f, rc);
+    simple_request_body(config, f, rc);
     gpr_log(GPR_INFO, "Passed simple request %d", i);
   }
   end_test(&f);
diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c
index 25150e6f2d61049fe01e849d5bc58761c5699b52..f96ef6aa94dfde898d1e8dab5ae853790d133ddc 100644
--- a/test/core/end2end/tests/request_with_flags.c
+++ b/test/core/end2end/tests/request_with_flags.c
@@ -120,8 +120,10 @@ static void test_invoke_request_with_flags(
   size_t details_capacity = 0;
   grpc_call_error expectation;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
index 67208c050c18acf428342996853f6fbe574ec5ae..359f4e9fd29c0caf6fc32f6127fb526fe695aa5c 100644
--- a/test/core/end2end/tests/request_with_payload.c
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -119,8 +119,10 @@ static void test_invoke_request_with_payload(grpc_end2end_test_config config) {
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -208,7 +210,8 @@ static void test_invoke_request_with_payload(grpc_end2end_test_config config) {
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 0);
   GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world"));
 
diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c
index 7fb9025aa38ec60dd5a5a7768ac434319a983277..3bb25fd9242b343369d8b4466a4e69645bc78bd4 100644
--- a/test/core/end2end/tests/server_finishes_request.c
+++ b/test/core/end2end/tests/server_finishes_request.c
@@ -97,7 +97,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -114,9 +115,10 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -183,7 +185,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
@@ -202,7 +205,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f;
 
   f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
-  simple_request_body(f);
+  simple_request_body(config, f);
   end_test(&f);
   config.tear_down_data(&f);
 }
diff --git a/test/core/end2end/tests/shutdown_finishes_calls.c b/test/core/end2end/tests/shutdown_finishes_calls.c
index dff2e6f280984e44c5fa9eab852a2af2bb18a422..b80a2e35f2334b04aae9f90fee94667e2d6a8b17 100644
--- a/test/core/end2end/tests/shutdown_finishes_calls.c
+++ b/test/core/end2end/tests/shutdown_finishes_calls.c
@@ -104,8 +104,10 @@ static void test_early_server_shutdown_finishes_inflight_calls(
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -171,7 +173,8 @@ static void test_early_server_shutdown_finishes_inflight_calls(
 
   GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
diff --git a/test/core/end2end/tests/simple_cacheable_request.c b/test/core/end2end/tests/simple_cacheable_request.c
index b52eb19315ebf828314bb9656b4ff5e98c833b4c..9f6a6a08a0f4f8bed112a64f2de2c404fe18d4bb 100644
--- a/test/core/end2end/tests/simple_cacheable_request.c
+++ b/test/core/end2end/tests/simple_cacheable_request.c
@@ -133,8 +133,10 @@ static void test_cacheable_request_response_with_metadata_and_payload(
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -235,7 +237,8 @@ static void test_cacheable_request_response_with_metadata_and_payload(
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   if (config.feature_mask & FEATURE_MASK_SUPPORTS_REQUEST_PROXYING) {
     // Our simple proxy does not support cacheable requests
   } else {
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
index 50d1975c8d0c347e9770703550305ed6a638ad64..ec40c8f22dba4d0a6792225ef5b9ce1e32867103 100644
--- a/test/core/end2end/tests/simple_delayed_request.c
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -106,8 +106,10 @@ static void simple_delayed_request_body(grpc_end2end_test_config config,
 
   config.init_client(f, client_args);
 
-  c = grpc_channel_create_call(f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -180,7 +182,8 @@ static void simple_delayed_request_body(grpc_end2end_test_config config,
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
diff --git a/test/core/end2end/tests/simple_metadata.c b/test/core/end2end/tests/simple_metadata.c
index 13c77c033e0cc112d713181fb8314460f365f5eb..7b8adb1f32a13cf9a143f7b9949d474b58c8620f 100644
--- a/test/core/end2end/tests/simple_metadata.c
+++ b/test/core/end2end/tests/simple_metadata.c
@@ -130,8 +130,10 @@ static void test_request_response_with_metadata_and_payload(
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -232,7 +234,8 @@ static void test_request_response_with_metadata_and_payload(
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 0);
   GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world"));
   GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, "hello you"));
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index ed7b850808a9557a2a6697966fc507fc77e52b0b..2dea5d6af2ef1ba6eccb2b1a0811eed94c020695 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -97,7 +97,8 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-static void simple_request_body(grpc_end2end_test_fixture f) {
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
   gpr_timespec deadline = five_seconds_time();
@@ -115,9 +116,10 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   int was_cancelled = 2;
   char *peer;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr:1234", deadline,
-                               NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   peer = grpc_call_get_peer(c);
@@ -202,7 +204,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(0 == call_details.flags);
   GPR_ASSERT(was_cancelled == 1);
 
@@ -222,7 +225,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f;
 
   f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
-  simple_request_body(f);
+  simple_request_body(config, f);
   end_test(&f);
   config.tear_down_data(&f);
 }
@@ -232,7 +235,7 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_10_simple_requests", NULL, NULL);
   for (i = 0; i < 10; i++) {
-    simple_request_body(f);
+    simple_request_body(config, f);
     gpr_log(GPR_INFO, "Passed simple request %d", i);
   }
   end_test(&f);
diff --git a/test/core/end2end/tests/streaming_error_response.c b/test/core/end2end/tests/streaming_error_response.c
index 8285468321c5e38d3cccfe7c7a37af595709a1eb..7b5315d667f4ce3688cfdb4ed12e57abfb567fcf 100644
--- a/test/core/end2end/tests/streaming_error_response.c
+++ b/test/core/end2end/tests/streaming_error_response.c
@@ -125,8 +125,10 @@ static void test(grpc_end2end_test_config config, bool request_status_early) {
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -245,7 +247,8 @@ static void test(grpc_end2end_test_config config, bool request_status_early) {
   GPR_ASSERT(status == GRPC_STATUS_FAILED_PRECONDITION);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(was_cancelled == 1);
 
   gpr_free(details);
diff --git a/test/core/end2end/tests/trailing_metadata.c b/test/core/end2end/tests/trailing_metadata.c
index d7093ae7239e4feb7d5fa25e9050ea04a423d6c4..87e29a934fbf1deca1326dcc6f071aa47b96016b 100644
--- a/test/core/end2end/tests/trailing_metadata.c
+++ b/test/core/end2end/tests/trailing_metadata.c
@@ -133,8 +133,10 @@ static void test_request_response_with_metadata_and_payload(
   size_t details_capacity = 0;
   int was_cancelled = 2;
 
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo",
+      get_host_override_string("foo.test.google.fr:1234", config), deadline,
+      NULL);
   GPR_ASSERT(c);
 
   grpc_metadata_array_init(&initial_metadata_recv);
@@ -236,7 +238,8 @@ static void test_request_response_with_metadata_and_payload(
   GPR_ASSERT(status == GRPC_STATUS_OK);
   GPR_ASSERT(0 == strcmp(details, "xyz"));
   GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
-  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
   GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, "hello world"));
   GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, "hello you"));
   GPR_ASSERT(contains_metadata(&request_metadata_recv, "key1", "val1"));
diff --git a/test/core/iomgr/resource_quota_test.c b/test/core/iomgr/resource_quota_test.c
index 34dee1aee19c5f24fd1ff7f80c13b5ad6f3e5643..22c4e4e98974edf3da1c3528eb6618be2281b082 100644
--- a/test/core/iomgr/resource_quota_test.c
+++ b/test/core/iomgr/resource_quota_test.c
@@ -81,11 +81,7 @@ grpc_closure *make_unused_reclaimer(grpc_closure *then) {
 
 static void destroy_user(grpc_resource_user *usr) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  bool done = false;
-  grpc_resource_user_shutdown(&exec_ctx, usr, set_bool(&done));
-  grpc_exec_ctx_flush(&exec_ctx);
-  GPR_ASSERT(done);
-  grpc_resource_user_destroy(&exec_ctx, usr);
+  grpc_resource_user_unref(&exec_ctx, usr);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -106,10 +102,9 @@ static void test_resource_user_no_op(void) {
   gpr_log(GPR_INFO, "** test_resource_user_no_op **");
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_resource_user_no_op");
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
 }
 
 static void test_instant_alloc_then_free(void) {
@@ -117,20 +112,19 @@ static void test_instant_alloc_then_free(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_instant_alloc_then_free");
   grpc_resource_quota_resize(q, 1024 * 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, NULL);
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, NULL);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
 }
 
 static void test_instant_alloc_free_pair(void) {
@@ -138,16 +132,15 @@ static void test_instant_alloc_free_pair(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_instant_alloc_free_pair");
   grpc_resource_quota_resize(q, 1024 * 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, NULL);
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, NULL);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
 }
 
 static void test_simple_async_alloc(void) {
@@ -155,22 +148,21 @@ static void test_simple_async_alloc(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_simple_async_alloc");
   grpc_resource_quota_resize(q, 1024 * 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
 }
 
 static void test_async_alloc_blocked_by_size(void) {
@@ -178,12 +170,11 @@ static void test_async_alloc_blocked_by_size(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_async_alloc_blocked_by_size");
   grpc_resource_quota_resize(q, 1);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   bool done = false;
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(!done);
   }
@@ -191,87 +182,83 @@ static void test_async_alloc_blocked_by_size(void) {
   GPR_ASSERT(done);
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
 }
 
 static void test_scavenge(void) {
   gpr_log(GPR_INFO, "** test_scavenge **");
   grpc_resource_quota *q = grpc_resource_quota_create("test_scavenge");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr1;
-  grpc_resource_user usr2;
-  grpc_resource_user_init(&usr1, q, "usr1");
-  grpc_resource_user_init(&usr2, q, "usr2");
+  grpc_resource_user *usr1 = grpc_resource_user_create(q, "usr1");
+  grpc_resource_user *usr2 = grpc_resource_user_create(q, "usr2");
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr1, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr1, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr1, 1024);
+    grpc_resource_user_free(&exec_ctx, usr1, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr2, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr2, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr2, 1024);
+    grpc_resource_user_free(&exec_ctx, usr2, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr1);
-  destroy_user(&usr2);
+  destroy_user(usr1);
+  destroy_user(usr2);
 }
 
 static void test_scavenge_blocked(void) {
   gpr_log(GPR_INFO, "** test_scavenge_blocked **");
   grpc_resource_quota *q = grpc_resource_quota_create("test_scavenge_blocked");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr1;
-  grpc_resource_user usr2;
-  grpc_resource_user_init(&usr1, q, "usr1");
-  grpc_resource_user_init(&usr2, q, "usr2");
+  grpc_resource_user *usr1 = grpc_resource_user_create(q, "usr1");
+  grpc_resource_user *usr2 = grpc_resource_user_create(q, "usr2");
   bool done;
   {
     done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr1, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr1, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
   {
     done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr2, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr2, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(!done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr1, 1024);
+    grpc_resource_user_free(&exec_ctx, usr1, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr2, 1024);
+    grpc_resource_user_free(&exec_ctx, usr2, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr1);
-  destroy_user(&usr2);
+  destroy_user(usr1);
+  destroy_user(usr2);
 }
 
 static void test_blocked_until_scheduled_reclaim(void) {
@@ -279,12 +266,11 @@ static void test_blocked_until_scheduled_reclaim(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_blocked_until_scheduled_reclaim");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
@@ -292,25 +278,25 @@ static void test_blocked_until_scheduled_reclaim(void) {
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr, false,
-        make_reclaimer(&usr, 1024, set_bool(&reclaim_done)));
+        &exec_ctx, usr, false,
+        make_reclaimer(usr, 1024, set_bool(&reclaim_done)));
     grpc_exec_ctx_finish(&exec_ctx);
   }
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(reclaim_done);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
 }
 
 static void test_blocked_until_scheduled_reclaim_and_scavenge(void) {
@@ -318,14 +304,12 @@ static void test_blocked_until_scheduled_reclaim_and_scavenge(void) {
   grpc_resource_quota *q = grpc_resource_quota_create(
       "test_blocked_until_scheduled_reclaim_and_scavenge");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr1;
-  grpc_resource_user usr2;
-  grpc_resource_user_init(&usr1, q, "usr1");
-  grpc_resource_user_init(&usr2, q, "usr2");
+  grpc_resource_user *usr1 = grpc_resource_user_create(q, "usr1");
+  grpc_resource_user *usr2 = grpc_resource_user_create(q, "usr2");
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr1, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr1, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
@@ -333,26 +317,26 @@ static void test_blocked_until_scheduled_reclaim_and_scavenge(void) {
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr1, false,
-        make_reclaimer(&usr1, 1024, set_bool(&reclaim_done)));
+        &exec_ctx, usr1, false,
+        make_reclaimer(usr1, 1024, set_bool(&reclaim_done)));
     grpc_exec_ctx_finish(&exec_ctx);
   }
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr2, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr2, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(reclaim_done);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr2, 1024);
+    grpc_resource_user_free(&exec_ctx, usr2, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr1);
-  destroy_user(&usr2);
+  destroy_user(usr1);
+  destroy_user(usr2);
 }
 
 static void test_blocked_until_scheduled_destructive_reclaim(void) {
@@ -360,12 +344,11 @@ static void test_blocked_until_scheduled_destructive_reclaim(void) {
   grpc_resource_quota *q = grpc_resource_quota_create(
       "test_blocked_until_scheduled_destructive_reclaim");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
@@ -373,25 +356,25 @@ static void test_blocked_until_scheduled_destructive_reclaim(void) {
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr, true,
-        make_reclaimer(&usr, 1024, set_bool(&reclaim_done)));
+        &exec_ctx, usr, true,
+        make_reclaimer(usr, 1024, set_bool(&reclaim_done)));
     grpc_exec_ctx_finish(&exec_ctx);
   }
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(reclaim_done);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
 }
 
 static void test_unused_reclaim_is_cancelled(void) {
@@ -399,23 +382,22 @@ static void test_unused_reclaim_is_cancelled(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_unused_reclaim_is_cancelled");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   bool benign_done = false;
   bool destructive_done = false;
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr, false, make_unused_reclaimer(set_bool(&benign_done)));
+        &exec_ctx, usr, false, make_unused_reclaimer(set_bool(&benign_done)));
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr, true,
+        &exec_ctx, usr, true,
         make_unused_reclaimer(set_bool(&destructive_done)));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(!benign_done);
     GPR_ASSERT(!destructive_done);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
   GPR_ASSERT(benign_done);
   GPR_ASSERT(destructive_done);
 }
@@ -425,24 +407,23 @@ static void test_benign_reclaim_is_preferred(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_benign_reclaim_is_preferred");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   bool benign_done = false;
   bool destructive_done = false;
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr, false,
-        make_reclaimer(&usr, 1024, set_bool(&benign_done)));
+        &exec_ctx, usr, false,
+        make_reclaimer(usr, 1024, set_bool(&benign_done)));
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr, true,
+        &exec_ctx, usr, true,
         make_unused_reclaimer(set_bool(&destructive_done)));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(!benign_done);
@@ -451,7 +432,7 @@ static void test_benign_reclaim_is_preferred(void) {
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(benign_done);
     GPR_ASSERT(!destructive_done);
@@ -459,11 +440,11 @@ static void test_benign_reclaim_is_preferred(void) {
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
   GPR_ASSERT(benign_done);
   GPR_ASSERT(destructive_done);
 }
@@ -473,25 +454,24 @@ static void test_multiple_reclaims_can_be_triggered(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_multiple_reclaims_can_be_triggered");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   bool benign_done = false;
   bool destructive_done = false;
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr, false,
-        make_reclaimer(&usr, 512, set_bool(&benign_done)));
+        &exec_ctx, usr, false,
+        make_reclaimer(usr, 512, set_bool(&benign_done)));
     grpc_resource_user_post_reclaimer(
-        &exec_ctx, &usr, true,
-        make_reclaimer(&usr, 512, set_bool(&destructive_done)));
+        &exec_ctx, usr, true,
+        make_reclaimer(usr, 512, set_bool(&destructive_done)));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(!benign_done);
     GPR_ASSERT(!destructive_done);
@@ -499,7 +479,7 @@ static void test_multiple_reclaims_can_be_triggered(void) {
   {
     bool done = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&done));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&done));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(benign_done);
     GPR_ASSERT(destructive_done);
@@ -507,11 +487,11 @@ static void test_multiple_reclaims_can_be_triggered(void) {
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_resource_quota_unref(q);
-  destroy_user(&usr);
+  destroy_user(usr);
   GPR_ASSERT(benign_done);
   GPR_ASSERT(destructive_done);
 }
@@ -522,30 +502,21 @@ static void test_resource_user_stays_allocated_until_memory_released(void) {
   grpc_resource_quota *q = grpc_resource_quota_create(
       "test_resource_user_stays_allocated_until_memory_released");
   grpc_resource_quota_resize(q, 1024 * 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
-  bool done = false;
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, NULL);
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, NULL);
     grpc_exec_ctx_finish(&exec_ctx);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     grpc_resource_quota_unref(q);
-    grpc_resource_user_shutdown(&exec_ctx, &usr, set_bool(&done));
+    grpc_resource_user_unref(&exec_ctx, usr);
     grpc_exec_ctx_finish(&exec_ctx);
-    GPR_ASSERT(!done);
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
-    grpc_exec_ctx_finish(&exec_ctx);
-    GPR_ASSERT(done);
-  }
-  {
-    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_destroy(&exec_ctx, &usr);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
 }
@@ -562,14 +533,12 @@ test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released(
       "released");
   grpc_resource_quota_resize(q, 1024);
   for (int i = 0; i < 10; i++) {
-    grpc_resource_user usr;
-    grpc_resource_user_init(&usr, q, "usr");
-    bool done = false;
+    grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
     bool reclaimer_cancelled = false;
     {
       grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
       grpc_resource_user_post_reclaimer(
-          &exec_ctx, &usr, false,
+          &exec_ctx, usr, false,
           make_unused_reclaimer(set_bool(&reclaimer_cancelled)));
       grpc_exec_ctx_finish(&exec_ctx);
       GPR_ASSERT(!reclaimer_cancelled);
@@ -577,30 +546,23 @@ test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released(
     {
       bool allocated = false;
       grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-      grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&allocated));
+      grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&allocated));
       grpc_exec_ctx_finish(&exec_ctx);
       GPR_ASSERT(allocated);
       GPR_ASSERT(!reclaimer_cancelled);
     }
     {
       grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-      grpc_resource_user_shutdown(&exec_ctx, &usr, set_bool(&done));
+      grpc_resource_user_unref(&exec_ctx, usr);
       grpc_exec_ctx_finish(&exec_ctx);
-      GPR_ASSERT(!done);
       GPR_ASSERT(!reclaimer_cancelled);
     }
     {
       grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-      grpc_resource_user_free(&exec_ctx, &usr, 1024);
+      grpc_resource_user_free(&exec_ctx, usr, 1024);
       grpc_exec_ctx_finish(&exec_ctx);
-      GPR_ASSERT(done);
       GPR_ASSERT(reclaimer_cancelled);
     }
-    {
-      grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-      grpc_resource_user_destroy(&exec_ctx, &usr);
-      grpc_exec_ctx_finish(&exec_ctx);
-    }
   }
   grpc_resource_quota_unref(q);
 }
@@ -610,12 +572,11 @@ static void test_reclaimers_can_be_posted_repeatedly(void) {
   grpc_resource_quota *q =
       grpc_resource_quota_create("test_reclaimers_can_be_posted_repeatedly");
   grpc_resource_quota_resize(q, 1024);
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
   {
     bool allocated = false;
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&allocated));
+    grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&allocated));
     grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(allocated);
   }
@@ -624,15 +585,15 @@ static void test_reclaimers_can_be_posted_repeatedly(void) {
     {
       grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
       grpc_resource_user_post_reclaimer(
-          &exec_ctx, &usr, false,
-          make_reclaimer(&usr, 1024, set_bool(&reclaimer_done)));
+          &exec_ctx, usr, false,
+          make_reclaimer(usr, 1024, set_bool(&reclaimer_done)));
       grpc_exec_ctx_finish(&exec_ctx);
       GPR_ASSERT(!reclaimer_done);
     }
     {
       bool allocated = false;
       grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-      grpc_resource_user_alloc(&exec_ctx, &usr, 1024, set_bool(&allocated));
+      grpc_resource_user_alloc(&exec_ctx, usr, 1024, set_bool(&allocated));
       grpc_exec_ctx_finish(&exec_ctx);
       GPR_ASSERT(allocated);
       GPR_ASSERT(reclaimer_done);
@@ -640,10 +601,10 @@ static void test_reclaimers_can_be_posted_repeatedly(void) {
   }
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, &usr, 1024);
+    grpc_resource_user_free(&exec_ctx, usr, 1024);
     grpc_exec_ctx_finish(&exec_ctx);
   }
-  destroy_user(&usr);
+  destroy_user(usr);
   grpc_resource_quota_unref(q);
 }
 
@@ -653,13 +614,11 @@ static void test_one_slice(void) {
   grpc_resource_quota *q = grpc_resource_quota_create("test_one_slice");
   grpc_resource_quota_resize(q, 1024);
 
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
 
   grpc_resource_user_slice_allocator alloc;
   int num_allocs = 0;
-  grpc_resource_user_slice_allocator_init(&alloc, &usr, inc_int_cb,
-                                          &num_allocs);
+  grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs);
 
   gpr_slice_buffer buffer;
   gpr_slice_buffer_init(&buffer);
@@ -673,7 +632,7 @@ static void test_one_slice(void) {
   }
 
   gpr_slice_buffer_destroy(&buffer);
-  destroy_user(&usr);
+  destroy_user(usr);
   grpc_resource_quota_unref(q);
 }
 
@@ -684,13 +643,11 @@ static void test_one_slice_deleted_late(void) {
       grpc_resource_quota_create("test_one_slice_deleted_late");
   grpc_resource_quota_resize(q, 1024);
 
-  grpc_resource_user usr;
-  grpc_resource_user_init(&usr, q, "usr");
+  grpc_resource_user *usr = grpc_resource_user_create(q, "usr");
 
   grpc_resource_user_slice_allocator alloc;
   int num_allocs = 0;
-  grpc_resource_user_slice_allocator_init(&alloc, &usr, inc_int_cb,
-                                          &num_allocs);
+  grpc_resource_user_slice_allocator_init(&alloc, usr, inc_int_cb, &num_allocs);
 
   gpr_slice_buffer buffer;
   gpr_slice_buffer_init(&buffer);
@@ -703,22 +660,14 @@ static void test_one_slice_deleted_late(void) {
     GPR_ASSERT(num_allocs == start_allocs + 1);
   }
 
-  bool done = false;
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_shutdown(&exec_ctx, &usr, set_bool(&done));
+    grpc_resource_user_unref(&exec_ctx, usr);
     grpc_exec_ctx_finish(&exec_ctx);
-    GPR_ASSERT(!done);
   }
 
   grpc_resource_quota_unref(q);
   gpr_slice_buffer_destroy(&buffer);
-  GPR_ASSERT(done);
-  {
-    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_destroy(&exec_ctx, &usr);
-    grpc_exec_ctx_finish(&exec_ctx);
-  }
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/transport/pid_controller_test.c b/test/core/transport/pid_controller_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..9614983b007c39e31819974bf6d739a8eeb39f68
--- /dev/null
+++ b/test/core/transport/pid_controller_test.c
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * 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.
+ *
+ */
+
+#include "src/core/lib/transport/pid_controller.h"
+
+#include <math.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
+#include "test/core/util/test_config.h"
+
+static void test_noop(void) {
+  gpr_log(GPR_INFO, "test_noop");
+  grpc_pid_controller pid;
+  grpc_pid_controller_init(&pid, 1, 1, 1);
+}
+
+static void test_simple_convergence(double gain_p, double gain_i, double gain_d,
+                                    double dt, double set_point, double start) {
+  gpr_log(GPR_INFO,
+          "test_simple_convergence(p=%lf, i=%lf, d=%lf); dt=%lf set_point=%lf "
+          "start=%lf",
+          gain_p, gain_i, gain_d, dt, set_point, start);
+  grpc_pid_controller pid;
+  grpc_pid_controller_init(&pid, 0.2, 0.1, 0.1);
+
+  double current = start;
+
+  for (int i = 0; i < 1000; i++) {
+    current += grpc_pid_controller_update(&pid, set_point - current, 1);
+  }
+
+  GPR_ASSERT(fabs(set_point - current) < 0.1);
+  GPR_ASSERT(fabs(pid.error_integral) < 0.1);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_noop();
+  test_simple_convergence(0.2, 0, 0, 1, 100, 0);
+  test_simple_convergence(0.2, 0.1, 0, 1, 100, 0);
+  test_simple_convergence(0.2, 0.1, 0.1, 1, 100, 0);
+  return 0;
+}
diff --git a/test/core/util/mock_endpoint.c b/test/core/util/mock_endpoint.c
index 2b041a44841a09336878811e655f13f0b818444e..2dac877a65d8e69ac0870c622c80fd687ccb8609 100644
--- a/test/core/util/mock_endpoint.c
+++ b/test/core/util/mock_endpoint.c
@@ -41,12 +41,11 @@
 typedef struct grpc_mock_endpoint {
   grpc_endpoint base;
   gpr_mu mu;
-  int refs;
   void (*on_write)(gpr_slice slice);
   gpr_slice_buffer read_buffer;
   gpr_slice_buffer *on_read_out;
   grpc_closure *on_read;
-  grpc_resource_user resource_user;
+  grpc_resource_user *resource_user;
 } grpc_mock_endpoint;
 
 static void me_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@@ -78,24 +77,6 @@ static void me_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
 static void me_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
                                   grpc_pollset_set *pollset) {}
 
-static void unref(grpc_exec_ctx *exec_ctx, grpc_mock_endpoint *m) {
-  gpr_mu_lock(&m->mu);
-  if (0 == --m->refs) {
-    gpr_mu_unlock(&m->mu);
-    gpr_slice_buffer_destroy(&m->read_buffer);
-    grpc_resource_user_destroy(exec_ctx, &m->resource_user);
-    gpr_free(m);
-  } else {
-    gpr_mu_unlock(&m->mu);
-  }
-}
-
-static void me_finish_shutdown(grpc_exec_ctx *exec_ctx, void *me,
-                               grpc_error *error) {
-  grpc_mock_endpoint *m = me;
-  unref(exec_ctx, m);
-}
-
 static void me_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
   grpc_mock_endpoint *m = (grpc_mock_endpoint *)ep;
   gpr_mu_lock(&m->mu);
@@ -104,14 +85,15 @@ static void me_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
                         GRPC_ERROR_CREATE("Endpoint Shutdown"), NULL);
     m->on_read = NULL;
   }
-  grpc_resource_user_shutdown(exec_ctx, &m->resource_user,
-                              grpc_closure_create(me_finish_shutdown, m));
   gpr_mu_unlock(&m->mu);
+  grpc_resource_user_shutdown(exec_ctx, m->resource_user);
 }
 
 static void me_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
   grpc_mock_endpoint *m = (grpc_mock_endpoint *)ep;
-  unref(exec_ctx, m);
+  gpr_slice_buffer_destroy(&m->read_buffer);
+  grpc_resource_user_unref(exec_ctx, m->resource_user);
+  gpr_free(m);
 }
 
 static char *me_get_peer(grpc_endpoint *ep) {
@@ -120,7 +102,7 @@ static char *me_get_peer(grpc_endpoint *ep) {
 
 static grpc_resource_user *me_get_resource_user(grpc_endpoint *ep) {
   grpc_mock_endpoint *m = (grpc_mock_endpoint *)ep;
-  return &m->resource_user;
+  return m->resource_user;
 }
 
 static grpc_workqueue *me_get_workqueue(grpc_endpoint *ep) { return NULL; }
@@ -141,10 +123,9 @@ grpc_endpoint *grpc_mock_endpoint_create(void (*on_write)(gpr_slice slice),
                                          grpc_resource_quota *resource_quota) {
   grpc_mock_endpoint *m = gpr_malloc(sizeof(*m));
   m->base.vtable = &vtable;
-  m->refs = 2;
   char *name;
   gpr_asprintf(&name, "mock_endpoint_%" PRIxPTR, (intptr_t)m);
-  grpc_resource_user_init(&m->resource_user, resource_quota, name);
+  m->resource_user = grpc_resource_user_create(resource_quota, name);
   gpr_free(name);
   gpr_slice_buffer_init(&m->read_buffer);
   gpr_mu_init(&m->mu);
diff --git a/test/core/util/passthru_endpoint.c b/test/core/util/passthru_endpoint.c
index ee6ef7da6015195e219e16db6e136f9438e15676..a920a15aa5403f58e801b376da7318e95546e1be 100644
--- a/test/core/util/passthru_endpoint.c
+++ b/test/core/util/passthru_endpoint.c
@@ -46,7 +46,7 @@ typedef struct {
   gpr_slice_buffer read_buffer;
   gpr_slice_buffer *on_read_out;
   grpc_closure *on_read;
-  grpc_resource_user resource_user;
+  grpc_resource_user *resource_user;
 } half;
 
 struct passthru_endpoint {
@@ -123,10 +123,10 @@ static void me_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
     m->on_read = NULL;
   }
   gpr_mu_unlock(&m->parent->mu);
+  grpc_resource_user_shutdown(exec_ctx, m->resource_user);
 }
 
-static void me_really_destroy(grpc_exec_ctx *exec_ctx, void *ep,
-                              grpc_error *error) {
+static void me_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
   passthru_endpoint *p = ((half *)ep)->parent;
   gpr_mu_lock(&p->mu);
   if (0 == --p->halves) {
@@ -134,18 +134,14 @@ static void me_really_destroy(grpc_exec_ctx *exec_ctx, void *ep,
     gpr_mu_destroy(&p->mu);
     gpr_slice_buffer_destroy(&p->client.read_buffer);
     gpr_slice_buffer_destroy(&p->server.read_buffer);
+    grpc_resource_user_unref(exec_ctx, p->client.resource_user);
+    grpc_resource_user_unref(exec_ctx, p->server.resource_user);
     gpr_free(p);
   } else {
     gpr_mu_unlock(&p->mu);
   }
 }
 
-static void me_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
-  half *m = (half *)ep;
-  grpc_resource_user_shutdown(exec_ctx, &m->resource_user,
-                              grpc_closure_create(me_really_destroy, m));
-}
-
 static char *me_get_peer(grpc_endpoint *ep) {
   return gpr_strdup("fake:mock_endpoint");
 }
@@ -154,7 +150,7 @@ static grpc_workqueue *me_get_workqueue(grpc_endpoint *ep) { return NULL; }
 
 static grpc_resource_user *me_get_resource_user(grpc_endpoint *ep) {
   half *m = (half *)ep;
-  return &m->resource_user;
+  return m->resource_user;
 }
 
 static const grpc_endpoint_vtable vtable = {
@@ -179,7 +175,7 @@ static void half_init(half *m, passthru_endpoint *parent,
   char *name;
   gpr_asprintf(&name, "passthru_endpoint_%s_%" PRIxPTR, half_name,
                (intptr_t)parent);
-  grpc_resource_user_init(&m->resource_user, resource_quota, name);
+  m->resource_user = grpc_resource_user_create(resource_quota, name);
   gpr_free(name);
 }
 
diff --git a/test/cpp/qps/gen_build_yaml.py b/test/cpp/qps/gen_build_yaml.py
index 369da2c8ca2fd97f39c4a9f2995502f9c66bee43..e4d9e7ac58f68c851e06aef0d77c430f3458728f 100755
--- a/test/cpp/qps/gen_build_yaml.py
+++ b/test/cpp/qps/gen_build_yaml.py
@@ -82,7 +82,7 @@ print yaml.dump({
       'defaults': 'boringssl',
       'cpu_cost': guess_cpu(scenario_json),
       'exclude_configs': [],
-      'timeout_seconds': 3*60
+      'timeout_seconds': 6*60
     }
     for scenario_json in scenario_config.CXXLanguage().scenarios()
     if 'scalable' in scenario_json.get('CATEGORIES', [])
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index a55e90525298c4540b7dc1e7fbc82abb9afbc600..04e8f4e7f20d36abacfc6c0ebf016ca604207530 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -877,6 +877,7 @@ src/cpp/common/completion_queue_cc.cc \
 src/cpp/common/core_codegen.cc \
 src/cpp/common/resource_quota_cc.cc \
 src/cpp/common/rpc_method.cc \
+src/cpp/common/version_cc.cc \
 src/cpp/server/async_generic_service.cc \
 src/cpp/server/create_default_thread_pool.cc \
 src/cpp/server/dynamic_thread_pool.cc \
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index 003686cee69c13e84fb995435878c05c4ad6061d..91abb922ea0e09197099e8ba0c3157b25cedcc0f 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Core"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.1.0-dev
+PROJECT_NUMBER         = 2.0.0-dev
 
 # 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/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index e83298766fd70d11fdbd888cad05879d5f978d2b..793561d78f083d225e2a92bbd3102fed922e4902 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Core"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.1.0-dev
+PROJECT_NUMBER         = 2.0.0-dev
 
 # 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
@@ -876,6 +876,7 @@ src/core/lib/transport/mdstr_hash_table.h \
 src/core/lib/transport/metadata.h \
 src/core/lib/transport/metadata_batch.h \
 src/core/lib/transport/method_config.h \
+src/core/lib/transport/pid_controller.h \
 src/core/lib/transport/static_metadata.h \
 src/core/lib/transport/timeout_encoding.h \
 src/core/lib/transport/transport.h \
@@ -1064,6 +1065,7 @@ src/core/lib/transport/mdstr_hash_table.c \
 src/core/lib/transport/metadata.c \
 src/core/lib/transport/metadata_batch.c \
 src/core/lib/transport/method_config.c \
+src/core/lib/transport/pid_controller.c \
 src/core/lib/transport/static_metadata.c \
 src/core/lib/transport/timeout_encoding.c \
 src/core/lib/transport/transport.c \
diff --git a/tools/run_tests/sanity/check_version.py b/tools/run_tests/sanity/check_version.py
index 41dd5efe3887fde41b69aa70e2add1d876ec4161..e62f39081850bb9311f0de96d87592a6a2baa197 100755
--- a/tools/run_tests/sanity/check_version.py
+++ b/tools/run_tests/sanity/check_version.py
@@ -83,15 +83,15 @@ if not check_version(top_version):
 for tag, value in settings.iteritems():
   if re.match(r'^[a-z]+_version$', tag):
     value = Version(value)
-    if value.major != top_version.major:
-      errors += 1
-      print 'major version mismatch on %s: %d vs %d' % (tag, value.major, top_version.major)
-    if value.minor != top_version.minor:
-      errors += 1
-      print 'minor version mismatch on %s: %d vs %d' % (tag, value.minor, top_version.minor)
+    if tag != 'core_version':
+      if value.major != top_version.major:
+        errors += 1
+        print 'major version mismatch on %s: %d vs %d' % (tag, value.major, top_version.major)
+      if value.minor != top_version.minor:
+        errors += 1
+        print 'minor version mismatch on %s: %d vs %d' % (tag, value.minor, top_version.minor)
     if not check_version(value):
       errors += 1
       print warning % (tag, value)
 
 sys.exit(errors)
-
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 91b71933d3c7e7241b4e6a6c0f1c15f5bb64fa07..2faeed8d393a55f9eda5642b0b5ff209b0d4e42a 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -2062,6 +2062,23 @@
     "third_party": false, 
     "type": "target"
   }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "transport_pid_controller_test", 
+    "src": [
+      "test/core/transport/pid_controller_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
   {
     "deps": [
       "gpr", 
@@ -6092,7 +6109,28 @@
   }, 
   {
     "deps": [], 
-    "headers": [], 
+    "headers": [
+      "third_party/google_benchmark/include/benchmark/benchmark.h", 
+      "third_party/google_benchmark/include/benchmark/benchmark_api.h", 
+      "third_party/google_benchmark/include/benchmark/macros.h", 
+      "third_party/google_benchmark/include/benchmark/reporter.h", 
+      "third_party/google_benchmark/src/arraysize.h", 
+      "third_party/google_benchmark/src/benchmark_api_internal.h", 
+      "third_party/google_benchmark/src/check.h", 
+      "third_party/google_benchmark/src/colorprint.h", 
+      "third_party/google_benchmark/src/commandlineflags.h", 
+      "third_party/google_benchmark/src/complexity.h", 
+      "third_party/google_benchmark/src/cycleclock.h", 
+      "third_party/google_benchmark/src/internal_macros.h", 
+      "third_party/google_benchmark/src/log.h", 
+      "third_party/google_benchmark/src/mutex.h", 
+      "third_party/google_benchmark/src/re.h", 
+      "third_party/google_benchmark/src/sleep.h", 
+      "third_party/google_benchmark/src/stat.h", 
+      "third_party/google_benchmark/src/string_util.h", 
+      "third_party/google_benchmark/src/sysinfo.h", 
+      "third_party/google_benchmark/src/timers.h"
+    ], 
     "is_filegroup": false, 
     "language": "c++", 
     "name": "google_benchmark", 
@@ -6177,6 +6215,7 @@
     "language": "c", 
     "name": "end2end_tests", 
     "src": [
+      "test/core/end2end/end2end_test_utils.c", 
       "test/core/end2end/end2end_tests.c", 
       "test/core/end2end/end2end_tests.h", 
       "test/core/end2end/tests/bad_hostname.c", 
@@ -6245,6 +6284,7 @@
     "name": "end2end_nosec_tests", 
     "src": [
       "test/core/end2end/end2end_nosec_tests.c", 
+      "test/core/end2end/end2end_test_utils.c", 
       "test/core/end2end/end2end_tests.h", 
       "test/core/end2end/tests/bad_hostname.c", 
       "test/core/end2end/tests/binary_metadata.c", 
@@ -6629,6 +6669,7 @@
       "src/core/lib/transport/metadata.h", 
       "src/core/lib/transport/metadata_batch.h", 
       "src/core/lib/transport/method_config.h", 
+      "src/core/lib/transport/pid_controller.h", 
       "src/core/lib/transport/static_metadata.h", 
       "src/core/lib/transport/timeout_encoding.h", 
       "src/core/lib/transport/transport.h", 
@@ -6838,6 +6879,8 @@
       "src/core/lib/transport/metadata_batch.h", 
       "src/core/lib/transport/method_config.c", 
       "src/core/lib/transport/method_config.h", 
+      "src/core/lib/transport/pid_controller.c", 
+      "src/core/lib/transport/pid_controller.h", 
       "src/core/lib/transport/static_metadata.c", 
       "src/core/lib/transport/static_metadata.h", 
       "src/core/lib/transport/timeout_encoding.c", 
@@ -7532,6 +7575,7 @@
       "src/cpp/common/core_codegen.cc", 
       "src/cpp/common/resource_quota_cc.cc", 
       "src/cpp/common/rpc_method.cc", 
+      "src/cpp/common/version_cc.cc", 
       "src/cpp/server/async_generic_service.cc", 
       "src/cpp/server/create_default_thread_pool.cc", 
       "src/cpp/server/dynamic_thread_pool.cc", 
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 5c22979a9ad08e4f22c5a8541aa77976c7368c73..cb1ddca40bc758ef21f2d5ac31a0b53c3c9408e0 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -2193,6 +2193,28 @@
       "windows"
     ]
   }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "transport_pid_controller_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
   {
     "args": [], 
     "ci_platforms": [
@@ -35244,7 +35266,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_generic_async_streaming_ping_pong_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35265,7 +35287,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35286,7 +35308,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_one_server_core_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35307,7 +35329,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35328,7 +35350,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35349,7 +35371,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_unary_ping_pong_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35370,7 +35392,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_unary_qps_unconstrained_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35391,7 +35413,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_unary_qps_unconstrained_secure_500kib_resource_quota", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35412,7 +35434,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35433,7 +35455,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35454,7 +35476,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_secure_500kib_resource_quota", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35475,7 +35497,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_ping_pong_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35496,7 +35518,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35517,7 +35539,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_secure_500kib_resource_quota", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35538,7 +35560,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_streaming_ping_pong_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35559,7 +35581,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_secure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35580,7 +35602,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_secure_500kib_resource_quota", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35601,7 +35623,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_generic_async_streaming_ping_pong_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35622,7 +35644,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35643,7 +35665,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_one_server_core_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35664,7 +35686,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35685,7 +35707,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35706,7 +35728,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_unary_ping_pong_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35727,7 +35749,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_unary_qps_unconstrained_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35748,7 +35770,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_unary_qps_unconstrained_insecure_500kib_resource_quota", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35769,7 +35791,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35790,7 +35812,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35811,7 +35833,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_insecure_500kib_resource_quota", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35832,7 +35854,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_ping_pong_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35853,7 +35875,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35874,7 +35896,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_insecure_500kib_resource_quota", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35895,7 +35917,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_streaming_ping_pong_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35916,7 +35938,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_insecure", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
@@ -35937,7 +35959,7 @@
       "linux"
     ], 
     "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_insecure_500kib_resource_quota", 
-    "timeout_seconds": 180
+    "timeout_seconds": 360
   }, 
   {
     "args": [
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index c84f1496576efe24d4c2515b6e1c5f76badec988..ad5c8f264015a5e74362b494bc6775e41d41bcab 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -1494,6 +1494,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "transport_metadata_test", "
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "transport_pid_controller_test", "vcxproj\test\transport_pid_controller_test\transport_pid_controller_test.vcxproj", "{B8790A2E-1106-2510-9D95-32C1D68E72EE}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unknown_frame_bad_client_test", "vcxproj\test\unknown_frame_bad_client_test\unknown_frame_bad_client_test.vcxproj", "{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -3781,6 +3792,22 @@ Global
 		{89A119C5-0F62-33B8-5D08-1FAA29DA7DEB}.Release-DLL|Win32.Build.0 = Release|Win32
 		{89A119C5-0F62-33B8-5D08-1FAA29DA7DEB}.Release-DLL|x64.ActiveCfg = Release|x64
 		{89A119C5-0F62-33B8-5D08-1FAA29DA7DEB}.Release-DLL|x64.Build.0 = Release|x64
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Debug|x64.ActiveCfg = Debug|x64
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Release|Win32.ActiveCfg = Release|Win32
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Release|x64.ActiveCfg = Release|x64
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Debug|Win32.Build.0 = Debug|Win32
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Debug|x64.Build.0 = Debug|x64
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Release|Win32.Build.0 = Release|Win32
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Release|x64.Build.0 = Release|x64
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Debug-DLL|x64.Build.0 = Debug|x64
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Release-DLL|Win32.Build.0 = Release|Win32
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Release-DLL|x64.ActiveCfg = Release|x64
+		{B8790A2E-1106-2510-9D95-32C1D68E72EE}.Release-DLL|x64.Build.0 = Release|x64
 		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Debug|x64.ActiveCfg = Debug|x64
 		{9E0A2239-20D5-DB2D-CA0D-69F24E3416E7}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/google_benchmark/google_benchmark.vcxproj b/vsprojects/vcxproj/google_benchmark/google_benchmark.vcxproj
index 1c875d7c093dadbadb7095a7b833468470ed876c..52774e0802586a73446f937d04e417e708a258bf 100644
--- a/vsprojects/vcxproj/google_benchmark/google_benchmark.vcxproj
+++ b/vsprojects/vcxproj/google_benchmark/google_benchmark.vcxproj
@@ -147,7 +147,53 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\vsprojects\dummy.c">
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\include\benchmark\benchmark.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\include\benchmark\benchmark_api.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\include\benchmark\macros.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\include\benchmark\reporter.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\arraysize.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\benchmark_api_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\check.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\colorprint.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\commandlineflags.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\complexity.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\cycleclock.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\internal_macros.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\mutex.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\re.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\sleep.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\stat.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\string_util.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\sysinfo.h" />
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\timers.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\benchmark.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\benchmark_register.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\colorprint.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\commandlineflags.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\complexity.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\console_reporter.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\csv_reporter.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\json_reporter.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\reporter.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\sleep.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\string_util.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\sysinfo.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\timers.cc">
     </ClCompile>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/vsprojects/vcxproj/google_benchmark/google_benchmark.vcxproj.filters b/vsprojects/vcxproj/google_benchmark/google_benchmark.vcxproj.filters
index 00e4276f1d4a4424020141e0c5296974350bd7ba..9db6ed465742fa812b31c133d28dd8d6a60c1112 100644
--- a/vsprojects/vcxproj/google_benchmark/google_benchmark.vcxproj.filters
+++ b/vsprojects/vcxproj/google_benchmark/google_benchmark.vcxproj.filters
@@ -1,7 +1,125 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\benchmark.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\benchmark_register.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\colorprint.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\commandlineflags.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\complexity.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\console_reporter.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\csv_reporter.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\json_reporter.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\reporter.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\sleep.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\string_util.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\sysinfo.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\third_party\google_benchmark\src\timers.cc">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\include\benchmark\benchmark.h">
+      <Filter>third_party\google_benchmark\include\benchmark</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\include\benchmark\benchmark_api.h">
+      <Filter>third_party\google_benchmark\include\benchmark</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\include\benchmark\macros.h">
+      <Filter>third_party\google_benchmark\include\benchmark</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\include\benchmark\reporter.h">
+      <Filter>third_party\google_benchmark\include\benchmark</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\arraysize.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\benchmark_api_internal.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\check.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\colorprint.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\commandlineflags.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\complexity.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\cycleclock.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\internal_macros.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\log.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\mutex.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\re.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\sleep.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\stat.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\string_util.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\sysinfo.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\third_party\google_benchmark\src\timers.h">
+      <Filter>third_party\google_benchmark\src</Filter>
+    </ClInclude>
+  </ItemGroup>
 
   <ItemGroup>
+    <Filter Include="third_party">
+      <UniqueIdentifier>{7458b63d-7ba4-103d-2bed-3e3ad30d8237}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="third_party\google_benchmark">
+      <UniqueIdentifier>{54a154e8-669b-a7c1-9b6e-bd1aab2f86e3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="third_party\google_benchmark\include">
+      <UniqueIdentifier>{f54c3cb1-ec20-a651-6956-78379b51e1a5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="third_party\google_benchmark\include\benchmark">
+      <UniqueIdentifier>{0483a457-8050-4565-bc15-09695bf7b822}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="third_party\google_benchmark\src">
+      <UniqueIdentifier>{c39ff2d1-691e-4614-4d75-4bc20db05e09}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
 </Project>
 
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index e8946043b645b5180ea8d9c99d756c8fa94214e1..f281db72b6675506ab42685ae004772f97746a7f 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -400,6 +400,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\version_cc.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\create_default_thread_pool.cc">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index e7d6d557f1191402f6f28022b16e558937be0f1d..f359e4ef31ad032401244b72f29cda5ac3a7026d 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -64,6 +64,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\version_cc.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 17285752422fcba0aba24f11efe0320ca0189ff0..1511a2cfe4cec342e194c6f20563ce9b7ae15d9a 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -386,6 +386,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\version_cc.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\create_default_thread_pool.cc">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 7fc8ed33fcd1753ed4783a39eedccc909350fe1f..bed77b25a449d859bb76cbc5ebb61bbe21dcd617 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -49,6 +49,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\version_cc.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index d9d0d42d677bc99e8e86ff43dad6fddd136602eb..138246668f6298237db89493b9c01a6432518b97 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -385,6 +385,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
@@ -679,6 +680,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index ab9b76073cfc21cc4c19c4f3940afe33661e762e..c7b9b6664a53350fceab93a50920cca4c46aa20b 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -313,6 +313,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
@@ -977,6 +980,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 39c144d992ffd44b80f7ba79c1200433386542dd..40ec6cc8163234c41d599b732981e119335929f6 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -278,6 +278,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
@@ -530,6 +531,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 0fbfc3acd3726f41fca962c0b1fbd0ad2ffdbfcc..3a973616ecca2969736c31f213d0343f3a6c7961 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -370,6 +370,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
@@ -773,6 +776,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 87e3921ff96ffa1fe6fa90f8320ef42cb160f932..5573fc5cde7f9e7fe0096894b5b35216a33ab0fe 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -375,6 +375,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
@@ -647,6 +648,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 1e719226faf4957a304a14d9e73939710934b0ad..985abf7610866f5900849b9751b04ca0249a6e29 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -316,6 +316,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\method_config.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
@@ -890,6 +893,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\method_config.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
index a47c40f0f7358315bb37a64b2321be297a07bd90..3d510d5156858c849b64f216b6bbe3f834aa8ca8 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
@@ -153,6 +153,8 @@
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_nosec_tests.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_test_utils.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_hostname.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\binary_metadata.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
index 71cf6838fe2089fe14809789280543efb8efc15b..a0b01ddbc892eff0ab24d406acaba354badf7abd 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
@@ -4,6 +4,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_nosec_tests.c">
       <Filter>test\core\end2end</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_test_utils.c">
+      <Filter>test\core\end2end</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_hostname.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
index 68ff5f1ebd85e1e0573c9de85aaccb41ecd998bd..5699e8308ed16d9748a06d68e8c73c9d6e9af15f 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
@@ -153,6 +153,8 @@
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_tests.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_test_utils.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_hostname.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\binary_metadata.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
index 7a620f61a54151bd02a5b01eab816b7b894731f6..bfb5e2b2292453663683a51e2acd629d25c2336f 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
@@ -4,6 +4,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_tests.c">
       <Filter>test\core\end2end</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_test_utils.c">
+      <Filter>test\core\end2end</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_hostname.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/test/transport_pid_controller_test/transport_pid_controller_test.vcxproj b/vsprojects/vcxproj/test/transport_pid_controller_test/transport_pid_controller_test.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..b37310d7b07e417edeb336072a1ff1d9263b73cc
--- /dev/null
+++ b/vsprojects/vcxproj/test/transport_pid_controller_test/transport_pid_controller_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B8790A2E-1106-2510-9D95-32C1D68E72EE}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>transport_pid_controller_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>transport_pid_controller_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\transport\pid_controller_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/transport_pid_controller_test/transport_pid_controller_test.vcxproj.filters b/vsprojects/vcxproj/test/transport_pid_controller_test/transport_pid_controller_test.vcxproj.filters
new file mode 100644
index 0000000000000000000000000000000000000000..bfc3b8baf1774e71ad4f7d0bbf75fa3af1d7ef25
--- /dev/null
+++ b/vsprojects/vcxproj/test/transport_pid_controller_test/transport_pid_controller_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\transport\pid_controller_test.c">
+      <Filter>test\core\transport</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{dd5fb527-8567-108a-e6d2-51380df8a82f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{18437a81-c8a9-fd37-ad74-63e9ebf0eb7a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\transport">
+      <UniqueIdentifier>{6325372c-19b9-37ab-e8ff-16554de3bb3b}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+